823 lines
27 KiB
JavaScript
823 lines
27 KiB
JavaScript
|
/* ***** BEGIN LICENSE BLOCK *****
|
||
|
* Distributed under the BSD license:
|
||
|
*
|
||
|
* Copyright (c) 2010, Ajax.org B.V.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions are met:
|
||
|
* * Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* * Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in the
|
||
|
* documentation and/or other materials provided with the distribution.
|
||
|
* * Neither the name of Ajax.org B.V. nor the
|
||
|
* names of its contributors may be used to endorse or promote products
|
||
|
* derived from this software without specific prior written permission.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||
|
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||
|
*
|
||
|
* ***** END LICENSE BLOCK ***** */
|
||
|
|
||
|
ace.define('ace/mode/xml', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/text', 'ace/tokenizer', 'ace/mode/xml_highlight_rules', 'ace/mode/behaviour/xml', 'ace/mode/folding/xml'], function(require, exports, module) {
|
||
|
|
||
|
|
||
|
var oop = require("../lib/oop");
|
||
|
var TextMode = require("./text").Mode;
|
||
|
var Tokenizer = require("../tokenizer").Tokenizer;
|
||
|
var XmlHighlightRules = require("./xml_highlight_rules").XmlHighlightRules;
|
||
|
var XmlBehaviour = require("./behaviour/xml").XmlBehaviour;
|
||
|
var XmlFoldMode = require("./folding/xml").FoldMode;
|
||
|
|
||
|
var Mode = function() {
|
||
|
this.$tokenizer = new Tokenizer(new XmlHighlightRules().getRules());
|
||
|
this.$behaviour = new XmlBehaviour();
|
||
|
this.foldingRules = new XmlFoldMode();
|
||
|
};
|
||
|
|
||
|
oop.inherits(Mode, TextMode);
|
||
|
|
||
|
(function() {
|
||
|
|
||
|
this.getNextLineIndent = function(state, line, tab) {
|
||
|
return this.$getIndent(line);
|
||
|
};
|
||
|
|
||
|
}).call(Mode.prototype);
|
||
|
|
||
|
exports.Mode = Mode;
|
||
|
});
|
||
|
|
||
|
ace.define('ace/mode/xml_highlight_rules', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/xml_util', 'ace/mode/text_highlight_rules'], function(require, exports, module) {
|
||
|
|
||
|
|
||
|
var oop = require("../lib/oop");
|
||
|
var xmlUtil = require("./xml_util");
|
||
|
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
|
||
|
|
||
|
var XmlHighlightRules = function() {
|
||
|
|
||
|
// regexp must not have capturing parentheses
|
||
|
// regexps are ordered -> the first match is used
|
||
|
this.$rules = {
|
||
|
start : [{
|
||
|
token : "text",
|
||
|
regex : "<\\!\\[CDATA\\[",
|
||
|
next : "cdata"
|
||
|
}, {
|
||
|
token : "xml_pe",
|
||
|
regex : "<\\?.*?\\?>"
|
||
|
}, {
|
||
|
token : "comment",
|
||
|
merge : true,
|
||
|
regex : "<\\!--",
|
||
|
next : "comment"
|
||
|
}, {
|
||
|
token : "xml_pe",
|
||
|
regex : "<\\!.*?>"
|
||
|
}, {
|
||
|
token : "meta.tag", // opening tag
|
||
|
regex : "<\\/?",
|
||
|
next : "tag"
|
||
|
}, {
|
||
|
token : "text",
|
||
|
regex : "\\s+"
|
||
|
}, {
|
||
|
token : "constant.character.entity",
|
||
|
regex : "(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)"
|
||
|
}, {
|
||
|
token : "text",
|
||
|
regex : "[^<]+"
|
||
|
}],
|
||
|
|
||
|
cdata : [{
|
||
|
token : "text",
|
||
|
regex : "\\]\\]>",
|
||
|
next : "start"
|
||
|
}, {
|
||
|
token : "text",
|
||
|
regex : "\\s+"
|
||
|
}, {
|
||
|
token : "text",
|
||
|
regex : "(?:[^\\]]|\\](?!\\]>))+"
|
||
|
}],
|
||
|
|
||
|
comment : [{
|
||
|
token : "comment",
|
||
|
regex : ".*?-->",
|
||
|
next : "start"
|
||
|
}, {
|
||
|
token : "comment",
|
||
|
merge : true,
|
||
|
regex : ".+"
|
||
|
}]
|
||
|
};
|
||
|
|
||
|
xmlUtil.tag(this.$rules, "tag", "start");
|
||
|
};
|
||
|
|
||
|
oop.inherits(XmlHighlightRules, TextHighlightRules);
|
||
|
|
||
|
exports.XmlHighlightRules = XmlHighlightRules;
|
||
|
});
|
||
|
|
||
|
ace.define('ace/mode/xml_util', ['require', 'exports', 'module' ], function(require, exports, module) {
|
||
|
|
||
|
|
||
|
function string(state) {
|
||
|
return [{
|
||
|
token : "string",
|
||
|
regex : '".*?"'
|
||
|
}, {
|
||
|
token : "string", // multi line string start
|
||
|
merge : true,
|
||
|
regex : '["].*',
|
||
|
next : state + "_qqstring"
|
||
|
}, {
|
||
|
token : "string",
|
||
|
regex : "'.*?'"
|
||
|
}, {
|
||
|
token : "string", // multi line string start
|
||
|
merge : true,
|
||
|
regex : "['].*",
|
||
|
next : state + "_qstring"
|
||
|
}];
|
||
|
}
|
||
|
|
||
|
function multiLineString(quote, state) {
|
||
|
return [{
|
||
|
token : "string",
|
||
|
merge : true,
|
||
|
regex : ".*?" + quote,
|
||
|
next : state
|
||
|
}, {
|
||
|
token : "string",
|
||
|
merge : true,
|
||
|
regex : '.+'
|
||
|
}];
|
||
|
}
|
||
|
|
||
|
exports.tag = function(states, name, nextState, tagMap) {
|
||
|
states[name] = [{
|
||
|
token : "text",
|
||
|
regex : "\\s+"
|
||
|
}, {
|
||
|
//token : "meta.tag",
|
||
|
|
||
|
token : !tagMap ? "meta.tag.tag-name" : function(value) {
|
||
|
if (tagMap[value])
|
||
|
return "meta.tag.tag-name." + tagMap[value];
|
||
|
else
|
||
|
return "meta.tag.tag-name";
|
||
|
},
|
||
|
merge : true,
|
||
|
regex : "[-_a-zA-Z0-9:]+",
|
||
|
next : name + "_embed_attribute_list"
|
||
|
}, {
|
||
|
token: "empty",
|
||
|
regex: "",
|
||
|
next : name + "_embed_attribute_list"
|
||
|
}];
|
||
|
|
||
|
states[name + "_qstring"] = multiLineString("'", name + "_embed_attribute_list");
|
||
|
states[name + "_qqstring"] = multiLineString("\"", name + "_embed_attribute_list");
|
||
|
|
||
|
states[name + "_embed_attribute_list"] = [{
|
||
|
token : "meta.tag",
|
||
|
merge : true,
|
||
|
regex : "\/?>",
|
||
|
next : nextState
|
||
|
}, {
|
||
|
token : "keyword.operator",
|
||
|
regex : "="
|
||
|
}, {
|
||
|
token : "entity.other.attribute-name",
|
||
|
regex : "[-_a-zA-Z0-9:]+"
|
||
|
}, {
|
||
|
token : "constant.numeric", // float
|
||
|
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
|
||
|
}, {
|
||
|
token : "text",
|
||
|
regex : "\\s+"
|
||
|
}].concat(string(name));
|
||
|
};
|
||
|
|
||
|
});
|
||
|
|
||
|
ace.define('ace/mode/behaviour/xml', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/behaviour', 'ace/mode/behaviour/cstyle', 'ace/token_iterator'], function(require, exports, module) {
|
||
|
|
||
|
|
||
|
var oop = require("../../lib/oop");
|
||
|
var Behaviour = require("../behaviour").Behaviour;
|
||
|
var CstyleBehaviour = require("./cstyle").CstyleBehaviour;
|
||
|
var TokenIterator = require("../../token_iterator").TokenIterator;
|
||
|
|
||
|
function hasType(token, type) {
|
||
|
var hasType = true;
|
||
|
var typeList = token.type.split('.');
|
||
|
var needleList = type.split('.');
|
||
|
needleList.forEach(function(needle){
|
||
|
if (typeList.indexOf(needle) == -1) {
|
||
|
hasType = false;
|
||
|
return false;
|
||
|
}
|
||
|
});
|
||
|
return hasType;
|
||
|
}
|
||
|
|
||
|
var XmlBehaviour = function () {
|
||
|
|
||
|
this.inherit(CstyleBehaviour, ["string_dquotes"]); // Get string behaviour
|
||
|
|
||
|
this.add("autoclosing", "insertion", function (state, action, editor, session, text) {
|
||
|
if (text == '>') {
|
||
|
var position = editor.getCursorPosition();
|
||
|
var iterator = new TokenIterator(session, position.row, position.column);
|
||
|
var token = iterator.getCurrentToken();
|
||
|
var atCursor = false;
|
||
|
if (!token || !hasType(token, 'meta.tag') && !(hasType(token, 'text') && token.value.match('/'))){
|
||
|
do {
|
||
|
token = iterator.stepBackward();
|
||
|
} while (token && (hasType(token, 'string') || hasType(token, 'keyword.operator') || hasType(token, 'entity.attribute-name') || hasType(token, 'text')));
|
||
|
} else {
|
||
|
atCursor = true;
|
||
|
}
|
||
|
if (!token || !hasType(token, 'meta.tag-name') || iterator.stepBackward().value.match('/')) {
|
||
|
return
|
||
|
}
|
||
|
var tag = token.value;
|
||
|
if (atCursor){
|
||
|
var tag = tag.substring(0, position.column - token.start);
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
text: '>' + '</' + tag + '>',
|
||
|
selection: [1, 1]
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.add('autoindent', 'insertion', function (state, action, editor, session, text) {
|
||
|
if (text == "\n") {
|
||
|
var cursor = editor.getCursorPosition();
|
||
|
var line = session.doc.getLine(cursor.row);
|
||
|
var rightChars = line.substring(cursor.column, cursor.column + 2);
|
||
|
if (rightChars == '</') {
|
||
|
var indent = this.$getIndent(session.doc.getLine(cursor.row)) + session.getTabString();
|
||
|
var next_indent = this.$getIndent(session.doc.getLine(cursor.row));
|
||
|
|
||
|
return {
|
||
|
text: '\n' + indent + '\n' + next_indent,
|
||
|
selection: [1, indent.length, 1, indent.length]
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
}
|
||
|
oop.inherits(XmlBehaviour, Behaviour);
|
||
|
|
||
|
exports.XmlBehaviour = XmlBehaviour;
|
||
|
});
|
||
|
|
||
|
ace.define('ace/mode/behaviour/cstyle', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/behaviour'], function(require, exports, module) {
|
||
|
|
||
|
|
||
|
var oop = require("../../lib/oop");
|
||
|
var Behaviour = require("../behaviour").Behaviour;
|
||
|
|
||
|
var CstyleBehaviour = function () {
|
||
|
|
||
|
this.add("braces", "insertion", function (state, action, editor, session, text) {
|
||
|
if (text == '{') {
|
||
|
var selection = editor.getSelectionRange();
|
||
|
var selected = session.doc.getTextRange(selection);
|
||
|
if (selected !== "") {
|
||
|
return {
|
||
|
text: '{' + selected + '}',
|
||
|
selection: false
|
||
|
};
|
||
|
} else {
|
||
|
return {
|
||
|
text: '{}',
|
||
|
selection: [1, 1]
|
||
|
};
|
||
|
}
|
||
|
} else if (text == '}') {
|
||
|
var cursor = editor.getCursorPosition();
|
||
|
var line = session.doc.getLine(cursor.row);
|
||
|
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
||
|
if (rightChar == '}') {
|
||
|
var matching = session.$findOpeningBracket('}', {column: cursor.column + 1, row: cursor.row});
|
||
|
if (matching !== null) {
|
||
|
return {
|
||
|
text: '',
|
||
|
selection: [1, 1]
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
} else if (text == "\n") {
|
||
|
var cursor = editor.getCursorPosition();
|
||
|
var line = session.doc.getLine(cursor.row);
|
||
|
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
||
|
if (rightChar == '}') {
|
||
|
var openBracePos = session.findMatchingBracket({row: cursor.row, column: cursor.column + 1});
|
||
|
if (!openBracePos)
|
||
|
return null;
|
||
|
|
||
|
var indent = this.getNextLineIndent(state, line.substring(0, line.length - 1), session.getTabString());
|
||
|
var next_indent = this.$getIndent(session.doc.getLine(openBracePos.row));
|
||
|
|
||
|
return {
|
||
|
text: '\n' + indent + '\n' + next_indent,
|
||
|
selection: [1, indent.length, 1, indent.length]
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.add("braces", "deletion", function (state, action, editor, session, range) {
|
||
|
var selected = session.doc.getTextRange(range);
|
||
|
if (!range.isMultiLine() && selected == '{') {
|
||
|
var line = session.doc.getLine(range.start.row);
|
||
|
var rightChar = line.substring(range.end.column, range.end.column + 1);
|
||
|
if (rightChar == '}') {
|
||
|
range.end.column++;
|
||
|
return range;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.add("parens", "insertion", function (state, action, editor, session, text) {
|
||
|
if (text == '(') {
|
||
|
var selection = editor.getSelectionRange();
|
||
|
var selected = session.doc.getTextRange(selection);
|
||
|
if (selected !== "") {
|
||
|
return {
|
||
|
text: '(' + selected + ')',
|
||
|
selection: false
|
||
|
};
|
||
|
} else {
|
||
|
return {
|
||
|
text: '()',
|
||
|
selection: [1, 1]
|
||
|
};
|
||
|
}
|
||
|
} else if (text == ')') {
|
||
|
var cursor = editor.getCursorPosition();
|
||
|
var line = session.doc.getLine(cursor.row);
|
||
|
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
||
|
if (rightChar == ')') {
|
||
|
var matching = session.$findOpeningBracket(')', {column: cursor.column + 1, row: cursor.row});
|
||
|
if (matching !== null) {
|
||
|
return {
|
||
|
text: '',
|
||
|
selection: [1, 1]
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.add("parens", "deletion", function (state, action, editor, session, range) {
|
||
|
var selected = session.doc.getTextRange(range);
|
||
|
if (!range.isMultiLine() && selected == '(') {
|
||
|
var line = session.doc.getLine(range.start.row);
|
||
|
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
|
||
|
if (rightChar == ')') {
|
||
|
range.end.column++;
|
||
|
return range;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.add("brackets", "insertion", function (state, action, editor, session, text) {
|
||
|
if (text == '[') {
|
||
|
var selection = editor.getSelectionRange();
|
||
|
var selected = session.doc.getTextRange(selection);
|
||
|
if (selected !== "") {
|
||
|
return {
|
||
|
text: '[' + selected + ']',
|
||
|
selection: false
|
||
|
};
|
||
|
} else {
|
||
|
return {
|
||
|
text: '[]',
|
||
|
selection: [1, 1]
|
||
|
};
|
||
|
}
|
||
|
} else if (text == ']') {
|
||
|
var cursor = editor.getCursorPosition();
|
||
|
var line = session.doc.getLine(cursor.row);
|
||
|
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
||
|
if (rightChar == ']') {
|
||
|
var matching = session.$findOpeningBracket(']', {column: cursor.column + 1, row: cursor.row});
|
||
|
if (matching !== null) {
|
||
|
return {
|
||
|
text: '',
|
||
|
selection: [1, 1]
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.add("brackets", "deletion", function (state, action, editor, session, range) {
|
||
|
var selected = session.doc.getTextRange(range);
|
||
|
if (!range.isMultiLine() && selected == '[') {
|
||
|
var line = session.doc.getLine(range.start.row);
|
||
|
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
|
||
|
if (rightChar == ']') {
|
||
|
range.end.column++;
|
||
|
return range;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.add("string_dquotes", "insertion", function (state, action, editor, session, text) {
|
||
|
if (text == '"' || text == "'") {
|
||
|
var quote = text;
|
||
|
var selection = editor.getSelectionRange();
|
||
|
var selected = session.doc.getTextRange(selection);
|
||
|
if (selected !== "") {
|
||
|
return {
|
||
|
text: quote + selected + quote,
|
||
|
selection: false
|
||
|
};
|
||
|
} else {
|
||
|
var cursor = editor.getCursorPosition();
|
||
|
var line = session.doc.getLine(cursor.row);
|
||
|
var leftChar = line.substring(cursor.column-1, cursor.column);
|
||
|
|
||
|
// We're escaped.
|
||
|
if (leftChar == '\\') {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
// Find what token we're inside.
|
||
|
var tokens = session.getTokens(selection.start.row);
|
||
|
var col = 0, token;
|
||
|
var quotepos = -1; // Track whether we're inside an open quote.
|
||
|
|
||
|
for (var x = 0; x < tokens.length; x++) {
|
||
|
token = tokens[x];
|
||
|
if (token.type == "string") {
|
||
|
quotepos = -1;
|
||
|
} else if (quotepos < 0) {
|
||
|
quotepos = token.value.indexOf(quote);
|
||
|
}
|
||
|
if ((token.value.length + col) > selection.start.column) {
|
||
|
break;
|
||
|
}
|
||
|
col += tokens[x].value.length;
|
||
|
}
|
||
|
|
||
|
// Try and be smart about when we auto insert.
|
||
|
if (!token || (quotepos < 0 && token.type !== "comment" && (token.type !== "string" || ((selection.start.column !== token.value.length+col-1) && token.value.lastIndexOf(quote) === token.value.length-1)))) {
|
||
|
return {
|
||
|
text: quote + quote,
|
||
|
selection: [1,1]
|
||
|
};
|
||
|
} else if (token && token.type === "string") {
|
||
|
// Ignore input and move right one if we're typing over the closing quote.
|
||
|
var rightChar = line.substring(cursor.column, cursor.column + 1);
|
||
|
if (rightChar == quote) {
|
||
|
return {
|
||
|
text: '',
|
||
|
selection: [1, 1]
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.add("string_dquotes", "deletion", function (state, action, editor, session, range) {
|
||
|
var selected = session.doc.getTextRange(range);
|
||
|
if (!range.isMultiLine() && (selected == '"' || selected == "'")) {
|
||
|
var line = session.doc.getLine(range.start.row);
|
||
|
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
|
||
|
if (rightChar == '"') {
|
||
|
range.end.column++;
|
||
|
return range;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
};
|
||
|
|
||
|
oop.inherits(CstyleBehaviour, Behaviour);
|
||
|
|
||
|
exports.CstyleBehaviour = CstyleBehaviour;
|
||
|
});
|
||
|
|
||
|
ace.define('ace/mode/folding/xml', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/lib/lang', 'ace/range', 'ace/mode/folding/fold_mode', 'ace/token_iterator'], function(require, exports, module) {
|
||
|
|
||
|
|
||
|
var oop = require("../../lib/oop");
|
||
|
var lang = require("../../lib/lang");
|
||
|
var Range = require("../../range").Range;
|
||
|
var BaseFoldMode = require("./fold_mode").FoldMode;
|
||
|
var TokenIterator = require("../../token_iterator").TokenIterator;
|
||
|
|
||
|
var FoldMode = exports.FoldMode = function(voidElements) {
|
||
|
BaseFoldMode.call(this);
|
||
|
this.voidElements = voidElements || {};
|
||
|
};
|
||
|
oop.inherits(FoldMode, BaseFoldMode);
|
||
|
|
||
|
(function() {
|
||
|
|
||
|
this.getFoldWidget = function(session, foldStyle, row) {
|
||
|
var tag = this._getFirstTagInLine(session, row);
|
||
|
|
||
|
if (tag.closing)
|
||
|
return foldStyle == "markbeginend" ? "end" : "";
|
||
|
|
||
|
if (!tag.tagName || this.voidElements[tag.tagName.toLowerCase()])
|
||
|
return "";
|
||
|
|
||
|
if (tag.selfClosing)
|
||
|
return "";
|
||
|
|
||
|
if (tag.value.indexOf("/" + tag.tagName) !== -1)
|
||
|
return "";
|
||
|
|
||
|
return "start";
|
||
|
};
|
||
|
|
||
|
this._getFirstTagInLine = function(session, row) {
|
||
|
var tokens = session.getTokens(row);
|
||
|
var value = "";
|
||
|
for (var i = 0; i < tokens.length; i++) {
|
||
|
var token = tokens[i];
|
||
|
if (token.type.indexOf("meta.tag") === 0)
|
||
|
value += token.value;
|
||
|
else
|
||
|
value += lang.stringRepeat(" ", token.value.length);
|
||
|
}
|
||
|
|
||
|
return this._parseTag(value);
|
||
|
};
|
||
|
|
||
|
this.tagRe = /^(\s*)(<?(\/?)([-_a-zA-Z0-9:!]*)\s*(\/?)>?)/;
|
||
|
this._parseTag = function(tag) {
|
||
|
|
||
|
var match = this.tagRe.exec(tag);
|
||
|
var column = this.tagRe.lastIndex || 0;
|
||
|
this.tagRe.lastIndex = 0;
|
||
|
|
||
|
return {
|
||
|
value: tag,
|
||
|
match: match ? match[2] : "",
|
||
|
closing: match ? !!match[3] : false,
|
||
|
selfClosing: match ? !!match[5] || match[2] == "/>" : false,
|
||
|
tagName: match ? match[4] : "",
|
||
|
column: match[1] ? column + match[1].length : column
|
||
|
};
|
||
|
};
|
||
|
this._readTagForward = function(iterator) {
|
||
|
var token = iterator.getCurrentToken();
|
||
|
if (!token)
|
||
|
return null;
|
||
|
|
||
|
var value = "";
|
||
|
var start;
|
||
|
|
||
|
do {
|
||
|
if (token.type.indexOf("meta.tag") === 0) {
|
||
|
if (!start) {
|
||
|
var start = {
|
||
|
row: iterator.getCurrentTokenRow(),
|
||
|
column: iterator.getCurrentTokenColumn()
|
||
|
};
|
||
|
}
|
||
|
value += token.value;
|
||
|
if (value.indexOf(">") !== -1) {
|
||
|
var tag = this._parseTag(value);
|
||
|
tag.start = start;
|
||
|
tag.end = {
|
||
|
row: iterator.getCurrentTokenRow(),
|
||
|
column: iterator.getCurrentTokenColumn() + token.value.length
|
||
|
};
|
||
|
iterator.stepForward();
|
||
|
return tag;
|
||
|
}
|
||
|
}
|
||
|
} while(token = iterator.stepForward());
|
||
|
|
||
|
return null;
|
||
|
};
|
||
|
|
||
|
this._readTagBackward = function(iterator) {
|
||
|
var token = iterator.getCurrentToken();
|
||
|
if (!token)
|
||
|
return null;
|
||
|
|
||
|
var value = "";
|
||
|
var end;
|
||
|
|
||
|
do {
|
||
|
if (token.type.indexOf("meta.tag") === 0) {
|
||
|
if (!end) {
|
||
|
end = {
|
||
|
row: iterator.getCurrentTokenRow(),
|
||
|
column: iterator.getCurrentTokenColumn() + token.value.length
|
||
|
};
|
||
|
}
|
||
|
value = token.value + value;
|
||
|
if (value.indexOf("<") !== -1) {
|
||
|
var tag = this._parseTag(value);
|
||
|
tag.end = end;
|
||
|
tag.start = {
|
||
|
row: iterator.getCurrentTokenRow(),
|
||
|
column: iterator.getCurrentTokenColumn()
|
||
|
};
|
||
|
iterator.stepBackward();
|
||
|
return tag;
|
||
|
}
|
||
|
}
|
||
|
} while(token = iterator.stepBackward());
|
||
|
|
||
|
return null;
|
||
|
};
|
||
|
|
||
|
this._pop = function(stack, tag) {
|
||
|
while (stack.length) {
|
||
|
|
||
|
var top = stack[stack.length-1];
|
||
|
if (!tag || top.tagName == tag.tagName) {
|
||
|
return stack.pop();
|
||
|
}
|
||
|
else if (this.voidElements[tag.tagName]) {
|
||
|
return;
|
||
|
}
|
||
|
else if (this.voidElements[top.tagName]) {
|
||
|
stack.pop();
|
||
|
continue;
|
||
|
} else {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.getFoldWidgetRange = function(session, foldStyle, row) {
|
||
|
var firstTag = this._getFirstTagInLine(session, row);
|
||
|
|
||
|
if (!firstTag.match)
|
||
|
return null;
|
||
|
|
||
|
var isBackward = firstTag.closing || firstTag.selfClosing;
|
||
|
var stack = [];
|
||
|
var tag;
|
||
|
|
||
|
if (!isBackward) {
|
||
|
var iterator = new TokenIterator(session, row, firstTag.column);
|
||
|
var start = {
|
||
|
row: row,
|
||
|
column: firstTag.column + firstTag.tagName.length + 2
|
||
|
};
|
||
|
while (tag = this._readTagForward(iterator)) {
|
||
|
if (tag.selfClosing) {
|
||
|
if (!stack.length) {
|
||
|
tag.start.column += tag.tagName.length + 2;
|
||
|
tag.end.column -= 2;
|
||
|
return Range.fromPoints(tag.start, tag.end);
|
||
|
} else
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (tag.closing) {
|
||
|
this._pop(stack, tag);
|
||
|
if (stack.length == 0)
|
||
|
return Range.fromPoints(start, tag.start);
|
||
|
}
|
||
|
else {
|
||
|
stack.push(tag)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
var iterator = new TokenIterator(session, row, firstTag.column + firstTag.match.length);
|
||
|
var end = {
|
||
|
row: row,
|
||
|
column: firstTag.column
|
||
|
};
|
||
|
|
||
|
while (tag = this._readTagBackward(iterator)) {
|
||
|
if (tag.selfClosing) {
|
||
|
if (!stack.length) {
|
||
|
tag.start.column += tag.tagName.length + 2;
|
||
|
tag.end.column -= 2;
|
||
|
return Range.fromPoints(tag.start, tag.end);
|
||
|
} else
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (!tag.closing) {
|
||
|
this._pop(stack, tag);
|
||
|
if (stack.length == 0) {
|
||
|
tag.start.column += tag.tagName.length + 2;
|
||
|
return Range.fromPoints(tag.start, end);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
stack.push(tag)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
}).call(FoldMode.prototype);
|
||
|
|
||
|
});
|
||
|
|
||
|
ace.define('ace/mode/folding/fold_mode', ['require', 'exports', 'module' , 'ace/range'], function(require, exports, module) {
|
||
|
|
||
|
|
||
|
var Range = require("../../range").Range;
|
||
|
|
||
|
var FoldMode = exports.FoldMode = function() {};
|
||
|
|
||
|
(function() {
|
||
|
|
||
|
this.foldingStartMarker = null;
|
||
|
this.foldingStopMarker = null;
|
||
|
|
||
|
// must return "" if there's no fold, to enable caching
|
||
|
this.getFoldWidget = function(session, foldStyle, row) {
|
||
|
var line = session.getLine(row);
|
||
|
if (this.foldingStartMarker.test(line))
|
||
|
return "start";
|
||
|
if (foldStyle == "markbeginend"
|
||
|
&& this.foldingStopMarker
|
||
|
&& this.foldingStopMarker.test(line))
|
||
|
return "end";
|
||
|
return "";
|
||
|
};
|
||
|
|
||
|
this.getFoldWidgetRange = function(session, foldStyle, row) {
|
||
|
return null;
|
||
|
};
|
||
|
|
||
|
this.indentationBlock = function(session, row, column) {
|
||
|
var re = /\S/;
|
||
|
var line = session.getLine(row);
|
||
|
var startLevel = line.search(re);
|
||
|
if (startLevel == -1)
|
||
|
return;
|
||
|
|
||
|
var startColumn = column || line.length;
|
||
|
var maxRow = session.getLength();
|
||
|
var startRow = row;
|
||
|
var endRow = row;
|
||
|
|
||
|
while (++row < maxRow) {
|
||
|
var level = session.getLine(row).search(re);
|
||
|
|
||
|
if (level == -1)
|
||
|
continue;
|
||
|
|
||
|
if (level <= startLevel)
|
||
|
break;
|
||
|
|
||
|
endRow = row;
|
||
|
}
|
||
|
|
||
|
if (endRow > startRow) {
|
||
|
var endColumn = session.getLine(endRow).length;
|
||
|
return new Range(startRow, startColumn, endRow, endColumn);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
this.openingBracketBlock = function(session, bracket, row, column, typeRe) {
|
||
|
var start = {row: row, column: column + 1};
|
||
|
var end = session.$findClosingBracket(bracket, start, typeRe);
|
||
|
if (!end)
|
||
|
return;
|
||
|
|
||
|
var fw = session.foldWidgets[end.row];
|
||
|
if (fw == null)
|
||
|
fw = this.getFoldWidget(session, end.row);
|
||
|
|
||
|
if (fw == "start" && end.row > start.row) {
|
||
|
end.row --;
|
||
|
end.column = session.getLine(end.row).length;
|
||
|
}
|
||
|
return Range.fromPoints(start, end);
|
||
|
};
|
||
|
|
||
|
}).call(FoldMode.prototype);
|
||
|
|
||
|
});
|