1
/* ***** BEGIN LICENSE BLOCK *****
2
* Distributed under the BSD license:
4
* Copyright (c) 2010, Ajax.org B.V.
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions are met:
9
* * Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* * Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
* * Neither the name of Ajax.org B.V. nor the
15
* names of its contributors may be used to endorse or promote products
16
* derived from this software without specific prior written permission.
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
22
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
* ***** END LICENSE BLOCK ***** */
31
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) {
34
var oop = require("../lib/oop");
35
var TextMode = require("./text").Mode;
36
var Tokenizer = require("../tokenizer").Tokenizer;
37
var XmlHighlightRules = require("./xml_highlight_rules").XmlHighlightRules;
38
var XmlBehaviour = require("./behaviour/xml").XmlBehaviour;
39
var XmlFoldMode = require("./folding/xml").FoldMode;
41
var Mode = function() {
42
this.$tokenizer = new Tokenizer(new XmlHighlightRules().getRules());
43
this.$behaviour = new XmlBehaviour();
44
this.foldingRules = new XmlFoldMode();
47
oop.inherits(Mode, TextMode);
51
this.blockComment = {start: "<!--", end: "-->"};
53
}).call(Mode.prototype);
58
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) {
61
var oop = require("../lib/oop");
62
var xmlUtil = require("./xml_util");
63
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
65
var XmlHighlightRules = function() {
68
{token : "text", regex : "<\\!\\[CDATA\\[", next : "cdata"},
69
{token : "xml-pe", regex : "<\\?.*?\\?>"},
70
{token : "comment", regex : "<\\!--", next : "comment"},
71
{token : "xml-pe", regex : "<\\!.*?>"},
72
{token : "meta.tag", regex : "<\\/?", next : "tag"},
73
{token : "text", regex : "\\s+"},
75
token : "constant.character.entity",
76
regex : "(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)"
81
{token : "text", regex : "\\]\\]>", next : "start"},
82
{token : "text", regex : "\\s+"},
83
{token : "text", regex : "(?:[^\\]]|\\](?!\\]>))+"}
87
{token : "comment", regex : ".*?-->", next : "start"},
88
{token : "comment", regex : ".+"}
92
xmlUtil.tag(this.$rules, "tag", "start");
95
oop.inherits(XmlHighlightRules, TextHighlightRules);
97
exports.XmlHighlightRules = XmlHighlightRules;
100
define('ace/mode/xml_util', ['require', 'exports', 'module' ], function(require, exports, module) {
103
function string(state) {
107
next : state + "_qqstring"
111
next : state + "_qstring"
115
function multiLineString(quote, state) {
117
{token : "string", regex : quote, next : state},
119
token : "constant.language.escape",
120
regex : "(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)"
122
{defaultToken : "string"}
126
exports.tag = function(states, name, nextState, tagMap) {
132
token : !tagMap ? "meta.tag.tag-name" : function(value) {
134
return "meta.tag.tag-name." + tagMap[value];
136
return "meta.tag.tag-name";
138
regex : "[-_a-zA-Z0-9:]+",
139
next : name + "_embed_attribute_list"
143
next : name + "_embed_attribute_list"
146
states[name + "_qstring"] = multiLineString("'", name + "_embed_attribute_list");
147
states[name + "_qqstring"] = multiLineString("\"", name + "_embed_attribute_list");
149
states[name + "_embed_attribute_list"] = [{
150
token : "meta.tag.r",
154
token : "keyword.operator",
157
token : "entity.other.attribute-name",
158
regex : "[-_a-zA-Z0-9:]+"
160
token : "constant.numeric", // float
161
regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
165
}].concat(string(name));
170
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) {
173
var oop = require("../../lib/oop");
174
var Behaviour = require("../behaviour").Behaviour;
175
var CstyleBehaviour = require("./cstyle").CstyleBehaviour;
176
var TokenIterator = require("../../token_iterator").TokenIterator;
178
function hasType(token, type) {
180
var typeList = token.type.split('.');
181
var needleList = type.split('.');
182
needleList.forEach(function(needle){
183
if (typeList.indexOf(needle) == -1) {
191
var XmlBehaviour = function () {
193
this.inherit(CstyleBehaviour, ["string_dquotes"]); // Get string behaviour
195
this.add("autoclosing", "insertion", function (state, action, editor, session, text) {
197
var position = editor.getCursorPosition();
198
var iterator = new TokenIterator(session, position.row, position.column);
199
var token = iterator.getCurrentToken();
200
var atCursor = false;
201
if (!token || !hasType(token, 'meta.tag') && !(hasType(token, 'text') && token.value.match('/'))){
203
token = iterator.stepBackward();
204
} while (token && (hasType(token, 'string') || hasType(token, 'keyword.operator') || hasType(token, 'entity.attribute-name') || hasType(token, 'text')));
208
if (!token || !hasType(token, 'meta.tag-name') || iterator.stepBackward().value.match('/')) {
211
var tag = token.value;
213
var tag = tag.substring(0, position.column - token.start);
217
text: '>' + '</' + tag + '>',
223
this.add('autoindent', 'insertion', function (state, action, editor, session, text) {
225
var cursor = editor.getCursorPosition();
226
var line = session.doc.getLine(cursor.row);
227
var rightChars = line.substring(cursor.column, cursor.column + 2);
228
if (rightChars == '</') {
229
var indent = this.$getIndent(session.doc.getLine(cursor.row)) + session.getTabString();
230
var next_indent = this.$getIndent(session.doc.getLine(cursor.row));
233
text: '\n' + indent + '\n' + next_indent,
234
selection: [1, indent.length, 1, indent.length]
241
oop.inherits(XmlBehaviour, Behaviour);
243
exports.XmlBehaviour = XmlBehaviour;
246
define('ace/mode/behaviour/cstyle', ['require', 'exports', 'module' , 'ace/lib/oop', 'ace/mode/behaviour', 'ace/token_iterator', 'ace/lib/lang'], function(require, exports, module) {
249
var oop = require("../../lib/oop");
250
var Behaviour = require("../behaviour").Behaviour;
251
var TokenIterator = require("../../token_iterator").TokenIterator;
252
var lang = require("../../lib/lang");
254
var SAFE_INSERT_IN_TOKENS =
255
["text", "paren.rparen", "punctuation.operator"];
256
var SAFE_INSERT_BEFORE_TOKENS =
257
["text", "paren.rparen", "punctuation.operator", "comment"];
260
var autoInsertedBrackets = 0;
261
var autoInsertedRow = -1;
262
var autoInsertedLineEnd = "";
263
var maybeInsertedBrackets = 0;
264
var maybeInsertedRow = -1;
265
var maybeInsertedLineStart = "";
266
var maybeInsertedLineEnd = "";
268
var CstyleBehaviour = function () {
270
CstyleBehaviour.isSaneInsertion = function(editor, session) {
271
var cursor = editor.getCursorPosition();
272
var iterator = new TokenIterator(session, cursor.row, cursor.column);
273
if (!this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS)) {
274
var iterator2 = new TokenIterator(session, cursor.row, cursor.column + 1);
275
if (!this.$matchTokenType(iterator2.getCurrentToken() || "text", SAFE_INSERT_IN_TOKENS))
278
iterator.stepForward();
279
return iterator.getCurrentTokenRow() !== cursor.row ||
280
this.$matchTokenType(iterator.getCurrentToken() || "text", SAFE_INSERT_BEFORE_TOKENS);
283
CstyleBehaviour.$matchTokenType = function(token, types) {
284
return types.indexOf(token.type || token) > -1;
287
CstyleBehaviour.recordAutoInsert = function(editor, session, bracket) {
288
var cursor = editor.getCursorPosition();
289
var line = session.doc.getLine(cursor.row);
290
if (!this.isAutoInsertedClosing(cursor, line, autoInsertedLineEnd[0]))
291
autoInsertedBrackets = 0;
292
autoInsertedRow = cursor.row;
293
autoInsertedLineEnd = bracket + line.substr(cursor.column);
294
autoInsertedBrackets++;
297
CstyleBehaviour.recordMaybeInsert = function(editor, session, bracket) {
298
var cursor = editor.getCursorPosition();
299
var line = session.doc.getLine(cursor.row);
300
if (!this.isMaybeInsertedClosing(cursor, line))
301
maybeInsertedBrackets = 0;
302
maybeInsertedRow = cursor.row;
303
maybeInsertedLineStart = line.substr(0, cursor.column) + bracket;
304
maybeInsertedLineEnd = line.substr(cursor.column);
305
maybeInsertedBrackets++;
308
CstyleBehaviour.isAutoInsertedClosing = function(cursor, line, bracket) {
309
return autoInsertedBrackets > 0 &&
310
cursor.row === autoInsertedRow &&
311
bracket === autoInsertedLineEnd[0] &&
312
line.substr(cursor.column) === autoInsertedLineEnd;
315
CstyleBehaviour.isMaybeInsertedClosing = function(cursor, line) {
316
return maybeInsertedBrackets > 0 &&
317
cursor.row === maybeInsertedRow &&
318
line.substr(cursor.column) === maybeInsertedLineEnd &&
319
line.substr(0, cursor.column) == maybeInsertedLineStart;
322
CstyleBehaviour.popAutoInsertedClosing = function() {
323
autoInsertedLineEnd = autoInsertedLineEnd.substr(1);
324
autoInsertedBrackets--;
327
CstyleBehaviour.clearMaybeInsertedClosing = function() {
328
maybeInsertedBrackets = 0;
329
maybeInsertedRow = -1;
332
this.add("braces", "insertion", function (state, action, editor, session, text) {
333
var cursor = editor.getCursorPosition();
334
var line = session.doc.getLine(cursor.row);
336
var selection = editor.getSelectionRange();
337
var selected = session.doc.getTextRange(selection);
338
if (selected !== "" && selected !== "{" && editor.getWrapBehavioursEnabled()) {
340
text: '{' + selected + '}',
343
} else if (CstyleBehaviour.isSaneInsertion(editor, session)) {
344
if (/[\]\}\)]/.test(line[cursor.column])) {
345
CstyleBehaviour.recordAutoInsert(editor, session, "}");
351
CstyleBehaviour.recordMaybeInsert(editor, session, "{");
358
} else if (text == '}') {
359
var rightChar = line.substring(cursor.column, cursor.column + 1);
360
if (rightChar == '}') {
361
var matching = session.$findOpeningBracket('}', {column: cursor.column + 1, row: cursor.row});
362
if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) {
363
CstyleBehaviour.popAutoInsertedClosing();
370
} else if (text == "\n" || text == "\r\n") {
372
if (CstyleBehaviour.isMaybeInsertedClosing(cursor, line)) {
373
closing = lang.stringRepeat("}", maybeInsertedBrackets);
374
CstyleBehaviour.clearMaybeInsertedClosing();
376
var rightChar = line.substring(cursor.column, cursor.column + 1);
377
if (rightChar == '}' || closing !== "") {
378
var openBracePos = session.findMatchingBracket({row: cursor.row, column: cursor.column}, '}');
382
var indent = this.getNextLineIndent(state, line.substring(0, cursor.column), session.getTabString());
383
var next_indent = this.$getIndent(line);
386
text: '\n' + indent + '\n' + next_indent + closing,
387
selection: [1, indent.length, 1, indent.length]
393
this.add("braces", "deletion", function (state, action, editor, session, range) {
394
var selected = session.doc.getTextRange(range);
395
if (!range.isMultiLine() && selected == '{') {
396
var line = session.doc.getLine(range.start.row);
397
var rightChar = line.substring(range.end.column, range.end.column + 1);
398
if (rightChar == '}') {
402
maybeInsertedBrackets--;
407
this.add("parens", "insertion", function (state, action, editor, session, text) {
409
var selection = editor.getSelectionRange();
410
var selected = session.doc.getTextRange(selection);
411
if (selected !== "" && editor.getWrapBehavioursEnabled()) {
413
text: '(' + selected + ')',
416
} else if (CstyleBehaviour.isSaneInsertion(editor, session)) {
417
CstyleBehaviour.recordAutoInsert(editor, session, ")");
423
} else if (text == ')') {
424
var cursor = editor.getCursorPosition();
425
var line = session.doc.getLine(cursor.row);
426
var rightChar = line.substring(cursor.column, cursor.column + 1);
427
if (rightChar == ')') {
428
var matching = session.$findOpeningBracket(')', {column: cursor.column + 1, row: cursor.row});
429
if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) {
430
CstyleBehaviour.popAutoInsertedClosing();
440
this.add("parens", "deletion", function (state, action, editor, session, range) {
441
var selected = session.doc.getTextRange(range);
442
if (!range.isMultiLine() && selected == '(') {
443
var line = session.doc.getLine(range.start.row);
444
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
445
if (rightChar == ')') {
452
this.add("brackets", "insertion", function (state, action, editor, session, text) {
454
var selection = editor.getSelectionRange();
455
var selected = session.doc.getTextRange(selection);
456
if (selected !== "" && editor.getWrapBehavioursEnabled()) {
458
text: '[' + selected + ']',
461
} else if (CstyleBehaviour.isSaneInsertion(editor, session)) {
462
CstyleBehaviour.recordAutoInsert(editor, session, "]");
468
} else if (text == ']') {
469
var cursor = editor.getCursorPosition();
470
var line = session.doc.getLine(cursor.row);
471
var rightChar = line.substring(cursor.column, cursor.column + 1);
472
if (rightChar == ']') {
473
var matching = session.$findOpeningBracket(']', {column: cursor.column + 1, row: cursor.row});
474
if (matching !== null && CstyleBehaviour.isAutoInsertedClosing(cursor, line, text)) {
475
CstyleBehaviour.popAutoInsertedClosing();
485
this.add("brackets", "deletion", function (state, action, editor, session, range) {
486
var selected = session.doc.getTextRange(range);
487
if (!range.isMultiLine() && selected == '[') {
488
var line = session.doc.getLine(range.start.row);
489
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
490
if (rightChar == ']') {
497
this.add("string_dquotes", "insertion", function (state, action, editor, session, text) {
498
if (text == '"' || text == "'") {
500
var selection = editor.getSelectionRange();
501
var selected = session.doc.getTextRange(selection);
502
if (selected !== "" && selected !== "'" && selected != '"' && editor.getWrapBehavioursEnabled()) {
504
text: quote + selected + quote,
508
var cursor = editor.getCursorPosition();
509
var line = session.doc.getLine(cursor.row);
510
var leftChar = line.substring(cursor.column-1, cursor.column);
511
if (leftChar == '\\') {
514
var tokens = session.getTokens(selection.start.row);
516
var quotepos = -1; // Track whether we're inside an open quote.
518
for (var x = 0; x < tokens.length; x++) {
520
if (token.type == "string") {
522
} else if (quotepos < 0) {
523
quotepos = token.value.indexOf(quote);
525
if ((token.value.length + col) > selection.start.column) {
528
col += tokens[x].value.length;
530
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)))) {
531
if (!CstyleBehaviour.isSaneInsertion(editor, session))
537
} else if (token && token.type === "string") {
538
var rightChar = line.substring(cursor.column, cursor.column + 1);
539
if (rightChar == quote) {
550
this.add("string_dquotes", "deletion", function (state, action, editor, session, range) {
551
var selected = session.doc.getTextRange(range);
552
if (!range.isMultiLine() && (selected == '"' || selected == "'")) {
553
var line = session.doc.getLine(range.start.row);
554
var rightChar = line.substring(range.start.column + 1, range.start.column + 2);
555
if (rightChar == selected) {
564
oop.inherits(CstyleBehaviour, Behaviour);
566
exports.CstyleBehaviour = CstyleBehaviour;
569
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) {
572
var oop = require("../../lib/oop");
573
var lang = require("../../lib/lang");
574
var Range = require("../../range").Range;
575
var BaseFoldMode = require("./fold_mode").FoldMode;
576
var TokenIterator = require("../../token_iterator").TokenIterator;
578
var FoldMode = exports.FoldMode = function(voidElements) {
579
BaseFoldMode.call(this);
580
this.voidElements = voidElements || {};
582
oop.inherits(FoldMode, BaseFoldMode);
586
this.getFoldWidget = function(session, foldStyle, row) {
587
var tag = this._getFirstTagInLine(session, row);
590
return foldStyle == "markbeginend" ? "end" : "";
592
if (!tag.tagName || this.voidElements[tag.tagName.toLowerCase()])
598
if (tag.value.indexOf("/" + tag.tagName) !== -1)
604
this._getFirstTagInLine = function(session, row) {
605
var tokens = session.getTokens(row);
607
for (var i = 0; i < tokens.length; i++) {
608
var token = tokens[i];
609
if (token.type.indexOf("meta.tag") === 0)
610
value += token.value;
612
value += lang.stringRepeat(" ", token.value.length);
615
return this._parseTag(value);
618
this.tagRe = /^(\s*)(<?(\/?)([-_a-zA-Z0-9:!]*)\s*(\/?)>?)/;
619
this._parseTag = function(tag) {
621
var match = this.tagRe.exec(tag);
622
var column = this.tagRe.lastIndex || 0;
623
this.tagRe.lastIndex = 0;
627
match: match ? match[2] : "",
628
closing: match ? !!match[3] : false,
629
selfClosing: match ? !!match[5] || match[2] == "/>" : false,
630
tagName: match ? match[4] : "",
631
column: match[1] ? column + match[1].length : column
634
this._readTagForward = function(iterator) {
635
var token = iterator.getCurrentToken();
643
if (token.type.indexOf("meta.tag") === 0) {
646
row: iterator.getCurrentTokenRow(),
647
column: iterator.getCurrentTokenColumn()
650
value += token.value;
651
if (value.indexOf(">") !== -1) {
652
var tag = this._parseTag(value);
655
row: iterator.getCurrentTokenRow(),
656
column: iterator.getCurrentTokenColumn() + token.value.length
658
iterator.stepForward();
662
} while(token = iterator.stepForward());
667
this._readTagBackward = function(iterator) {
668
var token = iterator.getCurrentToken();
676
if (token.type.indexOf("meta.tag") === 0) {
679
row: iterator.getCurrentTokenRow(),
680
column: iterator.getCurrentTokenColumn() + token.value.length
683
value = token.value + value;
684
if (value.indexOf("<") !== -1) {
685
var tag = this._parseTag(value);
688
row: iterator.getCurrentTokenRow(),
689
column: iterator.getCurrentTokenColumn()
691
iterator.stepBackward();
695
} while(token = iterator.stepBackward());
700
this._pop = function(stack, tag) {
701
while (stack.length) {
703
var top = stack[stack.length-1];
704
if (!tag || top.tagName == tag.tagName) {
707
else if (this.voidElements[tag.tagName]) {
710
else if (this.voidElements[top.tagName]) {
719
this.getFoldWidgetRange = function(session, foldStyle, row) {
720
var firstTag = this._getFirstTagInLine(session, row);
725
var isBackward = firstTag.closing || firstTag.selfClosing;
730
var iterator = new TokenIterator(session, row, firstTag.column);
733
column: firstTag.column + firstTag.tagName.length + 2
735
while (tag = this._readTagForward(iterator)) {
736
if (tag.selfClosing) {
738
tag.start.column += tag.tagName.length + 2;
740
return Range.fromPoints(tag.start, tag.end);
746
this._pop(stack, tag);
747
if (stack.length == 0)
748
return Range.fromPoints(start, tag.start);
756
var iterator = new TokenIterator(session, row, firstTag.column + firstTag.match.length);
759
column: firstTag.column
762
while (tag = this._readTagBackward(iterator)) {
763
if (tag.selfClosing) {
765
tag.start.column += tag.tagName.length + 2;
767
return Range.fromPoints(tag.start, tag.end);
773
this._pop(stack, tag);
774
if (stack.length == 0) {
775
tag.start.column += tag.tagName.length + 2;
776
return Range.fromPoints(tag.start, end);
787
}).call(FoldMode.prototype);