diff --git a/AUTHORS b/AUTHORS index 280dea2f5f..f800b86b7d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -48,6 +48,7 @@ Andreas Reischuck Andres Taylor Andre von Houck Andrew Cheng +Andrew Dassonville Andrey Fedorov Andrey Klyuchnikov Andrey Lushnikov @@ -68,6 +69,7 @@ Anthony Grimes Anton Kovalyov Apollo Zhu AQNOUCH Mohammed +Aram Shatakhtsyan areos Arnab Bose Arsène von Wyss @@ -155,6 +157,7 @@ Daniel Kesler Daniel KJ Daniel Neel Daniel Parnell +Daniel Thwaites Danila Malyutin Danny Yoo darealshinji @@ -213,7 +216,9 @@ ForbesLindesay Forbes Lindesay Ford_Lawnmower Forrest Oliphant +Franco Catena Frank Wiegand +Fredrik Borg Gabriel Gheorghian Gabriel Horner Gabriel Nahmias @@ -238,6 +243,7 @@ Grant Skinner greengiant Gregory Koberger Grzegorz Mazur +Guan Gui Guillaume Massé Guillaume Massé guraga @@ -249,12 +255,14 @@ Harshvardhan Gupta Hasan Karahan Hector Oswaldo Caballero Hendrik Wallbaum +Henrik Haugbølle Herculano Campos Hiroyuki Makino hitsthings Hocdoc Hugues Malphettes Ian Beck +Ian Davies Ian Dickinson Ian Wehrman Ian Wetherbee @@ -303,6 +311,7 @@ jem (graphite) Jeremy Parmenter Jim Jim Avery +jkaplon JobJob jochenberger Jochen Berger @@ -336,6 +345,7 @@ ju1ius Juan Benavides Romero Jucovschi Constantin Juho Vuori +Julien CROUZET Julien Rebetez Justin Andresen Justin Hileman @@ -376,6 +386,7 @@ LloydMilligan LM lochel Lorenzo Stoakes +Louis Mauchet Luca Fabbri Luciano Longo Lu Fangjian @@ -405,6 +416,7 @@ Mark Lentczner Marko Bonaci Mark Peace Markus Bordihn +Markus Olsson Martin Balek Martín Gaitán Martin Hasoň @@ -522,8 +534,8 @@ peterkroon Peter Kroon Philipp A Philip Stadermann +Pi Delport Pierre Gerold -Piët Delport Pieter Ouwerkerk Pontus Melke prasanthj @@ -627,6 +639,7 @@ thanasis TheHowl themrmax think +Thomas Brouard Thomas Dvornik Thomas Kluyver Thomas Schmid @@ -656,10 +669,12 @@ vf Victor Bocharsky Vincent Woo Volker Mische +vtripolitakis Weiyan Shao wenli Wes Cossick Wesley Wiser +Weston Ruter Will Binns-Smith Will Dean William Jamieson diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cc7ed75fd..409c7234bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,45 @@ +## 5.31.0 (2017-10-20) + +### Bug fixes + +Further improve selection drawing and cursor motion in right-to-left documents. + +[vim bindings](http://codemirror.net/demo/vim.html): Fix ctrl-w behavior, support quote-dot and backtick-dot marks, make the wide cursor visible in contentEditable [input mode](http://codemirror.net/doc/manual.html#option_contentEditable). + +[continuecomment addon](http://codemirror.net/doc/manual.html#addon_continuecomment): Fix bug when pressing enter after a single-line block comment. + +[markdown mode](http://codemirror.net/mode/markdown/): Fix issue with leaving indented fenced code blocks. + +[javascript mode](http://codemirror.net/mode/javascript/): Fix bad parsing of operators without spaces between them. Fix some corner cases around semicolon insertion and regexps. + +### New features + +Modes added with [`addOverlay`](http://codemirror.net/doc/manual.html#addOverlay) now have access to a [`baseToken`](http://codemirror.net/doc/manual.html#baseToken) method on their input stream, giving access to the tokens of the underlying mode. + +## 5.30.0 (2017-09-20) + +### Bug fixes + +Fixed a number of issues with drawing right-to-left selections and mouse selection in bidirectional text. + +[search addon](http://codemirror.net/demo/search/): Fix crash when restarting search after doing empty search. + +[mark-selection addon](http://cm/doc/manual.html#addon_mark-selection): Fix off-by-one bug. + +[tern addon](http://codemirror.net/demo/tern.html): Fix bad request made when editing at the bottom of a large document. + +[javascript mode](http://codemirror.net/mode/javascript/): Improve parsing in a number of corner cases. + +[markdown mode](http://codemirror.net/mode/markdown/): Fix crash when a sub-mode doesn't support indentation, allow uppercase X in task lists. + +[gfm mode](http://codemirror.net/mode/gfm/): Don't highlight SHA1 'hashes' without numbers to avoid false positives. + +[soy mode](http://codemirror.net/mode/soy/): Support injected data and `@param` in comments. + +### New features + +[simple mode addon](http://codemirror.net/demo/simplemode.html): Allow groups in regexps when `token` isn't an array. + ## 5.29.0 (2017-08-24) ### Bug fixes @@ -54,7 +96,7 @@ Fix crash when using mode lookahead. ### Bug fixes -Fix crash in the [simple mode](http://codemirror.net/demo/simplemode.html) addon. +Fix crash in the [simple mode](http://codemirror.net/demo/simplemode.html)< addon. ## 5.27.0 (2017-06-22) diff --git a/README.md b/README.md index 3328e3bdfb..a3a351be4d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ CodeMirror is a versatile text editor implemented in JavaScript for the browser. It is specialized for editing code, and comes with over 100 language modes and various addons that implement more advanced -editing functionality. +editing functionality. Every language comes with fully-featured code +and syntax highlighting to help with reading and editing complex code. A rich programming API and a CSS theming system are available for customizing CodeMirror to fit your application, and extending it with diff --git a/addon/comment/continuecomment.js b/addon/comment/continuecomment.js index d7385ef223..d92318b345 100644 --- a/addon/comment/continuecomment.js +++ b/addon/comment/continuecomment.js @@ -9,11 +9,6 @@ else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { - var modes = ["clike", "css", "javascript"]; - - for (var i = 0; i < modes.length; ++i) - CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "}); - function continueComment(cm) { if (cm.getOption("disableInput")) return CodeMirror.Pass; var ranges = cm.listSelections(), mode, inserts = []; @@ -27,10 +22,10 @@ var insert = null; if (mode.blockCommentStart && mode.blockCommentContinue) { var line = cm.getLine(pos.line).slice(0, pos.ch) - var end = line.indexOf(mode.blockCommentEnd), found + var end = line.lastIndexOf(mode.blockCommentEnd), found if (end != -1 && end == pos.ch - mode.blockCommentEnd.length) { // Comment ended, don't continue it - } else if ((found = line.indexOf(mode.blockCommentStart)) > -1) { + } else if ((found = line.lastIndexOf(mode.blockCommentStart)) > -1 && found > end) { insert = line.slice(0, found) if (/\S/.test(insert)) { insert = "" diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 01fdd96ce1..7b07f7fd8a 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -23,6 +23,7 @@ cm.state.closeBrackets = null; } if (val) { + ensureBound(getOption(val, "pairs")) cm.state.closeBrackets = val; cm.addKeyMap(keyMap); } @@ -34,10 +35,14 @@ return defaults[name]; } - var bind = defaults.pairs + "`"; var keyMap = {Backspace: handleBackspace, Enter: handleEnter}; - for (var i = 0; i < bind.length; i++) - keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i)); + function ensureBound(chars) { + for (var i = 0; i < chars.length; i++) { + var ch = chars.charAt(i), key = "'" + ch + "'" + if (!keyMap[key]) keyMap[key] = handler(ch) + } + } + ensureBound(defaults.pairs + "`") function handler(ch) { return function(cm) { return handleChar(cm, ch); }; @@ -79,7 +84,8 @@ if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass; } cm.operation(function() { - cm.replaceSelection("\n\n", null); + var linesep = cm.lineSeparator() || "\n"; + cm.replaceSelection(linesep + linesep, null); cm.execCommand("goCharLeft"); ranges = cm.listSelections(); for (var i = 0; i < ranges.length; i++) { diff --git a/addon/edit/continuelist.js b/addon/edit/continuelist.js index 8cda0eaaad..fe950211b5 100644 --- a/addon/edit/continuelist.js +++ b/addon/edit/continuelist.js @@ -25,7 +25,8 @@ var inQuote = eolState.quote !== 0; var line = cm.getLine(pos.line), match = listRE.exec(line); - if (!ranges[i].empty() || (!inList && !inQuote) || !match) { + var cursorBeforeBullet = /^\s*$/.test(line.slice(0, pos.ch)); + if (!ranges[i].empty() || (!inList && !inQuote) || !match || cursorBeforeBullet) { cm.execCommand("newlineAndIndent"); return; } diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 604bd3b715..f72a0a9c69 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -302,7 +302,7 @@ setTimeout(function(){cm.focus();}, 20); }); - CodeMirror.signal(data, "select", completions[0], hints.firstChild); + CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]); return true; } diff --git a/addon/lint/css-lint.js b/addon/lint/css-lint.js index b7e1a4fe5d..135d031a35 100644 --- a/addon/lint/css-lint.js +++ b/addon/lint/css-lint.js @@ -15,7 +15,7 @@ })(function(CodeMirror) { "use strict"; -CodeMirror.registerHelper("lint", "css", function(text) { +CodeMirror.registerHelper("lint", "css", function(text, options) { var found = []; if (!window.CSSLint) { if (window.console) { @@ -23,7 +23,7 @@ CodeMirror.registerHelper("lint", "css", function(text) { } return found; } - var results = CSSLint.verify(text), messages = results.messages, message = null; + var results = CSSLint.verify(text, options), messages = results.messages, message = null; for ( var i = 0; i < messages.length; i++) { message = messages[i]; var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col; diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 825065ed2a..a9eb8fa66b 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -138,7 +138,11 @@ function startLinting(cm) { var state = cm.state.lint, options = state.options; - var passOptions = options.options || options; // Support deprecated passing of `options` property in options + /* + * Passing rules in `options` property prevents JSHint (and other linters) from complaining + * about unrecognized rules like `onUpdateLinting`, `delay`, `lintOnChange`, etc. + */ + var passOptions = options.options || options; var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint"); if (!getAnnotations) return; if (options.async || getAnnotations.async) { diff --git a/addon/mode/simple.js b/addon/mode/simple.js index 15cc215825..c0f801088c 100644 --- a/addon/mode/simple.js +++ b/addon/mode/simple.js @@ -136,7 +136,7 @@ state.indent.pop(); var token = rule.token if (token && token.apply) token = token(matches) - if (matches.length > 2) { + if (matches.length > 2 && rule.token && typeof rule.token != "string") { state.pending = []; for (var j = 2; j < matches.length; j++) if (matches[j]) diff --git a/addon/runmode/runmode.node.js b/addon/runmode/runmode.node.js index 093cb30876..21c72696c8 100644 --- a/addon/runmode/runmode.node.js +++ b/addon/runmode/runmode.node.js @@ -163,6 +163,18 @@ exports.getMode = function(options, spec) { return modeObj; }; + +exports.innerMode = function(mode, state) { + var info; + while (mode.innerMode) { + info = mode.innerMode(state); + if (!info || info.mode == mode) break; + state = info.state; + mode = info.mode; + } + return info || {mode: mode, state: state}; +} + exports.registerHelper = exports.registerGlobalHelper = Math.min; exports.runMode = function(string, modespec, callback, options) { diff --git a/addon/search/search.js b/addon/search/search.js index 82938b9a56..4059ccdd0e 100644 --- a/addon/search/search.js +++ b/addon/search/search.js @@ -117,6 +117,7 @@ var state = getSearchState(cm); if (state.query) return findNext(cm, rev); var q = cm.getSelection() || state.lastQuery; + if (q instanceof RegExp && q.source == "x^") q = null if (persistent && cm.openDialog) { var hiding = null var searchNext = function(query, event) { diff --git a/addon/selection/mark-selection.js b/addon/selection/mark-selection.js index 6cceeae6c7..1602acc3de 100644 --- a/addon/selection/mark-selection.js +++ b/addon/selection/mark-selection.js @@ -86,7 +86,7 @@ if (!array.length) return coverRange(cm, from, to); var coverStart = array[0].find(), coverEnd = array[array.length - 1].find(); - if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE || + if (!coverStart || !coverEnd || to.line - from.line <= CHUNK_SIZE || cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0) return reset(cm); diff --git a/addon/tern/tern.js b/addon/tern/tern.js index 644e495f65..a80dc7e4b8 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -571,7 +571,7 @@ return {type: "part", name: data.name, offsetLines: from.line, - text: doc.getRange(from, Pos(endLine, 0))}; + text: doc.getRange(from, Pos(endLine, end.line == endLine ? null : 0))}; } // Generic utilities diff --git a/bin/authors.sh b/bin/authors.sh index b3ee99c6dd..3f228c1fb0 100755 --- a/bin/authors.sh +++ b/bin/authors.sh @@ -1,6 +1,6 @@ # Combine existing list of authors with everyone known in git, sort, add header. tail --lines=+3 AUTHORS > AUTHORS.tmp -git log --format='%aN' >> AUTHORS.tmp +git log --format='%aN' | grep -v "Piët Delport" >> AUTHORS.tmp echo -e "List of CodeMirror contributors. Updated before every release.\n" > AUTHORS sort -u AUTHORS.tmp >> AUTHORS rm -f AUTHORS.tmp diff --git a/demo/simplemode.html b/demo/simplemode.html index d719b63d18..04c194a4ba 100644 --- a/demo/simplemode.html +++ b/demo/simplemode.html @@ -65,15 +65,14 @@

Simple Mode Demo

The regular expression that matches the token. May be a string or a regex object. When a regex, the ignoreCase flag will be taken into account when matching the token. This regex - should only capture groups when the token property is - an array.
-
token: string | null
+ has to capture groups when the token property is + an array. If it captures groups, it must capture all of the string + (since JS provides no way to find out where a group matched). +
token: string | array<string> | null
An optional token style. Multiple styles can be specified by - separating them with dots or spaces. When the regex for - this rule captures groups, it must capture all of the - string (since JS provides no way to find out where a group matched), - and this property must hold an array of token styles that has one - style for each matched group.
+ separating them with dots or spaces. When this property holds an array of token styles, + the regex for this rule must capture a group for each array item. +
sol: boolean
When true, this token will only match at the start of the line. (The ^ regexp marker doesn't work as you'd expect in diff --git a/demo/vim.html b/demo/vim.html index f27b8b8e2b..bd704f7583 100644 --- a/demo/vim.html +++ b/demo/vim.html @@ -95,7 +95,8 @@

Vim bindings demo

mode: "text/x-csrc", keyMap: "vim", matchBrackets: true, - showCursorWhenSelecting: true + showCursorWhenSelecting: true, + inputStyle: "contenteditable" }); var commandDisplay = document.getElementById('command-display'); var keys = ''; diff --git a/doc/manual.html b/doc/manual.html index 354194e6cb..f2f04459b4 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

User manual and reference guide - version 5.29.1 + version 5.31.0

CodeMirror is a code-editor component that can be embedded in @@ -3261,6 +3261,12 @@

Writing CodeMirror Modes

one, in order to scan ahead across line boundaries. Note that you want to do this carefully, since looking far ahead will make mode state caching much less effective.
+ +
baseToken() → ?{type: ?string, size: number}
+
Modes added + through addOverlay + (and only such modes) can use this method to inspect + the current token produced by the underlying mode.

By default, blank lines are simply skipped when diff --git a/doc/realworld.html b/doc/realworld.html index 7c5231ba81..f0a75abf72 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -45,6 +45,7 @@

CodeMirror real-world uses

  • Code per Node (Drupal module)
  • CodeBitt (Code snippet sharing)
  • Codebug (PHP Xdebug front-end)
  • +
  • CodeFights (practice programming)
  • CodeMirror Eclipse (embed CM in Eclipse)
  • CodeMirror movie (scripted editing demos)
  • CodeMirror2-GWT (Google Web Toolkit wrapper)
  • diff --git a/doc/releases.html b/doc/releases.html index 586e2117f4..23de4c8023 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,31 @@

    Release notes and version history

    Version 5.x

    +

    20-10-2017: Version 5.31.0:

    + + + +

    20-09-2017: Version 5.30.0:

    + + +

    24-08-2017: Version 5.29.0:

    MIME types defined: text/x-markdown.

    diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 53f9164dde..b2f79fc302 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -85,7 +85,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/ , listRE = /^(?:[*\-+]|^[0-9]+([.)]))\s+/ - , taskListRE = /^\[(x| )\](?=\s)/ // Must follow listRE + , taskListRE = /^\[(x| )\](?=\s)/i // Must follow listRE , atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/ , setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/ , textRE = /^[^#!\[\]*_\\<>` "'(~:]+/ @@ -403,7 +403,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } if (state.taskList) { - var taskOpen = stream.match(taskListRE, true)[1] !== "x"; + var taskOpen = stream.match(taskListRE, true)[1] === " "; if (taskOpen) state.taskOpen = true; else state.taskClosed = true; if (modeCfg.highlightFormatting) state.formatting = "task"; @@ -821,12 +821,14 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.trailingSpace = 0; state.trailingSpaceNewLine = false; - state.f = state.block; - if (state.f != htmlBlock) { - var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, expandedTab).length; - state.indentation = indentation; - state.indentationDiff = null; - if (indentation > 0) return null; + if (!state.localState) { + state.f = state.block; + if (state.f != htmlBlock) { + var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, expandedTab).length; + state.indentation = indentation; + state.indentationDiff = null; + if (indentation > 0) return null; + } } } return state.f(stream, state); @@ -839,8 +841,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { }, indent: function(state, textAfter, line) { - if (state.block == htmlBlock) return htmlMode.indent(state.htmlState, textAfter, line) - if (state.localState) return state.localMode.indent(state.localState, textAfter, line) + if (state.block == htmlBlock && htmlMode.indent) return htmlMode.indent(state.htmlState, textAfter, line) + if (state.localState && state.localMode.indent) return state.localMode.indent(state.localState, textAfter, line) return CodeMirror.Pass }, diff --git a/mode/meta.js b/mode/meta.js index c49bd6c737..34da269f33 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -47,6 +47,7 @@ {name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]}, {name: "Embedded Ruby", mime: "application/x-erb", mode: "htmlembedded", ext: ["erb"]}, {name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]}, + {name: "Esper", mime: "text/x-esper", mode: "sql"}, {name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]}, {name: "FCL", mime: "text/x-fcl", mode: "fcl"}, {name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]}, @@ -100,7 +101,7 @@ {name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]}, {name: "PEG.js", mime: "null", mode: "pegjs", ext: ["jsonld"]}, {name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]}, - {name: "PHP", mime: "application/x-httpd-php", mode: "php", ext: ["php", "php3", "php4", "php5", "php7", "phtml"]}, + {name: "PHP", mime: ["application/x-httpd-php", "text/x-php"], mode: "php", ext: ["php", "php3", "php4", "php5", "php7", "phtml"]}, {name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]}, {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]}, {name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]}, diff --git a/mode/php/php.js b/mode/php/php.js index 57ba812d72..589c9a6639 100644 --- a/mode/php/php.js +++ b/mode/php/php.js @@ -151,7 +151,7 @@ }; CodeMirror.defineMode("php", function(config, parserConfig) { - var htmlMode = CodeMirror.getMode(config, "text/html"); + var htmlMode = CodeMirror.getMode(config, (parserConfig && parserConfig.htmlMode) || "text/html"); var phpMode = CodeMirror.getMode(config, phpConfig); function dispatch(stream, state) { diff --git a/mode/protobuf/index.html b/mode/protobuf/index.html index cfe7b9dcd3..55d4535666 100644 --- a/mode/protobuf/index.html +++ b/mode/protobuf/index.html @@ -54,9 +54,49 @@

    ProtoBuf mode

    required bool deleted = 11 [default = false]; } - + + +

    MIME types defined: text/x-protobuf.

    diff --git a/mode/protobuf/protobuf.js b/mode/protobuf/protobuf.js index bcae276e8d..93cb3b0e05 100644 --- a/mode/protobuf/protobuf.js +++ b/mode/protobuf/protobuf.js @@ -19,7 +19,8 @@ "package", "message", "import", "syntax", "required", "optional", "repeated", "reserved", "default", "extensions", "packed", "bool", "bytes", "double", "enum", "float", "string", - "int32", "int64", "uint32", "uint64", "sint32", "sint64", "fixed32", "fixed64", "sfixed32", "sfixed64" + "int32", "int64", "uint32", "uint64", "sint32", "sint64", "fixed32", "fixed64", "sfixed32", "sfixed64", + "option", "service", "rpc", "returns" ]; var keywords = wordRegexp(keywordArray); diff --git a/mode/soy/soy.js b/mode/soy/soy.js index ba16363638..0e24457042 100644 --- a/mode/soy/soy.js +++ b/mode/soy/soy.js @@ -87,7 +87,7 @@ kindTag: [], soyState: [], templates: null, - variables: null, + variables: prepend(null, 'ij'), scopes: null, indent: 0, quoteKind: null, @@ -128,6 +128,13 @@ } else { stream.skipToEnd(); } + if (!state.scopes) { + var paramRe = /@param\??\s+(\S+)/g; + var current = stream.current(); + for (var match; (match = paramRe.exec(current)); ) { + state.variables = prepend(state.variables, match[1]); + } + } return "comment"; case "templ-def": @@ -187,6 +194,7 @@ if (stream.match(/^\/?}/)) { if (state.tag == "/template" || state.tag == "/deltemplate") { popscope(state); + state.variables = prepend(null, 'ij'); state.indent = 0; } else { if (state.tag == "/for" || state.tag == "/foreach") { @@ -248,8 +256,14 @@ if (stream.match(/^\/\*/)) { state.soyState.push("comment"); + if (!state.scopes) { + state.variables = prepend(null, 'ij'); + } return "comment"; } else if (stream.match(stream.sol() ? /^\s*\/\/.*/ : /^\s+\/\/.*/)) { + if (!state.scopes) { + state.variables = prepend(null, 'ij'); + } return "comment"; } else if (stream.match(/^\{literal}/)) { state.indent += config.indentUnit; @@ -274,18 +288,18 @@ state.soyState.push("tag"); if (state.tag == "template" || state.tag == "deltemplate") { state.soyState.push("templ-def"); - } - if (state.tag == "call" || state.tag == "delcall") { + } else if (state.tag == "call" || state.tag == "delcall") { state.soyState.push("templ-ref"); - } - if (state.tag == "let") { + } else if (state.tag == "let") { state.soyState.push("var-def"); - } - if (state.tag == "for" || state.tag == "foreach") { + } else if (state.tag == "for" || state.tag == "foreach") { state.scopes = prepend(state.scopes, state.variables); state.soyState.push("var-def"); - } - if (state.tag.match(/^@(?:param\??|inject)/)) { + } else if (state.tag == "namespace") { + if (!state.scopes) { + state.variables = prepend(null, 'ij'); + } + } else if (state.tag.match(/^@(?:param\??|inject)/)) { state.soyState.push("param-def"); } return "keyword"; diff --git a/mode/sql/index.html b/mode/sql/index.html index cd95872820..b434f0f405 100644 --- a/mode/sql/index.html +++ b/mode/sql/index.html @@ -49,7 +49,7 @@

    SQL Mode for CodeMirror

    LIMIT 1 OFFSET 0; -

    MIME types defined: +

    MIME types defined: text/x-sql, text/x-mysql, text/x-mariadb, @@ -60,6 +60,7 @@

    SQL Mode for CodeMirror

    text/x-pgsql, text/x-gql, text/x-gpsql. + text/x-esper.