diff --git a/codemirror/javascript.js b/codemirror/javascript.js index b522ec4..b0ba8d0 100644 --- a/codemirror/javascript.js +++ b/codemirror/javascript.js @@ -19,6 +19,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var jsonldMode = parserConfig.jsonld; var jsonMode = parserConfig.json || jsonldMode; var isTS = parserConfig.typescript; + var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/; // Tokenizer @@ -132,8 +133,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } else if (isOperatorChar.test(ch)) { stream.eatWhile(isOperatorChar); return ret("operator", "operator", stream.current()); - } else { - stream.eatWhile(/[\w\$_]/); + } else if (wordRE.test(ch)) { + stream.eatWhile(wordRE); var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word]; return (known && state.lastType != ".") ? ret(known.type, known.style, word) : ret("variable", "variable", word); @@ -202,7 +203,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (--depth == 0) break; } else if (bracket >= 3 && bracket < 6) { ++depth; - } else if (/[$\w]/.test(ch)) { + } else if (wordRE.test(ch)) { sawSomething = true; } else if (sawSomething && !depth) { ++pos; @@ -238,7 +239,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var cc = state.cc; // Communicate our context to the combinators. // (Less wasteful than consing up a hundred closures on every call.) - cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; + cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style; if (!state.lexical.hasOwnProperty("align")) state.lexical.align = true; @@ -298,6 +299,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var result = function() { var state = cx.state, indent = state.indented; if (state.lexical.type == "stat") indent = state.lexical.indented; + else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) + indent = outer.indented; state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); }; result.lex = true; @@ -343,7 +346,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), statement, poplex, popcontext); if (type == "module") return cont(pushlex("form"), pushcontext, afterModule, popcontext, poplex); - if (type == "class") return cont(pushlex("form"), className, objlit, poplex); + if (type == "class") return cont(pushlex("form"), className, poplex); if (type == "export") return cont(pushlex("form"), afterExport, poplex); if (type == "import") return cont(pushlex("form"), afterImport, poplex); return pass(pushlex("stat"), expression, expect(";"), poplex); @@ -388,7 +391,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function maybeoperatorNoComma(type, value, noComma) { var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; var expr = noComma == false ? expression : expressionNoComma; - if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); + if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); if (type == "operator") { if (/\+\+|--/.test(value)) return cont(me); if (value == "?") return cont(expression, expect(":"), expr); @@ -414,13 +417,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function arrowBody(type) { findFatArrow(cx.stream, cx.state); - if (type == "{") return pass(statement); - return pass(expression); + return pass(type == "{" ? statement : expression); } function arrowBodyNoComma(type) { findFatArrow(cx.stream, cx.state); - if (type == "{") return pass(statement); - return pass(expressionNoComma); + return pass(type == "{" ? statement : expressionNoComma); } function maybelabel(type) { if (type == ":") return cont(poplex, statement); @@ -430,15 +431,18 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "variable") {cx.marked = "property"; return cont();} } function objprop(type, value) { - if (type == "variable") { + if (type == "variable" || cx.style == "keyword") { cx.marked = "property"; if (value == "get" || value == "set") return cont(getterSetter); + return cont(afterprop); } else if (type == "number" || type == "string") { - cx.marked = jsonldMode ? "property" : (type + " property"); + cx.marked = jsonldMode ? "property" : (cx.style + " property"); + return cont(afterprop); + } else if (type == "jsonld-keyword") { + return cont(afterprop); } else if (type == "[") { return cont(expression, expect("]"), afterprop); } - if (atomicTypes.hasOwnProperty(type)) return cont(afterprop); } function getterSetter(type) { if (type != "variable") return pass(afterprop); @@ -537,11 +541,27 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function className(type, value) { if (type == "variable") {register(value); return cont(classNameAfter);} } - function classNameAfter(_type, value) { - if (value == "extends") return cont(expression); + function classNameAfter(type, value) { + if (value == "extends") return cont(expression, classNameAfter); + if (type == "{") return cont(pushlex("}"), classBody, poplex); + } + function classBody(type, value) { + if (type == "variable" || cx.style == "keyword") { + cx.marked = "property"; + if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody); + return cont(functiondef, classBody); + } + if (value == "*") { + cx.marked = "keyword"; + return cont(classBody); + } + if (type == ";") return cont(classBody); + if (type == "}") return cont(); } - function objlit(type) { - if (type == "{") return contCommasep(objprop, "}"); + function classGetterSetter(type) { + if (type != "variable") return pass(); + cx.marked = "property"; + return cont(); } function afterModule(type, value) { if (type == "string") return cont(statement); @@ -570,7 +590,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function maybeArrayComprehension(type) { if (type == "for") return pass(comprehension, expect("]")); - if (type == ",") return cont(commasep(expressionNoComma, "]")); + if (type == ",") return cont(commasep(maybeexpressionNoComma, "]")); return pass(commasep(expressionNoComma, "]")); } function comprehension(type) { @@ -636,7 +656,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { else return lexical.indented + (closing ? 0 : indentUnit); }, - electricChars: ":{}", + electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, blockCommentStart: jsonMode ? null : "/*", blockCommentEnd: jsonMode ? null : "*/", lineComment: jsonMode ? null : "//", @@ -648,11 +668,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { }; }); -CodeMirror.registerHelper("wordChars", "javascript", /[\\w$]/); +CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/); CodeMirror.defineMIME("text/javascript", "javascript"); CodeMirror.defineMIME("text/ecmascript", "javascript"); CodeMirror.defineMIME("application/javascript", "javascript"); +CodeMirror.defineMIME("application/x-javascript", "javascript"); CodeMirror.defineMIME("application/ecmascript", "javascript"); CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});