From 980fee2e99006d5b81b84664835b5b8a4a57b54a Mon Sep 17 00:00:00 2001 From: Fabian Jakobs Date: Fri, 16 Apr 2010 15:35:58 +0200 Subject: [PATCH] add html mode with mixed XML and JS highlighting --- demo/editor.html | 6 +- src/Editor.js | 3 +- src/Tokenizer.js | 4 +- src/mode/Html.js | 26 +++++++ src/mode/HtmlHighlightRules.js | 119 +++++++++++++++++++++++++++++++++ src/mode/JavaScript.js | 2 +- src/mode/Text.js | 2 +- test/mode/HtmlTokenizerTest.js | 25 +++++++ test/mode/JavaScriptTest.js | 6 +- test/mode/XmlTest.js | 2 +- test/mode/XmlTokenizerTest.js | 6 +- 11 files changed, 187 insertions(+), 14 deletions(-) create mode 100644 src/mode/Html.js create mode 100644 src/mode/HtmlHighlightRules.js create mode 100644 test/mode/HtmlTokenizerTest.js diff --git a/demo/editor.html b/demo/editor.html index 79248fff..9f1e9a7f 100644 --- a/demo/editor.html +++ b/demo/editor.html @@ -36,6 +36,8 @@ + + @@ -61,7 +63,8 @@ @@ -88,6 +91,7 @@ modeEl.onchange = function() { var modes = { text: new ace.mode.Text(), xml: new ace.mode.Xml(), + html: new ace.mode.Html(), javascript: new ace.mode.JavaScript() }; diff --git a/src/Editor.js b/src/Editor.js index 216f4a43..abee186f 100644 --- a/src/Editor.js +++ b/src/Editor.js @@ -344,7 +344,8 @@ ace.Editor.prototype.toggleCommentLines = function() { if (this.selection.isEmpty()) return; var range = this.getSelectionRange(); - var addedColumns = this.mode.toggleCommentLines(this.doc, range); + var state = this.bgTokenizer.getState(this.getCursorPosition().row); + var addedColumns = this.mode.toggleCommentLines(this.doc, range, state); this.selection.shiftSelection(addedColumns); }; diff --git a/src/Tokenizer.js b/src/Tokenizer.js index 3881f8ff..8313e900 100644 --- a/src/Tokenizer.js +++ b/src/Tokenizer.js @@ -39,7 +39,7 @@ ace.Tokenizer.prototype.getLineTokens = function(line, startState) { if (re.lastIndex == lastIndex) { throw new Error("tokenizer error"); } lastIndex = re.lastIndex; -// window.LOG && console.log(match); +// window.LOG && jstestdriver.console.log(currentState, match); for ( var i = 0; i < state.length; i++) { if (match[i + 1]) { @@ -79,7 +79,7 @@ ace.Tokenizer.prototype.getLineTokens = function(line, startState) { tokens.push(token); } -// window.LOG && console.log(tokens, currentState); +// window.LOG && jstestdriver.console.log(tokens, currentState); return { tokens : tokens, diff --git a/src/mode/Html.js b/src/mode/Html.js new file mode 100644 index 00000000..036e0656 --- /dev/null +++ b/src/mode/Html.js @@ -0,0 +1,26 @@ +ace.provide("ace.mode.Html"); + +ace.mode.Html = function() { + this.$tokenizer = new ace.Tokenizer(new ace.mode.HtmlHighlightRules().getRules()); + + this._js = new ace.mode.JavaScript(); +}; +ace.inherits(ace.mode.Html, ace.mode.Text); + +ace.mode.Html.prototype.toggleCommentLines = function(doc, range, state) { + var split = state.split("js-"); + if (!split[0] && split[1]) { + return this._js.toggleCommentLines(doc, range, state); + } + + return 0; +}; + +ace.mode.Html.prototype.getNextLineIndent = function(line, state, tab) { + var split = state.split("js-"); + if (!split[0] && split[1]) { + return this._js.getNextLineIndent(line, split[1], tab); + } + + return ""; +}; \ No newline at end of file diff --git a/src/mode/HtmlHighlightRules.js b/src/mode/HtmlHighlightRules.js new file mode 100644 index 00000000..2da964e7 --- /dev/null +++ b/src/mode/HtmlHighlightRules.js @@ -0,0 +1,119 @@ +ace.provide("ace.mode.HtmlHighlightRules"); + +ace.mode.HtmlHighlightRules = 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", + regex : "<\\!--", + next : "comment" + }, { + token : "text", + regex : "<(?=\s*script)", + next : "script" + }, { + token : "text", // opening tag + regex : "<\\/?", + next : "tag" + }, { + token : "text", + regex : "\\s+" + }, { + token : "text", + regex : "[^<]+" + } ], + + script : [ { + token : "text", + regex : ">", + next : "js-start" + }, { + token : "keyword", + regex : "[-_a-zA-Z0-9:]+" + }, { + token : "text", + regex : "\\s+" + }, { + token : "string", + regex : '".*?"' + }, { + token : "string", + regex : "'.*?'" + } ], + + tag : [ { + token : "text", + regex : ">", + next : "start" + }, { + token : "keyword", + regex : "[-_a-zA-Z0-9:]+" + }, { + token : "text", + regex : "\\s+" + }, { + token : "string", + regex : '".*?"' + }, { + token : "string", + regex : "'.*?'" + } ], + + cdata : [ { + token : "text", + regex : "\\]\\]>", + next : "start" + }, { + token : "text", + regex : "\\s+" + }, { + token : "text", + regex : ".+" + } ], + + comment : [ { + token : "comment", + regex : ".*?-->", + next : "start" + }, { + token : "comment", + regex : ".+" + } ] + }; + + var jsRules = new ace.mode.JavaScriptHighlightRules().getRules(); + this._addRules(jsRules, "js-"); + this._rules["js-start"].unshift({ + token: "text", + regex: "<\\/(?=script)", + next: "tag" + }); +}; + + +ace.mode.HtmlHighlightRules.prototype._addRules = function(rules, prefix) { + for (var key in rules) { + var state = rules[key]; + for (var i=0; i