add html mode with mixed XML and JS highlighting

This commit is contained in:
Fabian Jakobs 2010-04-16 15:35:58 +02:00
commit 980fee2e99
11 changed files with 187 additions and 14 deletions

View file

@ -36,6 +36,8 @@
<script src="../src/mode/Text.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/mode/JavaScript.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/mode/JavaScriptHighlightRules.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/mode/Html.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/mode/HtmlHighlightRules.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/mode/Xml.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/mode/XmlHighlightRules.js" type="text/javascript" charset="utf-8"></script>
<script src="../src/MEventEmitter.js" type="text/javascript" charset="utf-8"></script>
@ -61,7 +63,8 @@
<select id="mode" size="1">
<option value="text">Plain Text</option>
<option value="javascript">JavaScript</option>
<option value="xml">XML</option>
<option value="xml">XML</option>
<option value="html">HTML</option>
</select>
</td>
<td>
@ -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()
};

View file

@ -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);
};

View file

@ -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,

26
src/mode/Html.js Normal file
View file

@ -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 "";
};

View file

@ -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<state.length; i++) {
var rule = state[i];
if (rule.next) {
rule.next = prefix + rule.next;
}
}
this._rules[prefix + key] = state;
}
};
ace.mode.HtmlHighlightRules.prototype.getRules = function() {
return this._rules;
};

View file

@ -5,7 +5,7 @@ ace.mode.JavaScript = function() {
};
ace.inherits(ace.mode.JavaScript, ace.mode.Text);
ace.mode.JavaScript.prototype.toggleCommentLines = function(doc, range) {
ace.mode.JavaScript.prototype.toggleCommentLines = function(doc, range, state) {
var addedRows = doc.outdentRows(range, "//");
if (addedRows == 0) {
var addedRows = doc.indentRows(range, "//");

View file

@ -14,7 +14,7 @@ ace.mode.Text.prototype.getTokenizer = function() {
return this.$tokenizer;
};
ace.mode.Text.prototype.toggleCommentLines = function(doc, range) {
ace.mode.Text.prototype.toggleCommentLines = function(doc, range, state) {
return 0;
};

View file

@ -0,0 +1,25 @@
var HtmlTest = new TestCase("mode.HtmlTest", {
setUp : function() {
this.tokenizer = new ace.mode.Html().getTokenizer();
},
"test: tokenize embedded script" : function() {
var line = "<script a='a'>var</script>'123'";
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
//assertEquals(10, tokens.length);
assertEquals("text", tokens[0].type);
assertEquals("keyword", tokens[1].type);
assertEquals("text", tokens[2].type);
assertEquals("keyword", tokens[3].type);
assertEquals("text", tokens[4].type);
assertEquals("string", tokens[5].type);
assertEquals("text", tokens[6].type);
assertEquals("keyword", tokens[7].type);
assertEquals("text", tokens[8].type);
assertEquals("keyword", tokens[9].type);
assertEquals("text", tokens[10].type);
}
});

View file

@ -21,7 +21,7 @@ var JavaScriptTest = new TestCase("mode.JavaScriptTest", {
end: {row: 1, column: 1}
};
var comment = this.mode.toggleCommentLines(doc, range);
var comment = this.mode.toggleCommentLines(doc, range, "start");
assertEquals(["// abc", "//cde", "fg"].join("\n"), doc.toString());
},
@ -33,7 +33,7 @@ var JavaScriptTest = new TestCase("mode.JavaScriptTest", {
end: {row: 1, column: 1}
};
var comment = this.mode.toggleCommentLines(doc, range);
var comment = this.mode.toggleCommentLines(doc, range, "start");
assertEquals([" abc", "cde", "fg"].join("\n"), doc.toString());
},
@ -45,7 +45,7 @@ var JavaScriptTest = new TestCase("mode.JavaScriptTest", {
end: {row: 2, column: 1}
};
var comment = this.mode.toggleCommentLines(doc, range);
var comment = this.mode.toggleCommentLines(doc, range, "start");
assertEquals(["//// abc", "////cde", "//fg"].join("\n"), doc.toString());
},

View file

@ -21,7 +21,7 @@ var XmlTest = new TestCase("mode.XmlTest", {
end: {row: 1, column: 1}
};
var comment = this.mode.toggleCommentLines(doc, range);
var comment = this.mode.toggleCommentLines(doc, range, "start");
assertEquals([" abc", "cde", "fg"].join("\n"), doc.toString());
}
});

View file

@ -9,13 +9,11 @@ var XmlTest = new TestCase("mode.XmlTest", {
var line = "<Juhu>//Juhu Kinners</Kinners>";
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
assertEquals(7, tokens.length);
assertEquals(5, tokens.length);
assertEquals("text", tokens[0].type);
assertEquals("keyword", tokens[1].type);
assertEquals("text", tokens[2].type);
assertEquals("text", tokens[3].type);
assertEquals("keyword", tokens[3].type);
assertEquals("text", tokens[4].type);
assertEquals("keyword", tokens[5].type);
assertEquals("text", tokens[6].type);
}
});