From caed3308e3c406b911ed6ed9397fb92c3e92383e Mon Sep 17 00:00:00 2001 From: ken restivo Date: Sat, 20 Feb 2016 16:10:43 -0800 Subject: [PATCH 001/191] [mode/meta] Add cljc, cljx, and edn extensions for clojure language --- mode/meta.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/meta.js b/mode/meta.js index e90ab29448..8ef78dbe91 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -21,7 +21,7 @@ {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]}, {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]}, {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]}, - {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj"]}, + {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj", "cljc", "cljx", "edn"]}, {name: "ClojureScript", mime: "text/x-clojurescript", mode: "clojure", ext: ["cljs"]}, {name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]}, {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/}, From 8b9066a7f9f64474b3f6035de9f6af74c18e96b6 Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Mon, 22 Feb 2016 16:16:51 -0500 Subject: [PATCH 002/191] Nit: add semicolons to the end of several modes. Fixes #3842. --- mode/haskell-literate/haskell-literate.js | 2 +- mode/jsx/jsx.js | 2 +- mode/swift/swift.js | 2 +- mode/yaml-frontmatter/yaml-frontmatter.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mode/haskell-literate/haskell-literate.js b/mode/haskell-literate/haskell-literate.js index 9358994db9..906415b4c1 100644 --- a/mode/haskell-literate/haskell-literate.js +++ b/mode/haskell-literate/haskell-literate.js @@ -40,4 +40,4 @@ }, "haskell") CodeMirror.defineMIME("text/x-literate-haskell", "haskell-literate") -}) +}); diff --git a/mode/jsx/jsx.js b/mode/jsx/jsx.js index bc2ea79758..0c018318f2 100644 --- a/mode/jsx/jsx.js +++ b/mode/jsx/jsx.js @@ -144,4 +144,4 @@ }, "xml", "javascript") CodeMirror.defineMIME("text/jsx", "jsx") -}) +}); diff --git a/mode/swift/swift.js b/mode/swift/swift.js index 86d1c6b9b8..3c28ced329 100644 --- a/mode/swift/swift.js +++ b/mode/swift/swift.js @@ -199,4 +199,4 @@ }) CodeMirror.defineMIME("text/x-swift","swift") -}) +}); diff --git a/mode/yaml-frontmatter/yaml-frontmatter.js b/mode/yaml-frontmatter/yaml-frontmatter.js index 9f081b009a..5f49772370 100644 --- a/mode/yaml-frontmatter/yaml-frontmatter.js +++ b/mode/yaml-frontmatter/yaml-frontmatter.js @@ -65,4 +65,4 @@ } } }) -}) +}); From 3f752d0c4ec639a40fb081020843a098840f1fae Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Mon, 22 Feb 2016 15:00:46 +0700 Subject: [PATCH 003/191] [dylan mode] Improve and add tests * Support nested block comments. * Improve number and operator parsing. * Improve string parsing. * Style brackets correctly. * Improve #-words. --- mode/dylan/dylan.js | 85 ++++++++++++++++++++++++++++++++++--------- mode/dylan/test.js | 88 +++++++++++++++++++++++++++++++++++++++++++++ test/index.html | 2 ++ 3 files changed, 159 insertions(+), 16 deletions(-) create mode 100644 mode/dylan/test.js diff --git a/mode/dylan/dylan.js b/mode/dylan/dylan.js index 85f0166c10..1b46bc8284 100644 --- a/mode/dylan/dylan.js +++ b/mode/dylan/dylan.js @@ -169,15 +169,16 @@ CodeMirror.defineMode("dylan", function(_config) { } else if (stream.eat("/")) { stream.skipToEnd(); return "comment"; - } else { - stream.skipTo(" "); - return "operator"; } + stream.backUp(1); } // Decimal - else if (/\d/.test(ch)) { - stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/); - return "number"; + else if (/[+\-\d\.]/.test(ch)) { + if (stream.match(/^[+-]?[0-9]*\.[0-9]*([esdx][+-]?[0-9]+)?/i) || + stream.match(/^[+-]?[0-9]+([esdx][+-]?[0-9]+)/i) || + stream.match(/^[+-]?\d+/)) { + return "number"; + } } // Hash else if (ch == "#") { @@ -186,7 +187,7 @@ CodeMirror.defineMode("dylan", function(_config) { ch = stream.peek(); if (ch == '"') { stream.next(); - return chain(stream, state, tokenString('"', "string-2")); + return chain(stream, state, tokenString('"', "string")); } // Binary number else if (ch == "b") { @@ -206,11 +207,51 @@ CodeMirror.defineMode("dylan", function(_config) { stream.eatWhile(/[0-7]/); return "number"; } + // Token concatenation in macros + else if (ch == '#') { + stream.next(); + return "punctuation"; + } + // Sequence literals + else if ((ch == '[') || (ch == '(')) { + stream.next(); + return "bracket"; // Hash symbol - else { + } else if (stream.match(/f|t|all-keys|include|key|next|rest/i)) { + return "atom"; + } else { stream.eatWhile(/[-a-zA-Z]/); - return "keyword"; + return "error"; + } + } else if (ch == "~") { + stream.next(); + ch = stream.peek(); + if (ch == "=") { + stream.next(); + ch = stream.peek(); + if (ch == "=") { + stream.next(); + return "operator"; + } + return "operator"; } + return "operator"; + } else if (ch == ":") { + stream.next(); + ch = stream.peek(); + if (ch == "=") { + stream.next(); + return "operator"; + } else if (ch == ":") { + stream.next(); + return "punctuation"; + } + } else if ("[](){}".indexOf(ch) != -1) { + stream.next(); + return "bracket"; + } else if (".,".indexOf(ch) != -1) { + stream.next(); + return "punctuation"; } else if (stream.match("end")) { return "keyword"; } @@ -223,6 +264,10 @@ CodeMirror.defineMode("dylan", function(_config) { return patternStyles[name]; } } + if (/[+\-*\/^=<>&|]/.test(ch)) { + stream.next(); + return "operator"; + } if (stream.match("define")) { return "def"; } else { @@ -240,29 +285,37 @@ CodeMirror.defineMode("dylan", function(_config) { } function tokenComment(stream, state) { - var maybeEnd = false, - ch; + var maybeEnd = false, maybeNested = false, nestedCount = 0, ch; while ((ch = stream.next())) { if (ch == "/" && maybeEnd) { - state.tokenize = tokenBase; - break; + if (nestedCount > 0) { + nestedCount--; + } else { + state.tokenize = tokenBase; + break; + } + } else if (ch == "*" && maybeNested) { + nestedCount++; } maybeEnd = (ch == "*"); + maybeNested = (ch == "/"); } return "comment"; } function tokenString(quote, style) { return function(stream, state) { - var next, end = false; + var escaped = false, next, end = false; while ((next = stream.next()) != null) { - if (next == quote) { + if (next == quote && !escaped) { end = true; break; } + escaped = !escaped && next == "\\"; } - if (end) + if (end || !escaped) { state.tokenize = tokenBase; + } return style; }; } diff --git a/mode/dylan/test.js b/mode/dylan/test.js new file mode 100644 index 0000000000..bf25be27e1 --- /dev/null +++ b/mode/dylan/test.js @@ -0,0 +1,88 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "dylan"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT('comments', + '[comment // This is a line comment]', + '[comment /* This is a block comment */]', + '[comment /* This is a multi]', + '[comment line comment]', + '[comment */]', + '[comment /* And this is a /*]', + '[comment /* nested */ comment */]'); + + MT('unary_operators', + '[operator -][variable a]', + '[operator -] [variable a]', + '[operator ~][variable a]', + '[operator ~] [variable a]'); + + MT('binary_operators', + '[variable a] [operator +] [variable b]', + '[variable a] [operator -] [variable b]', + '[variable a] [operator *] [variable b]', + '[variable a] [operator /] [variable b]', + '[variable a] [operator ^] [variable b]', + '[variable a] [operator =] [variable b]', + '[variable a] [operator ==] [variable b]', + '[variable a] [operator ~=] [variable b]', + '[variable a] [operator ~==] [variable b]', + '[variable a] [operator <] [variable b]', + '[variable a] [operator <=] [variable b]', + '[variable a] [operator >] [variable b]', + '[variable a] [operator >=] [variable b]', + '[variable a] [operator &] [variable b]', + '[variable a] [operator |] [variable b]', + '[variable a] [operator :=] [variable b]'); + + MT('integers', + '[number 1]', + '[number 123]', + '[number -123]', + '[number +456]', + '[number #b010]', + '[number #o073]', + '[number #xabcDEF123]'); + + MT('floats', + '[number .3]', + '[number -1.]', + '[number -2.335]', + '[number +3.78d1]', + '[number 3.78s-1]', + '[number -3.32e+5]'); + + MT('characters_and_strings', + "[string 'a']", + "[string '\\\\'']", + '[string ""]', + '[string "a"]', + '[string "abc def"]', + '[string "More escaped characters: \\\\\\\\ \\\\a \\\\b \\\\e \\\\f \\\\n \\\\r \\\\t \\\\0 ..."]'); + + MT('brackets', + '[bracket #[[]]]', + '[bracket #()]', + '[bracket #(][number 1][bracket )]', + '[bracket [[][number 1][punctuation ,] [number 3][bracket ]]]', + '[bracket ()]', + '[bracket {}]', + '[keyword if] [bracket (][variable foo][bracket )]', + '[bracket (][number 1][bracket )]', + '[bracket [[][number 1][bracket ]]]'); + + MT('hash_words', + '[punctuation ##]', + '[atom #f]', '[atom #F]', + '[atom #t]', '[atom #T]', + '[atom #all-keys]', + '[atom #include]', + '[atom #key]', + '[atom #next]', + '[atom #rest]', + '[string #"foo"]', + '[error #invalid]'); +})(); diff --git a/test/index.html b/test/index.html index 3e227a061d..5f8ebadc15 100644 --- a/test/index.html +++ b/test/index.html @@ -40,6 +40,7 @@ + + + +
+

ProtoBuf mode

+
+ + +

MIME types defined: text/x-protobuf.

+ +
diff --git a/mode/protobuf/protobuf.js b/mode/protobuf/protobuf.js new file mode 100644 index 0000000000..fdbf8fdec6 --- /dev/null +++ b/mode/protobuf/protobuf.js @@ -0,0 +1,72 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b", "i"); + }; + + var keywordArray = [ + "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" + ]; + var keywords = wordRegexp(keywordArray); + + CodeMirror.registerHelper("hintWords", "protobuf", keywordArray); + + var identifiers = new RegExp("^[_A-Za-z\xa1-\uffff][_A-Za-z0-9\xa1-\uffff]*"); + + function tokenBase(stream) { + // whitespaces + if (stream.eatSpace()) return null; + + // Handle one line Comments + if (stream.match("//")) { + stream.skipToEnd(); + return "comment"; + } + + // Handle Number Literals + if (stream.match(/^[0-9\.+-]/, false)) { + if (stream.match(/^[+-]?0x[0-9a-fA-F]+/)) + return "number"; + if (stream.match(/^[+-]?\d*\.\d+([EeDd][+-]?\d+)?/)) + return "number"; + if (stream.match(/^[+-]?\d+([EeDd][+-]?\d+)?/)) + return "number"; + } + + // Handle Strings + if (stream.match(/^"([^"]|(""))*"/)) { return "string"; } + if (stream.match(/^'([^']|(''))*'/)) { return "string"; } + + // Handle words + if (stream.match(keywords)) { return "keyword"; } + if (stream.match(identifiers)) { return "variable"; } ; + + // Handle non-detected items + stream.next(); + return null; + }; + + CodeMirror.defineMode("protobuf", function() { + return { + token: function(stream) { + return tokenBase(stream); + } + }; + }); + + CodeMirror.defineMIME("text/x-protobuf", "protobuf"); +}); From 4787735aad6a31ef75598665f128932282430a92 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 3 Mar 2016 11:24:14 +0100 Subject: [PATCH 021/191] [protobuf mode] Integrate Issue #3862 --- doc/compress.html | 1 + mode/index.html | 1 + mode/meta.js | 1 + mode/protobuf/protobuf.js | 6 +----- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 8f0d3e9f42..302890c477 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -181,6 +181,7 @@

Script compression helper

+ diff --git a/mode/index.html b/mode/index.html index 08f5e97b9a..5e77655bf4 100644 --- a/mode/index.html +++ b/mode/index.html @@ -104,6 +104,7 @@

Language modes

  • PHP
  • Pig Latin
  • Properties files
  • +
  • ProtoBuf
  • Puppet
  • Python
  • Q
  • diff --git a/mode/meta.js b/mode/meta.js index 03ae66d36a..8852e7cdeb 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -103,6 +103,7 @@ {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"]}, {name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]}, + {name: "ProtoBuf", mime: "text/x-protobuf", mode: "protobuf", ext: ["proto"]}, {name: "Python", mime: "text/x-python", mode: "python", ext: ["py", "pyw"]}, {name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]}, {name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]}, diff --git a/mode/protobuf/protobuf.js b/mode/protobuf/protobuf.js index fdbf8fdec6..bcae276e8d 100644 --- a/mode/protobuf/protobuf.js +++ b/mode/protobuf/protobuf.js @@ -61,11 +61,7 @@ }; CodeMirror.defineMode("protobuf", function() { - return { - token: function(stream) { - return tokenBase(stream); - } - }; + return {token: tokenBase}; }); CodeMirror.defineMIME("text/x-protobuf", "protobuf"); From afed95af113abc53c1bc1306b3898495609dbff7 Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Fri, 4 Mar 2016 00:16:09 -0500 Subject: [PATCH 022/191] [markdown mode] Fix indentation rules to match CommonMark See http://spec.commonmark.org/0.24/#list-items Closes #3833 --- mode/markdown/markdown.js | 27 ++++++++++++++++----------- mode/markdown/test.js | 12 ++++++++++++ 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index ed8452abe6..a6942b39c8 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -149,10 +149,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.list = null; } else if (state.indentation > 0) { state.list = null; - state.listDepth = Math.floor(state.indentation / 4); } else { // No longer a list state.list = false; - state.listDepth = 0; } } @@ -199,7 +197,17 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } state.indentation = stream.column() + stream.current().length; state.list = true; - state.listDepth++; + + // While this list item's marker's indentation + // is less than the deepest list item's content's indentation, + // pop the deepest list item indentation off the stack. + while (state.listStack && stream.column() < state.listStack[state.listStack.length - 1]) { + state.listStack.pop(); + } + + // Add this list item's content's indentation to the stack + state.listStack.push(state.indentation); + if (modeCfg.taskLists && stream.match(taskListRE, false)) { state.taskList = true; } @@ -321,7 +329,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } if (state.list !== false) { - var listMod = (state.listDepth - 1) % 3; + var listMod = (state.listStack.length - 1) % 3; if (!listMod) { styles.push(tokenTypes.list1); } else if (listMod === 1) { @@ -697,7 +705,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { hr: false, taskList: false, list: false, - listDepth: 0, + listStack: [], quote: 0, trailingSpace: 0, trailingSpaceNewLine: false, @@ -732,7 +740,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { hr: s.hr, taskList: s.taskList, list: s.list, - listDepth: s.listDepth, + listStack: s.listStack.slice(0), quote: s.quote, indentedCode: s.indentedCode, trailingSpace: s.trailingSpace, @@ -772,11 +780,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.f = state.block; var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length; - var difference = Math.floor((indentation - state.indentation) / 4) * 4; - if (difference > 4) difference = 4; - var adjustedIndentation = state.indentation + difference; - state.indentationDiff = adjustedIndentation - state.indentation; - state.indentation = adjustedIndentation; + state.indentationDiff = Math.min(indentation - state.indentation, 4); + state.indentation = state.indentation + state.indentationDiff; if (indentation > 0) return null; } return state.f(stream, state); diff --git a/mode/markdown/test.js b/mode/markdown/test.js index 6d7829fa57..a48d153107 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -452,6 +452,18 @@ "", "hello"); + MT("listCommonMarkIndentationCode", + "[variable-2 * Code blocks also affect]", + " [variable-3 * The next level starts where the contents start.]", + " [variable-3 * Anything less than that will keep the item on the same level.]", + " [variable-3 * Each list item can indent the first level further and further.]", + " [variable-3 * For the most part, this makes sense while writing a list.]", + " [keyword * This means two items with same indentation can be different levels.]", + " [keyword * Each level has an indent requirement that can change between items.]", + " [keyword * A list item that meets this will be part of the next level.]", + " [variable-3 * Otherwise, it will be part of the level where it does meet this.]", + " [variable-2 * World]"); + // Blockquote MT("blockquote", "[variable-2 * foo]", From 12168b275d6e26b736b9e7d3b478131327fba8fa Mon Sep 17 00:00:00 2001 From: sinkuu Date: Mon, 7 Mar 2016 09:39:01 +0900 Subject: [PATCH 023/191] [troff mode] Fix MIME type `text/troff` is the standard approved by IANA. Also add some non-standard MIME types. https://bugs.freedesktop.org/show_bug.cgi?id=5072 --- mode/troff/troff.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mode/troff/troff.js b/mode/troff/troff.js index beca778eeb..7e043a11f0 100644 --- a/mode/troff/troff.js +++ b/mode/troff/troff.js @@ -77,6 +77,9 @@ CodeMirror.defineMode('troff', function() { }; }); +CodeMirror.defineMIME('text/troff', 'troff'); +CodeMirror.defineMIME('text/x-troff', 'troff'); +CodeMirror.defineMIME('application/x-troff', 'troff'); CodeMirror.defineMIME('troff', 'troff'); }); From 0514f28ea6776911f093ba559b9bef11401f05e4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 7 Mar 2016 15:41:26 +0100 Subject: [PATCH 024/191] [troff mode] Remove bogus MIME string Issue #3869 --- mode/meta.js | 2 +- mode/troff/troff.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mode/meta.js b/mode/meta.js index 8852e7cdeb..3cb9de21e1 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -138,7 +138,7 @@ {name: "Tiki wiki", mime: "text/tiki", mode: "tiki"}, {name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]}, {name: "Tornado", mime: "text/x-tornado", mode: "tornado"}, - {name: "troff", mime: "troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]}, + {name: "troff", mime: "text/troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]}, {name: "TTCN", mime: "text/x-ttcn", mode: "ttcn", ext: ["ttcn", "ttcn3", "ttcnpp"]}, {name: "TTCN_CFG", mime: "text/x-ttcn-cfg", mode: "ttcn-cfg", ext: ["cfg"]}, {name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]}, diff --git a/mode/troff/troff.js b/mode/troff/troff.js index 7e043a11f0..86154b6e14 100644 --- a/mode/troff/troff.js +++ b/mode/troff/troff.js @@ -80,6 +80,5 @@ CodeMirror.defineMode('troff', function() { CodeMirror.defineMIME('text/troff', 'troff'); CodeMirror.defineMIME('text/x-troff', 'troff'); CodeMirror.defineMIME('application/x-troff', 'troff'); -CodeMirror.defineMIME('troff', 'troff'); }); From 79193c029ba25818cd5c891f34feaaca8675ea5b Mon Sep 17 00:00:00 2001 From: nightwing Date: Sat, 5 Mar 2016 19:25:38 +0400 Subject: [PATCH 025/191] [vim] fix s in visual block mode --- keymap/vim.js | 4 ++-- test/vim_test.js | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 87b94e352b..65555313cf 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -64,9 +64,9 @@ { keys: '', type: 'keyToKey', toKeys: '', context: 'insert' }, { keys: '', type: 'keyToKey', toKeys: '', context: 'insert' }, { keys: 's', type: 'keyToKey', toKeys: 'cl', context: 'normal' }, - { keys: 's', type: 'keyToKey', toKeys: 'xi', context: 'visual'}, + { keys: 's', type: 'keyToKey', toKeys: 'c', context: 'visual'}, { keys: 'S', type: 'keyToKey', toKeys: 'cc', context: 'normal' }, - { keys: 'S', type: 'keyToKey', toKeys: 'dcc', context: 'visual' }, + { keys: 'S', type: 'keyToKey', toKeys: 'VdO', context: 'visual' }, { keys: '', type: 'keyToKey', toKeys: '0' }, { keys: '', type: 'keyToKey', toKeys: '$' }, { keys: '', type: 'keyToKey', toKeys: '' }, diff --git a/test/vim_test.js b/test/vim_test.js index c75e003a47..bd62724b62 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1045,6 +1045,20 @@ testVim('D_visual_block', function(cm, vim, helpers) { eq('1\n5\na', cm.getValue()); }, {value: '1234\n5678\nabcdefg'}); +testVim('s_visual_block', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('', '2', 'j', 'l', 'l', 'l', 's'); + var replacement = fillArray('hello{', 3); + cm.replaceSelections(replacement); + eq('1hello{\n5hello{\nahello{fg\n', cm.getValue()); + helpers.doKeys(''); + cm.setCursor(2, 3); + helpers.doKeys('', '1', 'k', 'h', 'S'); + replacement = fillArray('world', 1); + cm.replaceSelections(replacement); + eq('1hello{\n world\n', cm.getValue()); +}, {value: '1234\n5678\nabcdefg\n'}); + // Swapcase commands edit in place and do not modify registers. testVim('g~w_repeat', function(cm, vim, helpers) { // Assert that dw does delete newline if it should go to the next line, and From d9b821a9b21b5b1622396b67744d226f57b69d2e Mon Sep 17 00:00:00 2001 From: Ben Mosher Date: Mon, 7 Mar 2016 17:12:03 -0500 Subject: [PATCH 026/191] [placeholder addon] Handle swapDoc event --- addon/display/placeholder.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addon/display/placeholder.js b/addon/display/placeholder.js index babddfb1fe..2f8b1f84ae 100644 --- a/addon/display/placeholder.js +++ b/addon/display/placeholder.js @@ -14,10 +14,12 @@ if (val && !prev) { cm.on("blur", onBlur); cm.on("change", onChange); + cm.on("swapDoc", onChange); onChange(cm); } else if (!val && prev) { cm.off("blur", onBlur); cm.off("change", onChange); + cm.off("swapDoc", onChange); clearPlaceholder(cm); var wrapper = cm.getWrapperElement(); wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); From be7612de2d879e9442025698d9e93b39d2f0749f Mon Sep 17 00:00:00 2001 From: Steve O'Hara Date: Wed, 9 Mar 2016 21:56:19 +0000 Subject: [PATCH 027/191] [velocity mode] Fix parsing of variables in nested quotes Closes #3876 --- mode/velocity/index.html | 2 ++ mode/velocity/velocity.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mode/velocity/index.html b/mode/velocity/index.html index 2747878667..7eba8f4185 100644 --- a/mode/velocity/index.html +++ b/mode/velocity/index.html @@ -77,6 +77,8 @@

    Velocity mode

    $someObject("This plus $something in the middle").method(7567).property +#set($something = "Parseable string with '$quotes'!") + #macro( tablerows $color $somelist ) #foreach( $something in $somelist ) $something diff --git a/mode/velocity/velocity.js b/mode/velocity/velocity.js index 8fc4f95d05..12ee221249 100644 --- a/mode/velocity/velocity.js +++ b/mode/velocity/velocity.js @@ -34,7 +34,7 @@ CodeMirror.defineMode("velocity", function() { state.beforeParams = false; var ch = stream.next(); // start of unparsed string? - if ((ch == "'") && state.inParams) { + if ((ch == "'") && !state.inString && state.inParams) { state.lastTokenWasBuiltin = false; return chain(stream, state, tokenString(ch)); } From 934dd97dda56d2a8f8f5650c0ddaab65b47e6af9 Mon Sep 17 00:00:00 2001 From: guraga Date: Sat, 19 Mar 2016 14:51:08 +0600 Subject: [PATCH 028/191] [changelog] Fix typo in date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7eb70e9c53..fe78c71d5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 5.12.0 (2015-02-19) +## 5.12.0 (2016-02-19) ### New features From 1de61c6a2031b06045d0c867c7c27b5b9bbb7e3a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Mar 2016 09:47:46 +0100 Subject: [PATCH 029/191] [jsx mode] Support a 'base' configuration parameter To configure the inner mode. Closes #3893 --- mode/jsx/jsx.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/jsx/jsx.js b/mode/jsx/jsx.js index 0c018318f2..aff01b8d35 100644 --- a/mode/jsx/jsx.js +++ b/mode/jsx/jsx.js @@ -25,9 +25,9 @@ context.prev && copyContext(context.prev)) } - CodeMirror.defineMode("jsx", function(config) { + CodeMirror.defineMode("jsx", function(config, modeConfig) { var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false}) - var jsMode = CodeMirror.getMode(config, "javascript") + var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript") function flatXMLIndent(state) { var tagName = state.tagName From fa1a355a23977abf5abe22217ac2d74a77d58510 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Mar 2016 10:05:53 +0100 Subject: [PATCH 030/191] [simplescrollbar addon] Make sure bar position is clipped after update Closes #3891 --- addon/scroll/simplescrollbars.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/addon/scroll/simplescrollbars.js b/addon/scroll/simplescrollbars.js index f78353a130..32ba2f35ea 100644 --- a/addon/scroll/simplescrollbars.js +++ b/addon/scroll/simplescrollbars.js @@ -59,16 +59,20 @@ CodeMirror.on(this.node, "DOMMouseScroll", onWheel); } - Bar.prototype.moveTo = function(pos, update) { + Bar.prototype.setPos = function(pos) { if (pos < 0) pos = 0; if (pos > this.total - this.screen) pos = this.total - this.screen; - if (pos == this.pos) return; + if (pos == this.pos) return false; this.pos = pos; this.inner.style[this.orientation == "horizontal" ? "left" : "top"] = (pos * (this.size / this.total)) + "px"; - if (update !== false) this.scroll(pos, this.orientation); + return true }; + Bar.prototype.moveTo = function(pos) { + if (this.setPos(pos)) this.scroll(pos, this.orientation); + } + var minButtonSize = 10; Bar.prototype.update = function(scrollSize, clientSize, barSize) { @@ -83,8 +87,7 @@ } this.inner.style[this.orientation == "horizontal" ? "width" : "height"] = buttonSize + "px"; - this.inner.style[this.orientation == "horizontal" ? "left" : "top"] = - this.pos * (this.size / this.total) + "px"; + this.setPos(this.pos); }; function SimpleScrollbars(cls, place, scroll) { @@ -111,7 +114,6 @@ if (needsV) { this.vert.update(measure.scrollHeight, measure.clientHeight, measure.viewHeight - (needsH ? width : 0)); - this.vert.node.style.display = "block"; this.vert.node.style.bottom = needsH ? width + "px" : "0"; } if (needsH) { @@ -125,11 +127,11 @@ }; SimpleScrollbars.prototype.setScrollTop = function(pos) { - this.vert.moveTo(pos, false); + this.vert.setPos(pos); }; SimpleScrollbars.prototype.setScrollLeft = function(pos) { - this.horiz.moveTo(pos, false); + this.horiz.setPos(pos); }; SimpleScrollbars.prototype.clear = function() { From d4dbbcef22e3aadf25dad811a9faa988a50a0df4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Mar 2016 10:24:33 +0100 Subject: [PATCH 031/191] [dart mode] Support nested block comments Closes #3878 --- mode/dart/dart.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/mode/dart/dart.js b/mode/dart/dart.js index d92eb5190c..8d383a95ef 100644 --- a/mode/dart/dart.js +++ b/mode/dart/dart.js @@ -72,6 +72,12 @@ return null; } return false; + }, + + "/": function(stream, state) { + if (!stream.eat("*")) return false + state.tokenize = tokenNestedComment(1) + return state.tokenize(stream, state) } } }); @@ -121,6 +127,27 @@ return "variable"; } + function tokenNestedComment(depth) { + return function (stream, state) { + var ch + while (ch = stream.next()) { + if (ch == "*" && stream.eat("/")) { + if (depth == 1) { + state.tokenize = null + break + } else { + state.tokenize = tokenNestedComment(depth - 1) + return state.tokenize(stream, state) + } + } else if (ch == "/" && stream.eat("*")) { + state.tokenize = tokenNestedComment(depth + 1) + return state.tokenize(stream, state) + } + } + return "comment" + } + } + CodeMirror.registerHelper("hintWords", "application/dart", keywords.concat(atoms).concat(builtins)); // This is needed to make loading through meta.js work. From 66b0b4d383818f8ed80009c89a40097aa37a5990 Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Fri, 11 Mar 2016 13:48:26 +0100 Subject: [PATCH 032/191] [vim mode] Fix insert/command mode behavior difference --- keymap/vim.js | 11 ++++++----- test/vim_test.js | 16 ++++++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 65555313cf..5ed2d9bf73 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1696,11 +1696,12 @@ var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat; var first = cm.firstLine(); var last = cm.lastLine(); - // Vim cancels linewise motions that start on an edge and move beyond - // that edge. It does not cancel motions that do not start on an edge. - if ((line < first && cur.line == first) || - (line > last && cur.line == last)) { - return; + // Vim go to line begin or line end when cursor at first/last line and + // move to previous/next line is triggered. + if (line < first && cur.line == first){ + return this.moveToStartOfLine(cm, head, motionArgs, vim); + }else if (line > last && cur.line == last){ + return this.moveToEol(cm, head, motionArgs, vim); } if (motionArgs.toFirstChar){ endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line)); diff --git a/test/vim_test.js b/test/vim_test.js index bd62724b62..7080c3062f 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -634,11 +634,11 @@ testVim('dj_end_of_document', function(cm, vim, helpers) { var curStart = makeCursor(0, 3); cm.setCursor(curStart); helpers.doKeys('d', 'j'); - eq(' word1 ', cm.getValue()); + eq('', cm.getValue()); var register = helpers.getRegisterController().getRegister(); - eq('', register.toString()); - is(!register.linewise); - helpers.assertCursorAt(0, 3); + eq(' word1 \n', register.toString()); + is(register.linewise); + helpers.assertCursorAt(0, 0); }, { value: ' word1 ' }); testVim('dk', function(cm, vim, helpers) { var curStart = makeCursor(1, 3); @@ -654,11 +654,11 @@ testVim('dk_start_of_document', function(cm, vim, helpers) { var curStart = makeCursor(0, 3); cm.setCursor(curStart); helpers.doKeys('d', 'k'); - eq(' word1 ', cm.getValue()); + eq('', cm.getValue()); var register = helpers.getRegisterController().getRegister(); - eq('', register.toString()); - is(!register.linewise); - helpers.assertCursorAt(0, 3); + eq(' word1 \n', register.toString()); + is(register.linewise); + helpers.assertCursorAt(0, 0); }, { value: ' word1 ' }); testVim('dw_space', function(cm, vim, helpers) { var curStart = makeCursor(0, 0); From feed440b7e8343752e65e3683d25130593c78897 Mon Sep 17 00:00:00 2001 From: Julien Rebetez Date: Fri, 11 Mar 2016 20:03:51 +0100 Subject: [PATCH 033/191] Allow applications to listen for the dragleave event. --- doc/manual.html | 3 ++- lib/codemirror.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 29a7ed38e0..82687528f5 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -657,7 +657,8 @@

    Events

    "keydown", "keypress", "keyup", "cut", "copy", "paste", "dragstart", "dragenter", - "dragover", "drop" + "dragover", "dragleave", + "drop" (instance: CodeMirror, event: Event)
    Fired when CodeMirror is handling a DOM event of this type. You can preventDefault the event, or give it a diff --git a/lib/codemirror.js b/lib/codemirror.js index d1599c99e9..372020d873 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3495,7 +3495,7 @@ over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }}, start: function(e){onDragStart(cm, e);}, drop: operation(cm, onDrop), - leave: function() {clearDragCursor(cm);} + leave: function(e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }} }; var inp = d.input.getField(); From ecaa8914751ad5472f315bce5f0c49c232aa5c26 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Mar 2016 11:18:29 +0100 Subject: [PATCH 034/191] Make sure gutters are never left higher than the view height Closes #3884 --- lib/codemirror.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 372020d873..c736708ee4 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -747,6 +747,7 @@ function postUpdateDisplay(cm, update) { var viewport = update.viewport; + for (var first = true;; first = false) { if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { // Clip forced viewport to actual scrollable area. @@ -766,6 +767,9 @@ updateScrollbars(cm, barMeasure); } + if (parseInt(cm.display.gutters.style.height) > cm.display.scroller.clientHeight) + cm.display.gutters.style.height = cm.display.scroller.clientHeight + "px" + update.signal(cm, "update", cm); if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); From 8e6158c94c79797d9aa818d0572f6f2ac8c6113d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Mar 2016 11:37:00 +0100 Subject: [PATCH 035/191] Mark release 5.13.0 --- AUTHORS | 10 ++++++++++ CHANGELOG.md | 28 ++++++++++++++++++++++++++++ doc/compress.html | 1 + doc/manual.html | 2 +- doc/releases.html | 21 +++++++++++++++++++-- index.html | 2 +- lib/codemirror.js | 2 +- package.json | 2 +- 8 files changed, 62 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index 741ba1e35e..c3680eb4d8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -75,6 +75,7 @@ benbro Beni Cherniavsky-Paskin Benjamin DeCoste Ben Keen +Ben Mosher Bernhard Sirlinger Bert Chang Billy Moon @@ -137,6 +138,7 @@ David Barnett David Mignot David Pathakjee David Vázquez +David Whittington deebugger Deep Thought Devin Abbott @@ -184,6 +186,7 @@ galambalazs Gautam Mehta Gavin Douglas gekkoe +geowarin Gerard Braad Gergely Hegykozi Giovanni Calò @@ -198,6 +201,7 @@ greengiant Gregory Koberger Guillaume Massé Guillaume Massé +guraga Gustavo Rodrigues Hakan Tunc Hans Engel @@ -274,6 +278,7 @@ ju1ius Juan Benavides Romero Jucovschi Constantin Juho Vuori +Julien Rebetez Justin Andresen Justin Hileman jwallers@gmail.com @@ -281,6 +286,7 @@ kaniga karevn Kayur Patel Ken Newman +ken restivo Ken Rockot Kevin Earls Kevin Sawicki @@ -426,7 +432,9 @@ peter Peter Flynn peterkroon Peter Kroon +Philipp A Philip Stadermann +Pierre Gerold Piët Delport prasanthj Prasanth J @@ -476,6 +484,7 @@ Shiv Deepak Shmuel Englard Shubham Jain silverwind +sinkuu snasa soliton4 sonson @@ -518,6 +527,7 @@ Tom MacWright Tony Jian Travis Heppe Triangle717 +Tristan Tarrant TSUYUSATO Kitsune twifkak Vestimir Markov diff --git a/CHANGELOG.md b/CHANGELOG.md index fe78c71d5e..60ec9df51b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,31 @@ +## 5.13.0 (2016-03-21) + +### New features + +New DOM event forwarded: [`"dragleave"`](http://codemirror.net/doc/manual.html#event_dom). + +[protobuf mode](http://codemirror.net/mode/protobuf/index.html): Newly added. + +### Bugfixes + +Fix problem where [`findMarks`](http://codemirror.net/doc/manual.html#findMarks) sometimes failed to find multi-line marks. + +Fix crash that showed up when atomic ranges and bidi text were combined. + +[show-hint addon](http://codemirror.net/demo/complete.html): Completion widgets no longer close when the line indented or dedented. + +[merge addon](http://codemirror.net/demo/merge.html): Fix bug when merging chunks at the end of the file. + +[placeholder addon](http://codemirror.net/doc/manual.html#addon_placeholder): No longer gets confused by [`swapDoc`](http://codemirror.net/doc/manual.html#swapDoc). + +[simplescrollbars addon](http://codemirror.net/doc/manual.html#addon_simplescrollbars): Fix invalid state when deleting at end of document. + +[clike mode](http://codemirror.net/mode/clike/index.html): No longer gets confused when a comment starts after an operator. + +[markdown mode](http://codemirror.net/mode/markdown/index.html): Now supports CommonMark-style flexible list indentation. + +[dylan mode](http://codemirror.net/mode/dylan/index.html): Several improvements and fixes. + ## 5.12.0 (2016-02-19) ### New features diff --git a/doc/compress.html b/doc/compress.html index 302890c477..a0d4364a3e 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -36,6 +36,7 @@

    Script compression helper

    Version:

    Version: + + + +

    MIME types defined: text/x-powershell.

    + + diff --git a/mode/powershell/powershell.js b/mode/powershell/powershell.js new file mode 100644 index 0000000000..944088fbbe --- /dev/null +++ b/mode/powershell/powershell.js @@ -0,0 +1,191 @@ +CodeMirror.defineMode("powershell", function() { + var ERRORCLASS = 'error'; + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + var wordOperators = wordRegexp(['-eq', '-ne', '-gt', '-lt', '-le', '-ge']); + var commonkeywords = ['begin', 'break', 'continue', 'do', 'default', 'else', 'elseif', + 'end', 'filter', 'for', 'foreach', 'function', 'if', 'in', 'param', + 'process', 'return', 'switch', 'until', 'where', 'while']; + + var isOperatorChar = /[+\-*&^%:=<>!|\/]/; + var isString = /("|')(\`?.)*?\1/; + + var keywords = wordRegexp(commonkeywords); + //var builtins = wordRegexp(commonBuiltins); + + var indentInfo = null; + + // tokenizers + function tokenBase(stream, state) { + + + + // Handle Comments + //var ch = stream.peek(); + + if (stream.match(keywords)) { + return('variable-2'); + } + + if (stream.match(isString)) { + return('string'); + } + + if (stream.match(wordOperators)) { + return('variable-2'); + } + if (stream.match(isOperatorChar)) { + return('variable-1'); + } + + + // Handle Variables + + + // Handle Number Literals + if (stream.match(/^[0-9\.]/, false)) { + var floatLiteral = false; + // Floats + if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; } + if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; } + if (stream.match(/^\.\d+/)) { floatLiteral = true; } + if (floatLiteral) { + // Float literals may be "imaginary" + stream.eat(/J/i); + return 'number'; + } + // Integers + var intLiteral = false; + // Hex + if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; } + // Binary + if (stream.match(/^0b[01]+/i)) { intLiteral = true; } + // Octal + if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; } + // Decimal + if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) { + // Decimal literals may be "imaginary" + stream.eat(/J/i); + // TODO - Can you have imaginary longs? + intLiteral = true; + } + // Zero by itself with no other piece of number. + if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; } + if (intLiteral) { + // Integer literals may be "long" + stream.eat(/L/i); + return 'number'; + } + } + + var ch = stream.next(); + + if (ch === '$') { + if (stream.eat('{')) { + state.tokenize = tokenVariable; + return tokenVariable(stream, state); + } else { + stream.eatWhile(/[\w\\\-]/); + return 'variable-2'; + } + } + + if (ch === '<' && stream.eat('#')) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + + if (ch === '#') { + stream.skipToEnd(); + return 'comment'; + } + + if (ch === '@' && stream.eat('\"')) { + state.tokenize = tokenMultiString; + return tokenMultiString(stream, state); + } + + //if (isOperatorChar.test(ch)) { + // stream.eat; + //stream.next; + // return("variable-1"); + // } + + stream.next(); + return ERRORCLASS; + } + + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == ">") { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch === '#'); + } + return("comment"); + } + + function tokenVariable(stream, state) { + while ((ch = stream.next()) != null) { + if (ch == "}") { + state.tokenize = tokenBase; + break; + } + } + return("variable-2"); + } + + function tokenMultiString(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "@") { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch === '"'); + } + return("string"); + } + + function tokenLexer(stream, state) { + //indentInfo = null; + var style = state.tokenize(stream, state); + //var current = stream.current(); + return style; + } + + var external = { + startState: function(basecolumn) { + return { + tokenize: tokenBase, + scopes: [{offset:basecolumn || 0, type:'py'}], + lastToken: null, + lambda: false, + dedent: 0 + }; + }, + + token: function(stream, state) { + var style = tokenLexer(stream, state); + state.lastToken = {style:style, content: stream.current()}; + if (stream.eol() && stream.lambda) { + state.lambda = false; + } + + return style; + }, + + blockCommentStart: "<#", + blockCommentEnd: "#>", + lineComment: "#" + }; + return external; +}); + +CodeMirror.defineMIME("text/x-powershell", "powershell"); From 20641be6a4973f7914d4a7ef4261f78ebe969411 Mon Sep 17 00:00:00 2001 From: Andrey Shchekin Date: Mon, 30 Jun 2014 00:20:00 +1200 Subject: [PATCH 049/191] [powershell mode] Implement actual PowerShell syntax. --- mode/powershell/index.html | 231 +++++++++++------ mode/powershell/powershell.js | 462 ++++++++++++++++++++++------------ 2 files changed, 464 insertions(+), 229 deletions(-) diff --git a/mode/powershell/index.html b/mode/powershell/index.html index 940840c3b6..bc0f9c486c 100644 --- a/mode/powershell/index.html +++ b/mode/powershell/index.html @@ -3,97 +3,179 @@ CodeMirror: Powershell mode - - - - + + + - -

    CodeMirror: Powershell mode

    - -
    +# Built-in functions +A: +Add-Computer Add-Content Add-History Add-Member Add-PSSnapin Add-Type +B: +C: +Checkpoint-Computer Clear-Content Clear-EventLog Clear-History Clear-Host Clear-Item +Clear-ItemProperty Clear-Variable Compare-Object Complete-Transaction Connect-PSSession +ConvertFrom-Csv ConvertFrom-Json ConvertFrom-SecureString ConvertFrom-StringData +Convert-Path ConvertTo-Csv ConvertTo-Html ConvertTo-Json ConvertTo-SecureString +ConvertTo-Xml Copy-Item Copy-ItemProperty +D: +Debug-Process Disable-ComputerRestore Disable-PSBreakpoint Disable-PSRemoting +Disable-PSSessionConfiguration Disconnect-PSSession +E: +Enable-ComputerRestore Enable-PSBreakpoint Enable-PSRemoting Enable-PSSessionConfiguration +Enter-PSSession Exit-PSSession Export-Alias Export-Clixml Export-Console Export-Counter +Export-Csv Export-FormatData Export-ModuleMember Export-PSSession +F: +ForEach-Object Format-Custom Format-List Format-Table Format-Wide +G: +Get-Acl Get-Alias Get-AuthenticodeSignature Get-ChildItem Get-Command Get-ComputerRestorePoint +Get-Content Get-ControlPanelItem Get-Counter Get-Credential Get-Culture Get-Date +Get-Event Get-EventLog Get-EventSubscriber Get-ExecutionPolicy Get-FormatData Get-Help +Get-History Get-Host Get-HotFix Get-Item Get-ItemProperty Get-Job Get-Location Get-Member +Get-Module Get-PfxCertificate Get-Process Get-PSBreakpoint Get-PSCallStack Get-PSDrive +Get-PSProvider Get-PSSession Get-PSSessionConfiguration Get-PSSnapin Get-Random Get-Service +Get-TraceSource Get-Transaction Get-TypeData Get-UICulture Get-Unique Get-Variable Get-Verb +Get-WinEvent Get-WmiObject Group-Object +H: +help +I: +Import-Alias Import-Clixml Import-Counter Import-Csv Import-LocalizedData Import-Module +Import-PSSession ImportSystemModules Invoke-Command Invoke-Expression Invoke-History +Invoke-Item Invoke-RestMethod Invoke-WebRequest Invoke-WmiMethod +J: +Join-Path +K: +L: +Limit-EventLog +M: +Measure-Command Measure-Object mkdir more Move-Item Move-ItemProperty +N: +New-Alias New-Event New-EventLog New-Item New-ItemProperty New-Module New-ModuleManifest +New-Object New-PSDrive New-PSSession New-PSSessionConfigurationFile New-PSSessionOption +New-PSTransportOption New-Service New-TimeSpan New-Variable New-WebServiceProxy +New-WinEvent +O: +oss Out-Default Out-File Out-GridView Out-Host Out-Null Out-Printer Out-String +P: +Pause Pop-Location prompt Push-Location +Q: +R: +Read-Host Receive-Job Receive-PSSession Register-EngineEvent Register-ObjectEvent +Register-PSSessionConfiguration Register-WmiEvent Remove-Computer Remove-Event +Remove-EventLog Remove-Item Remove-ItemProperty Remove-Job Remove-Module +Remove-PSBreakpoint Remove-PSDrive Remove-PSSession Remove-PSSnapin Remove-TypeData +Remove-Variable Remove-WmiObject Rename-Computer Rename-Item Rename-ItemProperty +Reset-ComputerMachinePassword Resolve-Path Restart-Computer Restart-Service +Restore-Computer Resume-Job Resume-Service +S: +Save-Help Select-Object Select-String Select-Xml Send-MailMessage Set-Acl Set-Alias +Set-AuthenticodeSignature Set-Content Set-Date Set-ExecutionPolicy Set-Item +Set-ItemProperty Set-Location Set-PSBreakpoint Set-PSDebug +Set-PSSessionConfiguration Set-Service Set-StrictMode Set-TraceSource Set-Variable +Set-WmiInstance Show-Command Show-ControlPanelItem Show-EventLog Sort-Object +Split-Path Start-Job Start-Process Start-Service Start-Sleep Start-Transaction +Start-Transcript Stop-Computer Stop-Job Stop-Process Stop-Service Stop-Transcript +Suspend-Job Suspend-Service +T: +TabExpansion2 Tee-Object Test-ComputerSecureChannel Test-Connection +Test-ModuleManifest Test-Path Test-PSSessionConfigurationFile Trace-Command +U: +Unblock-File Undo-Transaction Unregister-Event Unregister-PSSessionConfiguration +Update-FormatData Update-Help Update-List Update-TypeData Use-Transaction +V: +W: +Wait-Event Wait-Job Wait-Process Where-Object Write-Debug Write-Error Write-EventLog +Write-Host Write-Output Write-Progress Write-Verbose Write-Warning +X: +Y: +Z: -

    MIME types defined: text/x-powershell.

    diff --git a/mode/powershell/powershell.js b/mode/powershell/powershell.js index 944088fbbe..f63111b2c8 100644 --- a/mode/powershell/powershell.js +++ b/mode/powershell/powershell.js @@ -1,191 +1,345 @@ -CodeMirror.defineMode("powershell", function() { - var ERRORCLASS = 'error'; +// Initially based on CodeMirror Python mode, copyright (c) by Marijn Haverbeke and others +// PowerShell mode, copyright (c) Andrey Shchekin, VapidWorx and others +// Distributed under an MIT license: http://codemirror.net/LICENSE - function wordRegexp(words) { - return new RegExp("^((" + words.join(")|(") + "))\\b"); +(function(mod) { + 'use strict'; + if (typeof exports == 'object' && typeof module == 'object') // CommonJS + mod(require('codemirror')); + else if (typeof define == 'function' && define.amd) // AMD + define(['codemirror'], mod); + else // Plain browser env + mod(window.CodeMirror); +})(function(CodeMirror) { +'use strict'; + +CodeMirror.defineMode('powershell', function() { + function buildRegexp(patterns, options) { + options = options || {}; + var prefix = options.prefix !== undefined ? options.prefix : '^'; + var suffix = options.suffix !== undefined ? options.suffix : '\\b'; + + for (var i = 0; i < patterns.length; i++) { + if (patterns[i] instanceof RegExp) { + patterns[i] = patterns[i].source; + } + else { + patterns[i] = patterns[i].replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + } + } + + return new RegExp(prefix + '(' + patterns.join('|') + ')' + suffix, 'i'); } - var wordOperators = wordRegexp(['-eq', '-ne', '-gt', '-lt', '-le', '-ge']); - var commonkeywords = ['begin', 'break', 'continue', 'do', 'default', 'else', 'elseif', - 'end', 'filter', 'for', 'foreach', 'function', 'if', 'in', 'param', - 'process', 'return', 'switch', 'until', 'where', 'while']; + var notCharacterOrDash = '(?=[^A-Z\\d\\-_]|$)'; + var keywords = buildRegexp([ + /begin|break|catch|continue|data|default|do|dynamicparam/, + /else|elseif|end|exit|filter|finally|for|foreach|from|function|if|in/, + /param|process|return|switch|throw|trap|try|until|where|while/ + ], { suffix: notCharacterOrDash }); + + var punctuation = /[\[\]{},;`\.]|@[({]/; + var wordOperators = buildRegexp([ + 'f', + /b?not/, + /[ic]?split/, 'join', + /is(not)?/, 'as', + /[ic]?(eq|ne|[gl][te])/, + /[ic]?(not)?(like|match|contains)/, + /[ic]?replace/, + /b?(and|or|xor)/ + ], { prefix: '-' }); + var symbolOperators = /[+\-*\/%]=|\+\+|--|\.\.|[+\-*&^%:=<>!|\/]/; + var operators = buildRegexp([wordOperators, symbolOperators], { suffix: '' }); + + var numbers = /^[+-]?(0x[\da-f]+|(\d+(\.\d+)?|\.\d*)(e[\+\-]?\d+)?)[ld]?([kmgtp]b)?/i; - var isOperatorChar = /[+\-*&^%:=<>!|\/]/; - var isString = /("|')(\`?.)*?\1/; - - var keywords = wordRegexp(commonkeywords); - //var builtins = wordRegexp(commonBuiltins); + var identifiers = /^[A-Za-z\_][A-Za-z\-\_\d]*\b/; - var indentInfo = null; + var symbolBuiltins = /[A-Z]:|%|\?/i; + var namedBuiltins = buildRegexp([ + /Add-(Computer|Content|History|Member|PSSnapin|Type)/, + /Checkpoint-Computer/, + /Clear-(Content|EventLog|History|Host|Item(Property)?|Variable)/, + /Compare-Object/, + /Complete-Transaction/, + /Connect-PSSession/, + /ConvertFrom-(Csv|Json|SecureString|StringData)/, + /Convert-Path/, + /ConvertTo-(Csv|Html|Json|SecureString|Xml)/, + /Copy-Item(Property)?/, + /Debug-Process/, + /Disable-(ComputerRestore|PSBreakpoint|PSRemoting|PSSessionConfiguration)/, + /Disconnect-PSSession/, + /Enable-(ComputerRestore|PSBreakpoint|PSRemoting|PSSessionConfiguration)/, + /(Enter|Exit)-PSSession/, + /Export-(Alias|Clixml|Console|Counter|Csv|FormatData|ModuleMember|PSSession)/, + /ForEach-Object/, + /Format-(Custom|List|Table|Wide)/, + new RegExp('Get-(Acl|Alias|AuthenticodeSignature|ChildItem|Command|ComputerRestorePoint|Content|ControlPanelItem|Counter|Credential' + + '|Culture|Date|Event|EventLog|EventSubscriber|ExecutionPolicy|FormatData|Help|History|Host|HotFix|Item|ItemProperty|Job' + + '|Location|Member|Module|PfxCertificate|Process|PSBreakpoint|PSCallStack|PSDrive|PSProvider|PSSession|PSSessionConfiguration' + + '|PSSnapin|Random|Service|TraceSource|Transaction|TypeData|UICulture|Unique|Variable|Verb|WinEvent|WmiObject)'), + /Group-Object/, + /Import-(Alias|Clixml|Counter|Csv|LocalizedData|Module|PSSession)/, + /ImportSystemModules/, + /Invoke-(Command|Expression|History|Item|RestMethod|WebRequest|WmiMethod)/, + /Join-Path/, + /Limit-EventLog/, + /Measure-(Command|Object)/, + /Move-Item(Property)?/, + new RegExp('New-(Alias|Event|EventLog|Item(Property)?|Module|ModuleManifest|Object|PSDrive|PSSession|PSSessionConfigurationFile' + + '|PSSessionOption|PSTransportOption|Service|TimeSpan|Variable|WebServiceProxy|WinEvent)'), + /Out-(Default|File|GridView|Host|Null|Printer|String)/, + /Pause/, + /(Pop|Push)-Location/, + /Read-Host/, + /Receive-(Job|PSSession)/, + /Register-(EngineEvent|ObjectEvent|PSSessionConfiguration|WmiEvent)/, + /Remove-(Computer|Event|EventLog|Item(Property)?|Job|Module|PSBreakpoint|PSDrive|PSSession|PSSnapin|TypeData|Variable|WmiObject)/, + /Rename-(Computer|Item(Property)?)/, + /Reset-ComputerMachinePassword/, + /Resolve-Path/, + /Restart-(Computer|Service)/, + /Restore-Computer/, + /Resume-(Job|Service)/, + /Save-Help/, + /Select-(Object|String|Xml)/, + /Send-MailMessage/, + new RegExp('Set-(Acl|Alias|AuthenticodeSignature|Content|Date|ExecutionPolicy|Item(Property)?|Location|PSBreakpoint|PSDebug' + + '|PSSessionConfiguration|Service|StrictMode|TraceSource|Variable|WmiInstance)'), + /Show-(Command|ControlPanelItem|EventLog)/, + /Sort-Object/, + /Split-Path/, + /Start-(Job|Process|Service|Sleep|Transaction|Transcript)/, + /Stop-(Computer|Job|Process|Service|Transcript)/, + /Suspend-(Job|Service)/, + /TabExpansion2/, + /Tee-Object/, + /Test-(ComputerSecureChannel|Connection|ModuleManifest|Path|PSSessionConfigurationFile)/, + /Trace-Command/, + /Unblock-File/, + /Undo-Transaction/, + /Unregister-(Event|PSSessionConfiguration)/, + /Update-(FormatData|Help|List|TypeData)/, + /Use-Transaction/, + /Wait-(Event|Job|Process)/, + /Where-Object/, + /Write-(Debug|Error|EventLog|Host|Output|Progress|Verbose|Warning)/, + /cd|help|mkdir|more|oss|prompt/, + /ac|asnp|cat|cd|chdir|clc|clear|clhy|cli|clp|cls|clv|cnsn|compare|copy|cp|cpi|cpp|cvpa|dbp|del|diff|dir|dnsn|ebp/, + /echo|epal|epcsv|epsn|erase|etsn|exsn|fc|fl|foreach|ft|fw|gal|gbp|gc|gci|gcm|gcs|gdr|ghy|gi|gjb|gl|gm|gmo|gp|gps/, + /group|gsn|gsnp|gsv|gu|gv|gwmi|h|history|icm|iex|ihy|ii|ipal|ipcsv|ipmo|ipsn|irm|ise|iwmi|iwr|kill|lp|ls|man|md/, + /measure|mi|mount|move|mp|mv|nal|ndr|ni|nmo|npssc|nsn|nv|ogv|oh|popd|ps|pushd|pwd|r|rbp|rcjb|rcsn|rd|rdr|ren|ri/, + /rjb|rm|rmdir|rmo|rni|rnp|rp|rsn|rsnp|rujb|rv|rvpa|rwmi|sajb|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls/, + /sort|sp|spjb|spps|spsv|start|sujb|sv|swmi|tee|trcm|type|where|wjb|write/, + ], { prefix: '', suffix: '' }); + var variableBuiltins = buildRegexp([ + /[$?^_]|Args|ConfirmPreference|ConsoleFileName|DebugPreference|Error|ErrorActionPreference|ErrorView|ExecutionContext/, + /FormatEnumerationLimit|Home|Host|Input|MaximumAliasCount|MaximumDriveCount|MaximumErrorCount|MaximumFunctionCount/, + /MaximumHistoryCount|MaximumVariableCount|MyInvocation|NestedPromptLevel|OutputEncoding|Pid|Profile|ProgressPreference/, + /PSBoundParameters|PSCommandPath|PSCulture|PSDefaultParameterValues|PSEmailServer|PSHome|PSScriptRoot|PSSessionApplicationName/, + /PSSessionConfigurationName|PSSessionOption|PSUICulture|PSVersionTable|Pwd|ShellId|StackTrace|VerbosePreference/, + /WarningPreference|WhatIfPreference/, + + /Event|EventArgs|EventSubscriber|Sender/, + /Matches|Ofs|ForEach|LastExitCode|PSCmdlet|PSItem|PSSenderInfo|This/, + /true|false|null/ + ], { prefix: '\\$', suffix: '' }); + + var builtins = buildRegexp([ symbolBuiltins, namedBuiltins, variableBuiltins ], { suffix: notCharacterOrDash }); + + var grammar = { + keyword: keywords, + number: numbers, + operator: operators, + builtin: builtins, + punctuation: punctuation, + indetifier: identifiers + }; // tokenizers function tokenBase(stream, state) { - - - - // Handle Comments - //var ch = stream.peek(); - - if (stream.match(keywords)) { - return('variable-2'); - } - - if (stream.match(isString)) { - return('string'); - } - - if (stream.match(wordOperators)) { - return('variable-2'); - } - if (stream.match(isOperatorChar)) { - return('variable-1'); - } - - - // Handle Variables - - - // Handle Number Literals - if (stream.match(/^[0-9\.]/, false)) { - var floatLiteral = false; - // Floats - if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; } - if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; } - if (stream.match(/^\.\d+/)) { floatLiteral = true; } - if (floatLiteral) { - // Float literals may be "imaginary" - stream.eat(/J/i); - return 'number'; - } - // Integers - var intLiteral = false; - // Hex - if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; } - // Binary - if (stream.match(/^0b[01]+/i)) { intLiteral = true; } - // Octal - if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; } - // Decimal - if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) { - // Decimal literals may be "imaginary" - stream.eat(/J/i); - // TODO - Can you have imaginary longs? - intLiteral = true; - } - // Zero by itself with no other piece of number. - if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; } - if (intLiteral) { - // Integer literals may be "long" - stream.eat(/L/i); - return 'number'; + // Handle Comments + //var ch = stream.peek(); + + if (stream.eatSpace()) { + return null; + } + + var parent = state.returnStack[state.returnStack.length - 1]; + if (parent && parent.shouldReturnFrom(state)) { + state.tokenize = parent.tokenize; + state.returnStack.pop(); + return state.tokenize(stream, state); + } + + if (stream.eat('(')) { + state.bracketNesting += 1; + return 'punctuation'; + } + + if (stream.eat(')')) { + state.bracketNesting -= 1; + return 'punctuation'; + } + + for (var key in grammar) { + if (stream.match(grammar[key])) { + return key; } } - var ch = stream.next(); + // single-quote string + if (stream.match(/'([^']|'')+'/)) { + return 'string'; + } + + var ch = stream.next(); + if (ch === '$') { + return tokenVariable(stream, state); + } + + // double-quote string + if (ch === '"') { + return tokenDoubleQuoteString(stream, state); + } - if (ch === '$') { - if (stream.eat('{')) { - state.tokenize = tokenVariable; - return tokenVariable(stream, state); - } else { - stream.eatWhile(/[\w\\\-]/); - return 'variable-2'; - } - } - if (ch === '<' && stream.eat('#')) { - state.tokenize = tokenComment; - return tokenComment(stream, state); - } - - if (ch === '#') { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + + if (ch === '#') { stream.skipToEnd(); return 'comment'; } - if (ch === '@' && stream.eat('\"')) { - state.tokenize = tokenMultiString; - return tokenMultiString(stream, state); - } - - //if (isOperatorChar.test(ch)) { - // stream.eat; - //stream.next; - // return("variable-1"); - // } + if (ch === '@') { + var quoteMatch = stream.eat(/["']/); + if (quoteMatch && stream.eol()) { + state.tokenize = tokenMultiString; + state.startQuote = quoteMatch[0]; + return tokenMultiString(stream, state); + } + } stream.next(); - return ERRORCLASS; + return 'error'; + } + + function tokenDoubleQuoteString(stream, state) { + var ch; + while((ch = stream.peek()) != null) { + if (ch === '$') { + state.tokenize = tokenInterpolation; + return 'string'; + } + + stream.next(); + if (ch === '`') { + stream.next(); + continue; + } + + if (ch === '"' && !stream.eat('"')) { + state.tokenize = tokenBase; + return 'string'; + } + } + + return 'error'; + } + + function tokenInterpolation(stream, state) { + if (stream.match('$(')) { + var savedBracketNesting = state.bracketNesting; + state.returnStack.push({ + /*jshint loopfunc:true */ + shouldReturnFrom: function(state) { + return state.bracketNesting === savedBracketNesting; + }, + tokenize: tokenDoubleQuoteString + }); + state.tokenize = tokenBase; + state.bracketNesting += 1; + return 'punctuation'; + } else { + stream.next(); + state.returnStack.push({ + shouldReturnFrom: function() { return true; }, + tokenize: tokenDoubleQuoteString + }); + state.tokenize = tokenVariable; + return state.tokenize(stream, state); + } } - - function tokenComment(stream, state) { - var maybeEnd = false, ch; - while ((ch = stream.next()) != null) { - if (maybeEnd && ch == ">") { - state.tokenize = tokenBase; - break; - } - maybeEnd = (ch === '#'); + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == '>') { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch === '#'); + } + return 'comment'; } - return("comment"); - } - - function tokenVariable(stream, state) { - while ((ch = stream.next()) != null) { - if (ch == "}") { - state.tokenize = tokenBase; - break; - } + + function tokenVariable(stream, state) { + if (stream.eat('{')) { + state.tokenize = tokenVariableWithBraces; + return tokenVariableWithBraces(stream, state); + } else { + stream.eatWhile(/[\w\\\-:]/); + state.tokenize = tokenBase; + return 'variable-2'; + } } - return("variable-2"); - } - - function tokenMultiString(stream, state) { - var maybeEnd = false, ch; - while ((ch = stream.next()) != null) { - if (maybeEnd && ch == "@") { - state.tokenize = tokenBase; - break; - } - maybeEnd = (ch === '"'); + + function tokenVariableWithBraces(stream, state) { + var ch; + while ((ch = stream.next()) != null) { + if (ch === '}') { + state.tokenize = tokenBase; + break; + } + } + return 'variable-2'; } - return("string"); - } - - function tokenLexer(stream, state) { - //indentInfo = null; - var style = state.tokenize(stream, state); - //var current = stream.current(); - return style; + + function tokenMultiString(stream, state) { + var quote = state.startQuote; + if (stream.sol() && stream.match(new RegExp(quote + '@'))) { + state.tokenize = tokenBase; + } + else { + stream.skipToEnd(); + } + + return 'string'; } var external = { - startState: function(basecolumn) { + startState: function() { return { - tokenize: tokenBase, - scopes: [{offset:basecolumn || 0, type:'py'}], - lastToken: null, - lambda: false, - dedent: 0 - }; + returnStack: [], + bracketNesting: 0, + tokenize: tokenBase + }; }, token: function(stream, state) { - var style = tokenLexer(stream, state); - state.lastToken = {style:style, content: stream.current()}; - if (stream.eol() && stream.lambda) { - state.lambda = false; - } - - return style; + return state.tokenize(stream, state); }, - blockCommentStart: "<#", - blockCommentEnd: "#>", - lineComment: "#" + blockCommentStart: '<#', + blockCommentEnd: '#>', + lineComment: '#' }; return external; }); -CodeMirror.defineMIME("text/x-powershell", "powershell"); +CodeMirror.defineMIME('text/x-powershell', 'powershell'); +}); \ No newline at end of file From d0e82a76f88a1e359447da39df2cb68c31067f6a Mon Sep 17 00:00:00 2001 From: Ben Miller Date: Thu, 24 Sep 2015 15:48:23 +1200 Subject: [PATCH 050/191] [powershell mode] Improve corrected angle bracket matching in operators (fixes block comments) corrected digit matching regex corrected spelling of 'identifier' in grammar dictionary notCharacterOrDash explicitly includes lowercase characters improved variable matching splatted variables now match bare '$' and '@' are errors, not variables moved single-quoted string processing into tokenSingleQuoteString incomplete strings are errors now empty strings are no longer errors added support for here-string interpolation with nesting support added highlighting for splatted vars removed arbitrary stream advancement prior to default error in tokenBase enabled folding braces --- mode/powershell/powershell.js | 104 ++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 24 deletions(-) diff --git a/mode/powershell/powershell.js b/mode/powershell/powershell.js index f63111b2c8..8295635a6f 100644 --- a/mode/powershell/powershell.js +++ b/mode/powershell/powershell.js @@ -1,6 +1,9 @@ -// Initially based on CodeMirror Python mode, copyright (c) by Marijn Haverbeke and others -// PowerShell mode, copyright (c) Andrey Shchekin, VapidWorx and others -// Distributed under an MIT license: http://codemirror.net/LICENSE +/** + * @license + * Initially based on CodeMirror Python mode, copyright (c) by Marijn Haverbeke and others + * PowerShell mode, copyright (c) Andrey Shchekin, VapidWorx and others + * Distributed under an MIT license: http://codemirror.net/LICENSE + */ (function(mod) { 'use strict'; @@ -31,7 +34,8 @@ CodeMirror.defineMode('powershell', function() { return new RegExp(prefix + '(' + patterns.join('|') + ')' + suffix, 'i'); } - var notCharacterOrDash = '(?=[^A-Z\\d\\-_]|$)'; + var notCharacterOrDash = '(?=[^A-Za-z\\d\\-_]|$)'; + var varNames = /[\w\-:]/ var keywords = buildRegexp([ /begin|break|catch|continue|data|default|do|dynamicparam/, /else|elseif|end|exit|filter|finally|for|foreach|from|function|if|in/, @@ -49,10 +53,10 @@ CodeMirror.defineMode('powershell', function() { /[ic]?replace/, /b?(and|or|xor)/ ], { prefix: '-' }); - var symbolOperators = /[+\-*\/%]=|\+\+|--|\.\.|[+\-*&^%:=<>!|\/]/; + var symbolOperators = /[+\-*\/%]=|\+\+|--|\.\.|[+\-*&^%:=!|\/]|<(?!#)|(?!#)>/; var operators = buildRegexp([wordOperators, symbolOperators], { suffix: '' }); - var numbers = /^[+-]?(0x[\da-f]+|(\d+(\.\d+)?|\.\d*)(e[\+\-]?\d+)?)[ld]?([kmgtp]b)?/i; + var numbers = /^[+-]?((0x[\da-f]+)|((\d+\.\d+|\d\.|\.\d+|\d+)(e[\+\-]?\d+)?))[ld]?([kmgtp]b)?/i; var identifiers = /^[A-Za-z\_][A-Za-z\-\_\d]*\b/; @@ -106,8 +110,8 @@ CodeMirror.defineMode('powershell', function() { /Save-Help/, /Select-(Object|String|Xml)/, /Send-MailMessage/, - new RegExp('Set-(Acl|Alias|AuthenticodeSignature|Content|Date|ExecutionPolicy|Item(Property)?|Location|PSBreakpoint|PSDebug' - + '|PSSessionConfiguration|Service|StrictMode|TraceSource|Variable|WmiInstance)'), + new RegExp('Set-(Acl|Alias|AuthenticodeSignature|Content|Date|ExecutionPolicy|Item(Property)?|Location|PSBreakpoint|PSDebug' + + '|PSSessionConfiguration|Service|StrictMode|TraceSource|Variable|WmiInstance)'), /Show-(Command|ControlPanelItem|EventLog)/, /Sort-Object/, /Split-Path/, @@ -132,7 +136,7 @@ CodeMirror.defineMode('powershell', function() { /group|gsn|gsnp|gsv|gu|gv|gwmi|h|history|icm|iex|ihy|ii|ipal|ipcsv|ipmo|ipsn|irm|ise|iwmi|iwr|kill|lp|ls|man|md/, /measure|mi|mount|move|mp|mv|nal|ndr|ni|nmo|npssc|nsn|nv|ogv|oh|popd|ps|pushd|pwd|r|rbp|rcjb|rcsn|rd|rdr|ren|ri/, /rjb|rm|rmdir|rmo|rni|rnp|rp|rsn|rsnp|rujb|rv|rvpa|rwmi|sajb|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls/, - /sort|sp|spjb|spps|spsv|start|sujb|sv|swmi|tee|trcm|type|where|wjb|write/, + /sort|sp|spjb|spps|spsv|start|sujb|sv|swmi|tee|trcm|type|where|wjb|write/ ], { prefix: '', suffix: '' }); var variableBuiltins = buildRegexp([ /[$?^_]|Args|ConfirmPreference|ConsoleFileName|DebugPreference|Error|ErrorActionPreference|ErrorView|ExecutionContext/, @@ -147,7 +151,7 @@ CodeMirror.defineMode('powershell', function() { /true|false|null/ ], { prefix: '\\$', suffix: '' }); - var builtins = buildRegexp([ symbolBuiltins, namedBuiltins, variableBuiltins ], { suffix: notCharacterOrDash }); + var builtins = buildRegexp([symbolBuiltins, namedBuiltins, variableBuiltins], { suffix: notCharacterOrDash }); var grammar = { keyword: keywords, @@ -155,7 +159,7 @@ CodeMirror.defineMode('powershell', function() { operator: operators, builtin: builtins, punctuation: punctuation, - indetifier: identifiers + identifier: identifiers }; // tokenizers @@ -190,12 +194,13 @@ CodeMirror.defineMode('powershell', function() { } } + var ch = stream.next(); + // single-quote string - if (stream.match(/'([^']|'')+'/)) { - return 'string'; + if (ch === "'") { + return tokenSingleQuoteString(stream, state); } - var ch = stream.next(); if (ch === '$') { return tokenVariable(stream, state); } @@ -221,18 +226,35 @@ CodeMirror.defineMode('powershell', function() { state.tokenize = tokenMultiString; state.startQuote = quoteMatch[0]; return tokenMultiString(stream, state); + } else if (stream.peek().match(/[({]/)) { + return 'punctuation'; + } else if (stream.match(varNames)) { + // splatted variable + return tokenVariable(stream, state); + } + } + return 'error'; + } + + function tokenSingleQuoteString(stream, state) { + var ch; + while ((ch = stream.peek()) != null) { + stream.next(); + + if (ch === "'" && !stream.eat("'")) { + state.tokenize = tokenBase; + return 'string'; } } - stream.next(); return 'error'; } function tokenDoubleQuoteString(stream, state) { var ch; - while((ch = stream.peek()) != null) { + while ((ch = stream.peek()) != null) { if (ch === '$') { - state.tokenize = tokenInterpolation; + state.tokenize = tokenStringInterpolation; return 'string'; } @@ -251,7 +273,22 @@ CodeMirror.defineMode('powershell', function() { return 'error'; } - function tokenInterpolation(stream, state) { + function tokenStringInterpolation(stream, state) { + return tokenInterpolation(stream, state, tokenDoubleQuoteString); + } + + function tokenMultiStringReturn(stream, state) { + state.tokenize = tokenMultiString; + state.startQuote = '"' + return tokenMultiString(stream, state); + } + + function tokenHereStringInterpolation(stream, state) { + var saved; + return tokenInterpolation(stream, state, tokenMultiStringReturn); + } + + function tokenInterpolation(stream, state, parentTokenize) { if (stream.match('$(')) { var savedBracketNesting = state.bracketNesting; state.returnStack.push({ @@ -259,7 +296,7 @@ CodeMirror.defineMode('powershell', function() { shouldReturnFrom: function(state) { return state.bracketNesting === savedBracketNesting; }, - tokenize: tokenDoubleQuoteString + tokenize: parentTokenize }); state.tokenize = tokenBase; state.bracketNesting += 1; @@ -268,7 +305,7 @@ CodeMirror.defineMode('powershell', function() { stream.next(); state.returnStack.push({ shouldReturnFrom: function() { return true; }, - tokenize: tokenDoubleQuoteString + tokenize: parentTokenize }); state.tokenize = tokenVariable; return state.tokenize(stream, state); @@ -288,13 +325,17 @@ CodeMirror.defineMode('powershell', function() { } function tokenVariable(stream, state) { + var ch = stream.peek(); if (stream.eat('{')) { state.tokenize = tokenVariableWithBraces; return tokenVariableWithBraces(stream, state); - } else { - stream.eatWhile(/[\w\\\-:]/); + } else if (ch != undefined && ch.match(varNames)) { + stream.eatWhile(varNames); state.tokenize = tokenBase; return 'variable-2'; + } else { + state.tokenize = tokenBase; + return 'error'; } } @@ -314,6 +355,20 @@ CodeMirror.defineMode('powershell', function() { if (stream.sol() && stream.match(new RegExp(quote + '@'))) { state.tokenize = tokenBase; } + else if (quote === '"') { + while (!stream.eol()) { + var ch = stream.peek(); + if (ch === '$') { + state.tokenize = tokenHereStringInterpolation; + return 'string'; + } + + stream.next(); + if (ch === '`') { + stream.next(); + } + } + } else { stream.skipToEnd(); } @@ -336,10 +391,11 @@ CodeMirror.defineMode('powershell', function() { blockCommentStart: '<#', blockCommentEnd: '#>', - lineComment: '#' + lineComment: '#', + fold: 'brace' }; return external; }); CodeMirror.defineMIME('text/x-powershell', 'powershell'); -}); \ No newline at end of file +}); From 95f6840611f8b7025de3783f8408e9f353a830cc Mon Sep 17 00:00:00 2001 From: Andrey Shchekin Date: Sun, 27 Mar 2016 22:11:07 +1300 Subject: [PATCH 051/191] [powershell mode] Prepare for merge into CodeMirror repository Added tests and fixed some issues uncovered by testing. --- mode/powershell/index.html | 46 ++- mode/powershell/powershell.js | 697 +++++++++++++++++----------------- mode/powershell/test.js | 72 ++++ test/index.html | 2 + 4 files changed, 451 insertions(+), 366 deletions(-) create mode 100644 mode/powershell/test.js diff --git a/mode/powershell/index.html b/mode/powershell/index.html index bc0f9c486c..6b235df8f1 100644 --- a/mode/powershell/index.html +++ b/mode/powershell/index.html @@ -3,15 +3,30 @@ CodeMirror: Powershell mode - - - + + + + -

    CodeMirror: Powershell mode

    +
    CodeMirror.defineDocExtension(name: string, value: any)
    -
    Like defineExtension, +
    Like defineExtension, but the method will be added to the interface for Doc objects instead.
    diff --git a/index.html b/index.html index 1f775abc69..da5a06c49d 100644 --- a/index.html +++ b/index.html @@ -106,7 +106,7 @@

    This is CodeMirror

    maintainers need to subsist.
    Current funding status =
    You can help per month or - once. + once.
    diff --git a/keymap/vim.js b/keymap/vim.js index b7e8d85889..7f2fb62743 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -26,7 +26,7 @@ * 2. Variable declarations and short basic helpers * 3. Instance (External API) implementation * 4. Internal state tracking objects (input state, counter) implementation - * and instanstiation + * and instantiation * 5. Key handler (the main command dispatcher) implementation * 6. Motion, operator, and action implementations * 7. Helper functions for the key handler, motions, operators, and actions @@ -642,7 +642,7 @@ jumpList: createCircularJumpList(), macroModeState: new MacroModeState, // Recording latest f, t, F or T motion command. - lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''}, + lastCharacterSearch: {increment:0, forward:true, selectedCharacter:''}, registerController: new RegisterController({}), // search history buffer searchHistoryController: new HistoryController({}), @@ -1373,7 +1373,7 @@ } }, evalInput: function(cm, vim) { - // If the motion comand is set, execute both the operator and motion. + // If the motion command is set, execute both the operator and motion. // Otherwise return. var inputState = vim.inputState; var motion = inputState.motion; @@ -1910,7 +1910,7 @@ }, repeatLastCharacterSearch: function(cm, head, motionArgs) { - var lastSearch = vimGlobalState.lastChararacterSearch; + var lastSearch = vimGlobalState.lastCharacterSearch; var repeat = motionArgs.repeat; var forward = motionArgs.forward === lastSearch.forward; var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1); @@ -3089,9 +3089,9 @@ } function recordLastCharacterSearch(increment, args) { - vimGlobalState.lastChararacterSearch.increment = increment; - vimGlobalState.lastChararacterSearch.forward = args.forward; - vimGlobalState.lastChararacterSearch.selectedCharacter = args.selectedCharacter; + vimGlobalState.lastCharacterSearch.increment = increment; + vimGlobalState.lastCharacterSearch.forward = args.forward; + vimGlobalState.lastCharacterSearch.selectedCharacter = args.selectedCharacter; } var symbolToMode = { @@ -3451,7 +3451,7 @@ } // TODO: perhaps this finagling of start and end positions belonds - // in codmirror/replaceRange? + // in codemirror/replaceRange? function selectCompanionObject(cm, head, symb, inclusive) { var cur = head, start, end; diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 34d3a5afd3..695d5ceff3 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -667,7 +667,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { def("text/x-objectivec", { name: "clike", - keywords: words(cKeywords + "inline restrict _Bool _Complex _Imaginery BOOL Class bycopy byref id IMP in " + + keywords: words(cKeywords + "inline restrict _Bool _Complex _Imaginary BOOL Class bycopy byref id IMP in " + "inout nil oneway out Protocol SEL self super atomic nonatomic retain copy readwrite readonly"), types: words(cTypes), atoms: words("YES NO NULL NILL ON OFF true false"), diff --git a/mode/crystal/crystal.js b/mode/crystal/crystal.js index 2e74bee436..e63627cee8 100644 --- a/mode/crystal/crystal.js +++ b/mode/crystal/crystal.js @@ -209,7 +209,7 @@ // Operators if (stream.match(operators)) { - stream.eat("="); // Operators can follow assigin symbol. + stream.eat("="); // Operators can follow assign symbol. return "operator"; } diff --git a/mode/django/django.js b/mode/django/django.js index a8a7d8311d..7b4ef3b566 100644 --- a/mode/django/django.js +++ b/mode/django/django.js @@ -66,11 +66,11 @@ } // A string can be included in either single or double quotes (this is - // the delimeter). Mark everything as a string until the start delimeter + // the delimiter). Mark everything as a string until the start delimiter // occurs again. - function inString (delimeter, previousTokenizer) { + function inString (delimiter, previousTokenizer) { return function (stream, state) { - if (!state.escapeNext && stream.eat(delimeter)) { + if (!state.escapeNext && stream.eat(delimiter)) { state.tokenize = previousTokenizer; } else { if (state.escapeNext) { @@ -80,7 +80,7 @@ var ch = stream.next(); // Take into account the backslash for escaping characters, such as - // the string delimeter. + // the string delimiter. if (ch == "\\") { state.escapeNext = true; } @@ -100,7 +100,7 @@ return "null"; } - // Dot folowed by a non-word character should be considered an error. + // Dot followed by a non-word character should be considered an error. if (stream.match(/\.\W+/)) { return "error"; } else if (stream.eat(".")) { @@ -119,7 +119,7 @@ return "null"; } - // Pipe folowed by a non-word character should be considered an error. + // Pipe followed by a non-word character should be considered an error. if (stream.match(/\.\W+/)) { return "error"; } else if (stream.eat("|")) { @@ -199,7 +199,7 @@ return "null"; } - // Dot folowed by a non-word character should be considered an error. + // Dot followed by a non-word character should be considered an error. if (stream.match(/\.\W+/)) { return "error"; } else if (stream.eat(".")) { @@ -218,7 +218,7 @@ return "null"; } - // Pipe folowed by a non-word character should be considered an error. + // Pipe followed by a non-word character should be considered an error. if (stream.match(/\.\W+/)) { return "error"; } else if (stream.eat("|")) { diff --git a/mode/gfm/index.html b/mode/gfm/index.html index 7e38c52d60..24c90c068e 100644 --- a/mode/gfm/index.html +++ b/mode/gfm/index.html @@ -47,7 +47,7 @@

    GFM mode

    GFM adds syntax to strikethrough text, which is missing from standard Markdown. ~~Mistaken text.~~ -~~**works with other fomatting**~~ +~~**works with other formatting**~~ ~~spans across lines~~ diff --git a/mode/haml/haml.js b/mode/haml/haml.js index 03ce83355c..86def73ebb 100644 --- a/mode/haml/haml.js +++ b/mode/haml/haml.js @@ -11,7 +11,7 @@ })(function(CodeMirror) { "use strict"; - // full haml mode. This handled embeded ruby and html fragments too + // full haml mode. This handled embedded ruby and html fragments too CodeMirror.defineMode("haml", function(config) { var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"}); var rubyMode = CodeMirror.getMode(config, "ruby"); diff --git a/mode/htmlembedded/index.html b/mode/htmlembedded/index.html index 365ef8f366..f27582ef86 100644 --- a/mode/htmlembedded/index.html +++ b/mode/htmlembedded/index.html @@ -52,7 +52,7 @@

    Html Embedded Scripts mode

    Mode for html embedded scripts like JSP and ASP.NET. Depends on HtmlMixed which in turn depends on - JavaScript, CSS and XML.
    Other dependancies include those of the scriping language chosen.

    + JavaScript, CSS and XML.
    Other dependencies include those of the scripting language chosen.

    MIME types defined: application/x-aspx (ASP.NET), application/x-ejs (Embedded Javascript), application/x-jsp (JavaServer Pages)

    diff --git a/mode/markdown/test.js b/mode/markdown/test.js index a48d153107..e2b3a81527 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -647,7 +647,7 @@ MT("linkReferenceEmStrong", "[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string&url [[bar]]] hello"); - // Reference-style links with optional space separator (per docuentation) + // Reference-style links with optional space separator (per documentation) // "You can optionally use a space to separate the sets of brackets" MT("linkReferenceSpace", "[link [[foo]]] [string&url [[bar]]] hello"); @@ -683,7 +683,7 @@ MT("labelTitleSingleQuotes", "[link [[foo]]:] [string&url http://example.com/ 'bar']"); - MT("labelTitleParenthese", + MT("labelTitleParentheses", "[link [[foo]]:] [string&url http://example.com/ (bar)]"); MT("labelTitleInvalid", @@ -700,7 +700,7 @@ "[link [[foo]]:] [string&url http://example.com/]", "[string 'bar'] hello"); - MT("labelTitleNextParenthese", + MT("labelTitleNextParentheses", "[link [[foo]]:] [string&url http://example.com/]", "[string (bar)] hello"); diff --git a/mode/octave/index.html b/mode/octave/index.html index 79df581199..3490ee6371 100644 --- a/mode/octave/index.html +++ b/mode/octave/index.html @@ -65,7 +65,7 @@

    Octave mode

    %one line comment %{ multi -line commment %} +line comment %} + + + + + +
    +

    yacas mode

    + + + + + + +

    MIME types defined: text/x-yacas (yacas).

    +
    diff --git a/mode/yacas/yacas.js b/mode/yacas/yacas.js new file mode 100644 index 0000000000..2967382b43 --- /dev/null +++ b/mode/yacas/yacas.js @@ -0,0 +1,138 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Yacas mode copyright (c) 2015 by Grzegorz Mazur +// Loosely based on mathematica mode by Calin Barbat + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode('yacas', function(_config, _parserConfig) { + + // patterns + var pFloatForm = "(?:(?:\\.\\d+|\\d+\\.\\d*|\\d+)(?:[eE][+-]?\\d+)?)"; + var pIdentifier = "(?:[a-zA-Z\\$'][a-zA-Z0-9\\$']*)"; + + // regular expressions + var reFloatForm = new RegExp(pFloatForm); + var reIdentifier = new RegExp(pIdentifier); + var rePattern = new RegExp(pIdentifier + "?_" + pIdentifier); + var reFunctionLike = new RegExp(pIdentifier + "\\s*\\("); + + function tokenBase(stream, state) { + var ch; + + // get next character + ch = stream.next(); + + // string + if (ch === '"') { + state.tokenize = tokenString; + return state.tokenize(stream, state); + } + + // comment + if (ch === '/') { + if (stream.eat('*')) { + state.tokenize = tokenComment; + return state.tokenize(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + + // go back one character + stream.backUp(1); + + // look for ordered rules + if (stream.match(/\d+ *#/, true, false)) { + return 'qualifier'; + } + + // look for numbers + if (stream.match(reFloatForm, true, false)) { + return 'number'; + } + + // look for placeholders + if (stream.match(rePattern, true, false)) { + return 'variable-3'; + } + + // match all braces separately + if (stream.match(/(?:\[|\]|{|}|\(|\))/, true, false)) { + return 'bracket'; + } + + // literals looking like function calls + if (stream.match(reFunctionLike, true, false)) { + stream.backUp(1); + return 'variable'; + } + + // all other identifiers + if (stream.match(reIdentifier, true, false)) { + return 'variable-2'; + } + + // operators; note that operators like @@ or /; are matched separately for each symbol. + if (stream.match(/(?:\\|\+|\-|\*|\/|,|;|\.|:|@|~|=|>|<|&|\||_|`|'|\^|\?|!|%)/, true, false)) { + return 'operator'; + } + + // everything else is an error + return 'error'; + } + + function tokenString(stream, state) { + var next, end = false, escaped = false; + while ((next = stream.next()) != null) { + if (next === '"' && !escaped) { + end = true; + break; + } + escaped = !escaped && next === '\\'; + } + if (end && !escaped) { + state.tokenize = tokenBase; + } + return 'string'; + }; + + function tokenComment(stream, state) { + var prev, next; + while((next = stream.next()) != null) { + if (prev === '*' && next === '/') + break; + prev = next; + } + state.tokenize = tokenBase; + return 'comment'; + } + + return { + startState: function() {return {tokenize: tokenBase, commentLevel: 0};}, + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + }, + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" + }; +}); + +CodeMirror.defineMIME('text/x-yacas', { + name: 'yacas' +}); + +}); From 66fd40ff072151a1a451e2f1b80e34340d293d38 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Apr 2016 10:25:46 +0200 Subject: [PATCH 068/191] [manual] Explain the way fromTextArea can leak memory Issue #3938 --- doc/manual.html | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 59419027c0..ce03bd30c3 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,4 +1,4 @@ - + CodeMirror: User Manual @@ -2064,26 +2064,29 @@

    Static properties

    else (usually one) for dev snapshots.
    CodeMirror.fromTextArea(textArea: TextAreaElement, ?config: object)
    -
    - The method provides another way to initialize an editor. It - takes a textarea DOM node as first argument and an optional - configuration object as second. It will replace the textarea - with a CodeMirror instance, and wire up the form of that - textarea (if any) to make sure the editor contents are put - into the textarea when the form is submitted. The text in the - textarea will provide the content for the editor. A CodeMirror - instance created this way has three additional methods: -
    -
    cm.save()
    -
    Copy the content of the editor into the textarea.
    - -
    cm.toTextArea()
    -
    Remove the editor, and restore the original textarea (with - the editor's current content).
    - -
    cm.getTextArea() → TextAreaElement
    -
    Returns the textarea that the instance was based on.
    -
    +
    This method provides another way to initialize an editor. It + takes a textarea DOM node as first argument and an optional + configuration object as second. It will replace the textarea + with a CodeMirror instance, and wire up the form of that + textarea (if any) to make sure the editor contents are put into + the textarea when the form is submitted. The text in the + textarea will provide the content for the editor. A CodeMirror + instance created this way has three additional methods: +
    +
    cm.save()
    +
    Copy the content of the editor into the textarea.
    + +
    cm.toTextArea()
    +
    Remove the editor, and restore the original textarea (with + the editor's current content). If you dynamically create and + destroy editors made with `fromTextArea`, without destroying + the form they are part of, you should make sure to call + `toTextArea` to remove the editor, or its `"submit"` handler + on the form will cause a memory leak.
    + +
    cm.getTextArea() → TextAreaElement
    +
    Returns the textarea that the instance was based on.
    +
    CodeMirror.defaults: object
    From 225a35fc4a107fc0027c544743fe6c10d86f9f52 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Apr 2016 21:55:28 +0200 Subject: [PATCH 069/191] Bump version number to 5.13.5 5.13.4 was a trivial release restoring a LICENSE file. --- doc/manual.html | 2 +- lib/codemirror.js | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index ce03bd30c3..b513bf9408 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.13.3 + version 5.13.5

    CodeMirror is a code-editor component that can be embedded in diff --git a/lib/codemirror.js b/lib/codemirror.js index 22186b45ad..19baf0098f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -8890,7 +8890,7 @@ // THE END - CodeMirror.version = "5.13.3"; + CodeMirror.version = "5.13.5"; return CodeMirror; }); diff --git a/package.json b/package.json index 11551de2d6..ca0d787e49 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version":"5.13.3", + "version":"5.13.5", "main": "lib/codemirror.js", "description": "In-browser code editing made bearable", "license": "MIT", From d6e8f34ae926f782379e96a1d911e74363a6a416 Mon Sep 17 00:00:00 2001 From: Matt Pass Date: Wed, 6 Apr 2016 23:20:39 +0100 Subject: [PATCH 070/191] [icecoder theme] Warmer background and fixed matchingbracket --- theme/icecoder.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/theme/icecoder.css b/theme/icecoder.css index d70d26e820..ffebaf2f0b 100644 --- a/theme/icecoder.css +++ b/theme/icecoder.css @@ -2,7 +2,7 @@ ICEcoder default theme by Matt Pass, used in code editor available at https://icecoder.net */ -.cm-s-icecoder { color: #666; background: #141612; } +.cm-s-icecoder { color: #666; background: #1d1d1b; } .cm-s-icecoder span.cm-keyword { color: #eee; font-weight:bold; } /* off-white 1 */ .cm-s-icecoder span.cm-atom { color: #e1c76e; } /* yellow */ @@ -37,7 +37,7 @@ ICEcoder default theme by Matt Pass, used in code editor available at https://ic .cm-s-icecoder .CodeMirror-cursor { border-left: 1px solid white; } .cm-s-icecoder div.CodeMirror-selected { color: #fff; background: #037; } -.cm-s-icecoder .CodeMirror-gutters { background: #141612; min-width: 41px; border-right: 0; } +.cm-s-icecoder .CodeMirror-gutters { background: #1d1d1b; min-width: 41px; border-right: 0; } .cm-s-icecoder .CodeMirror-linenumber { color: #555; cursor: default; } -.cm-s-icecoder .CodeMirror-matchingbracket { border: 1px solid grey; color: black !important; } -.cm-s-icecoder .CodeMirror-activeline-background { background: #000; } \ No newline at end of file +.cm-s-icecoder .CodeMirror-matchingbracket { color: #fff !important; background: #555 !important; } +.cm-s-icecoder .CodeMirror-activeline-background { background: #000; } From adb73ffa1810807bfedf4a218e8cd1462425df14 Mon Sep 17 00:00:00 2001 From: Timothy Gu Date: Sat, 2 Apr 2016 20:25:41 -0700 Subject: [PATCH 071/191] [webidl mode] Add --- doc/compress.html | 1 + mode/index.html | 1 + mode/meta.js | 1 + mode/webidl/index.html | 71 +++++++++++++++ mode/webidl/webidl.js | 197 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 271 insertions(+) create mode 100644 mode/webidl/index.html create mode 100644 mode/webidl/webidl.js diff --git a/doc/compress.html b/doc/compress.html index 538ecbe5f0..44e6fea828 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -226,6 +226,7 @@

    Script compression helper

    + diff --git a/mode/index.html b/mode/index.html index efb64143a1..822f04fc61 100644 --- a/mode/index.html +++ b/mode/index.html @@ -149,6 +149,7 @@

    Language modes

  • Verilog/SystemVerilog
  • VHDL
  • Vue.js app
  • +
  • Web IDL
  • XML/HTML
  • XQuery
  • Yacas
  • diff --git a/mode/meta.js b/mode/meta.js index 3539beaa17..dcdcdab9c0 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -145,6 +145,7 @@ {name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]}, {name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"], alias: ["ts"]}, {name: "Twig", mime: "text/x-twig", mode: "twig"}, + {name: "Web IDL", mime: "text/x-webidl", mode: "webidl", ext: ["webidl"]}, {name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]}, {name: "VBScript", mime: "text/vbscript", mode: "vbscript", ext: ["vbs"]}, {name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]}, diff --git a/mode/webidl/index.html b/mode/webidl/index.html new file mode 100644 index 0000000000..1d4112e1c3 --- /dev/null +++ b/mode/webidl/index.html @@ -0,0 +1,71 @@ + + +CodeMirror: Web IDL mode + + + + + + + + + + +
    +

    Web IDL mode

    + +
    + +
    + + + +

    MIME type defined: text/x-webidl.

    +
    diff --git a/mode/webidl/webidl.js b/mode/webidl/webidl.js new file mode 100644 index 0000000000..6a60fa23ef --- /dev/null +++ b/mode/webidl/webidl.js @@ -0,0 +1,197 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); +}; + +var builtinArray = [ + "Clamp", + "Constructor", + "EnforceRange", + "Exposed", + "ImplicitThis", + "Global", "PrimaryGlobal", + "LegacyArrayClass", + "LegacyUnenumerableNamedProperties", + "LenientThis", + "NamedConstructor", + "NewObject", + "NoInterfaceObject", + "OverrideBuiltins", + "PutForwards", + "Replaceable", + "SameObject", + "TreatNonObjectAsNull", + "TreatNullAs", + "EmptyString", + "Unforgeable", + "Unscopeable" +]; +var builtins = wordRegexp(builtinArray); + +var typeArray = [ + "unsigned", "short", "long", // UnsignedIntegerType + "unrestricted", "float", "double", // UnrestrictedFloatType + "boolean", "byte", "octet", // Rest of PrimitiveType + "Promise", // PromiseType + "ArrayBuffer", "DataView", "Int8Array", "Int16Array", "Int32Array", + "Uint8Array", "Uint16Array", "Uint32Array", "Uint8ClampedArray", + "Float32Array", "Float64Array", // BufferRelatedType + "ByteString", "DOMString", "USVString", "sequence", "object", "RegExp", + "Error", "DOMException", "FrozenArray", // Rest of NonAnyType + "any", // Rest of SingleType + "void" // Rest of ReturnType +]; +var types = wordRegexp(typeArray); + +var keywordArray = [ + "attribute", "callback", "const", "deleter", "dictionary", "enum", "getter", + "implements", "inherit", "interface", "iterable", "legacycaller", "maplike", + "partial", "required", "serializer", "setlike", "setter", "static", + "stringifier", "typedef", // ArgumentNameKeyword except + // "unrestricted" + "optional", "readonly", "or" +]; +var keywords = wordRegexp(keywordArray); + +var atomArray = [ + "true", "false", // BooleanLiteral + "Infinity", "NaN", // FloatLiteral + "null" // Rest of ConstValue +]; +var atoms = wordRegexp(atomArray); + +CodeMirror.registerHelper("hintWords", "webidl", + builtinArray.concat(typeArray).concat(keywordArray).concat(atomArray)); + +var startDefArray = ["callback", "dictionary", "enum", "interface"]; +var startDefs = wordRegexp(startDefArray); + +var endDefArray = ["typedef"]; +var endDefs = wordRegexp(endDefArray); + +var singleOperators = /^[:<=>?]/; +var integers = /^-?([1-9][0-9]*|0[Xx][0-9A-Fa-f]+|0[0-7]*)/; +var floats = /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+)/; +var identifiers = /^_?[A-Za-z][0-9A-Z_a-z-]*/; +var strings = /^"[^"]*"/; +var multilineComments = /^\/\*.*?\*\//; +var multilineCommentsStart = /^\/\*.*/; +var multilineCommentsEnd = /^.*?\*\//; + +function readToken(stream, state) { + // whitespace + if (stream.eatSpace()) return null; + + // comment + if (state.inComment) { + if (stream.match(multilineCommentsEnd)) { + state.inComment = false; + return "comment"; + } + stream.skipToEnd(); + return "comment"; + } + if (stream.match("//")) { + stream.skipToEnd(); + return "comment"; + } + if (stream.match(multilineComments)) return "comment"; + if (stream.match(multilineCommentsStart)) { + state.inComment = true; + return "comment"; + } + + // integer and float + if (stream.match(/^-?[0-9\.]/, false)) { + if (stream.match(integers) || stream.match(floats)) return "number"; + } + + // string + if (stream.match(strings)) return "string"; + + // identifier + var pos = stream.pos; + if (stream.match(identifiers)) { + if (state.startDef) return "def"; + if (state.endDef && stream.match(/^\s*;/, false)) { + state.endDef = false; + return "def"; + } + stream.pos = pos; + } + + if (stream.match(keywords)) return "keyword"; + + if (stream.match(types)) { + var lastToken = state.lastToken; + var nextToken = (stream.match(/^\s*(.+?)\b/, false) || [])[1]; + + if (lastToken === ":" || lastToken === "implements" || + nextToken === "implements" || nextToken === "=") { + // Used as identifier + return "builtin"; + } else { + // Used as type + return "variable-3"; + } + } + + if (stream.match(builtins)) return "builtin"; + if (stream.match(atoms)) return "atom"; + if (stream.match(identifiers)) return "variable"; + + // other + if (stream.match(singleOperators)) return "operator"; + + // unrecognized + stream.next(); + return null; +}; + +CodeMirror.defineMode("webidl", function() { + return { + startState: function() { + return { + // Is in multiline comment + inComment: false, + // Last non-whitespace, matched token + lastToken: "", + // Next token is a definition + startDef: false, + // Last token of the statement is a definition + endDef: false + }; + }, + token: function(stream, state) { + var style = readToken(stream, state); + + if (style) { + var cur = stream.current(); + state.lastToken = cur; + if (style === "keyword") { + state.startDef = startDefs.test(cur); + state.endDef = state.endDef || endDefs.test(cur); + } else { + state.startDef = false; + } + } + + return style; + } + }; +}); + +CodeMirror.defineMIME("text/x-webidl", "webidl"); +}); From def70631ca7a50cfb5bf414c27df4db53f899a15 Mon Sep 17 00:00:00 2001 From: Timothy Gu Date: Thu, 7 Apr 2016 06:36:38 -0700 Subject: [PATCH 072/191] [webidl mode] Remove unnecessary pos saving --- mode/webidl/webidl.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/mode/webidl/webidl.js b/mode/webidl/webidl.js index 6a60fa23ef..6f024c63f8 100644 --- a/mode/webidl/webidl.js +++ b/mode/webidl/webidl.js @@ -122,14 +122,12 @@ function readToken(stream, state) { if (stream.match(strings)) return "string"; // identifier - var pos = stream.pos; if (stream.match(identifiers)) { if (state.startDef) return "def"; if (state.endDef && stream.match(/^\s*;/, false)) { state.endDef = false; return "def"; } - stream.pos = pos; } if (stream.match(keywords)) return "keyword"; From 300f7f8eb885fa5ff5cdbf0a43126849a7881095 Mon Sep 17 00:00:00 2001 From: Kris Ciccarello Date: Thu, 7 Apr 2016 13:35:42 -0400 Subject: [PATCH 073/191] [docs] `doc.getSelections` returns an array of strings. --- doc/manual.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index b513bf9408..8b600eac54 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1254,7 +1254,7 @@

    Cursor and selection methods

    separator to put between the lines in the output. When multiple selections are present, they are concatenated with instances of lineSep in between. -
    doc.getSelections(?lineSep: string) → string
    +
    doc.getSelections(?lineSep: string) → array<string>
    Returns an array containing a string for each selection, representing the content of the selections.
    From bef7e37a093a55ca7f14e1cd823431db07326200 Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Thu, 7 Apr 2016 17:10:23 -0400 Subject: [PATCH 074/191] [mode/meta] Recognize Bazel, Buck and Pants build files as Python in mode/meta.js BUCK, BUILD, *.BUILD and *.bzl files are build files for the three build systems mentioned, and they are all valid Python files. --- mode/meta.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/meta.js b/mode/meta.js index dcdcdab9c0..20ebe0ae22 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -105,7 +105,7 @@ {name: "PowerShell", mime: "application/x-powershell", mode: "powershell", ext: ["ps1", "psd1", "psm1"]}, {name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]}, {name: "ProtoBuf", mime: "text/x-protobuf", mode: "protobuf", ext: ["proto"]}, - {name: "Python", mime: "text/x-python", mode: "python", ext: ["py", "pyw"]}, + {name: "Python", mime: "text/x-python", mode: "python", ext: ["BUILD", "bzl", "py", "pyw"], file: /^(BUCK|BUILD)$/}, {name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]}, {name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]}, {name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r"], alias: ["rscript"]}, From 44e4bd42c7ecbd67a48d1c005bdde6140f8475cd Mon Sep 17 00:00:00 2001 From: Gary Sheng Date: Thu, 7 Apr 2016 17:07:17 -0400 Subject: [PATCH 075/191] [sql mode] Add __key__ keyword to GQL MIME definition --- mode/sql/sql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/sql/sql.js b/mode/sql/sql.js index c90918b7f2..daec60ce6f 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -376,7 +376,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { name: "sql", keywords: set("ancestor and asc by contains desc descendant distinct from group has in is limit offset on order select superset where"), atoms: set("false true"), - builtin: set("blob datetime first key string integer double boolean null"), + builtin: set("blob datetime first key __key__ string integer double boolean null"), operatorChars: /^[*+\-%<>!=]/ }); }()); From 7fa0cdc493e48571e163317d27b58483f5c8d464 Mon Sep 17 00:00:00 2001 From: Jared Dean Date: Fri, 1 Apr 2016 11:37:36 -0400 Subject: [PATCH 076/191] [sas mode] Add --- AUTHORS | 1 + mode/meta.js | 1 + mode/sas/index.html | 87 ++++++++++ mode/sas/sas.js | 381 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 470 insertions(+) create mode 100644 mode/sas/index.html create mode 100755 mode/sas/sas.js diff --git a/AUTHORS b/AUTHORS index 03b1ac5b0a..2c8a9bf3d1 100644 --- a/AUTHORS +++ b/AUTHORS @@ -238,6 +238,7 @@ Jan Keromnes Jan Odvarko Jan Schär Jan T. Sott +Jared Dean Jared Forsyth Jason Jason Barnabe diff --git a/mode/meta.js b/mode/meta.js index 20ebe0ae22..f93078c00b 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -114,6 +114,7 @@ {name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]}, {name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"], alias: ["jruby", "macruby", "rake", "rb", "rbx"]}, {name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]}, + {name: "SAS", mime: "text/x-sas", mode: "sas", ext: ["sas"]}, {name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]}, {name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]}, {name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]}, diff --git a/mode/sas/index.html b/mode/sas/index.html new file mode 100644 index 0000000000..80957403d5 --- /dev/null +++ b/mode/sas/index.html @@ -0,0 +1,87 @@ + + +CodeMirror: SAS mode + + + + + + + + + + + +
    +

    SAS mode

    + + + + + +

    MIME types defined: text/x-sas.

    + + +
    diff --git a/mode/sas/sas.js b/mode/sas/sas.js new file mode 100755 index 0000000000..4043bc7027 --- /dev/null +++ b/mode/sas/sas.js @@ -0,0 +1,381 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + + +// SAS mode copyright (c) 2016 Jared Dean, SAS Institute +// Created by Jared Dean + +// TODO +// indent and de-indent +// identify macro variables + + +//Definitions +// comment -- text withing * ; or /* */ +// keyword -- SAS language variable +// variable -- macro variables starts with '&' or variable formats +// variable-2 -- DATA Step, proc, or macro names +// string -- text within ' ' or " " +// operator -- numeric operator + / - * ** le eq ge ... and so on +// builtin -- proc %macro data run mend +// atom +// def + + +(function (mod) { + if (typeof exports == "object" && typeof module == "object") { // CommonJS + mod(require("../../lib/codemirror")); + } + else if (typeof define == "function" && define.amd) {// AMD + define(["../../lib/codemirror"], mod); + } + else {// Plain browser env + mod(CodeMirror); + } +})(function (CodeMirror) { + "use strict"; + + CodeMirror.defineMode("sas", function () { + var words = {}; + var isDoubleOperatorSym = { + eq: 'operator', + lt: 'operator', + le: 'operator', + gt: 'operator', + ge: 'operator', + in: 'operator', + ne: 'operator', + or: 'operator' + }; + var isDoubleOperatorChar = /(<=|>=|!=|<>)/; + var isSingleOperatorChar = /[=\(:\),{}.*<>+\-\/^\[\]]/; + + // Takes a string of words separated by spaces and adds them as + // keys with the value of the first argument 'style' + var define = function (style, string, context) { + if (context) { + var split = string.split(' '); + for (var i = 0; i < split.length; i++) { + words[split[i]] = {style: style, state: context}; + } + } + }; + //datastep + define('def', 'stack pgm view source debug nesting nolist', ['inDataStep']); + define('def', 'if while until for do do; end end; then else cancel', ['inDataStep']); + define('def', 'label format _n_ _error_', ['inDataStep']); + define('def', 'ALTER BUFNO BUFSIZE CNTLLEV COMPRESS DLDMGACTION ENCRYPT ENCRYPTKEY EXTENDOBSCOUNTER GENMAX GENNUM INDEX LABEL OBSBUF OUTREP PW PWREQ READ REPEMPTY REPLACE REUSE ROLE SORTEDBY SPILL TOBSNO TYPE WRITE FILECLOSE FIRSTOBS IN OBS POINTOBS WHERE WHEREUP IDXNAME IDXWHERE DROP KEEP RENAME', ['inDataStep']); + define('def', 'filevar finfo finv fipname fipnamel fipstate first firstobs floor', ['inDataStep']); + define('def', 'varfmt varinfmt varlabel varlen varname varnum varray varrayx vartype verify vformat vformatd vformatdx vformatn vformatnx vformatw vformatwx vformatx vinarray vinarrayx vinformat vinformatd vinformatdx vinformatn vinformatnx vinformatw vinformatwx vinformatx vlabel vlabelx vlength vlengthx vname vnamex vnferr vtype vtypex weekday', ['inDataStep']); + define('def', 'zipfips zipname zipnamel zipstate', ['inDataStep']); + define('def', 'put putc putn', ['inDataStep']); + define('builtin', 'data run', ['inDataStep']); + + + //proc + define('def', 'data', ['inProc']); + + // flow control for macros + define('def', '%if %end %end; %else %else; %do %do; %then', ['inMacro']); + + //everywhere + define('builtin', 'proc run; quit; libname filename %macro %mend option options', ['ALL']); + + define('def', 'footnote title libname ods', ['ALL']); + define('def', '%let %put %global %sysfunc %eval ', ['ALL']); + // automatic macro variables http://support.sas.com/documentation/cdl/en/mcrolref/61885/HTML/default/viewer.htm#a003167023.htm + define('variable', '&sysbuffr &syscc &syscharwidth &syscmd &sysdate &sysdate9 &sysday &sysdevic &sysdmg &sysdsn &sysencoding &sysenv &syserr &syserrortext &sysfilrc &syshostname &sysindex &sysinfo &sysjobid &syslast &syslckrc &syslibrc &syslogapplname &sysmacroname &sysmenv &sysmsg &sysncpu &sysodspath &sysparm &syspbuff &sysprocessid &sysprocessname &sysprocname &sysrc &sysscp &sysscpl &sysscpl &syssite &sysstartid &sysstartname &systcpiphostname &systime &sysuserid &sysver &sysvlong &sysvlong4 &syswarningtext', ['ALL']); + + //footnote[1-9]? title[1-9]? + + //options statement + define('def', 'source2 nosource2 page pageno pagesize', ['ALL']); + + //proc and datastep + define('def', '_all_ _character_ _cmd_ _freq_ _i_ _infile_ _last_ _msg_ _null_ _numeric_ _temporary_ _type_ abort abs addr adjrsq airy alpha alter altlog altprint and arcos array arsin as atan attrc attrib attrn authserver autoexec awscontrol awsdef awsmenu awsmenumerge awstitle backward band base betainv between blocksize blshift bnot bor brshift bufno bufsize bxor by byerr byline byte calculated call cards cards4 catcache cbufno cdf ceil center cexist change chisq cinv class cleanup close cnonct cntllev coalesce codegen col collate collin column comamid comaux1 comaux2 comdef compbl compound compress config continue convert cos cosh cpuid create cross crosstab css curobs cv daccdb daccdbsl daccsl daccsyd dacctab dairy datalines datalines4 datejul datepart datetime day dbcslang dbcstype dclose ddm delete delimiter depdb depdbsl depsl depsyd deptab dequote descending descript design= device dflang dhms dif digamma dim dinfo display distinct dkricond dkrocond dlm dnum do dopen doptname doptnum dread drop dropnote dsname dsnferr echo else emaildlg emailid emailpw emailserver emailsys encrypt end endsas engine eof eov erf erfc error errorcheck errors exist exp fappend fclose fcol fdelete feedback fetch fetchobs fexist fget file fileclose fileexist filefmt filename fileref fmterr fmtsearch fnonct fnote font fontalias fopen foptname foptnum force formatted formchar formdelim formdlim forward fpoint fpos fput fread frewind frlen from fsep fuzz fwrite gaminv gamma getoption getvarc getvarn go goto group gwindow hbar hbound helpenv helploc hms honorappearance hosthelp hostprint hour hpct html hvar ibessel ibr id if index indexc indexw initcmd initstmt inner input inputc inputn inr insert int intck intnx into intrr invaliddata irr is jbessel join juldate keep kentb kurtosis label lag last lbound leave left length levels lgamma lib library libref line linesize link list log log10 log2 logpdf logpmf logsdf lostcard lowcase lrecl ls macro macrogen maps mautosource max maxdec maxr mdy mean measures median memtype merge merror min minute missing missover mlogic mod mode model modify month mopen mort mprint mrecall msglevel msymtabmax mvarsize myy n nest netpv new news nmiss no nobatch nobs nocaps nocardimage nocenter nocharcode nocmdmac nocol nocum nodate nodbcs nodetails nodmr nodms nodmsbatch nodup nodupkey noduplicates noechoauto noequals noerrorabend noexitwindows nofullstimer noicon noimplmac noint nolist noloadlist nomiss nomlogic nomprint nomrecall nomsgcase nomstored nomultenvappl nonotes nonumber noobs noovp nopad nopercent noprint noprintinit normal norow norsasuser nosetinit nosplash nosymbolgen note notes notitle notitles notsorted noverbose noxsync noxwait npv null number numkeys nummousekeys nway obs on open order ordinal otherwise out outer outp= output over ovp p(1 5 10 25 50 75 90 95 99) pad pad2 paired parm parmcards path pathdll pathname pdf peek peekc pfkey pmf point poisson poke position printer probbeta probbnml probchi probf probgam probhypr probit probnegb probnorm probsig probt procleave prt ps pw pwreq qtr quote r ranbin rancau ranexp rangam range ranks rannor ranpoi rantbl rantri ranuni read recfm register regr remote remove rename repeat replace resolve retain return reuse reverse rewind right round rsquare rtf rtrace rtraceloc s s2 samploc sasautos sascontrol sasfrscr sasmsg sasmstore sasscript sasuser saving scan sdf second select selection separated seq serror set setcomm setot sign simple sin sinh siteinfo skewness skip sle sls sortedby sortpgm sortseq sortsize soundex spedis splashlocation split spool sqrt start std stderr stdin stfips stimer stname stnamel stop stopover subgroup subpopn substr sum sumwgt symbol symbolgen symget symput sysget sysin sysleave sysmsg sysparm sysprint sysprintfont sysprod sysrc system t table tables tan tanh tapeclose tbufsize terminal test then timepart tinv tnonct to today tol tooldef totper transformout translate trantab tranwrd trigamma trim trimn trunc truncover type unformatted uniform union until upcase update user usericon uss validate value var weight when where while wincharset window work workinit workterm write wsum xsync xwait yearcutoff yes yyq min max', ['inDataStep', 'inProc']); + define('operator', 'and not ', ['inDataStep', 'inProc']); + + // Main function + function tokenize(stream, state) { + // Finally advance the stream + var ch = stream.next(); + + // BLOCKCOMMENT + if (ch === '/' && stream.eat('*')) { + state.continueComment = true; + return "comment"; + } + // in comment block + else if (state.continueComment === true) { + //comment ends at the beginning of the line + if (ch === '*' && stream.peek() === '/') { + stream.next(); + state.continueComment = false; + } + //comment is potentially later in line + else if (stream.skipTo('*')) { + stream.skipTo('*'); + stream.next(); + if (stream.eat('/')) { + state.continueComment = false; + } + } + else { + stream.skipToEnd(); + } + return "comment"; + } + + // DoubleOperator match + var doubleOperator = ch + stream.peek(); + + // Match all line comments. + var myString = stream.string; + var myRegexp = /(?:^\s*|[;]\s*)(\*.*?);/ig; + var match = myRegexp.exec(myString); + if (match !== null) + { + if (match.index === 0 && (stream.column() !== (match.index + match[0].length - 1))) { + stream.backUp(stream.column()); + stream.skipTo(';'); + stream.next(); + return 'comment'; + } + // the ';' triggers the match so move one past it to start + // the comment block that is why match.index+1 + else if (match.index + 1 < stream.column() && stream.column() < match.index + match[0].length - 1) { + stream.backUp(stream.column() - match.index - 1); + stream.skipTo(';'); + stream.next(); + return 'comment'; + } + } + // Have we found a string? + else + if (!state.continueString && (ch === '"' || ch === "'")) { + state.continueString = ch; //save the matching quote in the state + return "string"; + } + else if (state.continueString !== null) { + if (stream.skipTo(state.continueString)) { + // quote found on this line + stream.next(); + state.continueString = null; + } + else { + stream.skipToEnd(); + } + return "string"; + } + else if (state.continueString !== null && stream.eol()) { + stream.skipTo(state.continueString) || stream.skipToEnd(); + return "string"; + } + //find numbers + else if (/[\d\.]/.test(ch)) { + if (ch === ".") { + stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/); + } else if (ch === "0") { + stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/); + } else { + stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/); + } + return "number"; + } + // TWO SYMBOL TOKENS + else if (isDoubleOperatorChar.test(ch + stream.peek())) { + stream.next(); + state.tokenize = null; + return "operator"; + } + else if (isDoubleOperatorSym.hasOwnProperty(doubleOperator)) { + stream.next(); + if (stream.peek() === ' ') { + return isDoubleOperatorSym[doubleOperator.toLowerCase()]; + } + + } + // SINGLE SYMBOL TOKENS + else if (isSingleOperatorChar.test(ch)) { + state.tokenize = null; + return "operator"; + } + + // Matches one whole word -- even if the word is a character + var word; + if (stream.match(/[%&;\w]+/, false) != null) { + word = ch + stream.match(/[%&;\w]+/, true); + if (/&/.test(word)) { + return 'variable' + } + } + else { + + word = ch; + } + // the word after DATA PROC or MACRO + if (state.nextword) { + stream.match(/[\w]+/); + // match memname.libname + if (stream.peek() === '.') { + stream.skipTo(' '); + } + state.nextword = false; + return 'variable-2'; + + } + + // Are we in a DATA Step? + if (state.inDataStep) { + if (word.toLowerCase() === 'run;' || stream.match(/run\s;/)) { + state.inDataStep = false; + return 'builtin'; + } + // variable formats + if ((word) && stream.next() === '.') { + //either a format or libname.memname + if (/\w/.test(stream.peek())) { + //libname.memname + return 'variable-2'; + } + else { + //format + return 'variable'; + } + } + // do we have a DATA Step keyword + if (word && words.hasOwnProperty(word.toLowerCase()) && (words[word.toLowerCase()].state.indexOf("inDataStep") !== -1 || words[word.toLowerCase()].state.indexOf("ALL") !== -1)) { + //backup to the start of the word + if (stream.start < stream.pos) { + stream.backUp(stream.pos - stream.start); + } + //advance the length of the word and return + for (var i = 0; i < word.length; ++i) { + stream.next(); + } + return words[word.toLowerCase()].style; + } + + + } + // Are we in an Proc statement? + if (state.inProc) { + if (word.toLowerCase() === 'run;' || word.toLowerCase() === 'quit;') { + state.inProc = false; + return 'builtin'; + } + // do we have a proc keyword + if (word && words.hasOwnProperty(word.toLowerCase()) && (words[word.toLowerCase()].state.indexOf("inProc") !== -1 || words[word.toLowerCase()].state.indexOf("ALL") !== -1)) { + stream.match(/[\w]+/); + return words[word].style; + } + + + } + // Are we in a Macro statement? + if (state.inMacro) { + if (word.toLowerCase() === '%mend') { + if (stream.peek() === ';') { + stream.next(); + } + state.inMacro = false; + return 'builtin'; + } + if (word && words.hasOwnProperty(word.toLowerCase()) && (words[word.toLowerCase()].state.indexOf("inMacro") !== -1 || words[word.toLowerCase()].state.indexOf("ALL") !== -1)) { + stream.match(/[\w]+/); + return words[word.toLowerCase()].style; + } + + return 'atom'; + } + // Do we have Keywords specific words? + if (word && words.hasOwnProperty(word.toLowerCase())) { + // Negates the initial next() + stream.backUp(1); + // Actually move the stream + stream.match(/[\w]+/); + if (word.toLowerCase() === 'data' && /=/.test(stream.peek()) === false) { + state.inDataStep = true; + state.nextword = true; + return 'builtin'; + } + if (word.toLowerCase() === 'proc') { + state.inProc = true; + state.nextword = true; + return 'builtin'; + } + if (word.toLowerCase() === '%macro') { + state.inMacro = true; + state.nextword = true; + return 'builtin'; + } + if (/title[1-9]/i.test(word/*+stream.peek()*/)) { + //if (/title[1-9]/.test(word.toLowerCase())) { + //stream.next(); + return 'def'; + } + if (word.toLowerCase() === 'footnote' && /[1-9]/.test(stream.peek())) { + stream.eat(); + return 'def'; + } + else if (word.toLowerCase() === 'footnote') { + return 'def'; + } + + // Returns their value as state in the prior define methods + if (state.inDataStep === true && words[word.toLowerCase()].state.indexOf("inDataStep") !== -1) { + return words[word.toLowerCase()].style; + } + else if (state.inProc === true && words[word.toLowerCase()].state.indexOf("inProc") !== -1) { + return words[word.toLowerCase()].style; + } + else if (state.inMacro === true && words[word.toLowerCase()].state.indexOf("inMacro") !== -1) { + return words[word.toLowerCase()].style; + } + else if (words[word.toLowerCase()].state.indexOf("ALL") !== -1) { + return words[word.toLowerCase()].style; + } + else { + return null; + } + } + // Return a blank line for everything else + return null; + } + + // Start here + return { + startState: function () { + var state = {}; + state.inDataStep = false; + state.inProc = false; + state.inMacro = false; + state.pending = false; + state.lastToken = null; + state.nextword = false; + state.continueString = null; + state.continueComment = false; + state.tokenize = null; + return state; + }, + token: function (stream, state) { + if (state.tokenize != null) { + return state.tokenize(stream, state); + } + // Strip the spaces, but regex will account for them either way + if (stream.eatSpace()) return null; + var style = state.tokenize; + if (style === "comment") return style; + // Go through the main process + return tokenize(stream, state); + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/" + }; + + }); + + CodeMirror.defineMIME("text/x-sas", "sas"); + +}); From 9389a050790e2be94530f34a3513e34602d39483 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 8 Apr 2016 16:44:18 +0200 Subject: [PATCH 077/191] [sas mode] Code style, integrate Issue #3932 --- mode/index.html | 1 + mode/sas/index.html | 34 +-- mode/sas/sas.js | 624 ++++++++++++++++++++------------------------ 3 files changed, 294 insertions(+), 365 deletions(-) diff --git a/mode/index.html b/mode/index.html index 822f04fc61..be583159e1 100644 --- a/mode/index.html +++ b/mode/index.html @@ -114,6 +114,7 @@

    Language modes

  • reStructuredText
  • Ruby
  • Rust
  • +
  • SAS
  • Sass
  • Spreadsheet
  • Scala
  • diff --git a/mode/sas/index.html b/mode/sas/index.html index 80957403d5..636e06594b 100644 --- a/mode/sas/index.html +++ b/mode/sas/index.html @@ -6,15 +6,14 @@ - + .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} + .cm-s-default .cm-trailing-space-a:before, + .cm-s-default .cm-trailing-space-b:before {position: absolute; content: "\00B7"; color: #777;} + .cm-s-default .cm-trailing-space-new-line:before {position: absolute; content: "\21B5"; color: #777;} +