diff --git a/lib/ace/edit_session/folding.js b/lib/ace/edit_session/folding.js index 9cc829e4..46aacfea 100644 --- a/lib/ace/edit_session/folding.js +++ b/lib/ace/edit_session/folding.js @@ -391,7 +391,7 @@ function Folding() { this.removeFold(fold); }, this); this.$modified = true; - } + }; this.expandFold = function(fold) { this.removeFold(fold); @@ -399,13 +399,13 @@ function Folding() { this.addFold(fold); }, this); fold.subFolds = []; - } + }; this.expandFolds = function(folds) { folds.forEach(function(fold) { this.expandFold(fold); }, this); - } + }; this.unfold = function(location, expandInner) { var range, folds; @@ -418,7 +418,7 @@ function Folding() { else range = location; - var folds = this.getFoldsInRange(range); + folds = this.getFoldsInRange(range); if (expandInner) { this.removeFolds(folds); } else { @@ -429,7 +429,7 @@ function Folding() { folds = this.getFoldsInRange(range); } } - } + }; /** * Checks if a given documentRow is folded. This is true if there are some @@ -458,7 +458,6 @@ function Folding() { } // Build the textline using the FoldLine walker. - var line = ""; var doc = this.doc; var textLine = ""; @@ -494,7 +493,6 @@ function Folding() { }; this.$cloneFoldData = function() { - var foldData = this.$foldData; var fd = []; fd = this.$foldData.map(function(foldLine) { var folds = foldLine.folds.map(function(fold) { @@ -511,9 +509,9 @@ function Folding() { var range = selection.getRange(); if (range.isEmpty()) { - var cursor = range.start + var cursor = range.start; var fold = this.getFoldAt(cursor.row, cursor.column); - var bracketPos, column; + var bracketPos; if (fold) { this.expandFold(fold); @@ -601,7 +599,6 @@ function Folding() { continue var range = this.getFoldWidgetRange(row); - console.log(row, range) if (range) this.addFold("...", range) } @@ -771,7 +768,98 @@ Folding.commonFoldingRules = { } }, // TODO: folding based only on indentation - "indentation": null + "indentation": null, + + "xml": { + getFoldWidget: function(row) { + var tags = this.getTokens(row, row)[0].tokens + .filter(function(token) { + return token.type === "meta.tag" + }) + .map(function(token) { + return token.value; + }). + join("") + .trim() + .replace(/^<|>$|\s+/g, "") + .split("><") + + var fold = tags[0]; + + if (!fold) + return; + if (fold.charAt(0) == "/") + return "end"; + + if (tags.indexOf("/" + fold) !== -1) + return; + + return "start"; + }, + + getFoldWidgetRange: function(row) { + var start, end; + var stack = []; + + var iterator = new TokenIterator(this, row, 0); + var step = "stepForward"; + var isBack = false; + + do { + var token = iterator.getCurrentToken(); + + var value = token.value.trim(); + if (token && token.type == "meta.tag" && token.value !== ">") { + var tagName = value.replace(/^[<\s]*|[\s*>]$/g, ""); + if (!start) { + if (tagName.charAt(0) == "/") { + tagName = tagName.slice(1); + step = "stepBackward"; + isBack = true; + } + + start = { + row: row, + column: iterator.getCurrentTokenColumn() + (isBack ? 0 : value.length + 1) + }; + + stack.push(tagName); + } + else { + if (tagName.charAt(0) == "/") { + tagName = tagName.slice(1); + var close = !isBack; + } + else + close = isBack; + + if (close) { + if (stack[stack.length-1] == tagName) { + stack.pop(); + if (stack.length == 0) { + end = { + row: iterator.getCurrentTokenRow(), + column: iterator.getCurrentTokenColumn() + (isBack ? value.length : 0) + }; + if (isBack) + return Range.fromPoints(end, start); + else + return Range.fromPoints(start, end); + } + } + else { + console.error("unmatched tags!", tagName, stack) + } + } + else { + stack.push(tagName); + } + } + } + + } while(token = iterator[step]()); + } + } } exports.Folding = Folding; diff --git a/lib/ace/mode/html.js b/lib/ace/mode/html.js index 4f0c6b85..fe4975f2 100644 --- a/lib/ace/mode/html.js +++ b/lib/ace/mode/html.js @@ -60,6 +60,8 @@ oop.inherits(Mode, TextMode); (function() { + this.foldingRules = "xml"; + this.toggleCommentLines = function(state, doc, startRow, endRow) { return 0; }; diff --git a/lib/ace/mode/html_highlight_rules.js b/lib/ace/mode/html_highlight_rules.js index 372e4027..d552a738 100644 --- a/lib/ace/mode/html_highlight_rules.js +++ b/lib/ace/mode/html_highlight_rules.js @@ -40,81 +40,13 @@ define(function(require, exports, module) { var oop = require("../lib/oop"); var CssHighlightRules = require("./css_highlight_rules").CssHighlightRules; var JavaScriptHighlightRules = require("./javascript_highlight_rules").JavaScriptHighlightRules; +var xmlUtil = require("./xml_util"); var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; var HtmlHighlightRules = function() { // regexp must not have capturing parentheses // regexps are ordered -> the first match is used - function string(state) { - return [{ - token : "string", - regex : '".*?"' - }, { - token : "meta.tag", // multi line string start - merge : true, - regex : '["].*$', - next : state + "-qqstring" - }, { - token : "string", - regex : "'.*?'" - }, { - token : "meta.tag", // multi line string start - merge : true, - regex : "['].*$", - next : state + "-qstring" - }] - } - - function multiLineString(quote, state) { - return [{ - token : "meta.tag", - merge : true, - regex : ".*" + quote, - next : state - }, { - token : "string", - merge : true, - regex : '.+' - }] - } - - function tag(states, name, nextState) { - states[name] = [{ - token : "text", - regex : "\\s+" - }, { - token : "meta.tag", - regex : "[-_a-zA-Z0-9:]+", - next : name + "embed-attribute-list" - }, { - token: "empty", - regex: "", - next : name + "embed-attribute-list" - }]; - - states[name + "-qstring"] = multiLineString("'", name); - states[name + "-qqstring"] = multiLineString("\"", name); - - states[name + "embed-attribute-list"] = [{ - token : "meta.tag", - regex : ">", - next : nextState - }, { - token : "meta.tag", - 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)); - }; - this.$rules = { start : [ { token : "meta.tag", @@ -174,12 +106,12 @@ var HtmlHighlightRules = function() { } ] }; - tag(this.$rules, "tag", "start"); - tag(this.$rules, "css", "css-start"); - tag(this.$rules, "script", "js-start"); + xmlUtil.tag(this.$rules, "tag", "start"); + xmlUtil.tag(this.$rules, "css", "css-start"); + xmlUtil.tag(this.$rules, "script", "js-start"); this.embedRules(JavaScriptHighlightRules, "js-", [{ - token: "meta.tag", + token: "comment", regex: "\\/\\/.*(?=<\\/script>)", next: "tag" }, { diff --git a/lib/ace/mode/svg.js b/lib/ace/mode/svg.js index 37b9c1f9..075ffef0 100644 --- a/lib/ace/mode/svg.js +++ b/lib/ace/mode/svg.js @@ -59,6 +59,8 @@ oop.inherits(Mode, XmlMode); (function() { + this.foldingRules = "xml"; + this.toggleCommentLines = function(state, doc, startRow, endRow) { return 0; }; diff --git a/lib/ace/mode/svg_highlight_rules.js b/lib/ace/mode/svg_highlight_rules.js index 90f05a7f..d1a5f0c9 100644 --- a/lib/ace/mode/svg_highlight_rules.js +++ b/lib/ace/mode/svg_highlight_rules.js @@ -40,43 +40,28 @@ define(function(require, exports, module) { var oop = require("../lib/oop"); var JavaScriptHighlightRules = require("./javascript_highlight_rules").JavaScriptHighlightRules; var XmlHighlightRules = require("./xml_highlight_rules").XmlHighlightRules; +var xmlUtil = require("./xml_util"); var SvgHighlightRules = function() { XmlHighlightRules.call(this); this.$rules.start.splice(3, 0, { - token : "text", + token : "meta.tag", regex : "<(?=\s*script)", next : "script" }); - this.$rules.script = [{ - token : "text", - regex : ">", - next : "js-start" - }, { - token : "keyword", - regex : "[-_a-zA-Z0-9:]+" - }, { - token : "text", - regex : "\\s+" - }, { - token : "string", - regex : '".*?"' - }, { - token : "string", - regex : "'.*?'" - }]; + + xmlUtil.tag(this.$rules, "script", "js-start"); this.embedRules(JavaScriptHighlightRules, "js-", [{ token: "comment", regex: "\\/\\/.*(?=<\\/script>)", next: "tag" }, { - token: "text", + token: "meta.tag", regex: "<\\/(?=script)", next: "tag" }]); - }; oop.inherits(SvgHighlightRules, XmlHighlightRules); diff --git a/lib/ace/mode/xml.js b/lib/ace/mode/xml.js index ad0bc656..4abed2f5 100644 --- a/lib/ace/mode/xml.js +++ b/lib/ace/mode/xml.js @@ -51,7 +51,9 @@ var Mode = function() { oop.inherits(Mode, TextMode); (function() { - + + this.foldingRules = "xml"; + this.getNextLineIndent = function(state, line, tab) { return this.$getIndent(line); }; diff --git a/lib/ace/mode/xml_highlight_rules.js b/lib/ace/mode/xml_highlight_rules.js index a9b87b52..777c0d9c 100644 --- a/lib/ace/mode/xml_highlight_rules.js +++ b/lib/ace/mode/xml_highlight_rules.js @@ -38,13 +38,13 @@ define(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", @@ -61,7 +61,6 @@ var XmlHighlightRules = function() { }, { token : "meta.tag", // opening tag regex : "<\\/?", - merge : true, next : "tag" }, { token : "text", @@ -70,75 +69,6 @@ var XmlHighlightRules = function() { token : "text", regex : "[^<]+" }], - - tag : [{ - token : "meta.tag", - merge : true, - regex : "\\s+" - }, { - token : "meta.tag", - regex : "[-_a-zA-Z0-9:]+", - merge : true, - next : "attribute-list" - }, { - token: "empty", - regex: "", - next : name + "attribute-list" - }], - - "attribute-list": [{ - token : "meta.tag", - regex : ">", - next : "start" - }, { - token : "meta.tag", - 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+" - }, { - token : "string", - regex : '".*?"' - }, { - token : "string", // multi line string start - merge : true, - regex : '["].*', - next : "qqstring" - }, { - token : "string", - regex : "'.*?'" - }, { - token : "string", // multi line string start - merge : true, - regex : "['].*", - next : "qstring" - }], - - qstring: [{ - token : "string", - regex : ".*?'", - next : "attribute-list" - }, { - token : "string", - merge : true, - regex : '.+' - }], - - qqstring: [{ - token : "string", - regex : ".*?\"", - next : "attribute-list" - }, { - token : "string", - merge : true, - regex : '.+' - }], cdata : [{ token : "text", @@ -162,6 +92,8 @@ var XmlHighlightRules = function() { regex : ".+" }] }; + + xmlUtil.tag(this.$rules, "tag", "start"); }; oop.inherits(XmlHighlightRules, TextHighlightRules); diff --git a/lib/ace/mode/xml_util.js b/lib/ace/mode/xml_util.js new file mode 100644 index 00000000..e3e654e0 --- /dev/null +++ b/lib/ace/mode/xml_util.js @@ -0,0 +1,110 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Ajax.org Code Editor (ACE). + * + * The Initial Developer of the Original Code is + * Ajax.org B.V. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Fabian Jakobs + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +define(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) { + states[name] = [{ + token : "text", + regex : "\\s+" + }, { + token : "meta.tag", + 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); + states[name + "-qqstring"] = multiLineString("\"", name); + + states[name + "embed-attribute-list"] = [{ + token : "meta.tag", + 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)); +}; + +}); diff --git a/lib/ace/token_iterator.js b/lib/ace/token_iterator.js index 2eee9386..7d36b567 100644 --- a/lib/ace/token_iterator.js +++ b/lib/ace/token_iterator.js @@ -62,7 +62,7 @@ var TokenIterator = function(session, initialRow, initialColumn) { } return this.$rowTokens[this.$tokenIndex]; - } + }; this.stepForward = function() { var rowCount = this.$session.getLength(); @@ -78,15 +78,15 @@ var TokenIterator = function(session, initialRow, initialColumn) { } return this.$rowTokens[this.$tokenIndex]; - } + }; this.getCurrentToken = function () { return this.$rowTokens[this.$tokenIndex]; - } + }; this.getCurrentTokenRow = function () { return this.$row; - } + }; this.getCurrentTokenColumn = function() { var rowTokens = this.$rowTokens; @@ -104,7 +104,7 @@ var TokenIterator = function(session, initialRow, initialColumn) { } return column; - } + }; }).call(TokenIterator.prototype);