|
@@ -1,134 +1,139 @@
|
|
|
-CodeMirror.defineMode("smalltalk", function(config, parserConfig) {
|
|
|
- var keywords = {"true": 1, "false": 1, nil: 1, self: 1, "super": 1, thisContext: 1};
|
|
|
- var indentUnit = config.indentUnit;
|
|
|
-
|
|
|
- function chain(stream, state, f) {
|
|
|
- state.tokenize = f;
|
|
|
- return f(stream, state);
|
|
|
- }
|
|
|
-
|
|
|
- var type;
|
|
|
- function ret(tp, style) {
|
|
|
- type = tp;
|
|
|
- return style;
|
|
|
- }
|
|
|
-
|
|
|
- function tokenBase(stream, state) {
|
|
|
- var ch = stream.next();
|
|
|
- if (ch == '"')
|
|
|
- return chain(stream, state, tokenComment(ch));
|
|
|
- else if (ch == "'")
|
|
|
- return chain(stream, state, tokenString(ch));
|
|
|
- else if (ch == "#") {
|
|
|
- stream.eatWhile(/[\w\$_]/);
|
|
|
- return ret("string", "string");
|
|
|
- }
|
|
|
- else if(ch == "^") {
|
|
|
- return ret("return", "return");
|
|
|
- }
|
|
|
- else if(/[A-Z]/.test(ch)) {
|
|
|
- stream.eatWhile(/[^\s]/);
|
|
|
- return ret("className", "className");
|
|
|
- }
|
|
|
- else if (/\d/.test(ch)) {
|
|
|
- stream.eatWhile(/[\w\.]/);
|
|
|
- return ret("number", "number");
|
|
|
- }
|
|
|
- else if (/[\[\]()]/.test(ch)) {
|
|
|
- return ret(ch, null);
|
|
|
- }
|
|
|
- else {
|
|
|
- if(ch == ":") {
|
|
|
- if(stream.eat("=")) {
|
|
|
- return ret("assignment", "assignment");
|
|
|
+CodeMirror.defineMode('smalltalk', function(config, modeConfig) {
|
|
|
+
|
|
|
+ var specialChars = /[+\-/\\*~<>=@%|&?!.:;^]/;
|
|
|
+ var keywords = /true|false|nil|self|super|thisContext/;
|
|
|
+
|
|
|
+ var Context = function(tokenizer, parent) {
|
|
|
+ this.next = tokenizer;
|
|
|
+ this.parent = parent;
|
|
|
+ };
|
|
|
+
|
|
|
+ var Token = function(name, context, eos) {
|
|
|
+ this.name = name;
|
|
|
+ this.context = context;
|
|
|
+ this.eos = eos;
|
|
|
+ };
|
|
|
+
|
|
|
+ var State = function() {
|
|
|
+ this.context = new Context(next, null);
|
|
|
+ this.expectVariable = true;
|
|
|
+ this.indentation = 0;
|
|
|
+ this.userIndentationDelta = 0;
|
|
|
+ };
|
|
|
+
|
|
|
+ State.prototype.userIndent = function(indentation) {
|
|
|
+ this.userIndentationDelta = indentation > 0 ? (indentation / config.indentUnit - this.indentation) : 0;
|
|
|
+ };
|
|
|
+
|
|
|
+ var next = function(stream, context, state) {
|
|
|
+ var token = new Token(null, context, false);
|
|
|
+ var aChar = stream.next();
|
|
|
+
|
|
|
+ if (aChar === '"') {
|
|
|
+ token = nextComment(stream, new Context(nextComment, context));
|
|
|
+
|
|
|
+ } else if (aChar === '\'') {
|
|
|
+ token = nextString(stream, new Context(nextString, context));
|
|
|
+
|
|
|
+ } else if (aChar === '#') {
|
|
|
+ stream.eatWhile(/[^ .]/);
|
|
|
+ token.name = 'string-2';
|
|
|
+
|
|
|
+ } else if (aChar === '$') {
|
|
|
+ stream.eatWhile(/[^ ]/);
|
|
|
+ token.name = 'string-2';
|
|
|
+
|
|
|
+ } else if (aChar === '|' && state.expectVariable) {
|
|
|
+ token.context = new Context(nextTemporaries, context);
|
|
|
+
|
|
|
+ } else if (/[\[\]{}()]/.test(aChar)) {
|
|
|
+ token.name = 'bracket';
|
|
|
+ token.eos = /[\[{(]/.test(aChar);
|
|
|
+
|
|
|
+ if (aChar === '[') {
|
|
|
+ state.indentation++;
|
|
|
+ } else if (aChar === ']') {
|
|
|
+ state.indentation = Math.max(0, state.indentation - 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if (specialChars.test(aChar)) {
|
|
|
+ stream.eatWhile(specialChars);
|
|
|
+ token.name = 'operator';
|
|
|
+ token.eos = aChar !== ';'; // ; cascaded message expression
|
|
|
+
|
|
|
+ } else if (/\d/.test(aChar)) {
|
|
|
+ stream.eatWhile(/[\w\d]/);
|
|
|
+ token.name = 'number';
|
|
|
+
|
|
|
+ } else if (/[\w_]/.test(aChar)) {
|
|
|
+ stream.eatWhile(/[\w\d_]/);
|
|
|
+ token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ token.eos = state.expectVariable;
|
|
|
}
|
|
|
- }
|
|
|
- stream.eatWhile(/[\w\$_]/);
|
|
|
- if (keywords && keywords.propertyIsEnumerable(stream.current())) return ret("keyword", "keyword");
|
|
|
- return ret("operator", "operator");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- function tokenString(quote) {
|
|
|
- return function(stream, state) {
|
|
|
- var escaped = false, next, end = false;
|
|
|
- while ((next = stream.next()) != null) {
|
|
|
- if (next == quote && !escaped) {end = true; break;}
|
|
|
- escaped = !escaped && next == "\\";
|
|
|
- }
|
|
|
- if (end || !(escaped))
|
|
|
- state.tokenize = tokenBase;
|
|
|
- return ret("string", "string");
|
|
|
+
|
|
|
+ return token;
|
|
|
+ };
|
|
|
+
|
|
|
+ var nextComment = function(stream, context) {
|
|
|
+ stream.eatWhile(/[^"]/);
|
|
|
+ return new Token('comment', stream.eat('"') ? context.parent : context, true);
|
|
|
+ };
|
|
|
+
|
|
|
+ var nextString = function(stream, context) {
|
|
|
+ stream.eatWhile(/[^']/);
|
|
|
+ return new Token('string', stream.eat('\'') ? context.parent : context, false);
|
|
|
+ };
|
|
|
+
|
|
|
+ var nextTemporaries = function(stream, context, state) {
|
|
|
+ var token = new Token(null, context, false);
|
|
|
+ var aChar = stream.next();
|
|
|
+
|
|
|
+ if (aChar === '|') {
|
|
|
+ token.context = context.parent;
|
|
|
+ token.eos = true;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ stream.eatWhile(/[^|]/);
|
|
|
+ token.name = 'variable';
|
|
|
+ }
|
|
|
+
|
|
|
+ return token;
|
|
|
};
|
|
|
- }
|
|
|
-
|
|
|
- function tokenComment(quote) {
|
|
|
- return function(stream, state) {
|
|
|
- var next, end = false;
|
|
|
- while ((next = stream.next()) != null) {
|
|
|
- if (next == quote) {end = true; break;}
|
|
|
- }
|
|
|
- if (end)
|
|
|
- state.tokenize = tokenBase;
|
|
|
- return ret("comment", "comment");
|
|
|
+
|
|
|
+ return {
|
|
|
+ startState: function() {
|
|
|
+ return new State;
|
|
|
+ },
|
|
|
+
|
|
|
+ token: function(stream, state) {
|
|
|
+ state.userIndent(stream.indentation());
|
|
|
+
|
|
|
+ if (stream.eatSpace()) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ var token = state.context.next(stream, state.context, state);
|
|
|
+ state.context = token.context;
|
|
|
+ state.expectVariable = token.eos;
|
|
|
+
|
|
|
+ state.lastToken = token;
|
|
|
+ return token.name;
|
|
|
+ },
|
|
|
+
|
|
|
+ blankLine: function(state) {
|
|
|
+ state.userIndent(0);
|
|
|
+ },
|
|
|
+
|
|
|
+ indent: function(state, textAfter) {
|
|
|
+ var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta;
|
|
|
+ return (state.indentation + i) * config.indentUnit;
|
|
|
+ },
|
|
|
+
|
|
|
+ electricChars: ']'
|
|
|
};
|
|
|
- }
|
|
|
-
|
|
|
- function Context(indented, column, type, align, prev) {
|
|
|
- this.indented = indented;
|
|
|
- this.column = column;
|
|
|
- this.type = type;
|
|
|
- this.align = align;
|
|
|
- this.prev = prev;
|
|
|
- }
|
|
|
-
|
|
|
- function pushContext(state, col, type) {
|
|
|
- return state.context = new Context(state.indented, col, type, null, state.context);
|
|
|
- }
|
|
|
- function popContext(state) {
|
|
|
- return state.context = state.context.prev;
|
|
|
- }
|
|
|
-
|
|
|
- // Interface
|
|
|
-
|
|
|
- return {
|
|
|
- startState: function(basecolumn) {
|
|
|
- return {
|
|
|
- tokenize: tokenBase,
|
|
|
- context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
|
|
|
- indented: 0,
|
|
|
- startOfLine: true
|
|
|
- };
|
|
|
- },
|
|
|
-
|
|
|
- token: function(stream, state) {
|
|
|
- var ctx = state.context;
|
|
|
- if (stream.sol()) {
|
|
|
- if (ctx.align == null) ctx.align = false;
|
|
|
- state.indented = stream.indentation();
|
|
|
- state.startOfLine = true;
|
|
|
- }
|
|
|
- if (stream.eatSpace()) return null;
|
|
|
- var style = state.tokenize(stream, state);
|
|
|
- if (type == "comment") return style;
|
|
|
- if (ctx.align == null) ctx.align = true;
|
|
|
-
|
|
|
- if (type == "[") pushContext(state, stream.column(), "]");
|
|
|
- else if (type == "(") pushContext(state, stream.column(), ")");
|
|
|
- else if (type == ctx.type) popContext(state);
|
|
|
- state.startOfLine = false;
|
|
|
- return style;
|
|
|
- },
|
|
|
-
|
|
|
- indent: function(state, textAfter) {
|
|
|
- if (state.tokenize != tokenBase) return 0;
|
|
|
- var firstChar = textAfter && textAfter.charAt(0), ctx = state.context, closing = firstChar == ctx.type;
|
|
|
- if (ctx.align) return ctx.column + (closing ? 0 : 1);
|
|
|
- else return ctx.indented + (closing ? 0 : indentUnit);
|
|
|
- },
|
|
|
-
|
|
|
- electricChars: "]"
|
|
|
- };
|
|
|
+
|
|
|
});
|
|
|
|
|
|
-CodeMirror.defineMIME("text/x-stsrc", {name: "smalltalk"});
|
|
|
+CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'});
|