From a540182b6ae25a9c05f25422ec2dae8eaf2444e7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Oct 2013 10:19:40 +0200 Subject: [PATCH 01/81] Bump version number post-3.19 --- lib/codemirror.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 563f688a26..e316031fa5 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -5902,7 +5902,7 @@ window.CodeMirror = (function() { // THE END - CodeMirror.version = "3.19.0"; + CodeMirror.version = "3.19.1"; return CodeMirror; })(); diff --git a/package.json b/package.json index 8310ab1551..10e70a1b9f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version":"3.19.0", + "version":"3.19.1", "main": "lib/codemirror.js", "description": "In-browser code editing made bearable", "licenses": [{"type": "MIT", From a4452796415309ba6da2a89861d8ce9b8d0e77f5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 22 Oct 2013 08:17:05 +0200 Subject: [PATCH 02/81] [manual] Mention using content form textarea in fromTextArea docs --- doc/manual.html | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index e5a000a5c6..ba8789a836 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1615,13 +1615,14 @@

Static properties

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. A CodeMirror instance created this way has three - additional methods: + 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.
From cdf55221a8a2fb8059f159feadc3797ba967e515 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 22 Oct 2013 09:40:14 +0200 Subject: [PATCH 03/81] Allow marked ranges that are inclusive on boths sides to be zero-length --- lib/codemirror.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index e316031fa5..289e8f9d78 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3850,7 +3850,9 @@ window.CodeMirror = (function() { if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); var marker = new TextMarker(doc, type); - if (type == "range" && !posLess(from, to)) return marker; + if (posLess(to, from) || posEq(from, to) && type == "range" && + !(options.inclusiveLeft && options.inclusiveRight)) + return marker; if (options) copyObj(options, marker); if (marker.replacedWith) { marker.collapsed = true; @@ -3966,7 +3968,9 @@ window.CodeMirror = (function() { if (old) for (var i = 0, nw; i < old.length; ++i) { var span = old[i], marker = span.marker; var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); - if (startsBefore || marker.type == "bookmark" && span.from == startCh && (!isInsert || !span.marker.insertLeft)) { + if (startsBefore || + (marker.inclusiveLeft && marker.inclusiveRight || marker.type == "bookmark") && + span.from == startCh && (!isInsert || !span.marker.insertLeft)) { var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); (nw || (nw = [])).push({from: span.from, to: endsAfter ? null : span.to, From a6a32922952dfd2360031d0a692f6373972e8759 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 22 Oct 2013 09:41:28 +0200 Subject: [PATCH 04/81] [tern demo] Include polyfill script for IE7/8 --- demo/tern.html | 1 + 1 file changed, 1 insertion(+) diff --git a/demo/tern.html b/demo/tern.html index adc79e5c3d..6843c7f5ec 100644 --- a/demo/tern.html +++ b/demo/tern.html @@ -16,6 +16,7 @@ + From e7b736aed0af447445a523852bb0d12dd9194833 Mon Sep 17 00:00:00 2001 From: Jon Malmaud Date: Mon, 21 Oct 2013 19:47:08 -0400 Subject: [PATCH 05/81] [julia mode] Add --- mode/julia/index.html | 121 +++++++++++++++++++++++ mode/julia/julia.js | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 389 insertions(+) create mode 100644 mode/julia/index.html create mode 100644 mode/julia/julia.js diff --git a/mode/julia/index.html b/mode/julia/index.html new file mode 100644 index 0000000000..a79341df7a --- /dev/null +++ b/mode/julia/index.html @@ -0,0 +1,121 @@ + + +CodeMirror: Julia mode + + + + + + + + + +
+

Julia mode

+ +
+ + +

MIME types defined: text/x-julia.

+
diff --git a/mode/julia/julia.js b/mode/julia/julia.js new file mode 100644 index 0000000000..e2510e37de --- /dev/null +++ b/mode/julia/julia.js @@ -0,0 +1,268 @@ +CodeMirror.defineMode("julia", function(conf, parserConf) { + var ERRORCLASS = 'error'; + + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + var singleOperators = parserConf.singleOperators || /^[?:=+&\-*%|$^~<>!/\\]/; + var singleDelimiters = parserConf.singleDelimiters || /^[;,()[\]{}]/; + var doubleOperators = parserConf.doubleOperators || /^(==)|(!=)|(<=)|(<:)|(>=)|(\.>)|(\.<)|(<<)|(>>)|(->)|[//]{2}/; + var doubleDelimiters = parserConf.doubleDelimiters || /^(\+=)|(-=)|(\*=)|(%=)|(\\=)|(\^=)|(&=)|(\|=)|(&=)|([//]=)/; + var tripleDelimiters = parserConf.tripleDelimiters || /^(>>=)|(<<=)|(\.>=)|(\.<=)|(\.==)|(>>>)/; + var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*!*/ + var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif"]; + var blockClosers = ["end", "else", "elseif"]; + var wordOperators = wordRegexp(['in']); + var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'in', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote']; + var builtinList = ['all', 'true', 'false', 'any', 'enumerate', 'open', 'close', 'linspace', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'error', 'warn', 'info']; + + //var stringPrefixes = new RegExp("^[br]?('|\")") + var stringPrefixes = /^[br]?('|")/; + var keywords = wordRegexp(keywordList); + var builtins = wordRegexp(builtinList); + var openers = wordRegexp(blockOpeners); + var closers = wordRegexp(blockClosers); + var indentInfo = null; + + function in_array(state) { + ch = cur_scope(state); + if(ch=="[" || ch=="{") { + return true; + } + else { + return false; + } + } + + function cur_scope(state) { + if(state.scopes.length==0) { + return null; + } + return state.scopes[state.scopes.length - 1]; + } + + // tokenizers + function tokenBase(stream, state) { + // Handle scope changes + if(state.leaving_expr) { + if(stream.match(/^'+/)) { + return 'operator'; + } + if(stream.match("...")) { + return 'operator'; + } + } + + if (stream.eatSpace()) { + return null; + } + + var ch = stream.peek(); + // Handle Comments + if (ch === '#') { + stream.skipToEnd(); + return 'comment'; + } + if(ch==='[') { + state.scopes.push("["); + } + + if(ch==='{') { + state.scopes.push("{"); + } + + var scope=cur_scope(state); + + if(scope==='[' && ch===']') { + state.scopes.pop(); + state.leaving_expr=true; + } + + if(scope==='{' && ch==='}') { + state.scopes.pop(); + state.leaving_expr=true; + } + + if(match=stream.match(openers, false)) { + state.scopes.push(match); + } + + if(!in_array(state) && stream.match(closers, false)) { + state.scopes.pop(); + } + + if(in_array(state)) { + if(stream.match("end")) { + return 'number'; + } + + } + if(stream.match("=>")) { + return 'operator'; + } + // Handle Number Literals + if (stream.match(/^[0-9\.]/, false)) { + var imMatcher = RegExp(/^im\b/); + 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.match(imMatcher); + 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.match(imMatcher); + return 'number'; + } + } + + // Handle Strings + if (stream.match(stringPrefixes)) { + state.tokenize = tokenStringFactory(stream.current()); + return state.tokenize(stream, state); + } + + // Handle operators and Delimiters + if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) { + return null; + } + if (stream.match(doubleOperators) + || stream.match(singleOperators) + || stream.match(wordOperators)) { + return 'operator'; + } + if (stream.match(singleDelimiters)) { + return null; + } + + if (stream.match(keywords)) { + return 'keyword'; + } + + if (stream.match(builtins)) { + return 'builtin'; + } + + + if (stream.match(identifiers)) { + state.leaving_expr=true; + return 'variable'; + } + // Handle non-detected items + stream.next(); + return ERRORCLASS; + } + + function tokenStringFactory(delimiter) { + while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) { + delimiter = delimiter.substr(1); + } + var singleline = delimiter.length == 1; + var OUTCLASS = 'string'; + + function tokenString(stream, state) { + while (!stream.eol()) { + stream.eatWhile(/[^'"\\]/); + if (stream.eat('\\')) { + stream.next(); + if (singleline && stream.eol()) { + return OUTCLASS; + } + } else if (stream.match(delimiter)) { + state.tokenize = tokenBase; + return OUTCLASS; + } else { + stream.eat(/['"]/); + } + } + if (singleline) { + if (parserConf.singleLineStringErrors) { + return ERRORCLASS; + } else { + state.tokenize = tokenBase; + } + } + return OUTCLASS; + } + tokenString.isString = true; + return tokenString; + } + + function tokenLexer(stream, state) { + indentInfo = null; + var style = state.tokenize(stream, state); + var current = stream.current(); + + // Handle '.' connected identifiers + if (current === '.') { + style = stream.match(identifiers, false) ? null : ERRORCLASS; + if (style === null && state.lastStyle === 'meta') { + // Apply 'meta' style to '.' connected identifiers when + // appropriate. + style = 'meta'; + } + return style; + } + + // Handle macro calls + if (current === '@') { + return stream.match(identifiers, false) ? 'meta' : ERRORCLASS; + } + + return style; + } + + var external = { + startState: function(basecolumn) { + return { + tokenize: tokenBase, + scopes: [], + leaving_expr: false + }; + }, + + token: function(stream, state) { + var style = tokenLexer(stream, state); + state.lastStyle = style; + return style; + }, + + indent: function(state, textAfter) { + var delta = 0; + if(textAfter=="end" || textAfter=="]" || textAfter=="}" || textAfter=="else" || textAfter=="elseif") { + delta = -1; + } + return (state.scopes.length + delta) * 2; + }, + + lineComment: "#", + fold: "indent", + electricChars: "endlsif]}" + }; + return external; +}); + + +CodeMirror.defineMIME("text/x-julia", "julia"); From 0611e27f66ee93ce14efeefde6b0a51a70153839 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 22 Oct 2013 10:34:39 +0200 Subject: [PATCH 06/81] [julia mode] Simplify regexps, fix lint errors Issue #1897 --- mode/julia/julia.js | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/mode/julia/julia.js b/mode/julia/julia.js index e2510e37de..667ffc32d4 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -1,19 +1,15 @@ -CodeMirror.defineMode("julia", function(conf, parserConf) { +CodeMirror.defineMode("julia", function(_conf, parserConf) { var ERRORCLASS = 'error'; function wordRegexp(words) { return new RegExp("^((" + words.join(")|(") + "))\\b"); } - var singleOperators = parserConf.singleOperators || /^[?:=+&\-*%|$^~<>!/\\]/; - var singleDelimiters = parserConf.singleDelimiters || /^[;,()[\]{}]/; - var doubleOperators = parserConf.doubleOperators || /^(==)|(!=)|(<=)|(<:)|(>=)|(\.>)|(\.<)|(<<)|(>>)|(->)|[//]{2}/; - var doubleDelimiters = parserConf.doubleDelimiters || /^(\+=)|(-=)|(\*=)|(%=)|(\\=)|(\^=)|(&=)|(\|=)|(&=)|([//]=)/; - var tripleDelimiters = parserConf.tripleDelimiters || /^(>>=)|(<<=)|(\.>=)|(\.<=)|(\.==)|(>>>)/; - var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*!*/ + var operators = parserConf.operators || /^(?:[|&^\\%*+\-<>!=\/]=?|\?|~|:|$|<:|\.[<>]|<<=?|>>>?=?|\.[<>]=|->?|\/\/|in)/; + var delimiters = parserConf.delimiters || /^[;,()[\]{}]/; + var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*!*/; var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif"]; var blockClosers = ["end", "else", "elseif"]; - var wordOperators = wordRegexp(['in']); var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'in', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote']; var builtinList = ['all', 'true', 'false', 'any', 'enumerate', 'open', 'close', 'linspace', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'error', 'warn', 'info']; @@ -26,7 +22,7 @@ CodeMirror.defineMode("julia", function(conf, parserConf) { var indentInfo = null; function in_array(state) { - ch = cur_scope(state); + var ch = cur_scope(state); if(ch=="[" || ch=="{") { return true; } @@ -84,6 +80,7 @@ CodeMirror.defineMode("julia", function(conf, parserConf) { state.leaving_expr=true; } + var match; if(match=stream.match(openers, false)) { state.scopes.push(match); } @@ -145,15 +142,10 @@ CodeMirror.defineMode("julia", function(conf, parserConf) { } // Handle operators and Delimiters - if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) { - return null; - } - if (stream.match(doubleOperators) - || stream.match(singleOperators) - || stream.match(wordOperators)) { + if (stream.match(operators)) { return 'operator'; } - if (stream.match(singleDelimiters)) { + if (stream.match(delimiters)) { return null; } @@ -235,7 +227,7 @@ CodeMirror.defineMode("julia", function(conf, parserConf) { } var external = { - startState: function(basecolumn) { + startState: function() { return { tokenize: tokenBase, scopes: [], From 700c239364971ac4f5e038f8c2682399a43da4c2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 22 Oct 2013 10:36:05 +0200 Subject: [PATCH 07/81] [julia mode] Integrate --- doc/compress.html | 1 + mode/index.html | 1 + mode/meta.js | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/compress.html b/doc/compress.html index e01001d2bb..d1384a76ef 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -107,6 +107,7 @@ + diff --git a/mode/index.html b/mode/index.html index cbdef24f09..337f3336e4 100644 --- a/mode/index.html +++ b/mode/index.html @@ -60,6 +60,7 @@
  • Jade
  • JavaScript
  • Jinja2
  • +
  • Julia
  • LESS
  • LiveScript
  • Lua
  • diff --git a/mode/meta.js b/mode/meta.js index f6bbd1b45c..47f042568d 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -36,7 +36,8 @@ CodeMirror.modeInfo = [ {name: 'JSON', mime: 'application/x-json', mode: 'javascript'}, {name: 'JSON', mime: 'application/json', mode: 'javascript'}, {name: 'TypeScript', mime: 'application/typescript', mode: 'javascript'}, - {name: 'Jinja2', mime: 'jinja2', mode: 'jinja2'}, + {name: 'Jinja2', mime: null, mode: 'jinja2'}, + {name: 'Julia', mime: 'text/x-julia', mode: 'julia'}, {name: 'LESS', mime: 'text/x-less', mode: 'less'}, {name: 'LiveScript', mime: 'text/x-livescript', mode: 'livescript'}, {name: 'Lua', mime: 'text/x-lua', mode: 'lua'}, From dda5ed52ae60e920de913285d134f5d62a0d3be2 Mon Sep 17 00:00:00 2001 From: Jon Malmaud Date: Tue, 22 Oct 2013 10:29:24 -0400 Subject: [PATCH 08/81] [julia mode] small tweaks Closes #1899 --- mode/julia/index.html | 3 +++ mode/julia/julia.js | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/mode/julia/index.html b/mode/julia/index.html index a79341df7a..3e42e9b9bf 100644 --- a/mode/julia/index.html +++ b/mode/julia/index.html @@ -69,6 +69,9 @@ end end +#function invocation +f('b', (2, 3)...) + #operators - + diff --git a/mode/julia/julia.js b/mode/julia/julia.js index 667ffc32d4..0a7939a729 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -5,7 +5,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { return new RegExp("^((" + words.join(")|(") + "))\\b"); } - var operators = parserConf.operators || /^(?:[|&^\\%*+\-<>!=\/]=?|\?|~|:|$|<:|\.[<>]|<<=?|>>>?=?|\.[<>]=|->?|\/\/|in)/; + var operators = parserConf.operators || /^(?:[|&^\\%*+\-<>!=\/]=?|\?|~|:|$|<:|\.[<>]|<<=?|>>>?=?|\.[<>=]=|->?|\/\/|in|\.{3})/; var delimiters = parserConf.delimiters || /^[;,()[\]{}]/; var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*!*/; var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif"]; @@ -41,7 +41,9 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { // tokenizers function tokenBase(stream, state) { // Handle scope changes - if(state.leaving_expr) { + leaving_expr = state.leaving_expr + state.leaving_expr = false + if(leaving_expr) { if(stream.match(/^'+/)) { return 'operator'; } From bc1e97f19c5e40f083d338cbfebdd2b48b0cabd7 Mon Sep 17 00:00:00 2001 From: Jon Malmaud Date: Tue, 22 Oct 2013 11:20:19 -0400 Subject: [PATCH 09/81] [julia mode] add single-precision literals --- mode/julia/index.html | 1 + mode/julia/julia.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mode/julia/index.html b/mode/julia/index.html index 3e42e9b9bf..5fa900190b 100644 --- a/mode/julia/index.html +++ b/mode/julia/index.html @@ -32,6 +32,7 @@ .234 .234im 2.23im +2.3f3 23e2 0x234 diff --git a/mode/julia/julia.js b/mode/julia/julia.js index 0a7939a729..0369b3ec73 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -105,7 +105,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { var imMatcher = RegExp(/^im\b/); var floatLiteral = false; // Floats - if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; } + if (stream.match(/^\d*\.\d+([ef][\+\-]?\d+)?/i)) { floatLiteral = true; } if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; } if (stream.match(/^\.\d+/)) { floatLiteral = true; } if (floatLiteral) { From 3ba1029b0366768606c4a0211bb208a6b9a84e83 Mon Sep 17 00:00:00 2001 From: Jon Malmaud Date: Tue, 22 Oct 2013 11:27:39 -0400 Subject: [PATCH 10/81] [julia mode] add triple-quote strings and exception-handling support --- mode/julia/index.html | 13 +++++++++++++ mode/julia/julia.js | 12 ++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/mode/julia/index.html b/mode/julia/index.html index 5fa900190b..6b9db12386 100644 --- a/mode/julia/index.html +++ b/mode/julia/index.html @@ -42,6 +42,10 @@ r"regex" b"bytestring" +""" +multiline string +""" + #identifiers a as123 @@ -56,6 +60,15 @@ x[end-1] x={"julia"=>"language of technical computing"} +#exception handling +try + f() +catch + @printf "Error" +finally + g() +end + #types immutable Color{T<:Number} r::T diff --git a/mode/julia/julia.js b/mode/julia/julia.js index 0369b3ec73..7b5e5b1ed7 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -8,13 +8,13 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { var operators = parserConf.operators || /^(?:[|&^\\%*+\-<>!=\/]=?|\?|~|:|$|<:|\.[<>]|<<=?|>>>?=?|\.[<>=]=|->?|\/\/|in|\.{3})/; var delimiters = parserConf.delimiters || /^[;,()[\]{}]/; var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*!*/; - var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif"]; - var blockClosers = ["end", "else", "elseif"]; - var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'in', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote']; + var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif", "try", "finally", "catch"]; + var blockClosers = ["end", "else", "elseif", "catch", "finally"]; + var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'in', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote', 'typealias']; var builtinList = ['all', 'true', 'false', 'any', 'enumerate', 'open', 'close', 'linspace', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'error', 'warn', 'info']; //var stringPrefixes = new RegExp("^[br]?('|\")") - var stringPrefixes = /^[br]?('|")/; + var stringPrefixes = /^[br]?('|"{3}|")/; var keywords = wordRegexp(keywordList); var builtins = wordRegexp(builtinList); var openers = wordRegexp(blockOpeners); @@ -245,7 +245,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { indent: function(state, textAfter) { var delta = 0; - if(textAfter=="end" || textAfter=="]" || textAfter=="}" || textAfter=="else" || textAfter=="elseif") { + if(textAfter=="end" || textAfter=="]" || textAfter=="}" || textAfter=="else" || textAfter=="elseif" || textAfter=="catch" || textAfter=="finally") { delta = -1; } return (state.scopes.length + delta) * 2; @@ -253,7 +253,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { lineComment: "#", fold: "indent", - electricChars: "endlsif]}" + electricChars: "edlsifyh]}" }; return external; }); From 4bde3e184d32345e200ea1a498ce7c31012296b6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 22 Oct 2013 17:31:44 +0200 Subject: [PATCH 11/81] Fix lint errors Issue #1900 --- mode/julia/julia.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/julia/julia.js b/mode/julia/julia.js index 7b5e5b1ed7..c0e5902f3f 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -41,8 +41,8 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { // tokenizers function tokenBase(stream, state) { // Handle scope changes - leaving_expr = state.leaving_expr - state.leaving_expr = false + var leaving_expr = state.leaving_expr; + state.leaving_expr = false; if(leaving_expr) { if(stream.match(/^'+/)) { return 'operator'; From 32d7db0cf78f5ed9dde3450ad885ced98851271b Mon Sep 17 00:00:00 2001 From: Narciso Jaramillo Date: Tue, 22 Oct 2013 15:41:21 -0700 Subject: [PATCH 12/81] Always move cursor to end of indent even if whitespace didn't change --- lib/codemirror.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 289e8f9d78..e52c883201 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2759,7 +2759,9 @@ window.CodeMirror = (function() { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} if (pos < indentation) indentString += spaceStr(indentation - pos); - if (indentString != curSpaceString) + if (indentString == curSpaceString) + setSelection(cm.doc, Pos(n, curSpaceString.length), Pos(n, curSpaceString.length)); + else replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); line.stateAfter = null; } From d88a9daf0e5df8a062793e383e69c0c07c493413 Mon Sep 17 00:00:00 2001 From: Jon Malmaud Date: Tue, 22 Oct 2013 16:41:50 -0400 Subject: [PATCH 13/81] [julia mode] added additional operators and fixed 'in' keyword --- mode/julia/index.html | 76 +++++++++++++++++++++++++++++++++++++++++---------- mode/julia/julia.js | 4 +-- 2 files changed, 63 insertions(+), 17 deletions(-) diff --git a/mode/julia/index.html b/mode/julia/index.html index 6b9db12386..bdb357bd49 100644 --- a/mode/julia/index.html +++ b/mode/julia/index.html @@ -87,29 +87,75 @@ f('b', (2, 3)...) #operators -- -+ -= -/ -\ -// --> +|= +&= +^= +\- +%= +*= ++= +-= +<= +>= +!= == -> +% +* ++ +- < +> +! += | & ->= -<= -& +^ +\ +? ~ -.>= +: +$ +<: +.< +.> +<< +<<= +>> +>>>> +>>= +>>>= +<<= +<<<= .<= +.>= .== -+= --= -/= +-> +// +in ... +// +:= +.//= +.*= +./= +.^= +.%= +.+= +.-= +\= +\\= +|| +=== +&& +|= +.|= +<: +>: +|> +<| +:: +x ? y : z + #keywords and operators if else elseif while for diff --git a/mode/julia/julia.js b/mode/julia/julia.js index c0e5902f3f..edf9dc41b5 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -5,12 +5,12 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { return new RegExp("^((" + words.join(")|(") + "))\\b"); } - var operators = parserConf.operators || /^(?:[|&^\\%*+\-<>!=\/]=?|\?|~|:|$|<:|\.[<>]|<<=?|>>>?=?|\.[<>=]=|->?|\/\/|in|\.{3})/; + var operators = parserConf.operators || /^(?:\.?[|&^\\%*+\-<>!=\/]=?|\?|~|:|\$|<:|\.[<>]|<<=?|>>>?=?|\.[<>=]=|->?|\/\/|\bin\b|\.{3})/; var delimiters = parserConf.delimiters || /^[;,()[\]{}]/; var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*!*/; var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif", "try", "finally", "catch"]; var blockClosers = ["end", "else", "elseif", "catch", "finally"]; - var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'in', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote', 'typealias']; + var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote', 'typealias', 'abstract', 'bitstype', 'ccall']; var builtinList = ['all', 'true', 'false', 'any', 'enumerate', 'open', 'close', 'linspace', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'error', 'warn', 'info']; //var stringPrefixes = new RegExp("^[br]?('|\")") From b03a9bcb927d281a8d937a4b3b71ead61fe00e3a Mon Sep 17 00:00:00 2001 From: Jon Malmaud Date: Wed, 23 Oct 2013 10:38:58 -0400 Subject: [PATCH 14/81] [julia mode] added support for macros and revised keyword and builtin list --- mode/julia/index.html | 7 +++++-- mode/julia/julia.js | 12 ++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/mode/julia/index.html b/mode/julia/index.html index bdb357bd49..dd567a623b 100644 --- a/mode/julia/index.html +++ b/mode/julia/index.html @@ -156,16 +156,19 @@ :: x ? y : z +#macros +@spawnat 2 1+1 +@eval(:x) #keywords and operators if else elseif while for -in begin let end do + begin let end do try catch finally return break continue global local const export import importall using function macro module baremodule type immutable quote -all true false any enumerate +true false enumerate diff --git a/mode/julia/julia.js b/mode/julia/julia.js index edf9dc41b5..9ec2428cd4 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -11,7 +11,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif", "try", "finally", "catch"]; var blockClosers = ["end", "else", "elseif", "catch", "finally"]; var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote', 'typealias', 'abstract', 'bitstype', 'ccall']; - var builtinList = ['all', 'true', 'false', 'any', 'enumerate', 'open', 'close', 'linspace', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'error', 'warn', 'info']; + var builtinList = ['true', 'false', 'enumerate', 'open', 'close', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'UTF8String', 'ASCIIString', 'error', 'warn', 'info', '@printf']; //var stringPrefixes = new RegExp("^[br]?('|\")") var stringPrefixes = /^[br]?('|"{3}|")/; @@ -19,6 +19,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { var builtins = wordRegexp(builtinList); var openers = wordRegexp(blockOpeners); var closers = wordRegexp(blockClosers); + var macro = /@[_A-Za-z][_A-Za-z0-9]*!*/; var indentInfo = null; function in_array(state) { @@ -147,6 +148,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { if (stream.match(operators)) { return 'operator'; } + if (stream.match(delimiters)) { return null; } @@ -159,6 +161,9 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { return 'builtin'; } + if (stream.match(macro)) { + return 'meta'; + } if (stream.match(identifiers)) { state.leaving_expr=true; @@ -220,11 +225,6 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { return style; } - // Handle macro calls - if (current === '@') { - return stream.match(identifiers, false) ? 'meta' : ERRORCLASS; - } - return style; } From d64d8ba868dac600ba8572d3e4b51d612a9116fa Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Tue, 22 Oct 2013 13:41:45 -0600 Subject: [PATCH 15/81] [matchbrackets addon] add a maxScanLines configuration, defaulting to 100. --- addon/edit/matchbrackets.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js index 131fe831fd..9d9b3882f7 100644 --- a/addon/edit/matchbrackets.js +++ b/addon/edit/matchbrackets.js @@ -8,6 +8,7 @@ function findMatchingBracket(cm, where, strict) { var state = cm.state.matchBrackets; var maxScanLen = (state && state.maxScanLineLength) || 10000; + var maxScanLines = (state && state.maxScanLines) || 100; var cur = where || cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1; var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)]; @@ -32,7 +33,7 @@ } } } - for (var i = cur.line, found, e = forward ? Math.min(i + 100, cm.lineCount()) : Math.max(-1, i - 100); i != e; i+=d) { + for (var i = cur.line, found, e = forward ? Math.min(i + maxScanLines, cm.lineCount()) : Math.max(-1, i - maxScanLines); i != e; i+=d) { if (i == cur.line) found = scan(line, i, pos); else found = scan(cm.getLineHandle(i), i); if (found) break; From 02f49478ebbe133a1567832726589f05af0d4a3f Mon Sep 17 00:00:00 2001 From: angelozerr Date: Tue, 22 Oct 2013 17:03:01 +0200 Subject: [PATCH 16/81] [tern addon] Make it possible to pass in explicit positions Create Tern request with optionnal pos to manage for instance tern hover. See demo at http://codemirror-java.opensagres.eu.cloudbees.net/codemirror-javascript/demo/javascript-all.html --- addon/tern/tern.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/addon/tern/tern.js b/addon/tern/tern.js index fe93fa7335..1f18a657fb 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -96,7 +96,7 @@ getHint: function(cm, c) { return hint(this, cm, c); }, - showType: function(cm) { showType(this, cm); }, + showType: function(cm, pos) { showType(this, cm, pos); }, updateArgHints: function(cm) { updateArgHints(this, cm); }, @@ -106,10 +106,10 @@ rename: function(cm) { rename(this, cm); }, - request: function (cm, query, c) { + request: function (cm, query, c, pos) { var self = this; var doc = findDoc(this, cm.getDoc()); - var request = buildRequest(this, doc, query); + var request = buildRequest(this, doc, query, pos); this.server.request(request, function (error, data) { if (!error && self.options.responseFilter) @@ -221,7 +221,7 @@ // Type queries - function showType(ts, cm) { + function showType(ts, cm, pos) { ts.request(cm, "type", function(error, data) { if (error) return showError(ts, cm, error); if (ts.options.typeTip) { @@ -236,7 +236,7 @@ } } tempTooltip(cm, tip); - }); + }, pos); } // Maintaining argument hints @@ -450,13 +450,13 @@ // Generic request-building helper - function buildRequest(ts, doc, query) { + function buildRequest(ts, doc, query, pos) { var files = [], offsetLines = 0, allowFragments = !query.fullDocs; if (!allowFragments) delete query.fullDocs; if (typeof query == "string") query = {type: query}; query.lineCharPositions = true; if (query.end == null) { - query.end = doc.doc.getCursor("end"); + query.end = pos || doc.doc.getCursor("end"); if (doc.doc.somethingSelected()) query.start = doc.doc.getCursor("start"); } From ae0640c4befccf946cdbe12988d59bd3572ec00e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 24 Oct 2013 14:49:43 +0200 Subject: [PATCH 17/81] [javascript mode] Properly handle regexp at start of file --- mode/javascript/javascript.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index e8ace32d89..9fca783c44 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -103,7 +103,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return ret("comment", "comment"); } else if (state.lastType == "operator" || state.lastType == "keyword c" || - /^[\[{}\(,;:]$/.test(state.lastType)) { + state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) { nextUntilUnescaped(stream, "/"); stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla return ret("regexp", "string-2"); @@ -410,7 +410,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { startState: function(basecolumn) { return { tokenize: jsTokenBase, - lastType: null, + lastType: "sof", cc: [], lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), localVars: parserConfig.localVars, From 759b3a0e9ab1ce6486341651252d968e417ffe5e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 26 Oct 2013 22:06:59 +0200 Subject: [PATCH 18/81] Fix undesirable selection-mangling in indentLine Issue #1910 --- lib/codemirror.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index e52c883201..231b782971 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2759,9 +2759,7 @@ window.CodeMirror = (function() { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} if (pos < indentation) indentString += spaceStr(indentation - pos); - if (indentString == curSpaceString) - setSelection(cm.doc, Pos(n, curSpaceString.length), Pos(n, curSpaceString.length)); - else + if (indentString != curSpaceString || doc.sel.head.line == n && doc.sel.head.ch < curSpaceString.length) replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); line.stateAfter = null; } From 8d000ddae0935f73e32ef517841c4df21db175e2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 28 Oct 2013 19:40:54 +0100 Subject: [PATCH 19/81] [javascript mode] Fix bug in recognizing local variable in nested context --- mode/javascript/javascript.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 9fca783c44..05ae70bd2f 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -165,6 +165,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function inScope(state, varname) { for (var v = state.localVars; v; v = v.next) if (v.name == varname) return true; + for (var cx = state.context; cx; cx = cx.prev) { + for (var v = cx.vars; v; v = v.next) + if (v.name == varname) return true; + } } function parseJS(state, style, type, content, stream) { From bf55dac09202b4dbca190a8323ed698e0d2eff74 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 29 Oct 2013 08:46:21 +0100 Subject: [PATCH 20/81] Disable textarea when readOnly=nocursor Issue #1909 --- lib/codemirror.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 231b782971..9e7b720781 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3308,8 +3308,14 @@ window.CodeMirror = (function() { option("resetSelectionOnContextMenu", true); option("readOnly", false, function(cm, val) { - if (val == "nocursor") {onBlur(cm); cm.display.input.blur();} - else if (!val) resetInput(cm, true); + if (val == "nocursor") { + onBlur(cm); + cm.display.input.blur(); + cm.display.disabled = true; + } else { + cm.display.disabled = false; + if (!val) resetInput(cm, true); + } }); option("dragDrop", true); From 65c750e8f7b04c7b99a915d912c16f235430ca3e Mon Sep 17 00:00:00 2001 From: ilvalle Date: Mon, 28 Oct 2013 10:21:27 +0100 Subject: [PATCH 21/81] [indent-fold addon] Fix folding for empty files --- addon/fold/indent-fold.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addon/fold/indent-fold.js b/addon/fold/indent-fold.js index b54da34777..7ae005d904 100644 --- a/addon/fold/indent-fold.js +++ b/addon/fold/indent-fold.js @@ -1,8 +1,9 @@ CodeMirror.registerHelper("fold", "indent", function(cm, start) { var lastLine = cm.lastLine(), tabSize = cm.getOption("tabSize"), - firstLine = cm.getLine(start.line), - myIndent = CodeMirror.countColumn(firstLine, null, tabSize); + firstLine = cm.getLine(start.line); + if (!tabSize || !firstLine) return; + var myIndent = CodeMirror.countColumn(firstLine, null, tabSize); function foldEnded(curColumn, prevColumn) { return curColumn < myIndent || From 701b226107b3eded05cb10575c258647854c0352 Mon Sep 17 00:00:00 2001 From: Forbes Lindesay Date: Tue, 22 Oct 2013 17:17:16 +0100 Subject: [PATCH 22/81] Add the PEG.js language --- mode/peg/index.html | 66 +++++++++++++++++++++++++++++++++ mode/peg/peg.js | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 mode/peg/index.html create mode 100644 mode/peg/peg.js diff --git a/mode/peg/index.html b/mode/peg/index.html new file mode 100644 index 0000000000..3e55a5e4b5 --- /dev/null +++ b/mode/peg/index.html @@ -0,0 +1,66 @@ + + + + CodeMirror: PEG Mode + + + + + + + + + + + + +
    +

    PEG.js Mode

    +
    + +

    The PEG.js Mode

    +

    Created by Forbes Lindesay.

    +
    + + \ No newline at end of file diff --git a/mode/peg/peg.js b/mode/peg/peg.js new file mode 100644 index 0000000000..6f8b480946 --- /dev/null +++ b/mode/peg/peg.js @@ -0,0 +1,103 @@ +CodeMirror.defineMode("peg", function (config) { + var jsMode = CodeMirror.getMode(config, "javascript"); + + function identifier(stream) { + return stream.match(/^[a-zA-Z_][a-zA-Z0-9_]*/); + } + + return { + startState: function () { + return { + inString: false, + stringType: null, + inComment: false, + inChracterClass: false, + braced: 0, + lhs: true, + localState: null + }; + }, + token: function (stream, state) { + if (stream) + + //check for state changes + if (!state.inString && !state.inComment && ((stream.peek() == '"') || (stream.peek() == "'"))) { + state.stringType = stream.peek(); + stream.next(); // Skip quote + state.inString = true; // Update state + } + if (!state.inString && !state.inComment && stream.match(/^\/\*/)) { + state.inComment = true; + } + + //return state + if (state.inString) { + while (state.inString && !stream.eol()) { + if (stream.peek() === state.stringType) { + stream.next(); // Skip quote + state.inString = false; // Clear flag + } else if (stream.peek() === '\\') { + stream.next(); + stream.next(); + } else { + stream.match(/^.[^\\\"\']*/); + } + } + return state.lhs ? "property string" : "string"; // Token style + } else if (state.inComment) { + while (state.inComment && !stream.eol()) { + if (stream.match(/\*\//)) { + state.inComment = false; // Clear flag + } else { + stream.match(/^.[^\*]*/); + } + } + return "comment"; + } else if (state.inChracterClass) { + if (stream.match(/^[^\]\\]+/)) { + return; + } else if (stream.match(/^\\./)) { + return; + } else { + stream.next(); + state.inChracterClass = false; + return 'bracket'; + } + } else if (stream.peek() === '[') { + stream.next(); + state.inChracterClass = true; + return 'bracket'; + } else if (stream.match(/^\/\//)) { + stream.skipToEnd(); + return "comment"; + } else if (state.braced || stream.peek() === '{') { + if (state.localState === null) { + state.localState = jsMode.startState(); + } + var token = jsMode.token(stream, state.localState); + var text = stream.current(); + if (!token) { + for (var i = 0; i < text.length; i++) { + if (text[i] === '{') { + state.braced++; + } else if (text[i] === '}') { + state.braced--; + } + }; + } + return token; + } else if (identifier(stream)) { + if (stream.peek() === ':') { + return 'variable'; + } + return 'variable-2'; + } else if (['[', ']', '(', ')'].indexOf(stream.peek()) != -1) { + stream.next(); + return 'bracket'; + } else if (!stream.eatSpace()) { + stream.next(); + } + return null; + } + }; +}); From acb16d4be0aba6edf51b97c413cd66a4e248c9e1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 29 Oct 2013 08:58:07 +0100 Subject: [PATCH 23/81] [pegjs mode] Integrate --- doc/compress.html | 1 + mode/index.html | 1 + mode/meta.js | 1 + mode/{peg => pegjs}/index.html | 10 +++++----- mode/{peg/peg.js => pegjs/pegjs.js} | 4 ++-- 5 files changed, 10 insertions(+), 7 deletions(-) rename mode/{peg => pegjs}/index.html (90%) rename mode/{peg/peg.js => pegjs/pegjs.js} (97%) diff --git a/doc/compress.html b/doc/compress.html index d1384a76ef..f49c978b2e 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -118,6 +118,7 @@ + diff --git a/mode/index.html b/mode/index.html index 337f3336e4..81abc42d8c 100644 --- a/mode/index.html +++ b/mode/index.html @@ -71,6 +71,7 @@
  • OCaml
  • Octave (MATLAB)
  • Pascal
  • +
  • PEG.js
  • Perl
  • PHP
  • Pig Latin
  • diff --git a/mode/meta.js b/mode/meta.js index 47f042568d..226cff12e5 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -48,6 +48,7 @@ CodeMirror.modeInfo = [ {name: 'OCaml', mime: 'text/x-ocaml', mode: 'ocaml'}, {name: 'Octave', mime: 'text/x-octave', mode: 'octave'}, {name: 'Pascal', mime: 'text/x-pascal', mode: 'pascal'}, + {name: 'PEG.js', mime: null, mode: 'pegjs'}, {name: 'Perl', mime: 'text/x-perl', mode: 'perl'}, {name: 'PHP', mime: 'text/x-php', mode: 'php'}, {name: 'PHP(HTML)', mime: 'application/x-httpd-php', mode: 'php'}, diff --git a/mode/peg/index.html b/mode/pegjs/index.html similarity index 90% rename from mode/peg/index.html rename to mode/pegjs/index.html index 3e55a5e4b5..678b714d8e 100644 --- a/mode/peg/index.html +++ b/mode/pegjs/index.html @@ -1,14 +1,14 @@ - CodeMirror: PEG Mode + CodeMirror: PEG.js Mode - + @@ -22,7 +22,7 @@ @@ -55,7 +55,7 @@ letter = [a-z]+ @@ -63,4 +63,4 @@

    Created by Forbes Lindesay.

    - \ No newline at end of file + diff --git a/mode/peg/peg.js b/mode/pegjs/pegjs.js similarity index 97% rename from mode/peg/peg.js rename to mode/pegjs/pegjs.js index 6f8b480946..6cdcc61f30 100644 --- a/mode/peg/peg.js +++ b/mode/pegjs/pegjs.js @@ -1,4 +1,4 @@ -CodeMirror.defineMode("peg", function (config) { +CodeMirror.defineMode("pegjs", function (config) { var jsMode = CodeMirror.getMode(config, "javascript"); function identifier(stream) { @@ -100,4 +100,4 @@ CodeMirror.defineMode("peg", function (config) { return null; } }; -}); +}, "javascript"); From 0d32c1e73bd30408e4d70503aebeefdaef8fecda Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 30 Oct 2013 20:03:31 +0100 Subject: [PATCH 24/81] [haskell mode] Fix unintended prototype property access bug Closes #1917 --- mode/haskell/haskell.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/haskell/haskell.js b/mode/haskell/haskell.js index 59ca7f0baa..68a6317e64 100644 --- a/mode/haskell/haskell.js +++ b/mode/haskell/haskell.js @@ -237,7 +237,7 @@ CodeMirror.defineMode("haskell", function(_config, modeConfig) { token: function(stream, state) { var t = state.f(stream, function(s) { state.f = s; }); var w = stream.current(); - return (w in wellKnownWords) ? wellKnownWords[w] : t; + return wellKnownWords.hasOwnProperty(w) ? wellKnownWords[w] : t; }, blockCommentStart: "{-", From de91f48272d060cfe83406280242ba469f5aba27 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 31 Oct 2013 08:23:15 +0100 Subject: [PATCH 25/81] [real-world uses] Add Crudzilla --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 8afe73aa0a..4e0896c377 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -51,6 +51,7 @@
  • Community Code Camp (code snippet sharing)
  • compilejava.net (online Java sandbox)
  • CKWNC (UML editor)
  • +
  • Crudzilla (self-hosted web IDE)
  • CSSDeck (CSS showcase)
  • Deck.js integration (slides with editors)
  • DbNinja (MySQL access interface)
  • From b41fc2b370c0cb530060f5f2fb7b391ef7afa5d2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 31 Oct 2013 08:53:52 +0100 Subject: [PATCH 26/81] [closetag addon] Don't react to > and / keys when in an attribute Closes #1916 --- addon/edit/closetag.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index d6a8fafd3c..7b0975043a 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -54,7 +54,8 @@ if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); var lowerTagName = tagName.toLowerCase(); // Don't process the '>' at the end of an end-tag or self-closing tag - if (tok.type == "tag" && state.type == "closeTag" || + if (tok.type == "string" && (tok.string.charAt(tok.string.length - 1) != '"' || tok.string.length == 1) || + tok.type == "tag" && state.type == "closeTag" || tok.string.indexOf("/") == (tok.string.length - 1) || // match something like dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1) return CodeMirror.Pass; @@ -72,7 +73,9 @@ function autoCloseSlash(cm) { var pos = cm.getCursor(), tok = cm.getTokenAt(pos); var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; - if (tok.string.charAt(0) != "<" || tok.start != pos.ch - 1 || inner.mode.name != "xml") return CodeMirror.Pass; + if (tok.type == "string" || tok.string.charAt(0) != "<" || + tok.start != pos.ch - 1 || inner.mode.name != "xml") + return CodeMirror.Pass; var tagName = state.context && state.context.tagName; if (tagName) cm.replaceSelection("/" + tagName + ">", "end"); From 01e9fbb6496cda9e3e8fb3b29b4830770cebe642 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 31 Oct 2013 10:17:57 +0100 Subject: [PATCH 27/81] [closetag addon] Another corner case when typing in attribute Issue #1916 --- addon/edit/closetag.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index 7b0975043a..a0dc32618e 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -54,7 +54,7 @@ if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); var lowerTagName = tagName.toLowerCase(); // Don't process the '>' at the end of an end-tag or self-closing tag - if (tok.type == "string" && (tok.string.charAt(tok.string.length - 1) != '"' || tok.string.length == 1) || + if (tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) || tok.type == "tag" && state.type == "closeTag" || tok.string.indexOf("/") == (tok.string.length - 1) || // match something like dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1) From dcf0b65a89e2d8fd9cc254cb39ee58bae44650c0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 3 Nov 2013 20:18:53 +0100 Subject: [PATCH 28/81] Another iteration on pushing the selection forward on no-change reindents --- lib/codemirror.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 9e7b720781..23fc2c5bee 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2759,8 +2759,10 @@ window.CodeMirror = (function() { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} if (pos < indentation) indentString += spaceStr(indentation - pos); - if (indentString != curSpaceString || doc.sel.head.line == n && doc.sel.head.ch < curSpaceString.length) + if (indentString != curSpaceString) replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); + else if (doc.sel.head.line == n && doc.sel.head.ch < curSpaceString.length) + setSelection(doc, Pos(n, curSpaceString.length), Pos(n, curSpaceString.length), 1); line.stateAfter = null; } From a8c5cfb5cc0f48bed8c9f7e3e264503a17d20b07 Mon Sep 17 00:00:00 2001 From: soliton4 Date: Sat, 2 Nov 2013 17:48:11 +0100 Subject: [PATCH 29/81] [less mode] Bugfix --- mode/less/less.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/less/less.js b/mode/less/less.js index ec62319080..fb42241c8c 100644 --- a/mode/less/less.js +++ b/mode/less/less.js @@ -204,7 +204,7 @@ CodeMirror.defineMode("less", function(config) { else if(type === "unit" && state.stack[state.stack.length-1] === "rule")return ret(null, "unit"); else if(type === "unit" && state.stack[state.stack.length-1] === ";")return ret(null, "unit"); else if(type === ")" && state.stack[state.stack.length-1] === "rule")return ret(null, "unit"); - else if(type.match("@") !== null && state.stack[state.stack.length-1] === "rule")return ret(null, "unit"); + else if(type && type.match("@") !== null && state.stack[state.stack.length-1] === "rule")return ret(null, "unit"); //else if(type === "unit" && state.stack[state.stack.length-1] === "rule")return ret(null, stream.current()); else if((type === ";" || type === "}" || type === ",") && state.stack[state.stack.length-1] === ";")return ret("tag", stream.current()); From 36b887d52e12767212ddfb4af353a9e2ecf64366 Mon Sep 17 00:00:00 2001 From: Marko Bonaci Date: Sun, 3 Nov 2013 19:24:29 +0100 Subject: [PATCH 30/81] [mbo theme] Fix matching tag background highlighting --- theme/mbo.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/theme/mbo.css b/theme/mbo.css index f3250a7313..93fe3ee24c 100644 --- a/theme/mbo.css +++ b/theme/mbo.css @@ -24,9 +24,11 @@ .cm-s-mbo .CodeMirror-activeline-background {background: #494b41 !important;} .cm-s-mbo .CodeMirror-matchingbracket { - text-decoration: underline; + text-decoration: underline; color: #f5e107 !important; } + +.cm-s-mbo .CodeMirror-matchingtag {background: #4e4e4e;} div.CodeMirror span.CodeMirror-searching { background-color: none; From 464dd7b555c6fc3eb27afc5c78b34883ba972ba4 Mon Sep 17 00:00:00 2001 From: Peter Kroon Date: Mon, 4 Nov 2013 11:03:23 +0100 Subject: [PATCH 31/81] [less mode] Fix null dereference bug Issue #1926 --- mode/less/less.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mode/less/less.js b/mode/less/less.js index fb42241c8c..6333a98c48 100644 --- a/mode/less/less.js +++ b/mode/less/less.js @@ -70,7 +70,9 @@ CodeMirror.defineMode("less", function(config) { stream.eatWhile(/[\a-zA-Z0-9\-_]/); if(stream.peek() === " ")stream.eatSpace(); if(stream.peek() === ")" || type === ":")return ret("number", "unit");//rgba(0,0,0,.25); - else if(state.stack[state.stack.length-1] === "rule" && stream.peek().match(/{|,|\+|\(/) === null)return ret("number", "unit"); + else if(stream.peek() !== undefined ){ + if(state.stack[state.stack.length-1] === "rule" && stream.peek().match(/{|,|\+|\(/) === null)return ret("number", "unit"); + } return ret("tag", "tag"); } else if (ch == "#") { //we don't eat white-space, we want the hex color and or id only From 8c42f651f15b6b43022a75b1162f7953bae0559e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 4 Nov 2013 15:07:12 +0100 Subject: [PATCH 32/81] [less mode] Fix null dereference bug (part 2) Issue #1926 --- mode/less/less.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/less/less.js b/mode/less/less.js index 6333a98c48..da39074851 100644 --- a/mode/less/less.js +++ b/mode/less/less.js @@ -70,7 +70,7 @@ CodeMirror.defineMode("less", function(config) { stream.eatWhile(/[\a-zA-Z0-9\-_]/); if(stream.peek() === " ")stream.eatSpace(); if(stream.peek() === ")" || type === ":")return ret("number", "unit");//rgba(0,0,0,.25); - else if(stream.peek() !== undefined ){ + else if(stream.current().length >1){ if(state.stack[state.stack.length-1] === "rule" && stream.peek().match(/{|,|\+|\(/) === null)return ret("number", "unit"); } return ret("tag", "tag"); From bf7acd64a1a825dc077d9fcb2d90c1e961a1bebc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 4 Nov 2013 15:07:37 +0100 Subject: [PATCH 33/81] [javascript-hint addon] Don't fire hints in comments or strings --- addon/hint/javascript-hint.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/hint/javascript-hint.js b/addon/hint/javascript-hint.js index 513fb782b0..c66b0a7a5b 100644 --- a/addon/hint/javascript-hint.js +++ b/addon/hint/javascript-hint.js @@ -21,6 +21,7 @@ function scriptHint(editor, keywords, getToken, options) { // Find the token at the cursor var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token; + if (/\b(?:string|comment)\b/.test(token.type)) return; token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; // If it's not a 'word-style' token, ignore the token. From 977c64fbaa0c610edff107a4c13099f18858f3d6 Mon Sep 17 00:00:00 2001 From: Forbes Lindesay Date: Mon, 4 Nov 2013 15:23:13 +0000 Subject: [PATCH 34/81] [pig mode] Add DUMP as keyword --- mode/pig/pig.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/pig/pig.js b/mode/pig/pig.js index c2f611a1a0..4b44e7ccc3 100644 --- a/mode/pig/pig.js +++ b/mode/pig/pig.js @@ -157,7 +157,7 @@ CodeMirror.defineMode("pig", function(_config, parserConfig) { + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL " + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE " + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE " - + "NEQ MATCHES TRUE FALSE "; + + "NEQ MATCHES TRUE FALSE DUMP"; // data types var pTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP "; From 575a29a40942229bee4f02f73f3b73c838b5b386 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 5 Nov 2013 10:12:18 +0100 Subject: [PATCH 35/81] Add IE11+ detection, use it to fix failing test Closes #1826 --- lib/codemirror.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 23fc2c5bee..254c0e03fc 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -7,9 +7,13 @@ window.CodeMirror = (function() { // Crude, but necessary to handle a number of hard-to-feature-detect // bugs and behavior differences. var gecko = /gecko\/\d/i.test(navigator.userAgent); + // IE11 currently doesn't count as 'ie', since it has almost none of + // the same bugs as earlier versions. Use ie_gt10 to handle + // incompatibilities in that version. var ie = /MSIE \d/.test(navigator.userAgent); var ie_lt8 = ie && (document.documentMode == null || document.documentMode < 8); var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); + var ie_gt10 = /Trident\/([7-9]|\d{2,})\./; var webkit = /WebKit\//.test(navigator.userAgent); var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); var chrome = /Chrome\//.test(navigator.userAgent); @@ -4403,7 +4407,7 @@ window.CodeMirror = (function() { // Work around problem with the reported dimensions of single-char // direction spans on IE (issue #1129). See also the comment in // cursorCoords. - if (measure && ie && (order = getOrder(line))) { + if (measure && (ie || ie_gt10) && (order = getOrder(line))) { var l = order.length - 1; if (order[l].from == order[l].to) --l; var last = order[l], prev = order[l - 1]; From 567a94b89cbe8bf12f6a210e2e395c5c147272a9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 5 Nov 2013 22:27:04 +0100 Subject: [PATCH 36/81] [coffeescript mode] Some refinement in indentation Issue #1932 --- mode/coffeescript/coffeescript.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/mode/coffeescript/coffeescript.js b/mode/coffeescript/coffeescript.js index d29ad2b73a..93b77bcb67 100644 --- a/mode/coffeescript/coffeescript.js +++ b/mode/coffeescript/coffeescript.js @@ -213,6 +213,8 @@ CodeMirror.defineMode("coffeescript", function(conf) { if (type !== "coffee") { align = null; alignOffset = stream.column() + stream.current().length; + } else if (state.scope.align) { + state.scope.align = false; } state.scope = { offset: offset, @@ -268,7 +270,6 @@ CodeMirror.defineMode("coffeescript", function(conf) { } if (((current === "->" || current === "=>") && !state.lambda && - state.scope.type == "coffee" && !stream.peek()) || style === "indent") { indent(stream, state); @@ -292,9 +293,10 @@ CodeMirror.defineMode("coffeescript", function(conf) { } delimiter_index = "])}".indexOf(current); if (delimiter_index !== -1) { - if (dedent(stream, state)) { - return ERRORCLASS; - } + while (state.scope.type == "coffee" && state.scope.prev) + state.scope = state.scope.prev; + if (state.scope.type == current) + state.scope = state.scope.prev; } if (state.dedent > 0 && stream.eol() && state.scope.type == "coffee") { if (state.scope.prev) state.scope = state.scope.prev; @@ -333,11 +335,14 @@ CodeMirror.defineMode("coffeescript", function(conf) { indent: function(state, text) { if (state.tokenize != tokenBase) return 0; - var closes = state.scope.type === (text && text.charAt(0)); - if (state.scope.align) - return state.scope.alignOffset - (closes ? 1 : 0); + var scope = state.scope; + var closer = "])}".indexOf(text.charAt(0)) > -1; + if (closer) while (scope.type == "coffee" && scope.prev) scope = scope.prev; + var closes = scope.type === text.charAt(0); + if (scope.align) + return scope.alignOffset - (closes ? 1 : 0); else - return (closes ? state.scope.prev : state.scope).offset; + return (closes ? scope.prev : scope).offset; }, lineComment: "#", From 4da56b598000a451423cf38598e413b10b8a4f62 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Nov 2013 08:29:25 +0100 Subject: [PATCH 37/81] [coffeescript mode] Fix bug introduced by 567a94b89cbe8b Issue #1932 --- mode/coffeescript/coffeescript.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/coffeescript/coffeescript.js b/mode/coffeescript/coffeescript.js index 93b77bcb67..e8bfe48a24 100644 --- a/mode/coffeescript/coffeescript.js +++ b/mode/coffeescript/coffeescript.js @@ -336,9 +336,9 @@ CodeMirror.defineMode("coffeescript", function(conf) { indent: function(state, text) { if (state.tokenize != tokenBase) return 0; var scope = state.scope; - var closer = "])}".indexOf(text.charAt(0)) > -1; + var closer = text && "])}".indexOf(text.charAt(0)) > -1; if (closer) while (scope.type == "coffee" && scope.prev) scope = scope.prev; - var closes = scope.type === text.charAt(0); + var closes = closer && scope.type === text.charAt(0); if (scope.align) return scope.alignOffset - (closes ? 1 : 0); else From c8639251bb6d06c1b6c4b729a6656642ae4aa8d2 Mon Sep 17 00:00:00 2001 From: Maksym Taran Date: Tue, 5 Nov 2013 15:54:31 -0800 Subject: [PATCH 38/81] [indent-fold addon] Include empty lines --- addon/fold/indent-fold.js | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/addon/fold/indent-fold.js b/addon/fold/indent-fold.js index 7ae005d904..fabfa4f04e 100644 --- a/addon/fold/indent-fold.js +++ b/addon/fold/indent-fold.js @@ -1,27 +1,29 @@ CodeMirror.registerHelper("fold", "indent", function(cm, start) { - var lastLine = cm.lastLine(), - tabSize = cm.getOption("tabSize"), - firstLine = cm.getLine(start.line); - if (!tabSize || !firstLine) return; - var myIndent = CodeMirror.countColumn(firstLine, null, tabSize); - - function foldEnded(curColumn, prevColumn) { - return curColumn < myIndent || - (curColumn == myIndent && prevColumn >= myIndent) || - (curColumn > myIndent && i == lastLine); - } - - for (var i = start.line + 1; i <= lastLine; i++) { - var curColumn = CodeMirror.countColumn(cm.getLine(i), null, tabSize); - var prevColumn = CodeMirror.countColumn(cm.getLine(i-1), null, tabSize); - - if (foldEnded(curColumn, prevColumn)) { - var lastFoldLineNumber = curColumn > myIndent && i == lastLine ? i : i-1; - var lastFoldLine = cm.getLine(lastFoldLineNumber); - return {from: CodeMirror.Pos(start.line, firstLine.length), - to: CodeMirror.Pos(lastFoldLineNumber, lastFoldLine.length)}; + var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line); + var getIndent = function(lineNum) { + return CodeMirror.countColumn(lineNum, null, tabSize); + }; + var myIndent = getIndent(firstLine); + var lastLineInFold = null; + // Go through lines until we find a line that definitely doesn't belong in + // the block we're folding, or to the end. + for (var i = start.line + 1, end = cm.lineCount(); i < end; ++i) { + var curLine = cm.getLine(i); + var curIndent = getIndent(curLine); + if (curIndent > myIndent) { + // Lines with a greater indent are considered part of the block. + lastLineInFold = i; + } else if (curIndent == 0 && curLine.length == 0) { + // Empty lines might be breaks within the block we're trying to fold. + } else { + // A non-empty line at an indent equal to or less than ours marks the + // start of another block. + break; } } + return { + from: CodeMirror.Pos(start.line, firstLine.length), + to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) + }; }); - CodeMirror.indentRangeFinder = CodeMirror.fold.indent; // deprecated From 5b875f598e94ee4a4eb74faf69065c84eb7b7a0e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Nov 2013 08:51:57 +0100 Subject: [PATCH 39/81] [indent-fold addon] Consider all-whitespace lines empty lines --- addon/fold/indent-fold.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/fold/indent-fold.js b/addon/fold/indent-fold.js index fabfa4f04e..3787b3f378 100644 --- a/addon/fold/indent-fold.js +++ b/addon/fold/indent-fold.js @@ -13,7 +13,7 @@ CodeMirror.registerHelper("fold", "indent", function(cm, start) { if (curIndent > myIndent) { // Lines with a greater indent are considered part of the block. lastLineInFold = i; - } else if (curIndent == 0 && curLine.length == 0) { + } else if (!/\S/.test(curLine)) { // Empty lines might be breaks within the block we're trying to fold. } else { // A non-empty line at an indent equal to or less than ours marks the From 47a3734c3286d7525ba9451ff0ce25984d22f1e5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Nov 2013 08:54:57 +0100 Subject: [PATCH 40/81] [indent-fold addon] Return nothing on edge cases --- addon/fold/indent-fold.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addon/fold/indent-fold.js b/addon/fold/indent-fold.js index 3787b3f378..1bd600be42 100644 --- a/addon/fold/indent-fold.js +++ b/addon/fold/indent-fold.js @@ -1,5 +1,6 @@ CodeMirror.registerHelper("fold", "indent", function(cm, start) { var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line); + if (!/\S/.test(firstLine)) return; var getIndent = function(lineNum) { return CodeMirror.countColumn(lineNum, null, tabSize); }; @@ -7,7 +8,7 @@ CodeMirror.registerHelper("fold", "indent", function(cm, start) { var lastLineInFold = null; // Go through lines until we find a line that definitely doesn't belong in // the block we're folding, or to the end. - for (var i = start.line + 1, end = cm.lineCount(); i < end; ++i) { + for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) { var curLine = cm.getLine(i); var curIndent = getIndent(curLine); if (curIndent > myIndent) { @@ -21,7 +22,7 @@ CodeMirror.registerHelper("fold", "indent", function(cm, start) { break; } } - return { + if (lastLineInFold) return { from: CodeMirror.Pos(start.line, firstLine.length), to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) }; From c63d7e342079143eed9a18fd115930366be5f6c3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Nov 2013 08:21:55 +0100 Subject: [PATCH 41/81] Clip scroll positions given to scrollTo to scrollable space Closes #1934 --- lib/codemirror.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 254c0e03fc..0b65bb13cf 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1387,8 +1387,10 @@ window.CodeMirror = (function() { } if (!updated && op.selectionChanged) updateSelection(cm); if (op.updateScrollPos) { - display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = newScrollPos.scrollTop; - display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = newScrollPos.scrollLeft; + var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, newScrollPos.scrollTop)); + var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, newScrollPos.scrollLeft)); + display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top; + display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left; alignHorizontally(cm); if (op.scrollToPos) scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos.from), From 66a5cd630a8a2423cd79eccb170df4d7ee1bb83c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Nov 2013 08:24:19 +0100 Subject: [PATCH 42/81] Add more extending unicode ranges --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 0b65bb13cf..6d0e9d6459 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -5491,7 +5491,7 @@ window.CodeMirror = (function() { return true; } - var isExtendingChar = /[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\uA670-\uA672\uA674-\uA67D\uA69F\udc00-\udfff]/; + var isExtendingChar = /[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\u1DC0–\u1DFF\u20D0–\u20FF\uA670-\uA672\uA674-\uA67D\uA69F\udc00-\udfff\uFE20–\uFE2F]/; // DOM UTILITIES From b8d83f2e461e87f5b87773301f27792490963a35 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Nov 2013 08:31:25 +0100 Subject: [PATCH 43/81] Document execCommand Issue #1935 --- doc/manual.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/manual.html b/doc/manual.html index ba8789a836..d79265fd6b 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1576,6 +1576,9 @@

    Miscellaneous methods

    given an argument), or sets the overwrite mode to a specific state (when given an argument).
    +
    cm.execCommand(name: string)
    +
    Runs the command with the given name on the editor.
    +
    doc.posFromIndex(index: integer) → {line, ch}
    Calculates and returns a {line, ch} object for a zero-based index who's value is relative to the start of the From 398915a47ed46d86decadadf24aa7059f26e96c3 Mon Sep 17 00:00:00 2001 From: Andy Joslin Date: Thu, 7 Nov 2013 13:48:24 -0500 Subject: [PATCH 44/81] [dialog addon] Add cm.openNotification: timed & unobtrusive dialog --- addon/dialog/dialog.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/addon/dialog/dialog.js b/addon/dialog/dialog.js index 71e2287447..14ab724849 100644 --- a/addon/dialog/dialog.js +++ b/addon/dialog/dialog.js @@ -77,4 +77,39 @@ CodeMirror.on(b, "focus", function() { ++blurring; }); } }); + + /* + * openNotification + * Opens a notification, that can be closed with an optional timer + * (default 5000ms timer) and always closes on click. + * + * If a notification is opened while another is opened, it will close the + * currently opened one and open the new one immediately. + */ + var currentNotificationClose; + CodeMirror.defineExtension("openNotification", function(template, callback, options) { + var dialog = dialogDiv(this, template, options && options.bottom); + var duration = options && (options.duration === undefined ? 5000 : options.duration); + var closed = false, me = this, doneTimer; + + function close() { + if (closed) return; + closed = true; + clearTimeout(doneTimer); + doneTimer = null; + if (callback) callback(me); + dialog.parentNode.removeChild(dialog); + } + + if (currentNotificationClose) currentNotificationClose(); + currentNotificationClose = close; + + CodeMirror.on(dialog, 'click', function(e) { + CodeMirror.e_preventDefault(e); + close(); + }); + if (duration) { + doneTimer = setTimeout(close, options.duration); + } + }); })(); From 598648f13032852b285cec6509e3c7930e15d437 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Nov 2013 08:46:21 +0100 Subject: [PATCH 45/81] [dialog addon] Slight modifications to openNotification Remove callback argument, save currently open dialog in per-editor state. --- addon/dialog/dialog.js | 22 ++++++++++++---------- doc/manual.html | 13 ++++++++----- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/addon/dialog/dialog.js b/addon/dialog/dialog.js index 14ab724849..ced394d3fc 100644 --- a/addon/dialog/dialog.js +++ b/addon/dialog/dialog.js @@ -14,7 +14,14 @@ return dialog; } + function closeNotification(cm, newVal) { + if (cm.state.currentNotificationClose) + cm.state.currentNotificationClose(); + cm.state.currentNotificationClose = newVal; + } + CodeMirror.defineExtension("openDialog", function(template, callback, options) { + closeNotification(this, null); var dialog = dialogDiv(this, template, options && options.bottom); var closed = false, me = this; function close() { @@ -51,6 +58,7 @@ }); CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) { + closeNotification(this, null); var dialog = dialogDiv(this, template, options && options.bottom); var buttons = dialog.getElementsByTagName("button"); var closed = false, me = this, blurring = 1; @@ -86,30 +94,24 @@ * If a notification is opened while another is opened, it will close the * currently opened one and open the new one immediately. */ - var currentNotificationClose; - CodeMirror.defineExtension("openNotification", function(template, callback, options) { + CodeMirror.defineExtension("openNotification", function(template, options) { + closeNotification(this, close); var dialog = dialogDiv(this, template, options && options.bottom); var duration = options && (options.duration === undefined ? 5000 : options.duration); - var closed = false, me = this, doneTimer; + var closed = false, doneTimer; function close() { if (closed) return; closed = true; clearTimeout(doneTimer); - doneTimer = null; - if (callback) callback(me); dialog.parentNode.removeChild(dialog); } - if (currentNotificationClose) currentNotificationClose(); - currentNotificationClose = close; - CodeMirror.on(dialog, 'click', function(e) { CodeMirror.e_preventDefault(e); close(); }); - if (duration) { + if (duration) doneTimer = setTimeout(close, options.duration); - } }); })(); diff --git a/doc/manual.html b/doc/manual.html index d79265fd6b..80de6d950f 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1708,11 +1708,14 @@

    Static properties

    dialog/dialog.js
    Provides a very simple way to query users for text input. - Adds an openDialog method to CodeMirror instances, - which can be called with an HTML fragment that provides the - prompt (should include an input tag), and a - callback function that is called when text has been entered. - Depends on addon/dialog/dialog.css.
    + Adds an openDialog method to + CodeMirror instances, which can be called with an HTML fragment + that provides the prompt (should include an input + tag), and a callback function that is called when text has been + entered. Also adds + an openNotification function that + simply shows an HTML fragment as a notification. Depends + on addon/dialog/dialog.css.
    search/searchcursor.js
    Adds the getSearchCursor(query, start, caseFold) → From 11c50cb69b406794eac7421b2997407a8d17528f Mon Sep 17 00:00:00 2001 From: Andy Joslin Date: Thu, 7 Nov 2013 13:49:19 -0500 Subject: [PATCH 46/81] [vim mode] use openNotification instead of openConfirm for errors --- keymap/vim.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index e67a46ed7f..dab10e21a4 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2726,10 +2726,9 @@ return regexp; } function showConfirm(cm, text) { - if (cm.openConfirm) { - cm.openConfirm('' + text + - ' ', function() {}, - {bottom: true}); + if (cm.openNotification) { + cm.openNotification('' + text + '', + {bottom: true, duration: 5000}); } else { alert(text); } From 74a3f2261d8f8646a282e089cf8d8c777e498274 Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Thu, 7 Nov 2013 17:13:09 -0500 Subject: [PATCH 47/81] [markdown mode] `\n* ` should not toggle em state. Closes #1920. --- mode/markdown/markdown.js | 7 ++++++- mode/markdown/test.js | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index bf1750d5b6..0d60b3db8f 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -257,6 +257,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.taskOpen = false; state.taskClosed = false; + // Get sol() value now, before character is consumed + var sol = stream.sol(); + var ch = stream.next(); if (ch === '\\') { @@ -355,7 +358,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } var t = getType(state); if (ch === '*' || (ch === '_' && !ignoreUnderscore)) { - if (state.strong === ch && stream.eat(ch)) { // Remove STRONG + if (sol && stream.peek() === ' ') { + // Do nothing, surrounded by newline and space + } else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG state.strong = false; return t; } else if (!state.strong && stream.eat(ch)) { // Add STRONG diff --git a/mode/markdown/test.js b/mode/markdown/test.js index f167917289..081be96be1 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -577,6 +577,10 @@ MT("emEscapedBySpaceOut", "foo _ bar[em _hello_]world"); + MT("emEscapedByNewline", + "foo", + "_ bar[em _hello_]world"); + // Unclosed emphasis characters // Instead of simply marking as EM / STRONG, it would be nice to have an // incomplete flag for EM and STRONG, that is styled slightly different. From a7120a79dc85e7caccc639e9192a63a6c209308f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Nov 2013 08:55:07 +0100 Subject: [PATCH 48/81] [real-world uses] Add MVC Playground --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 4e0896c377..6e23106793 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -88,6 +88,7 @@
  • Mergely (interactive diffing)
  • MIHTool (iOS web-app debugging tool)
  • Mongo MapReduce WebBrowser
  • +
  • MVC Playground
  • My2ndGeneration (social coding)
  • Navigate CMS
  • nodeMirror (IDE project)
  • From 8f491df2a175a942c4d3b51781998bb1ad868054 Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Sat, 9 Nov 2013 05:03:52 -0500 Subject: [PATCH 49/81] [clike demo] Fix duplicate variable names for C and C++ editors The C editor and the C++ editor have the same variable name, so the latter shadows the former. Fixed by renaming both. --- mode/clike/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/clike/index.html b/mode/clike/index.html index 45add4910b..93bd718a0a 100644 --- a/mode/clike/index.html +++ b/mode/clike/index.html @@ -165,12 +165,12 @@
    Provides a very simple way to query users for text input. Adds an openDialog method to CodeMirror instances, which can be called with an HTML fragment - that provides the prompt (should include an input - tag), and a callback function that is called when text has been - entered. Also adds + or a detached DOM node that provides the prompt (should include + an input tag), and a callback function that is called + when text has been entered. Also adds an openNotification function that simply shows an HTML fragment as a notification. Depends on addon/dialog/dialog.css.
    From bd374efc143ccb4515d001a647ba89d2fdd11201 Mon Sep 17 00:00:00 2001 From: Alberto Pose Date: Mon, 18 Nov 2013 18:05:13 -0300 Subject: [PATCH 72/81] [foldgutter addon] Add options to customize change/update time spans --- addon/fold/foldgutter.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addon/fold/foldgutter.js b/addon/fold/foldgutter.js index e3c52bc229..57336fbff8 100644 --- a/addon/fold/foldgutter.js +++ b/addon/fold/foldgutter.js @@ -88,14 +88,14 @@ } function onChange(cm) { - var state = cm.state.foldGutter; + var state = cm.state.foldGutter, opts = cm.state.foldGutter.options; state.from = state.to = 0; clearTimeout(state.changeUpdate); - state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, 600); + state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600); } function onViewportChange(cm) { - var state = cm.state.foldGutter; + var state = cm.state.foldGutter, opts = cm.state.foldGutter.options; clearTimeout(state.changeUpdate); state.changeUpdate = setTimeout(function() { var vp = cm.getViewport(); @@ -113,7 +113,7 @@ } }); } - }, 400); + }, opts.updateViewportTimeSpan || 400); } function onFold(cm, from) { From f0610e60c3b220814d80c133326adebc7339a35f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 19 Nov 2013 18:33:06 +0100 Subject: [PATCH 73/81] Add specialChars and specialCharPlaceholder options Issue #649 --- doc/manual.html | 13 +++++++++++++ lib/codemirror.js | 22 ++++++++++++++++------ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 8100bb82a7..a0c650e170 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -208,6 +208,19 @@ indentation (only works if the mode supports indentation). Default is true. +
    specialChars: RegExp
    +
    A regular expression used to determine which characters + should be replaced by a + special placeholder. + Mostly useful for non-printing special characters. The default + is /[\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/.
    +
    specialCharPlaceholder: function(char) → Element
    +
    A function that, given a special character identified by + the specialChars + option, produces a DOM node that is used to represent the + character. By default, a red dot () + is shown, with a title tooltip to indicate the character code.
    +
    rtlMoveVisually: boolean
    Determines whether horizontal cursor movement through right-to-left (Arabic, Hebrew) text is visual (pressing the left diff --git a/lib/codemirror.js b/lib/codemirror.js index 78939b5599..8d4fbcaa26 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3281,6 +3281,11 @@ window.CodeMirror = (function() { clearCaches(cm); regChange(cm); }, true); + option("specialChars", /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/, function(cm, val) { + cm.options.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); + cm.refresh(); + }, true); + option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true); option("electricChars", true); option("rtlMoveVisually", !windows); @@ -4426,17 +4431,23 @@ window.CodeMirror = (function() { return builder; } - var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g; + function defaultSpecialCharPlaceholder(ch) { + var token = elt("span", "\u2022", "cm-invalidchar"); + token.title = "\\u" + ch.toString(16); + return token; + } + function buildToken(builder, text, style, startStyle, endStyle, title) { if (!text) return; - if (!tokenSpecialChars.test(text)) { + var special = builder.cm.options.specialChars; + if (!special.test(text)) { builder.col += text.length; var content = document.createTextNode(text); } else { var content = document.createDocumentFragment(), pos = 0; while (true) { - tokenSpecialChars.lastIndex = pos; - var m = tokenSpecialChars.exec(text); + special.lastIndex = pos; + var m = special.exec(text); var skipped = m ? m.index - pos : text.length - pos; if (skipped) { content.appendChild(document.createTextNode(text.slice(pos, pos + skipped))); @@ -4449,8 +4460,7 @@ window.CodeMirror = (function() { content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); builder.col += tabWidth; } else { - var token = elt("span", "\u2022", "cm-invalidchar"); - token.title = "\\u" + m[0].charCodeAt(0).toString(16); + var token = builder.cm.options.specialCharPlaceholder(m[0].charCodeAt(0)); content.appendChild(token); builder.col += 1; } From 3853222ea46bff376fca7a965d6be178ccc568fa Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 19 Nov 2013 18:46:41 +0100 Subject: [PATCH 74/81] Fix two bugs in f0610e60c3b220 Issue #649 --- lib/codemirror.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 8d4fbcaa26..73782aa4fd 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3281,7 +3281,7 @@ window.CodeMirror = (function() { clearCaches(cm); regChange(cm); }, true); - option("specialChars", /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/, function(cm, val) { + option("specialChars", /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/g, function(cm, val) { cm.options.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); cm.refresh(); }, true); @@ -4433,7 +4433,7 @@ window.CodeMirror = (function() { function defaultSpecialCharPlaceholder(ch) { var token = elt("span", "\u2022", "cm-invalidchar"); - token.title = "\\u" + ch.toString(16); + token.title = "\\u" + ch.charCodeAt(0).toString(16); return token; } @@ -4460,7 +4460,7 @@ window.CodeMirror = (function() { content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); builder.col += tabWidth; } else { - var token = builder.cm.options.specialCharPlaceholder(m[0].charCodeAt(0)); + var token = builder.cm.options.specialCharPlaceholder(m[0]); content.appendChild(token); builder.col += 1; } From e446407ac121532a21ef7b129b32365532529404 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 19 Nov 2013 18:56:51 +0100 Subject: [PATCH 75/81] Run mode over the whole line in long lines when in background-processing mode Issue #1908 --- lib/codemirror.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 73782aa4fd..1dff8d4c35 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -910,7 +910,7 @@ window.CodeMirror = (function() { doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.showingTo + 500), function(line) { if (doc.frontier >= cm.display.showingFrom) { // Visible var oldStyles = line.styles; - line.styles = highlightLine(cm, line, state); + line.styles = highlightLine(cm, line, state, true); var ischange = !oldStyles || oldStyles.length != line.styles.length; for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; if (ischange) { @@ -919,7 +919,7 @@ window.CodeMirror = (function() { } line.stateAfter = copyState(doc.mode, state); } else { - processLine(cm, line, state); + processLine(cm, line.text, state); line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; } ++doc.frontier; @@ -963,7 +963,7 @@ window.CodeMirror = (function() { if (!state) state = startState(doc.mode); else state = copyState(doc.mode, state); doc.iter(pos, n, function(line) { - processLine(cm, line, state); + processLine(cm, line.text, state); var save = pos == n - 1 || pos % 5 == 0 || pos >= display.showingFrom && pos < display.showingTo; line.stateAfter = save ? copyState(doc.mode, state) : null; ++pos; @@ -4281,7 +4281,7 @@ window.CodeMirror = (function() { // Run the given mode's parser over a line, update the styles // array, which contains alternating fragments of text and CSS // classes. - function runMode(cm, text, mode, state, f) { + function runMode(cm, text, mode, state, f, forceToEnd) { var flattenSpans = mode.flattenSpans; if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; var curStart = 0, curStyle = null; @@ -4290,6 +4290,7 @@ window.CodeMirror = (function() { while (!stream.eol()) { if (stream.pos > cm.options.maxHighlightLength) { flattenSpans = false; + if (forceToEnd) processLine(cm, text, state, stream.pos); stream.pos = text.length; style = null; } else { @@ -4309,12 +4310,14 @@ window.CodeMirror = (function() { } } - function highlightLine(cm, line, state) { + function highlightLine(cm, line, state, forceToEnd) { // A styles array always starts with a number identifying the // mode/overlays that it is based on (for easy invalidation). var st = [cm.state.modeGen]; // Compute the base array of styles - runMode(cm, line.text, cm.doc.mode, state, function(end, style) {st.push(end, style);}); + runMode(cm, line.text, cm.doc.mode, state, function(end, style) { + st.push(end, style); + }, forceToEnd); // Run overlays, adjust style array. for (var o = 0; o < cm.state.overlays.length; ++o) { @@ -4353,10 +4356,11 @@ window.CodeMirror = (function() { // Lightweight form of highlight -- proceed over this line and // update state, but don't save a style array. - function processLine(cm, line, state) { + function processLine(cm, text, state, startAt) { var mode = cm.doc.mode; - var stream = new StringStream(line.text, cm.options.tabSize); - if (line.text == "" && mode.blankLine) mode.blankLine(state); + var stream = new StringStream(text, cm.options.tabSize); + stream.start = stream.pos = startAt || 0; + if (text == "" && mode.blankLine) mode.blankLine(state); while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { mode.token(stream, state); stream.start = stream.pos; From 53cce13c9e67985851efb2ff96a9388204ed25e5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Nov 2013 12:27:01 +0100 Subject: [PATCH 76/81] Fix completely botched IE11+ check --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 1dff8d4c35..1493b1a524 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -13,7 +13,7 @@ window.CodeMirror = (function() { var ie = /MSIE \d/.test(navigator.userAgent); var ie_lt8 = ie && (document.documentMode == null || document.documentMode < 8); var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); - var ie_gt10 = /Trident\/([7-9]|\d{2,})\./; + var ie_gt10 = /Trident\/([7-9]|\d{2,})\./.test(navigator.userAgent); var webkit = /WebKit\//.test(navigator.userAgent); var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); var chrome = /Chrome\//.test(navigator.userAgent); From 31a77ad4c8f2f28d153c9abf60a979784568a2dc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Nov 2013 12:34:32 +0100 Subject: [PATCH 77/81] Export lineNo utility Issue #1969 --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 1493b1a524..b91baacc27 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -5088,7 +5088,7 @@ window.CodeMirror = (function() { for (var n = line; n; n = n.parent) n.height += diff; } - function lineNo(line) { + var lineNo = CodeMirror.lineNo = function(line) { if (line.parent == null) return null; var cur = line.parent, no = indexOf(cur.lines, line); for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { @@ -5098,7 +5098,7 @@ window.CodeMirror = (function() { } } return no + cur.first; - } + }; function lineAtHeight(chunk, h) { var n = chunk.first; From 2546a4a4775b496911d993a8b9c767b410662132 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Nov 2013 12:36:21 +0100 Subject: [PATCH 78/81] Make lineNo a method after all Issue #1969 --- lib/codemirror.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index b91baacc27..fb2e0c5604 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4261,6 +4261,7 @@ window.CodeMirror = (function() { this.height = estimateHeight ? estimateHeight(this) : 1; }; eventMixin(Line); + Line.prototype.lineNo = function() { return lineNo(this); }; function updateLine(line, text, markedSpans, estimateHeight) { line.text = text; @@ -5088,7 +5089,7 @@ window.CodeMirror = (function() { for (var n = line; n; n = n.parent) n.height += diff; } - var lineNo = CodeMirror.lineNo = function(line) { + function lineNo(line) { if (line.parent == null) return null; var cur = line.parent, no = indexOf(cur.lines, line); for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { @@ -5098,7 +5099,7 @@ window.CodeMirror = (function() { } } return no + cur.first; - }; + } function lineAtHeight(chunk, h) { var n = chunk.first; From d07ec7eee25e557d1109b90e82c6d09a8204127e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Nov 2013 12:52:39 +0100 Subject: [PATCH 79/81] Add (undocumented) wholeLineUpdateBefore option Issue #1972 Issue #1967 --- lib/codemirror.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index fb2e0c5604..0343a176bf 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3288,6 +3288,7 @@ window.CodeMirror = (function() { option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true); option("electricChars", true); option("rtlMoveVisually", !windows); + option("wholeLineUpdateBefore", true); option("theme", "default", function(cm) { themeChanged(cm); @@ -4618,7 +4619,8 @@ window.CodeMirror = (function() { var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; // First adjust the line structure - if (from.ch == 0 && to.ch == 0 && lastText == "") { + if (from.ch == 0 && to.ch == 0 && lastText == "" && + (!doc.cm || doc.cm.options.wholeLineUpdateBefore)) { // This is a whole-line replace. Treated specially to make // sure line objects move the way they are supposed to. for (var i = 0, e = text.length - 1, added = []; i < e; ++i) From 9aa224094e26b8f9badd3a9877373a9c2ea86992 Mon Sep 17 00:00:00 2001 From: Luciano Longo Date: Wed, 20 Nov 2013 17:17:28 -0300 Subject: [PATCH 80/81] [placeholder addon] Don't hide placeholder text on focus Most modern browsers now keep displaying the placeholder even if the user has focus on the input and only hide it when the input has content. This change is to make this addon consistent with this, so users won't tell the difference with native inputs' placeholder behaviour. --- addon/display/placeholder.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/addon/display/placeholder.js b/addon/display/placeholder.js index 18f9dff3ab..748afe7275 100644 --- a/addon/display/placeholder.js +++ b/addon/display/placeholder.js @@ -2,12 +2,10 @@ CodeMirror.defineOption("placeholder", "", function(cm, val, old) { var prev = old && old != CodeMirror.Init; if (val && !prev) { - cm.on("focus", onFocus); cm.on("blur", onBlur); cm.on("change", onChange); onChange(cm); } else if (!val && prev) { - cm.off("focus", onFocus); cm.off("blur", onBlur); cm.off("change", onChange); clearPlaceholder(cm); @@ -33,9 +31,6 @@ cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild); } - function onFocus(cm) { - clearPlaceholder(cm); - } function onBlur(cm) { if (isEmpty(cm)) setPlaceholder(cm); } @@ -43,7 +38,6 @@ var wrapper = cm.getWrapperElement(), empty = isEmpty(cm); wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : ""); - if (cm.hasFocus()) return; if (empty) setPlaceholder(cm); else clearPlaceholder(cm); } From 0e58d2cf24d613805ee8b5fa41811a985515e924 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Nov 2013 13:34:46 +0100 Subject: [PATCH 81/81] Mark release 3.20 --- doc/compress.html | 1 + doc/releases.html | 11 +++++++++++ index.html | 2 +- lib/codemirror.js | 2 +- package.json | 2 +- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index f49c978b2e..3f3bfb0465 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -33,6 +33,7 @@

    Version: