Add support for doc doc comments:

- special highlighting
- highlight jsdoc tags
- special auto indent mode
This commit is contained in:
Fabian Jakobs 2010-04-16 12:08:03 +02:00
commit 257d80f379
7 changed files with 103 additions and 43 deletions

View file

@ -80,9 +80,17 @@
.line .comment { .line .comment {
font-style: italic; font-style: italic;
color: rgb(76, 136, 107);
}
.line .doc-comment {
color: rgb(0, 102, 255); color: rgb(0, 102, 255);
} }
.line .doc-comment-tag {
color: rgb(128, 159, 191);
}
.line .number { .line .number {
color: rgb(0, 0, 205); color: rgb(0, 0, 205);
} }

View file

@ -188,7 +188,7 @@ ace.KeyBinding = function(element, editor) {
case keys.TAB: case keys.TAB:
if (e.shiftKey) { if (e.shiftKey) {
editor.blockOutdent(); editor.blockOutdent();
} else if (selection.isMultiLineSelection()) { } else if (selection.isMultiLine()) {
editor.blockIndent(); editor.blockIndent();
} else { } else {
editor.onTextInput("\t"); editor.onTextInput("\t");

View file

@ -27,11 +27,14 @@ ace.Tokenizer.prototype.getLineTokens = function(line, startState) {
var lastIndex = 0; var lastIndex = 0;
var token = {
type: null,
value: ""
};
while (match = re.exec(line)) { while (match = re.exec(line)) {
var token = { var type = "text";
type : "text", var value = match[0];
value : match[0]
};
if (re.lastIndex == lastIndex) { throw new Error("tokenizer error"); } if (re.lastIndex == lastIndex) { throw new Error("tokenizer error"); }
lastIndex = re.lastIndex; lastIndex = re.lastIndex;
@ -41,10 +44,10 @@ ace.Tokenizer.prototype.getLineTokens = function(line, startState) {
for ( var i = 0; i < state.length; i++) { for ( var i = 0; i < state.length; i++) {
if (match[i + 1]) { if (match[i + 1]) {
if (typeof state[i].token == "function") { if (typeof state[i].token == "function") {
token.type = state[i].token(match[0]); type = state[i].token(match[0]);
} }
else { else {
token.type = state[i].token; type = state[i].token;
} }
if (state[i].next && state[i].next !== currentState) { if (state[i].next && state[i].next !== currentState) {
@ -59,9 +62,23 @@ ace.Tokenizer.prototype.getLineTokens = function(line, startState) {
} }
}; };
tokens.push(token); if (token.type !== type) {
if (token.type) {
tokens.push(token);
}
token = {
type: type,
value: value
};
} else {
token.value += value;
}
}; };
if (token.type) {
tokens.push(token);
}
// window.LOG && console.log(tokens, currentState); // window.LOG && console.log(tokens, currentState);
return { return {

View file

@ -13,18 +13,23 @@ ace.mode.JavaScript.prototype.toggleCommentLines = function(doc, range) {
return addedRows; return addedRows;
}; };
ace.mode.JavaScript.prototype.increaseIndentPatterns = {
"start" : /^(\s*).*[\{\(\[]\s*$/
};
ace.mode.JavaScript.prototype.getNextLineIndent = function(line, state, tab) { ace.mode.JavaScript.prototype.getNextLineIndent = function(line, state, tab) {
var re = this.increaseIndentPatterns[state]; if (state == "start") {
var re = /^(\s*).*[\{\(\[]\s*$/;
if (re) {
var match = line.match(re); var match = line.match(re);
if (match) { if (match) {
return (match[1] || "") + tab; return (match[1] || "") + tab;
} }
} else if (state == "doc-comment") {
var re = /^(\s*)(\/?)\*.*$/;
var match = line.match(re);
if (match) {
var indent = match[1];
if (match[2]) {
indent += " ";
}
return indent + "* ";
}
} }
var match = line.match(/^(\s+).*$/); var match = line.match(/^(\s+).*$/);

View file

@ -32,15 +32,16 @@ ace.mode.JavaScriptHighlightRules = function() {
// regexps are ordered -> the first match is used // regexps are ordered -> the first match is used
this._rules = { this._rules = {
start : [ { "start" : [ {
token : "comment", token : "comment",
regex : "\\/\\/.*$" regex : "\\/\\/.*$"
}, { }, {
token : "comment", // multi line comment in one line token : "doc-comment", // doc comment
regex : "\\/\\*.*?\\*\\/" regex : "\\/\\*\\*",
next : "doc-comment"
}, { }, {
token : "comment", // multi line comment start token : "comment", // multi line comment
regex : "\\/\\*.*$", regex : "\\/\\*",
next : "comment" next : "comment"
}, { }, {
token : "string", // single line token : "string", // single line
@ -82,6 +83,23 @@ ace.mode.JavaScriptHighlightRules = function() {
token : "text", token : "text",
regex : "\\s+" regex : "\\s+"
} ], } ],
"doc-comment" : [ {
token : "doc-comment", // closing comment
regex : "\\*\\/",
next : "start"
}, {
token : "doc-comment-tag",
regex : "@[\\w\\d_]+"
}, {
token : "doc-comment",
regex : "\s+"
}, {
token : "doc-comment",
regex : "[^@\\*]+"
}, {
token : "doc-comment",
regex : "."
}],
"comment" : [ { "comment" : [ {
token : "comment", // closing comment token : "comment", // closing comment
regex : ".*?\\*\\/", regex : ".*?\\*\\/",

View file

@ -50,32 +50,23 @@ var JavaScriptTest = new TestCase("mode.JavaScriptTest", {
}, },
"test: auto indent after opening brace" : function() { "test: auto indent after opening brace" : function() {
var doc = new ace.TextDocument(["if () {"].join("\n")); assertEquals(" ", this.mode.getNextLineIndent("if () {", "start", " "));
var editor = new ace.Editor(new MockRenderer(), doc, this.mode);
editor.navigateLineEnd();
editor.onTextInput("\n");
assertEquals(["if () {", doc.getTabString()].join("\n"), doc.toString());
}, },
"test: no auto indent after opening brace in multi line comment" : function() { "test: no auto indent after opening brace in multi line comment" : function() {
var doc = new ace.TextDocument(["/*if () {"].join("\n")); assertEquals("", this.mode.getNextLineIndent("/*if () {", " "));
var editor = new ace.Editor(new MockRenderer(), doc, this.mode);
editor.navigateLineEnd();
editor.onTextInput("\n");
assertEquals(["/*if () {", ""].join("\n"), doc.toString());
}, },
"test: no auto indent should add to existing indent" : function() { "test: no auto indent should add to existing indent" : function() {
var doc = new ace.TextDocument([" if () {"].join("\n")); assertEquals(" ", this.mode.getNextLineIndent(" if () {", "start", " "));
var editor = new ace.Editor(new MockRenderer(), doc, this.mode); assertEquals(" ", this.mode.getNextLineIndent(" cde", "start", " "));
},
editor.navigateLineEnd(); "test: special indent in doc comments" : function() {
editor.onTextInput("\n"); assertEquals(" * ", this.mode.getNextLineIndent("/**", "doc-comment", " "));
assertEquals(" * ", this.mode.getNextLineIndent(" /**", "doc-comment", " "));
assertEquals([" if () {", " " + doc.getTabString()].join("\n"), doc.toString()); assertEquals(" * ", this.mode.getNextLineIndent(" *", "doc-comment", " "));
assertEquals(" * ", this.mode.getNextLineIndent(" *", "doc-comment", " "));
assertEquals(" ", this.mode.getNextLineIndent(" abc", "doc-comment", " "));
} }
}); });

View file

@ -9,12 +9,33 @@ var JavaScriptTokenizerTest = new TestCase("mode.JavaScriptTokenizerTest", {
var tokens = this.tokenizer.getLineTokens(line, "start").tokens; var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
assertEquals(3, tokens.length);
assertEquals("identifier", tokens[0].type);
assertEquals("text", tokens[1].type);
assertEquals("keyword", tokens[2].type);
},
"test: tokenize doc comment" : function() {
var line = "abc /** de */ fg";
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
assertEquals(5, tokens.length); assertEquals(5, tokens.length);
assertEquals("identifier", tokens[0].type); assertEquals("identifier", tokens[0].type);
assertEquals("text", tokens[1].type); assertEquals("text", tokens[1].type);
assertEquals("text", tokens[2].type); assertEquals("doc-comment", tokens[2].type);
assertEquals("text", tokens[3].type); assertEquals("text", tokens[3].type);
assertEquals("keyword", tokens[4].type); assertEquals("identifier", tokens[4].type);
} },
"test: tokenize doc comment with tag" : function() {
var line = "/** @param {} */";
var tokens = this.tokenizer.getLineTokens(line, "start").tokens;
assertEquals(3, tokens.length);
assertEquals("doc-comment", tokens[0].type);
assertEquals("doc-comment-tag", tokens[1].type);
assertEquals("doc-comment", tokens[2].type);
}
}); });