From 3d89b71b955b72e61430f7f38e2350489cad9e15 Mon Sep 17 00:00:00 2001 From: Remi Nyborg Date: Tue, 13 Sep 2016 09:59:39 +0200 Subject: [PATCH 0001/1880] Add passing the FocusEvent to blur and focus --- doc/manual.html | 4 ++-- lib/codemirror.js | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index d7c15f653d..4d20f50f2e 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -626,10 +626,10 @@

Events

You can preventDefault the event, to signal that CodeMirror should do no further handling. -
"focus" (instance: CodeMirror)
+
"focus" (instance: CodeMirror, event: Event)
Fires whenever the editor is focused.
-
"blur" (instance: CodeMirror)
+
"blur" (instance: CodeMirror, event: Event)
Fires whenever the editor is unfocused.
"scroll" (instance: CodeMirror)
diff --git a/lib/codemirror.js b/lib/codemirror.js index 6e0b69c610..a44bf0e531 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3533,8 +3533,8 @@ on(inp, "keyup", function(e) { onKeyUp.call(cm, e); }); on(inp, "keydown", operation(cm, onKeyDown)); on(inp, "keypress", operation(cm, onKeyPress)); - on(inp, "focus", bind(onFocus, cm)); - on(inp, "blur", bind(onBlur, cm)); + on(inp, "focus", function (e) { onFocus(cm, e); }); + on(inp, "blur", function (e) { onBlur(cm, e); }); } function dragDropChanged(cm, value, old) { @@ -4262,12 +4262,12 @@ }, 100); } - function onFocus(cm) { + function onFocus(cm, e) { if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false; if (cm.options.readOnly == "nocursor") return; if (!cm.state.focused) { - signal(cm, "focus", cm); + signal(cm, "focus", cm, e); cm.state.focused = true; addClass(cm.display.wrapper, "CodeMirror-focused"); // This test prevents this from firing when a context @@ -4281,11 +4281,11 @@ } restartBlink(cm); } - function onBlur(cm) { + function onBlur(cm, e) { if (cm.state.delayingBlurEvent) return; if (cm.state.focused) { - signal(cm, "blur", cm); + signal(cm, "blur", cm, e); cm.state.focused = false; rmClass(cm.display.wrapper, "CodeMirror-focused"); } From 7db967f97565335c6e028b6f72617cac84316170 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 15 Sep 2016 15:58:58 +0200 Subject: [PATCH 0002/1880] [xml-fold addon] Clip iterator range to editor range Closes #4018 --- addon/fold/xml-fold.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/fold/xml-fold.js b/addon/fold/xml-fold.js index f8c67b8976..75a9e305bd 100644 --- a/addon/fold/xml-fold.js +++ b/addon/fold/xml-fold.js @@ -21,8 +21,8 @@ function Iter(cm, line, ch, range) { this.line = line; this.ch = ch; this.cm = cm; this.text = cm.getLine(line); - this.min = range ? range.from : cm.firstLine(); - this.max = range ? range.to - 1 : cm.lastLine(); + this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine(); + this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine(); } function tagAt(iter, ch) { From 02d4ab46ce9d0b5acadbd6b3c3d39bfaf5e76815 Mon Sep 17 00:00:00 2001 From: Siamak Mokhtari Date: Fri, 16 Sep 2016 20:46:46 +0430 Subject: [PATCH 0003/1880] [panda-syntax theme] Adjust colors --- theme/panda-syntax.css | 92 +++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 50 deletions(-) diff --git a/theme/panda-syntax.css b/theme/panda-syntax.css index 5d47fe5063..8c0c754082 100644 --- a/theme/panda-syntax.css +++ b/theme/panda-syntax.css @@ -1,93 +1,85 @@ /* - Name: Panda Syntax Author: Siamak Mokhtari (http://github.com/siamak/) - CodeMirror template by Siamak Mokhtari (https://github.com/siamak/atom-panda-syntax) - */ .cm-s-panda-syntax { - /*font-family: 'Operator Mono', 'Source Sans Pro', Helvetica, Arial, sans-serif;*/ - font-family: 'Operator Mono', 'Source Sans Pro', Menlo, Monaco, Consolas, Courier New, monospace; background: #292A2B; color: #E6E6E6; + line-height: 1.5; + font-family: 'Operator Mono', 'Source Sans Pro', Menlo, Monaco, Consolas, Courier New, monospace; } +.cm-s-panda-syntax .CodeMirror-cursor { border-color: #ff2c6d; } .cm-s-panda-syntax .CodeMirror-activeline-background { - background: #404954; + background: rgba(99, 123, 156, 0.1); +} +.cm-s-panda-syntax .CodeMirror-selected { + background: #FFF; } - .cm-s-panda-syntax .cm-comment { font-style: italic; color: #676B79; } -.cm-s-panda-syntax .cm-string, -.cm-s-panda-syntax .cm-string-2 { +.cm-s-panda-syntax .cm-operator { + color: #f3f3f3; +} +.cm-s-panda-syntax .cm-string { color: #19F9D8; } +.cm-s-panda-syntax .cm-string-2 { + color: #FFB86C; +} + +.cm-s-panda-syntax .cm-tag { + color: #ff2c6d; +} +.cm-s-panda-syntax .cm-meta { + color: #b084eb; +} + .cm-s-panda-syntax .cm-number { color: #FFB86C; } .cm-s-panda-syntax .cm-atom { - color: #FFB86C; + color: #ff2c6d; } - .cm-s-panda-syntax .cm-keyword { color: #FF75B5; } -.cm-s-panda-syntax .cm-keyword-2 { - color: #FF75B5; -} -.cm-s-panda-syntax .cm-keyword-3 { - color: #B084EB; -} - .cm-s-panda-syntax .cm-variable { - color: #FF9AC1; + color: #ffb86c; } .cm-s-panda-syntax .cm-variable-2 { - color: #e6e6e6; + color: #ff9ac1; } .cm-s-panda-syntax .cm-variable-3 { - color: #82B1FF; + color: #ff9ac1; } .cm-s-panda-syntax .cm-def { - /*font-style: italic;*/ color: #e6e6e6; } -.cm-s-panda-syntax .cm-def-2 { - font-style: italic; - color: #ffcc95; -} - - .cm-s-panda-syntax .cm-property { - color: #6FC1FF; + color: #f3f3f3; } - -.cm-s-panda-syntax .CodeMirror-matchingbracket { - color: #E6E6E6 !important; - border-bottom: 1px dotted #19f9d8; - padding-bottom: 2px; +.cm-s-panda-syntax .cm-unit { + color: #ffb86c; } -.cm-s-panda-syntax .CodeMirror-gutters { - background: #292A2B; - color: #757575; - border: none; +.cm-s-panda-syntax .cm-attribute { + color: #ffb86c; } -.cm-s-panda-syntax .CodeMirror-guttermarker, .cm-s-panda-syntax .CodeMirror-guttermarker-subtle, .cm-s-panda-syntax .CodeMirror-linenumber { - color: #757575; + +.cm-s-panda-syntax .CodeMirror-matchingbracket { + border-bottom: 1px dotted #19F9D8; + padding-bottom: 2px; + color: #e6e6e6; } -.cm-s-panda-syntax .CodeMirror-linenumber { - padding-right: 10px; +.CodeMirror-gutters { + background: #292a2b; + border-right-color: rgba(255, 255, 255, 0.1); } -.cm-s-panda-syntax .CodeMirror-cursor { - border-left: 1px solid #757575; +.CodeMirror-linenumber { + color: #e6e6e6; + opacity: 0.6; } -/*.cm-s-panda-syntax div.CodeMirror-selected { background: rgba(255, 255, 255, 0.5); }*/ -.cm-s-panda-syntax.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.25); } -.cm-s-panda-syntax .CodeMirror-line::selection, .cm-s-panda-syntax .CodeMirror-line > span::selection, .cm-s-panda-syntax .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); } -.cm-s-panda-syntax .CodeMirror-line::-moz-selection, .cm-s-panda-syntax .CodeMirror-line > span::-moz-selection, .cm-s-panda-syntax .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); } - -.cm-s-panda-syntax .CodeMirror-activeline-background { background: rgba(99, 123, 156, 0.125); } From 953a5dca4e2e8ffa251069bd46a8da29ab977f74 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 19 Sep 2016 21:09:51 +0200 Subject: [PATCH 0004/1880] [erlang mode] Fix problem with dereferencing empty context array Closes #4244 --- mode/erlang/erlang.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mode/erlang/erlang.js b/mode/erlang/erlang.js index 5aed76a526..9528e19f93 100644 --- a/mode/erlang/erlang.js +++ b/mode/erlang/erlang.js @@ -433,15 +433,16 @@ CodeMirror.defineMode("erlang", function(cmCfg) { } function maybe_drop_post(s) { + if (!s.length) return s var last = s.length-1; if (s[last].type === "dot") { return []; } - if (s[last].type === "fun" && s[last-1].token === "fun") { + if (last > 1 && s[last].type === "fun" && s[last-1].token === "fun") { return s.slice(0,last-1); } - switch (s[s.length-1].token) { + switch (s[last].token) { case "}": return d(s,{g:["{"]}); case "]": return d(s,{i:["["]}); case ")": return d(s,{i:["("]}); From e865bdef6ce087db02686267d57c34478da8621b Mon Sep 17 00:00:00 2001 From: Pontus Melke Date: Wed, 24 Aug 2016 14:41:27 +0200 Subject: [PATCH 0005/1880] [cypher mode] Added CALL and YIELD as keywords --- mode/cypher/cypher.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/cypher/cypher.js b/mode/cypher/cypher.js index 107e4f6d21..f99abe2385 100644 --- a/mode/cypher/cypher.js +++ b/mode/cypher/cypher.js @@ -62,7 +62,7 @@ var curPunc; var funcs = wordRegexp(["abs", "acos", "allShortestPaths", "asin", "atan", "atan2", "avg", "ceil", "coalesce", "collect", "cos", "cot", "count", "degrees", "e", "endnode", "exp", "extract", "filter", "floor", "haversin", "head", "id", "keys", "labels", "last", "left", "length", "log", "log10", "lower", "ltrim", "max", "min", "node", "nodes", "percentileCont", "percentileDisc", "pi", "radians", "rand", "range", "reduce", "rel", "relationship", "relationships", "replace", "reverse", "right", "round", "rtrim", "shortestPath", "sign", "sin", "size", "split", "sqrt", "startnode", "stdev", "stdevp", "str", "substring", "sum", "tail", "tan", "timestamp", "toFloat", "toInt", "toString", "trim", "type", "upper"]); var preds = wordRegexp(["all", "and", "any", "contains", "exists", "has", "in", "none", "not", "or", "single", "xor"]); - var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "detach", "distinct", "drop", "else", "end", "ends", "explain", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "join", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "profile", "remove", "return", "scan", "set", "skip", "start", "starts", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with"]); + var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "detach", "distinct", "drop", "else", "end", "ends", "explain", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "join", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "profile", "remove", "return", "scan", "set", "skip", "start", "starts", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with", "call", "yield"]); var operatorChars = /[*+\-<>=&|~%^]/; return { From 45f97d2f83f766108b13f52594b74071b11698f7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Sep 2016 10:47:45 +0200 Subject: [PATCH 0006/1880] [comment addon] Use first closing token when uncommenting And don't block-comment inside a block comment Closes #4208 --- addon/comment/comment.js | 11 +++++++---- test/comment_test.js | 9 +++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/addon/comment/comment.js b/addon/comment/comment.js index 2f2f071df9..d71cf43603 100644 --- a/addon/comment/comment.js +++ b/addon/comment/comment.js @@ -103,6 +103,7 @@ self.lineComment(from, to, options); return; } + if (/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line, 0)))) return var end = Math.min(to.line, self.lastLine()); if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end; @@ -162,13 +163,15 @@ var endString = options.blockCommentEnd || mode.blockCommentEnd; if (!startString || !endString) return false; var lead = options.blockCommentLead || mode.blockCommentLead; - var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end); - var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString); + var startLine = self.getLine(start), open = startLine.indexOf(startString) + if (open == -1) return false + var endLine = end == start ? startLine : self.getLine(end) + var close = endLine.indexOf(endString, end == start ? open + startString.length : 0); if (close == -1 && start != end) { endLine = self.getLine(--end); - close = endLine.lastIndexOf(endString); + close = endLine.indexOf(endString); } - if (open == -1 || close == -1 || + if (close == -1 || !/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) || !/comment/.test(self.getTokenTypeAt(Pos(end, close + 1)))) return false; diff --git a/test/comment_test.js b/test/comment_test.js index 3e6a86bbf2..c6b9fe8109 100644 --- a/test/comment_test.js +++ b/test/comment_test.js @@ -102,4 +102,13 @@ namespace = "comment_"; cm.execCommand("selectAll") cm.execCommand("toggleComment") }, "// foo\n// bar\nbaz", "// // foo\n// // bar\n// baz") + + test("uncommentWithTrailingBlockEnd", "xml", function(cm) { + cm.execCommand("toggleComment") + }, " -->", "foo -->") + + test("dontCommentInComment", "xml", function(cm) { + cm.setCursor(1, 0) + cm.execCommand("toggleComment") + }, "", "") })(); From 653f64cc744cf2b1e5658cc818d4d3ff52417d47 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Sep 2016 10:51:06 +0200 Subject: [PATCH 0007/1880] [javascript mode] Recognize TypeScript-style optional arguments Closes #4212 --- mode/javascript/javascript.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 15ffe03e67..c27b01f7a6 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -521,8 +521,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "}") return cont(); return pass(statement, block); } - function maybetype(type) { - if (isTS && type == ":") return cont(typeexpr); + function maybetype(type, value) { + if (isTS) { + if (type == ":") return cont(typeexpr); + if (value == "?") return cont(maybetype); + } } function maybedefault(_, value) { if (value == "=") return cont(expressionNoComma); From 88c54d1d8daf2cba70d49c06b9e142ab2917a067 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Sep 2016 11:03:34 +0200 Subject: [PATCH 0008/1880] Remove debug statement --- test/mode_test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/mode_test.js b/test/mode_test.js index f706c4f5c6..0aed50f7dc 100644 --- a/test/mode_test.js +++ b/test/mode_test.js @@ -61,7 +61,6 @@ test.mode = function(name, mode, tokens, modeName) { var data = parseTokens(tokens); - if (name == "extend_type") console.log("set", (modeName || mode.name) + "_" + name) return test((modeName || mode.name) + "_" + name, function() { return compare(data.plain, data.tokens, mode); }); From 14c8a436efa943060682c1b9845c63bbcee491cf Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Sep 2016 11:23:10 +0200 Subject: [PATCH 0009/1880] [javascript mode] Improve indentation with missing semicolons Closes #4214 --- mode/javascript/javascript.js | 18 +++++++++++++----- mode/javascript/test.js | 13 +++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index c27b01f7a6..e23560746d 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -344,19 +344,19 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function statement(type, value) { if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex); - if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex); + if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex); if (type == "keyword b") return cont(pushlex("form"), statement, poplex); if (type == "{") return cont(pushlex("}"), block, poplex); if (type == ";") return cont(); if (type == "if") { if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex) cx.state.cc.pop()(); - return cont(pushlex("form"), expression, statement, poplex, maybeelse); + return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse); } if (type == "function") return cont(functiondef); if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); if (type == "variable") return cont(pushlex("stat"), maybelabel); - if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), + if (type == "switch") return cont(pushlex("form"), parenExpr, pushlex("}", "switch"), expect("{"), block, poplex, poplex); if (type == "case") return cont(expression, expect(":")); if (type == "default") return cont(expect(":")); @@ -376,6 +376,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function expressionNoComma(type) { return expressionInner(type, true); } + function parenExpr(type) { + if (type != "(") return pass() + return cont(pushlex(")"), expression, expect(")"), poplex) + } function expressionInner(type, noComma) { if (cx.state.fatArrowAt == cx.stream.start) { var body = noComma ? arrowBodyNoComma : arrowBody; @@ -709,14 +713,18 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { indent: function(state, textAfter) { if (state.tokenize == tokenComment) return CodeMirror.Pass; if (state.tokenize != tokenBase) return 0; - var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; + var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top // Kludge to prevent 'maybelse' from blocking lexical scope pops if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) { var c = state.cc[i]; if (c == poplex) lexical = lexical.prev; else if (c != maybeelse) break; } - if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; + while ((lexical.type == "stat" || lexical.type == "form") && + (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) && + (top == maybeoperatorComma || top == maybeoperatorNoComma) && + !/^[,\.=+\-*:?[\(]/.test(textAfter)))) + lexical = lexical.prev; if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") lexical = lexical.prev; var type = lexical.type, closing = firstChar == type; diff --git a/mode/javascript/test.js b/mode/javascript/test.js index 7e88837ed8..91c8b7434a 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -140,6 +140,19 @@ " [number 1];", "[number 2];"); + MT("indent_semicolonless_if", + "[keyword function] [def foo]() {", + " [keyword if] ([variable x])", + " [variable foo]()", + "}") + + MT("indent_semicolonless_if_with_statement", + "[keyword function] [def foo]() {", + " [keyword if] ([variable x])", + " [variable foo]()", + " [variable bar]()", + "}") + MT("multilinestring", "[keyword var] [def x] [operator =] [string 'foo\\]", "[string bar'];"); From e59d75ad99d5499bb78e0a3103ad4ec51a184542 Mon Sep 17 00:00:00 2001 From: Joel Einbinder Date: Wed, 31 Aug 2016 17:17:55 -0700 Subject: [PATCH 0010/1880] Always move in the right direction for PageUp/PageDown --- lib/codemirror.js | 3 ++- test/test.js | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index a44bf0e531..251469c909 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4907,7 +4907,8 @@ var doc = cm.doc, x = pos.left, y; if (unit == "page") { var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); - y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); + var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3); + y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount; } else if (unit == "line") { y = dir > 0 ? pos.bottom + 3 : pos.top - 3; } diff --git a/test/test.js b/test/test.js index 1b3721a647..a7658311e7 100644 --- a/test/test.js +++ b/test/test.js @@ -1336,6 +1336,37 @@ testCM("verticalMovementCommandsWrapping", function(cm) { }, {value: "a very long line that wraps around somehow so that we can test cursor movement\nshortone\nk", lineWrapping: true}); +testCM("verticalMovementCommandsSingleLine", function(cm) { + cm.display.wrapper.style.height = "auto"; + cm.refresh(); + cm.execCommand("goLineUp"); + eqPos(cm.getCursor(), Pos(0, 0)); + cm.execCommand("goLineDown"); + eqPos(cm.getCursor(), Pos(0, 11)); + cm.setCursor(Pos(0, 5)); + cm.execCommand("goLineDown"); + eqPos(cm.getCursor(), Pos(0, 11)); + cm.execCommand("goLineDown"); + eqPos(cm.getCursor(), Pos(0, 11)); + cm.execCommand("goLineUp"); + eqPos(cm.getCursor(), Pos(0, 0)); + cm.execCommand("goLineUp"); + eqPos(cm.getCursor(), Pos(0, 0)); + cm.execCommand("goPageDown"); + eqPos(cm.getCursor(), Pos(0, 11)); + cm.execCommand("goPageDown"); cm.execCommand("goLineDown"); + eqPos(cm.getCursor(), Pos(0, 11)); + cm.execCommand("goPageUp"); + eqPos(cm.getCursor(), Pos(0, 0)); + cm.setCursor(Pos(0, 5)); + cm.execCommand("goPageUp"); + eqPos(cm.getCursor(), Pos(0, 0)); + cm.setCursor(Pos(0, 5)); + cm.execCommand("goPageDown"); + eqPos(cm.getCursor(), Pos(0, 11)); +}, {value: "single line"}); + + testCM("rtlMovement", function(cm) { if (cm.getOption("inputStyle") != "textarea") return; forEach(["خحج", "خحabcخحج", "abخحخحجcd", "abخde", "abخح2342خ1حج", "خ1ح2خح3حxج", @@ -1487,7 +1518,7 @@ testCM("lineWidgetChanged", function(cm) { // Good: // | ------------- display width ------------- | // | ------- widget-width when measured ------ | - // | | -- under-half -- | | -- under-half -- | | + // | | -- under-half -- | | -- under-half -- | | // | | --- over-half --- | | // | | --- over-half --- | | // Height: measured as 3 lines, same as it will be when actually displayed @@ -1504,7 +1535,7 @@ testCM("lineWidgetChanged", function(cm) { // Bad (too wide): // | ------------- display width ------------- | // | -------- widget-width when measured ------- | < -- uh oh - // | | -- under-half -- | | -- under-half -- | | + // | | -- under-half -- | | -- under-half -- | | // | | --- over-half --- | | --- over-half --- | | < -- when measured, combined on one line // Height: measured as 2 lines, less than expected. Will be displayed as 3 lines! From cc817cd9281fcc0e9a69fd8c7f0965313ea014ff Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Sep 2016 12:00:45 +0200 Subject: [PATCH 0011/1880] Lower max token size to 5000 Closes #4233 --- lib/codemirror.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 251469c909..17c3112236 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -6861,7 +6861,7 @@ } if (!flattenSpans || curStyle != style) { while (curStart < stream.start) { - curStart = Math.min(stream.start, curStart + 50000); + curStart = Math.min(stream.start, curStart + 5000); f(curStart, curStyle); } curStyle = style; @@ -6869,8 +6869,10 @@ stream.start = stream.pos; } while (curStart < stream.pos) { - // Webkit seems to refuse to render text nodes longer than 57444 characters - var pos = Math.min(stream.pos, curStart + 50000); + // Webkit seems to refuse to render text nodes longer than 57444 + // characters, and returns inaccurate measurements in nodes + // starting around 5000 chars. + var pos = Math.min(stream.pos, curStart + 5000); f(pos, curStyle); curStart = pos; } From a350d03f15df2892e41b094faa85a08459942845 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Sep 2016 12:26:58 +0200 Subject: [PATCH 0012/1880] Mark release 5.19.0 --- AUTHORS | 3 +++ CHANGELOG.md | 20 ++++++++++++++++++++ doc/compress.html | 1 + doc/manual.html | 2 +- doc/releases.html | 12 ++++++++++++ index.html | 2 +- lib/codemirror.js | 2 +- package.json | 2 +- 8 files changed, 40 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 0f2bc1bbf3..ada8c3f9cf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -405,6 +405,7 @@ Mike Brevoort Mike Diaz Mike Ivanov Mike Kadin +Mike Kobit MinRK Miraculix87 misfo @@ -464,6 +465,7 @@ Philipp A Philip Stadermann Pierre Gerold Piët Delport +Pontus Melke prasanthj Prasanth J Prayag Verma @@ -477,6 +479,7 @@ Randy Edmunds Rasmus Erik Voel Jensen ray ratchup Ray Ratchup +Remi Nyborg Richard Denton Richard van der Meer Richard Z.H. Wang diff --git a/CHANGELOG.md b/CHANGELOG.md index 9470deb79f..f368485cfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,23 @@ +## 5.19.0 (2016-09-20) + +### Bugfixes + +[erlang mode](http://codemirror.net/mode/erlang): Fix mode crash when trying to read an empty context. + +[comment addon](http://codemirror.net/doc/manual.html#addon_comment): Fix broken behavior when toggling comments inside a comment. + +xml-fold addon: Fix a null-dereference bug. + +Page up and page down now do something even in single-line documents. + +Fix an issue where the cursor position could be off in really long (~8000 character) tokens. + +### New features + +[javascript mode](http://codemirror.net/mode/javascript): Better indentation when semicolons are missing. Better support for TypeScript classes, optional parameters, and the `type` keyword. + +The [`blur`](http://codemirror.net/doc/manual.html#event_blur) and [`focus`](http://codemirror.net/doc/manual.html#event_focus) events now pass the DOM event to their handlers. + ## 5.18.2 (2016-08-23) ### Bugfixes diff --git a/doc/compress.html b/doc/compress.html index 7f12f2c430..c013d3b744 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -36,6 +36,7 @@

Script compression helper

Version:

From 562e8eff5b0916d3b63fc59eda9540f8f455c6ed Mon Sep 17 00:00:00 2001 From: Luke Browning Date: Thu, 22 Sep 2016 14:55:40 +0100 Subject: [PATCH 0018/1880] [sql mode] Add exec keyword to mssql --- mode/sql/sql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/sql/sql.js b/mode/sql/sql.js index 01ebd80ae1..e3cbae54cf 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -280,7 +280,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { CodeMirror.defineMIME("text/x-mssql", { name: "sql", client: set("charset clear connect edit ego exit go help nopager notee nowarning pager print prompt quit rehash source status system tee"), - keywords: set(sqlKeywords + "begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered declare"), + keywords: set(sqlKeywords + "begin trigger proc view index for add constraint key primary foreign collate clustered nonclustered declare exec"), builtin: set("bigint numeric bit smallint decimal smallmoney int tinyint money float real char varchar text nchar nvarchar ntext binary varbinary image cursor timestamp hierarchyid uniqueidentifier sql_variant xml table "), atoms: set("false true null unknown"), operatorChars: /^[*+\-%<>!=]/, From e15e2d5e50cce51e940f3a66cb03044dfd935bad Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 24 Sep 2016 15:52:45 +0200 Subject: [PATCH 0019/1880] Ignore keypress events for backspace Closes #4253 --- lib/codemirror.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 3798e5ec6c..ececc94c23 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4246,6 +4246,8 @@ if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return; var ch = String.fromCharCode(charCode == null ? keyCode : charCode); + // Some browsers fire keypress events for backspace + if (ch == "\x08") return; if (handleCharBinding(cm, e, ch)) return; cm.display.input.onKeyPress(e); } From 383c40e468319d0e98e86e7c9a6dcfbe256c8476 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 26 Sep 2016 12:59:43 +0200 Subject: [PATCH 0020/1880] [javascript mode] Fix indentation in TypeScript demo --- mode/javascript/typescript.html | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mode/javascript/typescript.html b/mode/javascript/typescript.html index 2cfc5381fe..1f26d7fe1b 100644 --- a/mode/javascript/typescript.html +++ b/mode/javascript/typescript.html @@ -28,13 +28,13 @@

TypeScript mode

- - - - - diff --git a/doc/manual.html b/doc/manual.html index 8a0e2dcb81..e97ce07e14 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -96,8 +96,7 @@

Basic Usage

The easiest way to use CodeMirror is to simply load the script and style sheet found under lib/ in the distribution, plus a mode script from one of the mode/ directories. - (See the compression helper for an - easy way to combine scripts.) For example:

+ For example:

<script src="lib/codemirror.js"></script>
 <link rel="stylesheet" href="lib/codemirror.css">
diff --git a/index.html b/index.html
index 636639ec08..3423eab209 100644
--- a/index.html
+++ b/index.html
@@ -97,9 +97,9 @@ 

This is CodeMirror

Get the current version: 5.19.0.
- You can see the code or
- read the release notes.
- There is a minification helper. + You can see the code,
+ read the release notes,
+ or study the user manual.
Software needs maintenance,
From 7955eadf723a9b6420fc4c822436bed1d8dd0203 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 26 Sep 2016 16:52:17 +0200 Subject: [PATCH 0027/1880] Add missing import Closes #4258 --- src/edit/mouse_events.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edit/mouse_events.js b/src/edit/mouse_events.js index 08a564bd2c..ebda0c28a9 100644 --- a/src/edit/mouse_events.js +++ b/src/edit/mouse_events.js @@ -5,7 +5,7 @@ import { clipPos, cmp, maxPos, minPos, Pos } from "../line/pos"; import { getLine, lineAtHeight } from "../line/utils_line"; import { posFromMouse } from "../measurement/position_measurement"; import { eventInWidget } from "../measurement/widgets"; -import { normalizeSelection, Range } from "../model/selection"; +import { normalizeSelection, Range, Selection } from "../model/selection"; import { extendRange, extendSelection, replaceOneSelection, setSelection } from "../model/selection_updates"; import { captureRightClick, chromeOS, ie, ie_version, mac, webkit } from "../util/browser"; import { activeElt } from "../util/dom"; From ac205e6783c631cf42a6e4771216d790f1a70e10 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Mon, 26 Sep 2016 09:55:06 +0200 Subject: [PATCH 0028/1880] Remove semicolons --- package.json | 2 +- src/codemirror.js | 4 +- src/display/Display.js | 98 ++-- src/display/focus.js | 48 +- src/display/gutters.js | 30 +- src/display/highlight_worker.js | 60 +-- src/display/line_numbers.js | 50 +- src/display/mode_state.js | 24 +- src/display/operations.js | 180 ++++---- src/display/scroll_events.js | 124 ++--- src/display/scrollbars.js | 178 ++++---- src/display/scrolling.js | 118 ++--- src/display/selection.js | 152 +++---- src/display/update_display.js | 228 +++++----- src/display/update_lines.js | 58 +-- src/display/view_tracking.js | 138 +++--- src/edit/CodeMirror.js | 242 +++++----- src/edit/commands.js | 230 +++++----- src/edit/deleteNearSelection.js | 28 +- src/edit/drop_events.js | 126 ++--- src/edit/fromTextArea.js | 64 +-- src/edit/global_events.js | 44 +- src/edit/key_events.js | 150 +++--- src/edit/legacy.js | 116 ++--- src/edit/main.js | 66 +-- src/edit/methods.js | 582 ++++++++++++------------ src/edit/mouse_events.js | 320 ++++++------- src/edit/options.js | 276 +++++------ src/edit/utils.js | 6 +- src/input/ContentEditableInput.js | 468 +++++++++---------- src/input/TextareaInput.js | 322 ++++++------- src/input/indent.js | 72 +-- src/input/input.js | 124 ++--- src/input/keymap.js | 114 ++--- src/input/keynames.js | 8 +- src/line/highlight.js | 202 ++++---- src/line/line_data.js | 304 ++++++------- src/line/pos.js | 36 +- src/line/saw_special_spans.js | 6 +- src/line/spans.js | 310 ++++++------- src/line/utils_line.js | 76 ++-- src/measurement/position_measurement.js | 532 +++++++++++----------- src/measurement/update_line.js | 178 ++++---- src/measurement/widgets.js | 22 +- src/model/Doc.js | 436 +++++++++--------- src/model/change_measurement.js | 54 +-- src/model/changes.js | 300 ++++++------ src/model/chunk.js | 154 +++---- src/model/document_data.js | 102 ++--- src/model/history.js | 174 +++---- src/model/line_widget.js | 92 ++-- src/model/mark_text.js | 284 ++++++------ src/model/selection.js | 68 +-- src/model/selection_updates.js | 156 +++---- src/modes.js | 84 ++-- src/util/StringStream.js | 84 ++-- src/util/bidi.js | 216 ++++----- src/util/browser.js | 48 +- src/util/dom.js | 98 ++-- src/util/event.js | 72 +-- src/util/feature_detection.js | 98 ++-- src/util/misc.js | 102 ++--- src/util/operation_group.js | 52 +-- 63 files changed, 4595 insertions(+), 4595 deletions(-) diff --git a/package.json b/package.json index 1f4b036e12..a6e61d06dc 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "lint": "bin/lint" }, "devDependencies": { - "blint": ">=0.1.1", + "blint": "^0.5.1", "node-static": "0.6.0", "phantomjs-prebuilt": "^2.1.12", "rollup": "^0.34.10", diff --git a/src/codemirror.js b/src/codemirror.js index 4b75d8cbaf..3c16cc875e 100644 --- a/src/codemirror.js +++ b/src/codemirror.js @@ -1,3 +1,3 @@ -import { CodeMirror } from "./edit/main"; +import { CodeMirror } from "./edit/main" -export default CodeMirror; +export default CodeMirror diff --git a/src/display/Display.js b/src/display/Display.js index e1cb6a0923..fa4c52fef7 100644 --- a/src/display/Display.js +++ b/src/display/Display.js @@ -1,105 +1,105 @@ -import { gecko, ie, ie_version, mobile, webkit } from "../util/browser"; -import { elt } from "../util/dom"; -import { scrollerGap } from "../util/misc"; +import { gecko, ie, ie_version, mobile, webkit } from "../util/browser" +import { elt } from "../util/dom" +import { scrollerGap } from "../util/misc" // The display handles the DOM integration, both for input reading // and content drawing. It holds references to DOM nodes and // display-related state. export function Display(place, doc, input) { - var d = this; - this.input = input; + var d = this + this.input = input // Covers bottom-right square when both scrollbars are present. - d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); - d.scrollbarFiller.setAttribute("cm-not-content", "true"); + d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler") + d.scrollbarFiller.setAttribute("cm-not-content", "true") // Covers bottom of gutter when coverGutterNextToScrollbar is on // and h scrollbar is present. - d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); - d.gutterFiller.setAttribute("cm-not-content", "true"); + d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler") + d.gutterFiller.setAttribute("cm-not-content", "true") // Will contain the actual code, positioned to cover the viewport. - d.lineDiv = elt("div", null, "CodeMirror-code"); + d.lineDiv = elt("div", null, "CodeMirror-code") // Elements are added to these to represent selection and cursors. - d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); - d.cursorDiv = elt("div", null, "CodeMirror-cursors"); + d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1") + d.cursorDiv = elt("div", null, "CodeMirror-cursors") // A visibility: hidden element used to find the size of things. - d.measure = elt("div", null, "CodeMirror-measure"); + d.measure = elt("div", null, "CodeMirror-measure") // When lines outside of the viewport are measured, they are drawn in this. - d.lineMeasure = elt("div", null, "CodeMirror-measure"); + d.lineMeasure = elt("div", null, "CodeMirror-measure") // Wraps everything that needs to exist inside the vertically-padded coordinate system d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], - null, "position: relative; outline: none"); + null, "position: relative; outline: none") // Moved around its parent to cover visible view. - d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative"); + d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative") // Set to the height of the document, allowing scrolling. - d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); - d.sizerWidth = null; + d.sizer = elt("div", [d.mover], "CodeMirror-sizer") + d.sizerWidth = null // Behavior of elts with overflow: auto and padding is // inconsistent across browsers. This is used to ensure the // scrollable area is big enough. - d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;"); + d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;") // Will contain the gutters, if any. - d.gutters = elt("div", null, "CodeMirror-gutters"); - d.lineGutter = null; + d.gutters = elt("div", null, "CodeMirror-gutters") + d.lineGutter = null // Actual scrollable element. - d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); - d.scroller.setAttribute("tabIndex", "-1"); + d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll") + d.scroller.setAttribute("tabIndex", "-1") // The element in which the editor lives. - d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); + d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror") // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) - if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } - if (!webkit && !(gecko && mobile)) d.scroller.draggable = true; + if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0 } + if (!webkit && !(gecko && mobile)) d.scroller.draggable = true if (place) { - if (place.appendChild) place.appendChild(d.wrapper); - else place(d.wrapper); + if (place.appendChild) place.appendChild(d.wrapper) + else place(d.wrapper) } // Current rendered range (may be bigger than the view window). - d.viewFrom = d.viewTo = doc.first; - d.reportedViewFrom = d.reportedViewTo = doc.first; + d.viewFrom = d.viewTo = doc.first + d.reportedViewFrom = d.reportedViewTo = doc.first // Information about the rendered lines. - d.view = []; - d.renderedView = null; + d.view = [] + d.renderedView = null // Holds info about a single rendered line when it was rendered // for measurement, while not in view. - d.externalMeasured = null; + d.externalMeasured = null // Empty space (in pixels) above the view - d.viewOffset = 0; - d.lastWrapHeight = d.lastWrapWidth = 0; - d.updateLineNumbers = null; + d.viewOffset = 0 + d.lastWrapHeight = d.lastWrapWidth = 0 + d.updateLineNumbers = null - d.nativeBarWidth = d.barHeight = d.barWidth = 0; - d.scrollbarsClipped = false; + d.nativeBarWidth = d.barHeight = d.barWidth = 0 + d.scrollbarsClipped = false // Used to only resize the line number gutter when necessary (when // the amount of lines crosses a boundary that makes its width change) - d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; + d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null // Set to true when a non-horizontal-scrolling line widget is // added. As an optimization, line widget aligning is skipped when // this is false. - d.alignWidgets = false; + d.alignWidgets = false - d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null // Tracks the maximum line length so that the horizontal scrollbar // can be kept static when scrolling. - d.maxLine = null; - d.maxLineLength = 0; - d.maxLineChanged = false; + d.maxLine = null + d.maxLineLength = 0 + d.maxLineChanged = false // Used for measuring wheel scrolling granularity - d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; + d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null // True when shift is held down. - d.shift = false; + d.shift = false // Used to track whether anything happened since the context menu // was opened. - d.selForContextMenu = null; + d.selForContextMenu = null - d.activeTouch = null; + d.activeTouch = null - input.init(d); + input.init(d) } diff --git a/src/display/focus.js b/src/display/focus.js index abe70f09d2..e6a9f5218d 100644 --- a/src/display/focus.js +++ b/src/display/focus.js @@ -1,49 +1,49 @@ -import { restartBlink } from "./selection"; -import { webkit } from "../util/browser"; -import { addClass, rmClass } from "../util/dom"; -import { signal } from "../util/event"; +import { restartBlink } from "./selection" +import { webkit } from "../util/browser" +import { addClass, rmClass } from "../util/dom" +import { signal } from "../util/event" export function ensureFocus(cm) { - if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } + if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm) } } export function delayBlurEvent(cm) { - cm.state.delayingBlurEvent = true; + cm.state.delayingBlurEvent = true setTimeout(function() { if (cm.state.delayingBlurEvent) { - cm.state.delayingBlurEvent = false; - onBlur(cm); + cm.state.delayingBlurEvent = false + onBlur(cm) } - }, 100); + }, 100) } export function onFocus(cm, e) { - if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false; + if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false - if (cm.options.readOnly == "nocursor") return; + if (cm.options.readOnly == "nocursor") return if (!cm.state.focused) { - signal(cm, "focus", cm, e); - cm.state.focused = true; - addClass(cm.display.wrapper, "CodeMirror-focused"); + signal(cm, "focus", cm, e) + cm.state.focused = true + addClass(cm.display.wrapper, "CodeMirror-focused") // This test prevents this from firing when a context // menu is closed (since the input reset would kill the // select-all detection hack) if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { - cm.display.input.reset(); - if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730 + cm.display.input.reset() + if (webkit) setTimeout(function() { cm.display.input.reset(true) }, 20) // Issue #1730 } - cm.display.input.receivedFocus(); + cm.display.input.receivedFocus() } - restartBlink(cm); + restartBlink(cm) } export function onBlur(cm, e) { - if (cm.state.delayingBlurEvent) return; + if (cm.state.delayingBlurEvent) return if (cm.state.focused) { - signal(cm, "blur", cm, e); - cm.state.focused = false; - rmClass(cm.display.wrapper, "CodeMirror-focused"); + signal(cm, "blur", cm, e) + cm.state.focused = false + rmClass(cm.display.wrapper, "CodeMirror-focused") } - clearInterval(cm.display.blinker); - setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150); + clearInterval(cm.display.blinker) + setTimeout(function() {if (!cm.state.focused) cm.display.shift = false}, 150) } diff --git a/src/display/gutters.js b/src/display/gutters.js index 0a0f591a94..3fe9a13447 100644 --- a/src/display/gutters.js +++ b/src/display/gutters.js @@ -1,33 +1,33 @@ -import { elt, removeChildren } from "../util/dom"; -import { indexOf } from "../util/misc"; +import { elt, removeChildren } from "../util/dom" +import { indexOf } from "../util/misc" -import { updateGutterSpace } from "./update_display"; +import { updateGutterSpace } from "./update_display" // Rebuild the gutter elements, ensure the margin to the left of the // code matches their width. export function updateGutters(cm) { - var gutters = cm.display.gutters, specs = cm.options.gutters; - removeChildren(gutters); + var gutters = cm.display.gutters, specs = cm.options.gutters + removeChildren(gutters) for (var i = 0; i < specs.length; ++i) { - var gutterClass = specs[i]; - var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)); + var gutterClass = specs[i] + var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)) if (gutterClass == "CodeMirror-linenumbers") { - cm.display.lineGutter = gElt; - gElt.style.width = (cm.display.lineNumWidth || 1) + "px"; + cm.display.lineGutter = gElt + gElt.style.width = (cm.display.lineNumWidth || 1) + "px" } } - gutters.style.display = i ? "" : "none"; - updateGutterSpace(cm); + gutters.style.display = i ? "" : "none" + updateGutterSpace(cm) } // Make sure the gutters options contains the element // "CodeMirror-linenumbers" when the lineNumbers option is true. export function setGuttersForLineNumbers(options) { - var found = indexOf(options.gutters, "CodeMirror-linenumbers"); + var found = indexOf(options.gutters, "CodeMirror-linenumbers") if (found == -1 && options.lineNumbers) { - options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); + options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]) } else if (found > -1 && !options.lineNumbers) { - options.gutters = options.gutters.slice(0); - options.gutters.splice(found, 1); + options.gutters = options.gutters.slice(0) + options.gutters.splice(found, 1) } } diff --git a/src/display/highlight_worker.js b/src/display/highlight_worker.js index 101b9acb30..b8a48c0e91 100644 --- a/src/display/highlight_worker.js +++ b/src/display/highlight_worker.js @@ -1,51 +1,51 @@ -import { getStateBefore, highlightLine, processLine } from "../line/highlight"; -import { copyState } from "../modes"; -import { bind } from "../util/misc"; +import { getStateBefore, highlightLine, processLine } from "../line/highlight" +import { copyState } from "../modes" +import { bind } from "../util/misc" -import { runInOp } from "./operations"; -import { regLineChange } from "./view_tracking"; +import { runInOp } from "./operations" +import { regLineChange } from "./view_tracking" // HIGHLIGHT WORKER export function startWorker(cm, time) { if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) - cm.state.highlight.set(time, bind(highlightWorker, cm)); + cm.state.highlight.set(time, bind(highlightWorker, cm)) } function highlightWorker(cm) { - var doc = cm.doc; - if (doc.frontier < doc.first) doc.frontier = doc.first; - if (doc.frontier >= cm.display.viewTo) return; - var end = +new Date + cm.options.workTime; - var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); - var changedLines = []; + var doc = cm.doc + if (doc.frontier < doc.first) doc.frontier = doc.first + if (doc.frontier >= cm.display.viewTo) return + var end = +new Date + cm.options.workTime + var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)) + var changedLines = [] doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { if (doc.frontier >= cm.display.viewFrom) { // Visible - var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength; - var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true); - line.styles = highlighted.styles; - var oldCls = line.styleClasses, newCls = highlighted.classes; - if (newCls) line.styleClasses = newCls; - else if (oldCls) line.styleClasses = null; + var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength + var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true) + line.styles = highlighted.styles + var oldCls = line.styleClasses, newCls = highlighted.classes + if (newCls) line.styleClasses = newCls + else if (oldCls) line.styleClasses = null var ischange = !oldStyles || oldStyles.length != line.styles.length || - oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); - for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; - if (ischange) changedLines.push(doc.frontier); - line.stateAfter = tooLong ? state : copyState(doc.mode, state); + oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass) + for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i] + if (ischange) changedLines.push(doc.frontier) + line.stateAfter = tooLong ? state : copyState(doc.mode, state) } else { if (line.text.length <= cm.options.maxHighlightLength) - processLine(cm, line.text, state); - line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; + processLine(cm, line.text, state) + line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null } - ++doc.frontier; + ++doc.frontier if (+new Date > end) { - startWorker(cm, cm.options.workDelay); - return true; + startWorker(cm, cm.options.workDelay) + return true } - }); + }) if (changedLines.length) runInOp(cm, function() { for (var i = 0; i < changedLines.length; i++) - regLineChange(cm, changedLines[i], "text"); - }); + regLineChange(cm, changedLines[i], "text") + }) } diff --git a/src/display/line_numbers.js b/src/display/line_numbers.js index 85964db7ba..22bd32ffc4 100644 --- a/src/display/line_numbers.js +++ b/src/display/line_numbers.js @@ -1,48 +1,48 @@ -import { lineNumberFor } from "../line/utils_line"; -import { compensateForHScroll } from "../measurement/position_measurement"; -import { elt } from "../util/dom"; +import { lineNumberFor } from "../line/utils_line" +import { compensateForHScroll } from "../measurement/position_measurement" +import { elt } from "../util/dom" -import { updateGutterSpace } from "./update_display"; +import { updateGutterSpace } from "./update_display" // Re-align line numbers and gutter marks to compensate for // horizontal scrolling. export function alignHorizontally(cm) { - var display = cm.display, view = display.view; - if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; - var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; - var gutterW = display.gutters.offsetWidth, left = comp + "px"; + var display = cm.display, view = display.view + if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return + var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft + var gutterW = display.gutters.offsetWidth, left = comp + "px" for (var i = 0; i < view.length; i++) if (!view[i].hidden) { if (cm.options.fixedGutter) { if (view[i].gutter) - view[i].gutter.style.left = left; + view[i].gutter.style.left = left if (view[i].gutterBackground) - view[i].gutterBackground.style.left = left; + view[i].gutterBackground.style.left = left } - var align = view[i].alignable; + var align = view[i].alignable if (align) for (var j = 0; j < align.length; j++) - align[j].style.left = left; + align[j].style.left = left } if (cm.options.fixedGutter) - display.gutters.style.left = (comp + gutterW) + "px"; + display.gutters.style.left = (comp + gutterW) + "px" } // Used to ensure that the line number gutter is still the right // size for the current document size. Returns true when an update // is needed. export function maybeUpdateLineNumberWidth(cm) { - if (!cm.options.lineNumbers) return false; - var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; + if (!cm.options.lineNumbers) return false + var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display if (last.length != display.lineNumChars) { var test = display.measure.appendChild(elt("div", [elt("div", last)], - "CodeMirror-linenumber CodeMirror-gutter-elt")); - var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; - display.lineGutter.style.width = ""; - display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1; - display.lineNumWidth = display.lineNumInnerWidth + padding; - display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; - display.lineGutter.style.width = display.lineNumWidth + "px"; - updateGutterSpace(cm); - return true; + "CodeMirror-linenumber CodeMirror-gutter-elt")) + var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW + display.lineGutter.style.width = "" + display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1 + display.lineNumWidth = display.lineNumInnerWidth + padding + display.lineNumChars = display.lineNumInnerWidth ? last.length : -1 + display.lineGutter.style.width = display.lineNumWidth + "px" + updateGutterSpace(cm) + return true } - return false; + return false } diff --git a/src/display/mode_state.js b/src/display/mode_state.js index 005e60e3b0..7742c722a4 100644 --- a/src/display/mode_state.js +++ b/src/display/mode_state.js @@ -1,22 +1,22 @@ -import { getMode } from "../modes"; +import { getMode } from "../modes" -import { startWorker } from "./highlight_worker"; -import { regChange } from "./view_tracking"; +import { startWorker } from "./highlight_worker" +import { regChange } from "./view_tracking" // Used to get the editor into a consistent state again when options change. export function loadMode(cm) { - cm.doc.mode = getMode(cm.options, cm.doc.modeOption); - resetModeState(cm); + cm.doc.mode = getMode(cm.options, cm.doc.modeOption) + resetModeState(cm) } export function resetModeState(cm) { cm.doc.iter(function(line) { - if (line.stateAfter) line.stateAfter = null; - if (line.styles) line.styles = null; - }); - cm.doc.frontier = cm.doc.first; - startWorker(cm, 100); - cm.state.modeGen++; - if (cm.curOp) regChange(cm); + if (line.stateAfter) line.stateAfter = null + if (line.styles) line.styles = null + }) + cm.doc.frontier = cm.doc.first + startWorker(cm, 100) + cm.state.modeGen++ + if (cm.curOp) regChange(cm) } diff --git a/src/display/operations.js b/src/display/operations.js index a3439d0056..2873e0e91d 100644 --- a/src/display/operations.js +++ b/src/display/operations.js @@ -1,18 +1,18 @@ -import { clipPos } from "../line/pos"; -import { findMaxLine } from "../line/spans"; -import { displayWidth, measureChar, scrollGap } from "../measurement/position_measurement"; -import { signal } from "../util/event"; -import { activeElt } from "../util/dom"; -import { finishOperation, pushOperation } from "../util/operation_group"; - -import { ensureFocus } from "./focus"; -import { alignHorizontally } from "./line_numbers"; -import { measureForScrollbars, updateScrollbars } from "./scrollbars"; -import { setScrollLeft } from "./scroll_events"; -import { restartBlink } from "./selection"; -import { maybeScrollWindow, scrollPosIntoView } from "./scrolling"; -import { DisplayUpdate, maybeClipScrollbars, postUpdateDisplay, setDocumentHeight, updateDisplayIfNeeded } from "./update_display"; -import { updateHeightsInViewport } from "./update_lines"; +import { clipPos } from "../line/pos" +import { findMaxLine } from "../line/spans" +import { displayWidth, measureChar, scrollGap } from "../measurement/position_measurement" +import { signal } from "../util/event" +import { activeElt } from "../util/dom" +import { finishOperation, pushOperation } from "../util/operation_group" + +import { ensureFocus } from "./focus" +import { alignHorizontally } from "./line_numbers" +import { measureForScrollbars, updateScrollbars } from "./scrollbars" +import { setScrollLeft } from "./scroll_events" +import { restartBlink } from "./selection" +import { maybeScrollWindow, scrollPosIntoView } from "./scrolling" +import { DisplayUpdate, maybeClipScrollbars, postUpdateDisplay, setDocumentHeight, updateDisplayIfNeeded } from "./update_display" +import { updateHeightsInViewport } from "./update_lines" // Operations are used to wrap a series of changes to the editor // state in such a way that each change won't have to update the @@ -20,7 +20,7 @@ import { updateHeightsInViewport } from "./update_lines"; // error-prone). Instead, display updates are batched and then all // combined and executed at once. -var nextOpId = 0; +var nextOpId = 0 // Start a new operation. export function startOperation(cm) { cm.curOp = { @@ -39,177 +39,177 @@ export function startOperation(cm) { scrollToPos: null, // Used to scroll to a specific position focus: false, id: ++nextOpId // Unique ID - }; - pushOperation(cm.curOp); + } + pushOperation(cm.curOp) } // Finish an operation, updating the display and signalling delayed events export function endOperation(cm) { - var op = cm.curOp; + var op = cm.curOp finishOperation(op, function(group) { for (var i = 0; i < group.ops.length; i++) - group.ops[i].cm.curOp = null; - endOperations(group); - }); + group.ops[i].cm.curOp = null + endOperations(group) + }) } // The DOM updates done when an operation finishes are batched so // that the minimum number of relayouts are required. function endOperations(group) { - var ops = group.ops; + var ops = group.ops for (var i = 0; i < ops.length; i++) // Read DOM - endOperation_R1(ops[i]); + endOperation_R1(ops[i]) for (var i = 0; i < ops.length; i++) // Write DOM (maybe) - endOperation_W1(ops[i]); + endOperation_W1(ops[i]) for (var i = 0; i < ops.length; i++) // Read DOM - endOperation_R2(ops[i]); + endOperation_R2(ops[i]) for (var i = 0; i < ops.length; i++) // Write DOM (maybe) - endOperation_W2(ops[i]); + endOperation_W2(ops[i]) for (var i = 0; i < ops.length; i++) // Read DOM - endOperation_finish(ops[i]); + endOperation_finish(ops[i]) } function endOperation_R1(op) { - var cm = op.cm, display = cm.display; - maybeClipScrollbars(cm); - if (op.updateMaxLine) findMaxLine(cm); + var cm = op.cm, display = cm.display + maybeClipScrollbars(cm) + if (op.updateMaxLine) findMaxLine(cm) op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || op.scrollToPos.to.line >= display.viewTo) || - display.maxLineChanged && cm.options.lineWrapping; + display.maxLineChanged && cm.options.lineWrapping op.update = op.mustUpdate && - new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); + new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate) } function endOperation_W1(op) { - op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update); + op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update) } function endOperation_R2(op) { - var cm = op.cm, display = cm.display; - if (op.updatedDisplay) updateHeightsInViewport(cm); + var cm = op.cm, display = cm.display + if (op.updatedDisplay) updateHeightsInViewport(cm) - op.barMeasure = measureForScrollbars(cm); + op.barMeasure = measureForScrollbars(cm) // If the max line changed since it was last measured, measure it, // and ensure the document's width matches it. // updateDisplay_W2 will use these properties to do the actual resizing if (display.maxLineChanged && !cm.options.lineWrapping) { - op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3; - cm.display.sizerWidth = op.adjustWidthTo; + op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3 + cm.display.sizerWidth = op.adjustWidthTo op.barMeasure.scrollWidth = - Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth); - op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)); + Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth) + op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)) } if (op.updatedDisplay || op.selectionChanged) - op.preparedSelection = display.input.prepareSelection(op.focus); + op.preparedSelection = display.input.prepareSelection(op.focus) } function endOperation_W2(op) { - var cm = op.cm; + var cm = op.cm if (op.adjustWidthTo != null) { - cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"; + cm.display.sizer.style.minWidth = op.adjustWidthTo + "px" if (op.maxScrollLeft < cm.doc.scrollLeft) - setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); - cm.display.maxLineChanged = false; + setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true) + cm.display.maxLineChanged = false } var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus()) if (op.preparedSelection) - cm.display.input.showSelection(op.preparedSelection, takeFocus); + cm.display.input.showSelection(op.preparedSelection, takeFocus) if (op.updatedDisplay || op.startHeight != cm.doc.height) - updateScrollbars(cm, op.barMeasure); + updateScrollbars(cm, op.barMeasure) if (op.updatedDisplay) - setDocumentHeight(cm, op.barMeasure); + setDocumentHeight(cm, op.barMeasure) - if (op.selectionChanged) restartBlink(cm); + if (op.selectionChanged) restartBlink(cm) if (cm.state.focused && op.updateInput) - cm.display.input.reset(op.typing); - if (takeFocus) ensureFocus(op.cm); + cm.display.input.reset(op.typing) + if (takeFocus) ensureFocus(op.cm) } function endOperation_finish(op) { - var cm = op.cm, display = cm.display, doc = cm.doc; + var cm = op.cm, display = cm.display, doc = cm.doc - if (op.updatedDisplay) postUpdateDisplay(cm, op.update); + if (op.updatedDisplay) postUpdateDisplay(cm, op.update) // Abort mouse wheel delta measurement, when scrolling explicitly if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) - display.wheelStartX = display.wheelStartY = null; + display.wheelStartX = display.wheelStartY = null // Propagate the scroll position to the actual DOM scroller if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { - doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); - display.scrollbars.setScrollTop(doc.scrollTop); - display.scroller.scrollTop = doc.scrollTop; + doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)) + display.scrollbars.setScrollTop(doc.scrollTop) + display.scroller.scrollTop = doc.scrollTop } if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { - doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft)); - display.scrollbars.setScrollLeft(doc.scrollLeft); - display.scroller.scrollLeft = doc.scrollLeft; - alignHorizontally(cm); + doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft)) + display.scrollbars.setScrollLeft(doc.scrollLeft) + display.scroller.scrollLeft = doc.scrollLeft + alignHorizontally(cm) } // If we need to scroll a specific position into view, do so. if (op.scrollToPos) { var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), - clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin); - if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords); + clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin) + if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords) } // Fire events for markers that are hidden/unidden by editing or // undoing - var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; + var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers if (hidden) for (var i = 0; i < hidden.length; ++i) - if (!hidden[i].lines.length) signal(hidden[i], "hide"); + if (!hidden[i].lines.length) signal(hidden[i], "hide") if (unhidden) for (var i = 0; i < unhidden.length; ++i) - if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); + if (unhidden[i].lines.length) signal(unhidden[i], "unhide") if (display.wrapper.offsetHeight) - doc.scrollTop = cm.display.scroller.scrollTop; + doc.scrollTop = cm.display.scroller.scrollTop // Fire change events, and delayed event handlers if (op.changeObjs) - signal(cm, "changes", cm, op.changeObjs); + signal(cm, "changes", cm, op.changeObjs) if (op.update) - op.update.finish(); + op.update.finish() } // Run the given function in an operation export function runInOp(cm, f) { - if (cm.curOp) return f(); - startOperation(cm); - try { return f(); } - finally { endOperation(cm); } + if (cm.curOp) return f() + startOperation(cm) + try { return f() } + finally { endOperation(cm) } } // Wraps a function in an operation. Returns the wrapped function. export function operation(cm, f) { return function() { - if (cm.curOp) return f.apply(cm, arguments); - startOperation(cm); - try { return f.apply(cm, arguments); } - finally { endOperation(cm); } - }; + if (cm.curOp) return f.apply(cm, arguments) + startOperation(cm) + try { return f.apply(cm, arguments) } + finally { endOperation(cm) } + } } // Used to add methods to editor and doc instances, wrapping them in // operations. export function methodOp(f) { return function() { - if (this.curOp) return f.apply(this, arguments); - startOperation(this); - try { return f.apply(this, arguments); } - finally { endOperation(this); } - }; + if (this.curOp) return f.apply(this, arguments) + startOperation(this) + try { return f.apply(this, arguments) } + finally { endOperation(this) } + } } export function docMethodOp(f) { return function() { - var cm = this.cm; - if (!cm || cm.curOp) return f.apply(this, arguments); - startOperation(cm); - try { return f.apply(this, arguments); } - finally { endOperation(cm); } - }; + var cm = this.cm + if (!cm || cm.curOp) return f.apply(this, arguments) + startOperation(cm) + try { return f.apply(this, arguments) } + finally { endOperation(cm) } + } } diff --git a/src/display/scroll_events.js b/src/display/scroll_events.js index 3c5a666e28..99afe7ee50 100644 --- a/src/display/scroll_events.js +++ b/src/display/scroll_events.js @@ -1,30 +1,30 @@ -import { chrome, gecko, ie, mac, presto, safari, webkit } from "../util/browser"; -import { e_preventDefault } from "../util/event"; +import { chrome, gecko, ie, mac, presto, safari, webkit } from "../util/browser" +import { e_preventDefault } from "../util/event" -import { startWorker } from "./highlight_worker"; -import { alignHorizontally } from "./line_numbers"; -import { updateDisplaySimple} from "./update_display"; +import { startWorker } from "./highlight_worker" +import { alignHorizontally } from "./line_numbers" +import { updateDisplaySimple} from "./update_display" // Sync the scrollable area and scrollbars, ensure the viewport // covers the visible area. export function setScrollTop(cm, val) { - if (Math.abs(cm.doc.scrollTop - val) < 2) return; - cm.doc.scrollTop = val; - if (!gecko) updateDisplaySimple(cm, {top: val}); - if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; - cm.display.scrollbars.setScrollTop(val); - if (gecko) updateDisplaySimple(cm); - startWorker(cm, 100); + if (Math.abs(cm.doc.scrollTop - val) < 2) return + cm.doc.scrollTop = val + if (!gecko) updateDisplaySimple(cm, {top: val}) + if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val + cm.display.scrollbars.setScrollTop(val) + if (gecko) updateDisplaySimple(cm) + startWorker(cm, 100) } // Sync scroller and scrollbar, ensure the gutter elements are // aligned. export function setScrollLeft(cm, val, isScroller) { - if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return; - val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); - cm.doc.scrollLeft = val; - alignHorizontally(cm); - if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; - cm.display.scrollbars.setScrollLeft(val); + if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return + val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth) + cm.doc.scrollLeft = val + alignHorizontally(cm) + if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val + cm.display.scrollbars.setScrollLeft(val) } // Since the delta values reported on mouse wheel events are @@ -38,38 +38,38 @@ export function setScrollLeft(cm, val, isScroller) { // is that it gives us a chance to update the display before the // actual scrolling happens, reducing flickering. -var wheelSamples = 0, wheelPixelsPerUnit = null; +var wheelSamples = 0, wheelPixelsPerUnit = null // Fill in a browser-detected starting value on browsers where we // know one. These don't have to be accurate -- the result of them // being wrong would just be a slight flicker on the first wheel // scroll (if it is large enough). -if (ie) wheelPixelsPerUnit = -.53; -else if (gecko) wheelPixelsPerUnit = 15; -else if (chrome) wheelPixelsPerUnit = -.7; -else if (safari) wheelPixelsPerUnit = -1/3; +if (ie) wheelPixelsPerUnit = -.53 +else if (gecko) wheelPixelsPerUnit = 15 +else if (chrome) wheelPixelsPerUnit = -.7 +else if (safari) wheelPixelsPerUnit = -1/3 var wheelEventDelta = function(e) { - var dx = e.wheelDeltaX, dy = e.wheelDeltaY; - if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; - if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; - else if (dy == null) dy = e.wheelDelta; - return {x: dx, y: dy}; -}; + var dx = e.wheelDeltaX, dy = e.wheelDeltaY + if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail + if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail + else if (dy == null) dy = e.wheelDelta + return {x: dx, y: dy} +} export function wheelEventPixels(e) { - var delta = wheelEventDelta(e); - delta.x *= wheelPixelsPerUnit; - delta.y *= wheelPixelsPerUnit; - return delta; + var delta = wheelEventDelta(e) + delta.x *= wheelPixelsPerUnit + delta.y *= wheelPixelsPerUnit + return delta } export function onScrollWheel(cm, e) { - var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; + var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y - var display = cm.display, scroll = display.scroller; + var display = cm.display, scroll = display.scroller // Quit if there's nothing to scroll here - var canScrollX = scroll.scrollWidth > scroll.clientWidth; - var canScrollY = scroll.scrollHeight > scroll.clientHeight; - if (!(dx && canScrollX || dy && canScrollY)) return; + var canScrollX = scroll.scrollWidth > scroll.clientWidth + var canScrollY = scroll.scrollHeight > scroll.clientHeight + if (!(dx && canScrollX || dy && canScrollY)) return // Webkit browsers on OS X abort momentum scrolls when the target // of the scroll event is removed from the scrollable element. @@ -79,8 +79,8 @@ export function onScrollWheel(cm, e) { outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { for (var i = 0; i < view.length; i++) { if (view[i].node == cur) { - cm.display.currentWheelTarget = cur; - break outer; + cm.display.currentWheelTarget = cur + break outer } } } @@ -94,45 +94,45 @@ export function onScrollWheel(cm, e) { // better than glitching out. if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { if (dy && canScrollY) - setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); - setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); + setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))) + setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))) // Only prevent default scrolling if vertical scrolling is // actually possible. Otherwise, it causes vertical scroll // jitter on OSX trackpads when deltaX is small and deltaY // is large (issue #3579) if (!dy || (dy && canScrollY)) - e_preventDefault(e); - display.wheelStartX = null; // Abort measurement, if in progress - return; + e_preventDefault(e) + display.wheelStartX = null // Abort measurement, if in progress + return } // 'Project' the visible viewport to cover the area that is being // scrolled into view (if we know enough to estimate it). if (dy && wheelPixelsPerUnit != null) { - var pixels = dy * wheelPixelsPerUnit; - var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; - if (pixels < 0) top = Math.max(0, top + pixels - 50); - else bot = Math.min(cm.doc.height, bot + pixels + 50); - updateDisplaySimple(cm, {top: top, bottom: bot}); + var pixels = dy * wheelPixelsPerUnit + var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight + if (pixels < 0) top = Math.max(0, top + pixels - 50) + else bot = Math.min(cm.doc.height, bot + pixels + 50) + updateDisplaySimple(cm, {top: top, bottom: bot}) } if (wheelSamples < 20) { if (display.wheelStartX == null) { - display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; - display.wheelDX = dx; display.wheelDY = dy; + display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop + display.wheelDX = dx; display.wheelDY = dy setTimeout(function() { - if (display.wheelStartX == null) return; - var movedX = scroll.scrollLeft - display.wheelStartX; - var movedY = scroll.scrollTop - display.wheelStartY; + if (display.wheelStartX == null) return + var movedX = scroll.scrollLeft - display.wheelStartX + var movedY = scroll.scrollTop - display.wheelStartY var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || - (movedX && display.wheelDX && movedX / display.wheelDX); - display.wheelStartX = display.wheelStartY = null; - if (!sample) return; - wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); - ++wheelSamples; - }, 200); + (movedX && display.wheelDX && movedX / display.wheelDX) + display.wheelStartX = display.wheelStartY = null + if (!sample) return + wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1) + ++wheelSamples + }, 200) } else { - display.wheelDX += dx; display.wheelDY += dy; + display.wheelDX += dx; display.wheelDY += dy } } } diff --git a/src/display/scrollbars.js b/src/display/scrollbars.js index a29444b5d3..075ae41a1b 100644 --- a/src/display/scrollbars.js +++ b/src/display/scrollbars.js @@ -1,19 +1,19 @@ -import { addClass, elt, rmClass } from "../util/dom"; -import { on } from "../util/event"; -import { scrollGap, paddingVert } from "../measurement/position_measurement"; -import { ie, ie_version, mac, mac_geMountainLion } from "../util/browser"; -import { updateHeightsInViewport } from "./update_lines"; -import { copyObj, Delayed } from "../util/misc"; +import { addClass, elt, rmClass } from "../util/dom" +import { on } from "../util/event" +import { scrollGap, paddingVert } from "../measurement/position_measurement" +import { ie, ie_version, mac, mac_geMountainLion } from "../util/browser" +import { updateHeightsInViewport } from "./update_lines" +import { copyObj, Delayed } from "../util/misc" -import { setScrollLeft, setScrollTop } from "./scroll_events"; +import { setScrollLeft, setScrollTop } from "./scroll_events" // SCROLLBARS // Prepare DOM reads needed to update the scrollbars. Done in one // shot to minimize update/measure roundtrips. export function measureForScrollbars(cm) { - var d = cm.display, gutterW = d.gutters.offsetWidth; - var docH = Math.round(cm.doc.height + paddingVert(cm.display)); + var d = cm.display, gutterW = d.gutters.offsetWidth + var docH = Math.round(cm.doc.height + paddingVert(cm.display)) return { clientHeight: d.scroller.clientHeight, viewHeight: d.wrapper.clientHeight, @@ -24,81 +24,81 @@ export function measureForScrollbars(cm) { scrollHeight: docH + scrollGap(cm) + d.barHeight, nativeBarWidth: d.nativeBarWidth, gutterWidth: gutterW - }; + } } function NativeScrollbars(place, scroll, cm) { - this.cm = cm; - var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); - var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); - place(vert); place(horiz); + this.cm = cm + var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar") + var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar") + place(vert); place(horiz) on(vert, "scroll", function() { - if (vert.clientHeight) scroll(vert.scrollTop, "vertical"); - }); + if (vert.clientHeight) scroll(vert.scrollTop, "vertical") + }) on(horiz, "scroll", function() { - if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal"); - }); + if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal") + }) - this.checkedZeroWidth = false; + this.checkedZeroWidth = false // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). - if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; + if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px" } NativeScrollbars.prototype = copyObj({ update: function(measure) { - var needsH = measure.scrollWidth > measure.clientWidth + 1; - var needsV = measure.scrollHeight > measure.clientHeight + 1; - var sWidth = measure.nativeBarWidth; + var needsH = measure.scrollWidth > measure.clientWidth + 1 + var needsV = measure.scrollHeight > measure.clientHeight + 1 + var sWidth = measure.nativeBarWidth if (needsV) { - this.vert.style.display = "block"; - this.vert.style.bottom = needsH ? sWidth + "px" : "0"; - var totalHeight = measure.viewHeight - (needsH ? sWidth : 0); + this.vert.style.display = "block" + this.vert.style.bottom = needsH ? sWidth + "px" : "0" + var totalHeight = measure.viewHeight - (needsH ? sWidth : 0) // A bug in IE8 can cause this value to be negative, so guard it. this.vert.firstChild.style.height = - Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; + Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px" } else { - this.vert.style.display = ""; - this.vert.firstChild.style.height = "0"; + this.vert.style.display = "" + this.vert.firstChild.style.height = "0" } if (needsH) { - this.horiz.style.display = "block"; - this.horiz.style.right = needsV ? sWidth + "px" : "0"; - this.horiz.style.left = measure.barLeft + "px"; - var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0); + this.horiz.style.display = "block" + this.horiz.style.right = needsV ? sWidth + "px" : "0" + this.horiz.style.left = measure.barLeft + "px" + var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0) this.horiz.firstChild.style.width = - (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"; + (measure.scrollWidth - measure.clientWidth + totalWidth) + "px" } else { - this.horiz.style.display = ""; - this.horiz.firstChild.style.width = "0"; + this.horiz.style.display = "" + this.horiz.firstChild.style.width = "0" } if (!this.checkedZeroWidth && measure.clientHeight > 0) { - if (sWidth == 0) this.zeroWidthHack(); - this.checkedZeroWidth = true; + if (sWidth == 0) this.zeroWidthHack() + this.checkedZeroWidth = true } - return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}; + return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0} }, setScrollLeft: function(pos) { - if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos; - if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz); + if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos + if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz) }, setScrollTop: function(pos) { - if (this.vert.scrollTop != pos) this.vert.scrollTop = pos; - if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert); + if (this.vert.scrollTop != pos) this.vert.scrollTop = pos + if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert) }, zeroWidthHack: function() { - var w = mac && !mac_geMountainLion ? "12px" : "18px"; - this.horiz.style.height = this.vert.style.width = w; - this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"; - this.disableHoriz = new Delayed; - this.disableVert = new Delayed; + var w = mac && !mac_geMountainLion ? "12px" : "18px" + this.horiz.style.height = this.vert.style.width = w + this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none" + this.disableHoriz = new Delayed + this.disableVert = new Delayed }, enableZeroWidthBar: function(bar, delay) { - bar.style.pointerEvents = "auto"; + bar.style.pointerEvents = "auto" function maybeDisable() { // To find out whether the scrollbar is still visible, we // check whether the element under the pixel in the bottom @@ -106,83 +106,83 @@ NativeScrollbars.prototype = copyObj({ // itself (when the bar is still visible) or its filler child // (when the bar is hidden). If it is still visible, we keep // it enabled, if it's hidden, we disable pointer events. - var box = bar.getBoundingClientRect(); - var elt = document.elementFromPoint(box.left + 1, box.bottom - 1); - if (elt != bar) bar.style.pointerEvents = "none"; - else delay.set(1000, maybeDisable); + var box = bar.getBoundingClientRect() + var elt = document.elementFromPoint(box.left + 1, box.bottom - 1) + if (elt != bar) bar.style.pointerEvents = "none" + else delay.set(1000, maybeDisable) } - delay.set(1000, maybeDisable); + delay.set(1000, maybeDisable) }, clear: function() { - var parent = this.horiz.parentNode; - parent.removeChild(this.horiz); - parent.removeChild(this.vert); + var parent = this.horiz.parentNode + parent.removeChild(this.horiz) + parent.removeChild(this.vert) } -}, NativeScrollbars.prototype); +}, NativeScrollbars.prototype) function NullScrollbars() {} NullScrollbars.prototype = copyObj({ - update: function() { return {bottom: 0, right: 0}; }, + update: function() { return {bottom: 0, right: 0} }, setScrollLeft: function() {}, setScrollTop: function() {}, clear: function() {} -}, NullScrollbars.prototype); +}, NullScrollbars.prototype) export function updateScrollbars(cm, measure) { - if (!measure) measure = measureForScrollbars(cm); - var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight; - updateScrollbarsInner(cm, measure); + if (!measure) measure = measureForScrollbars(cm) + var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight + updateScrollbarsInner(cm, measure) for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { if (startWidth != cm.display.barWidth && cm.options.lineWrapping) - updateHeightsInViewport(cm); - updateScrollbarsInner(cm, measureForScrollbars(cm)); - startWidth = cm.display.barWidth; startHeight = cm.display.barHeight; + updateHeightsInViewport(cm) + updateScrollbarsInner(cm, measureForScrollbars(cm)) + startWidth = cm.display.barWidth; startHeight = cm.display.barHeight } } // Re-synchronize the fake scrollbars with the actual size of the // content. function updateScrollbarsInner(cm, measure) { - var d = cm.display; - var sizes = d.scrollbars.update(measure); + var d = cm.display + var sizes = d.scrollbars.update(measure) - d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; - d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; + d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px" + d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px" d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent" if (sizes.right && sizes.bottom) { - d.scrollbarFiller.style.display = "block"; - d.scrollbarFiller.style.height = sizes.bottom + "px"; - d.scrollbarFiller.style.width = sizes.right + "px"; - } else d.scrollbarFiller.style.display = ""; + d.scrollbarFiller.style.display = "block" + d.scrollbarFiller.style.height = sizes.bottom + "px" + d.scrollbarFiller.style.width = sizes.right + "px" + } else d.scrollbarFiller.style.display = "" if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { - d.gutterFiller.style.display = "block"; - d.gutterFiller.style.height = sizes.bottom + "px"; - d.gutterFiller.style.width = measure.gutterWidth + "px"; - } else d.gutterFiller.style.display = ""; + d.gutterFiller.style.display = "block" + d.gutterFiller.style.height = sizes.bottom + "px" + d.gutterFiller.style.width = measure.gutterWidth + "px" + } else d.gutterFiller.style.display = "" } -export var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}; +export var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars} export function initScrollbars(cm) { if (cm.display.scrollbars) { - cm.display.scrollbars.clear(); + cm.display.scrollbars.clear() if (cm.display.scrollbars.addClass) - rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); + rmClass(cm.display.wrapper, cm.display.scrollbars.addClass) } cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function(node) { - cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller); + cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller) // Prevent clicks in the scrollbars from killing focus on(node, "mousedown", function() { - if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0); - }); - node.setAttribute("cm-not-content", "true"); + if (cm.state.focused) setTimeout(function() { cm.display.input.focus() }, 0) + }) + node.setAttribute("cm-not-content", "true") }, function(pos, axis) { - if (axis == "horizontal") setScrollLeft(cm, pos); - else setScrollTop(cm, pos); - }, cm); + if (axis == "horizontal") setScrollLeft(cm, pos) + else setScrollTop(cm, pos) + }, cm) if (cm.display.scrollbars.addClass) - addClass(cm.display.wrapper, cm.display.scrollbars.addClass); + addClass(cm.display.wrapper, cm.display.scrollbars.addClass) } diff --git a/src/display/scrolling.js b/src/display/scrolling.js index 50ea401262..ec8cec6715 100644 --- a/src/display/scrolling.js +++ b/src/display/scrolling.js @@ -1,29 +1,29 @@ -import { Pos } from "../line/pos"; -import { cursorCoords, displayHeight, displayWidth, estimateCoords, paddingTop, paddingVert, scrollGap, textHeight } from "../measurement/position_measurement"; -import { phantom } from "../util/browser"; -import { elt } from "../util/dom"; -import { signalDOMEvent } from "../util/event"; +import { Pos } from "../line/pos" +import { cursorCoords, displayHeight, displayWidth, estimateCoords, paddingTop, paddingVert, scrollGap, textHeight } from "../measurement/position_measurement" +import { phantom } from "../util/browser" +import { elt } from "../util/dom" +import { signalDOMEvent } from "../util/event" -import { setScrollLeft, setScrollTop } from "./scroll_events"; +import { setScrollLeft, setScrollTop } from "./scroll_events" // SCROLLING THINGS INTO VIEW // If an editor sits on the top or bottom of the window, partially // scrolled out of view, this ensures that the cursor is visible. export function maybeScrollWindow(cm, coords) { - if (signalDOMEvent(cm, "scrollCursorIntoView")) return; + if (signalDOMEvent(cm, "scrollCursorIntoView")) return - var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; - if (coords.top + box.top < 0) doScroll = true; - else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; + var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null + if (coords.top + box.top < 0) doScroll = true + else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false if (doScroll != null && !phantom) { var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " + - coords.left + "px; width: 2px;"); - cm.display.lineSpace.appendChild(scrollNode); - scrollNode.scrollIntoView(doScroll); - cm.display.lineSpace.removeChild(scrollNode); + coords.left + "px; width: 2px;") + cm.display.lineSpace.appendChild(scrollNode) + scrollNode.scrollIntoView(doScroll) + cm.display.lineSpace.removeChild(scrollNode) } } @@ -31,33 +31,33 @@ export function maybeScrollWindow(cm, coords) { // it actually became visible (as line heights are accurately // measured, the position of something may 'drift' during drawing). export function scrollPosIntoView(cm, pos, end, margin) { - if (margin == null) margin = 0; + if (margin == null) margin = 0 for (var limit = 0; limit < 5; limit++) { - var changed = false, coords = cursorCoords(cm, pos); - var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); + var changed = false, coords = cursorCoords(cm, pos) + var endCoords = !end || end == pos ? coords : cursorCoords(cm, end) var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), Math.min(coords.top, endCoords.top) - margin, Math.max(coords.left, endCoords.left), - Math.max(coords.bottom, endCoords.bottom) + margin); - var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; + Math.max(coords.bottom, endCoords.bottom) + margin) + var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft if (scrollPos.scrollTop != null) { - setScrollTop(cm, scrollPos.scrollTop); - if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; + setScrollTop(cm, scrollPos.scrollTop) + if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true } if (scrollPos.scrollLeft != null) { - setScrollLeft(cm, scrollPos.scrollLeft); - if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; + setScrollLeft(cm, scrollPos.scrollLeft) + if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true } - if (!changed) break; + if (!changed) break } - return coords; + return coords } // Scroll a given set of coordinates into view (immediately). export function scrollIntoView(cm, x1, y1, x2, y2) { - var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2); - if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop); - if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft); + var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2) + if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop) + if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft) } // Calculate a new scroll position needed to scroll the given @@ -65,53 +65,53 @@ export function scrollIntoView(cm, x1, y1, x2, y2) { // scrollLeft properties. When these are undefined, the // vertical/horizontal position does not need to be adjusted. export function calculateScrollPos(cm, x1, y1, x2, y2) { - var display = cm.display, snapMargin = textHeight(cm.display); - if (y1 < 0) y1 = 0; - var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; - var screen = displayHeight(cm), result = {}; - if (y2 - y1 > screen) y2 = y1 + screen; - var docBottom = cm.doc.height + paddingVert(display); - var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; + var display = cm.display, snapMargin = textHeight(cm.display) + if (y1 < 0) y1 = 0 + var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop + var screen = displayHeight(cm), result = {} + if (y2 - y1 > screen) y2 = y1 + screen + var docBottom = cm.doc.height + paddingVert(display) + var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin if (y1 < screentop) { - result.scrollTop = atTop ? 0 : y1; + result.scrollTop = atTop ? 0 : y1 } else if (y2 > screentop + screen) { - var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen); - if (newTop != screentop) result.scrollTop = newTop; + var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen) + if (newTop != screentop) result.scrollTop = newTop } - var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; - var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); - var tooWide = x2 - x1 > screenw; - if (tooWide) x2 = x1 + screenw; + var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft + var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0) + var tooWide = x2 - x1 > screenw + if (tooWide) x2 = x1 + screenw if (x1 < 10) - result.scrollLeft = 0; + result.scrollLeft = 0 else if (x1 < screenleft) - result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)); + result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)) else if (x2 > screenw + screenleft - 3) - result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw; - return result; + result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw + return result } // Store a relative adjustment to the scroll position in the current // operation (to be applied when the operation finishes). export function addToScrollPos(cm, left, top) { - if (left != null || top != null) resolveScrollToPos(cm); + if (left != null || top != null) resolveScrollToPos(cm) if (left != null) - cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left; + cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left if (top != null) - cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; + cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top } // Make sure that at the end of the operation the current cursor is // shown. export function ensureCursorVisible(cm) { - resolveScrollToPos(cm); - var cur = cm.getCursor(), from = cur, to = cur; + resolveScrollToPos(cm) + var cur = cm.getCursor(), from = cur, to = cur if (!cm.options.lineWrapping) { - from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur; - to = Pos(cur.line, cur.ch + 1); + from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur + to = Pos(cur.line, cur.ch + 1) } - cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true}; + cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true} } // When an operation has its scrollToPos property set, and another @@ -119,14 +119,14 @@ export function ensureCursorVisible(cm) { // 'simulates' scrolling that position into view in a cheap way, so // that the effect of intermediate scroll commands is not ignored. export function resolveScrollToPos(cm) { - var range = cm.curOp.scrollToPos; + var range = cm.curOp.scrollToPos if (range) { - cm.curOp.scrollToPos = null; - var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); + cm.curOp.scrollToPos = null + var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to) var sPos = calculateScrollPos(cm, Math.min(from.left, to.left), Math.min(from.top, to.top) - range.margin, Math.max(from.right, to.right), - Math.max(from.bottom, to.bottom) + range.margin); - cm.scrollTo(sPos.scrollLeft, sPos.scrollTop); + Math.max(from.bottom, to.bottom) + range.margin) + cm.scrollTo(sPos.scrollLeft, sPos.scrollTop) } } diff --git a/src/display/selection.js b/src/display/selection.js index b6ca8b6f91..3ee79fa358 100644 --- a/src/display/selection.js +++ b/src/display/selection.js @@ -1,137 +1,137 @@ -import { Pos } from "../line/pos"; -import { visualLine } from "../line/spans"; -import { getLine } from "../line/utils_line"; -import { charCoords, cursorCoords, displayWidth, paddingH } from "../measurement/position_measurement"; -import { getOrder, iterateBidiSections } from "../util/bidi"; -import { elt } from "../util/dom"; +import { Pos } from "../line/pos" +import { visualLine } from "../line/spans" +import { getLine } from "../line/utils_line" +import { charCoords, cursorCoords, displayWidth, paddingH } from "../measurement/position_measurement" +import { getOrder, iterateBidiSections } from "../util/bidi" +import { elt } from "../util/dom" export function updateSelection(cm) { - cm.display.input.showSelection(cm.display.input.prepareSelection()); + cm.display.input.showSelection(cm.display.input.prepareSelection()) } export function prepareSelection(cm, primary) { - var doc = cm.doc, result = {}; - var curFragment = result.cursors = document.createDocumentFragment(); - var selFragment = result.selection = document.createDocumentFragment(); + var doc = cm.doc, result = {} + var curFragment = result.cursors = document.createDocumentFragment() + var selFragment = result.selection = document.createDocumentFragment() for (var i = 0; i < doc.sel.ranges.length; i++) { - if (primary === false && i == doc.sel.primIndex) continue; - var range = doc.sel.ranges[i]; - if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue; - var collapsed = range.empty(); + if (primary === false && i == doc.sel.primIndex) continue + var range = doc.sel.ranges[i] + if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue + var collapsed = range.empty() if (collapsed || cm.options.showCursorWhenSelecting) - drawSelectionCursor(cm, range.head, curFragment); + drawSelectionCursor(cm, range.head, curFragment) if (!collapsed) - drawSelectionRange(cm, range, selFragment); + drawSelectionRange(cm, range, selFragment) } - return result; + return result } // Draws a cursor for the given range export function drawSelectionCursor(cm, head, output) { - var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine); + var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine) - var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); - cursor.style.left = pos.left + "px"; - cursor.style.top = pos.top + "px"; - cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; + var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")) + cursor.style.left = pos.left + "px" + cursor.style.top = pos.top + "px" + cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px" if (pos.other) { // Secondary cursor, shown when on a 'jump' in bi-directional text - var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); - otherCursor.style.display = ""; - otherCursor.style.left = pos.other.left + "px"; - otherCursor.style.top = pos.other.top + "px"; - otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"; + var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")) + otherCursor.style.display = "" + otherCursor.style.left = pos.other.left + "px" + otherCursor.style.top = pos.other.top + "px" + otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px" } } // Draws the given range as a highlighted selection function drawSelectionRange(cm, range, output) { - var display = cm.display, doc = cm.doc; - var fragment = document.createDocumentFragment(); - var padding = paddingH(cm.display), leftSide = padding.left; - var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right; + var display = cm.display, doc = cm.doc + var fragment = document.createDocumentFragment() + var padding = paddingH(cm.display), leftSide = padding.left + var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right function add(left, top, width, bottom) { - if (top < 0) top = 0; - top = Math.round(top); - bottom = Math.round(bottom); + if (top < 0) top = 0 + top = Math.round(top) + bottom = Math.round(bottom) fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) + - "px; height: " + (bottom - top) + "px")); + "px; height: " + (bottom - top) + "px")) } function drawForLine(line, fromArg, toArg) { - var lineObj = getLine(doc, line); - var lineLen = lineObj.text.length; - var start, end; + var lineObj = getLine(doc, line) + var lineLen = lineObj.text.length + var start, end function coords(ch, bias) { - return charCoords(cm, Pos(line, ch), "div", lineObj, bias); + return charCoords(cm, Pos(line, ch), "div", lineObj, bias) } iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { - var leftPos = coords(from, "left"), rightPos, left, right; + var leftPos = coords(from, "left"), rightPos, left, right if (from == to) { - rightPos = leftPos; - left = right = leftPos.left; + rightPos = leftPos + left = right = leftPos.left } else { - rightPos = coords(to - 1, "right"); - if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } - left = leftPos.left; - right = rightPos.right; + rightPos = coords(to - 1, "right") + if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp } + left = leftPos.left + right = rightPos.right } - if (fromArg == null && from == 0) left = leftSide; + if (fromArg == null && from == 0) left = leftSide if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part - add(left, leftPos.top, null, leftPos.bottom); - left = leftSide; - if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); + add(left, leftPos.top, null, leftPos.bottom) + left = leftSide + if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top) } - if (toArg == null && to == lineLen) right = rightSide; + if (toArg == null && to == lineLen) right = rightSide if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) - start = leftPos; + start = leftPos if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) - end = rightPos; - if (left < leftSide + 1) left = leftSide; - add(left, rightPos.top, right - left, rightPos.bottom); - }); - return {start: start, end: end}; + end = rightPos + if (left < leftSide + 1) left = leftSide + add(left, rightPos.top, right - left, rightPos.bottom) + }) + return {start: start, end: end} } - var sFrom = range.from(), sTo = range.to(); + var sFrom = range.from(), sTo = range.to() if (sFrom.line == sTo.line) { - drawForLine(sFrom.line, sFrom.ch, sTo.ch); + drawForLine(sFrom.line, sFrom.ch, sTo.ch) } else { - var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); - var singleVLine = visualLine(fromLine) == visualLine(toLine); - var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; - var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; + var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line) + var singleVLine = visualLine(fromLine) == visualLine(toLine) + var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end + var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start if (singleVLine) { if (leftEnd.top < rightStart.top - 2) { - add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); - add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); + add(leftEnd.right, leftEnd.top, null, leftEnd.bottom) + add(leftSide, rightStart.top, rightStart.left, rightStart.bottom) } else { - add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); + add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom) } } if (leftEnd.bottom < rightStart.top) - add(leftSide, leftEnd.bottom, null, rightStart.top); + add(leftSide, leftEnd.bottom, null, rightStart.top) } - output.appendChild(fragment); + output.appendChild(fragment) } // Cursor-blinking export function restartBlink(cm) { - if (!cm.state.focused) return; - var display = cm.display; - clearInterval(display.blinker); - var on = true; - display.cursorDiv.style.visibility = ""; + if (!cm.state.focused) return + var display = cm.display + clearInterval(display.blinker) + var on = true + display.cursorDiv.style.visibility = "" if (cm.options.cursorBlinkRate > 0) display.blinker = setInterval(function() { - display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; - }, cm.options.cursorBlinkRate); + display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden" + }, cm.options.cursorBlinkRate) else if (cm.options.cursorBlinkRate < 0) - display.cursorDiv.style.visibility = "hidden"; + display.cursorDiv.style.visibility = "hidden" } diff --git a/src/display/update_display.js b/src/display/update_display.js index c69f75f9d4..06551eec8a 100644 --- a/src/display/update_display.js +++ b/src/display/update_display.js @@ -1,54 +1,54 @@ -import { sawCollapsedSpans } from "../line/saw_special_spans"; -import { heightAtLine, visualLineEndNo, visualLineNo } from "../line/spans"; -import { getLine, lineNumberFor } from "../line/utils_line"; -import { displayHeight, displayWidth, getDimensions, paddingVert, scrollGap } from "../measurement/position_measurement"; -import { buildLineElement, updateLineForChanges } from "../measurement/update_line"; -import { mac, webkit } from "../util/browser"; -import { activeElt, removeChildren } from "../util/dom"; -import { hasHandler, signal } from "../util/event"; -import { indexOf } from "../util/misc"; - -import { startWorker } from "./highlight_worker"; -import { maybeUpdateLineNumberWidth } from "./line_numbers"; -import { measureForScrollbars, updateScrollbars } from "./scrollbars"; -import { updateSelection } from "./selection"; -import { updateHeightsInViewport, visibleLines } from "./update_lines"; -import { adjustView, countDirtyView, resetView } from "./view_tracking"; +import { sawCollapsedSpans } from "../line/saw_special_spans" +import { heightAtLine, visualLineEndNo, visualLineNo } from "../line/spans" +import { getLine, lineNumberFor } from "../line/utils_line" +import { displayHeight, displayWidth, getDimensions, paddingVert, scrollGap } from "../measurement/position_measurement" +import { buildLineElement, updateLineForChanges } from "../measurement/update_line" +import { mac, webkit } from "../util/browser" +import { activeElt, removeChildren } from "../util/dom" +import { hasHandler, signal } from "../util/event" +import { indexOf } from "../util/misc" + +import { startWorker } from "./highlight_worker" +import { maybeUpdateLineNumberWidth } from "./line_numbers" +import { measureForScrollbars, updateScrollbars } from "./scrollbars" +import { updateSelection } from "./selection" +import { updateHeightsInViewport, visibleLines } from "./update_lines" +import { adjustView, countDirtyView, resetView } from "./view_tracking" // DISPLAY DRAWING export function DisplayUpdate(cm, viewport, force) { - var display = cm.display; + var display = cm.display - this.viewport = viewport; + this.viewport = viewport // Store some values that we'll need later (but don't want to force a relayout for) - this.visible = visibleLines(display, cm.doc, viewport); - this.editorIsHidden = !display.wrapper.offsetWidth; - this.wrapperHeight = display.wrapper.clientHeight; - this.wrapperWidth = display.wrapper.clientWidth; - this.oldDisplayWidth = displayWidth(cm); - this.force = force; - this.dims = getDimensions(cm); - this.events = []; + this.visible = visibleLines(display, cm.doc, viewport) + this.editorIsHidden = !display.wrapper.offsetWidth + this.wrapperHeight = display.wrapper.clientHeight + this.wrapperWidth = display.wrapper.clientWidth + this.oldDisplayWidth = displayWidth(cm) + this.force = force + this.dims = getDimensions(cm) + this.events = [] } DisplayUpdate.prototype.signal = function(emitter, type) { if (hasHandler(emitter, type)) - this.events.push(arguments); -}; + this.events.push(arguments) +} DisplayUpdate.prototype.finish = function() { for (var i = 0; i < this.events.length; i++) - signal.apply(null, this.events[i]); -}; + signal.apply(null, this.events[i]) +} export function maybeClipScrollbars(cm) { - var display = cm.display; + var display = cm.display if (!display.scrollbarsClipped && display.scroller.offsetWidth) { - display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth; - display.heightForcer.style.height = scrollGap(cm) + "px"; - display.sizer.style.marginBottom = -display.nativeBarWidth + "px"; - display.sizer.style.borderRightWidth = scrollGap(cm) + "px"; - display.scrollbarsClipped = true; + display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth + display.heightForcer.style.height = scrollGap(cm) + "px" + display.sizer.style.marginBottom = -display.nativeBarWidth + "px" + display.sizer.style.borderRightWidth = scrollGap(cm) + "px" + display.scrollbarsClipped = true } } @@ -56,11 +56,11 @@ export function maybeClipScrollbars(cm) { // (returning false) when there is nothing to be done and forced is // false. export function updateDisplayIfNeeded(cm, update) { - var display = cm.display, doc = cm.doc; + var display = cm.display, doc = cm.doc if (update.editorIsHidden) { - resetView(cm); - return false; + resetView(cm) + return false } // Bail out if the visible area is already rendered and nothing changed. @@ -68,104 +68,104 @@ export function updateDisplayIfNeeded(cm, update) { update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && display.renderedView == display.view && countDirtyView(cm) == 0) - return false; + return false if (maybeUpdateLineNumberWidth(cm)) { - resetView(cm); - update.dims = getDimensions(cm); + resetView(cm) + update.dims = getDimensions(cm) } // Compute a suitable new viewport (from & to) - var end = doc.first + doc.size; - var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first); - var to = Math.min(end, update.visible.to + cm.options.viewportMargin); - if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom); - if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo); + var end = doc.first + doc.size + var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first) + var to = Math.min(end, update.visible.to + cm.options.viewportMargin) + if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom) + if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo) if (sawCollapsedSpans) { - from = visualLineNo(cm.doc, from); - to = visualLineEndNo(cm.doc, to); + from = visualLineNo(cm.doc, from) + to = visualLineEndNo(cm.doc, to) } var different = from != display.viewFrom || to != display.viewTo || - display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth; - adjustView(cm, from, to); + display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth + adjustView(cm, from, to) - display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); + display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)) // Position the mover div to align with the current scroll position - cm.display.mover.style.top = display.viewOffset + "px"; + cm.display.mover.style.top = display.viewOffset + "px" - var toUpdate = countDirtyView(cm); + var toUpdate = countDirtyView(cm) if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) - return false; + return false // For big changes, we hide the enclosing element during the // update, since that speeds up the operations on most browsers. - var focused = activeElt(); - if (toUpdate > 4) display.lineDiv.style.display = "none"; - patchDisplay(cm, display.updateLineNumbers, update.dims); - if (toUpdate > 4) display.lineDiv.style.display = ""; - display.renderedView = display.view; + var focused = activeElt() + if (toUpdate > 4) display.lineDiv.style.display = "none" + patchDisplay(cm, display.updateLineNumbers, update.dims) + if (toUpdate > 4) display.lineDiv.style.display = "" + display.renderedView = display.view // There might have been a widget with a focused element that got // hidden or updated, if so re-focus it. - if (focused && activeElt() != focused && focused.offsetHeight) focused.focus(); + if (focused && activeElt() != focused && focused.offsetHeight) focused.focus() // Prevent selection and cursors from interfering with the scroll // width and height. - removeChildren(display.cursorDiv); - removeChildren(display.selectionDiv); - display.gutters.style.height = display.sizer.style.minHeight = 0; + removeChildren(display.cursorDiv) + removeChildren(display.selectionDiv) + display.gutters.style.height = display.sizer.style.minHeight = 0 if (different) { - display.lastWrapHeight = update.wrapperHeight; - display.lastWrapWidth = update.wrapperWidth; - startWorker(cm, 400); + display.lastWrapHeight = update.wrapperHeight + display.lastWrapWidth = update.wrapperWidth + startWorker(cm, 400) } - display.updateLineNumbers = null; + display.updateLineNumbers = null - return true; + return true } export function postUpdateDisplay(cm, update) { - var viewport = update.viewport; + var viewport = update.viewport for (var first = true;; first = false) { if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { // Clip forced viewport to actual scrollable area. if (viewport && viewport.top != null) - viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; + viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)} // Updated line heights might result in the drawn area not // actually covering the viewport. Keep looping until it does. - update.visible = visibleLines(cm.display, cm.doc, viewport); + update.visible = visibleLines(cm.display, cm.doc, viewport) if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) - break; + break } - if (!updateDisplayIfNeeded(cm, update)) break; - updateHeightsInViewport(cm); - var barMeasure = measureForScrollbars(cm); - updateSelection(cm); - updateScrollbars(cm, barMeasure); - setDocumentHeight(cm, barMeasure); + if (!updateDisplayIfNeeded(cm, update)) break + updateHeightsInViewport(cm) + var barMeasure = measureForScrollbars(cm) + updateSelection(cm) + updateScrollbars(cm, barMeasure) + setDocumentHeight(cm, barMeasure) } - update.signal(cm, "update", cm); + update.signal(cm, "update", cm) if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { - update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); - cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; + update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo) + cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo } } export function updateDisplaySimple(cm, viewport) { - var update = new DisplayUpdate(cm, viewport); + var update = new DisplayUpdate(cm, viewport) if (updateDisplayIfNeeded(cm, update)) { - updateHeightsInViewport(cm); - postUpdateDisplay(cm, update); - var barMeasure = measureForScrollbars(cm); - updateSelection(cm); - updateScrollbars(cm, barMeasure); - setDocumentHeight(cm, barMeasure); - update.finish(); + updateHeightsInViewport(cm) + postUpdateDisplay(cm, update) + var barMeasure = measureForScrollbars(cm) + updateSelection(cm) + updateScrollbars(cm, barMeasure) + setDocumentHeight(cm, barMeasure) + update.finish() } } @@ -174,54 +174,54 @@ export function updateDisplaySimple(cm, viewport) { // that are not there yet, and updating the ones that are out of // date. function patchDisplay(cm, updateNumbersFrom, dims) { - var display = cm.display, lineNumbers = cm.options.lineNumbers; - var container = display.lineDiv, cur = container.firstChild; + var display = cm.display, lineNumbers = cm.options.lineNumbers + var container = display.lineDiv, cur = container.firstChild function rm(node) { - var next = node.nextSibling; + var next = node.nextSibling // Works around a throw-scroll bug in OS X Webkit if (webkit && mac && cm.display.currentWheelTarget == node) - node.style.display = "none"; + node.style.display = "none" else - node.parentNode.removeChild(node); - return next; + node.parentNode.removeChild(node) + return next } - var view = display.view, lineN = display.viewFrom; + var view = display.view, lineN = display.viewFrom // Loop over the elements in the view, syncing cur (the DOM nodes // in display.lineDiv) with the view as we go. for (var i = 0; i < view.length; i++) { - var lineView = view[i]; + var lineView = view[i] if (lineView.hidden) { } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet - var node = buildLineElement(cm, lineView, lineN, dims); - container.insertBefore(node, cur); + var node = buildLineElement(cm, lineView, lineN, dims) + container.insertBefore(node, cur) } else { // Already drawn - while (cur != lineView.node) cur = rm(cur); + while (cur != lineView.node) cur = rm(cur) var updateNumber = lineNumbers && updateNumbersFrom != null && - updateNumbersFrom <= lineN && lineView.lineNumber; + updateNumbersFrom <= lineN && lineView.lineNumber if (lineView.changes) { - if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false; - updateLineForChanges(cm, lineView, lineN, dims); + if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false + updateLineForChanges(cm, lineView, lineN, dims) } if (updateNumber) { - removeChildren(lineView.lineNumber); - lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); + removeChildren(lineView.lineNumber) + lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))) } - cur = lineView.node.nextSibling; + cur = lineView.node.nextSibling } - lineN += lineView.size; + lineN += lineView.size } - while (cur) cur = rm(cur); + while (cur) cur = rm(cur) } export function updateGutterSpace(cm) { - var width = cm.display.gutters.offsetWidth; - cm.display.sizer.style.marginLeft = width + "px"; + var width = cm.display.gutters.offsetWidth + cm.display.sizer.style.marginLeft = width + "px" } export function setDocumentHeight(cm, measure) { - cm.display.sizer.style.minHeight = measure.docHeight + "px"; - cm.display.heightForcer.style.top = measure.docHeight + "px"; - cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px"; + cm.display.sizer.style.minHeight = measure.docHeight + "px" + cm.display.heightForcer.style.top = measure.docHeight + "px" + cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px" } diff --git a/src/display/update_lines.js b/src/display/update_lines.js index e10d8b9c1a..8de0698c6f 100644 --- a/src/display/update_lines.js +++ b/src/display/update_lines.js @@ -1,31 +1,31 @@ -import { heightAtLine } from "../line/spans"; -import { getLine, lineAtHeight, updateLineHeight } from "../line/utils_line"; -import { paddingTop, textHeight } from "../measurement/position_measurement"; -import { ie, ie_version } from "../util/browser"; +import { heightAtLine } from "../line/spans" +import { getLine, lineAtHeight, updateLineHeight } from "../line/utils_line" +import { paddingTop, textHeight } from "../measurement/position_measurement" +import { ie, ie_version } from "../util/browser" // Read the actual heights of the rendered lines, and update their // stored heights to match. export function updateHeightsInViewport(cm) { - var display = cm.display; - var prevBottom = display.lineDiv.offsetTop; + var display = cm.display + var prevBottom = display.lineDiv.offsetTop for (var i = 0; i < display.view.length; i++) { - var cur = display.view[i], height; - if (cur.hidden) continue; + var cur = display.view[i], height + if (cur.hidden) continue if (ie && ie_version < 8) { - var bot = cur.node.offsetTop + cur.node.offsetHeight; - height = bot - prevBottom; - prevBottom = bot; + var bot = cur.node.offsetTop + cur.node.offsetHeight + height = bot - prevBottom + prevBottom = bot } else { - var box = cur.node.getBoundingClientRect(); - height = box.bottom - box.top; + var box = cur.node.getBoundingClientRect() + height = box.bottom - box.top } - var diff = cur.line.height - height; - if (height < 2) height = textHeight(display); + var diff = cur.line.height - height + if (height < 2) height = textHeight(display) if (diff > .001 || diff < -.001) { - updateLineHeight(cur.line, height); - updateWidgetHeight(cur.line); + updateLineHeight(cur.line, height) + updateWidgetHeight(cur.line) if (cur.rest) for (var j = 0; j < cur.rest.length; j++) - updateWidgetHeight(cur.rest[j]); + updateWidgetHeight(cur.rest[j]) } } } @@ -34,29 +34,29 @@ export function updateHeightsInViewport(cm) { // given line. function updateWidgetHeight(line) { if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) - line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight; + line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight } // Compute the lines that are visible in a given viewport (defaults // the the current scroll position). viewport may contain top, // height, and ensure (see op.scrollToPos) properties. export function visibleLines(display, doc, viewport) { - var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop; - top = Math.floor(top - paddingTop(display)); - var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; + var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop + top = Math.floor(top - paddingTop(display)) + var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight - var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); + var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom) // Ensure is a {from: {line, ch}, to: {line, ch}} object, and // forces those lines into the viewport (if possible). if (viewport && viewport.ensure) { - var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; + var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line if (ensureFrom < from) { - from = ensureFrom; - to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight); + from = ensureFrom + to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight) } else if (Math.min(ensureTo, doc.lastLine()) >= to) { - from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight); - to = ensureTo; + from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight) + to = ensureTo } } - return {from: from, to: Math.max(to, from + 1)}; + return {from: from, to: Math.max(to, from + 1)} } diff --git a/src/display/view_tracking.js b/src/display/view_tracking.js index fd535178ce..d7ca682b1e 100644 --- a/src/display/view_tracking.js +++ b/src/display/view_tracking.js @@ -1,8 +1,8 @@ -import { buildViewArray } from "../line/line_data"; -import { sawCollapsedSpans } from "../line/saw_special_spans"; -import { visualLineEndNo, visualLineNo } from "../line/spans"; -import { findViewIndex } from "../measurement/position_measurement"; -import { indexOf } from "../util/misc"; +import { buildViewArray } from "../line/line_data" +import { sawCollapsedSpans } from "../line/saw_special_spans" +import { visualLineEndNo, visualLineNo } from "../line/spans" +import { findViewIndex } from "../measurement/position_measurement" +import { indexOf } from "../util/misc" // Updates the display.view data structure for a given change to the // document. From and to are in pre-change coordinates. Lendiff is @@ -11,142 +11,142 @@ import { indexOf } from "../util/misc"; // lines are divided into visual lines. regLineChange (below) // registers single-line changes. export function regChange(cm, from, to, lendiff) { - if (from == null) from = cm.doc.first; - if (to == null) to = cm.doc.first + cm.doc.size; - if (!lendiff) lendiff = 0; + if (from == null) from = cm.doc.first + if (to == null) to = cm.doc.first + cm.doc.size + if (!lendiff) lendiff = 0 - var display = cm.display; + var display = cm.display if (lendiff && to < display.viewTo && (display.updateLineNumbers == null || display.updateLineNumbers > from)) - display.updateLineNumbers = from; + display.updateLineNumbers = from - cm.curOp.viewChanged = true; + cm.curOp.viewChanged = true if (from >= display.viewTo) { // Change after if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) - resetView(cm); + resetView(cm) } else if (to <= display.viewFrom) { // Change before if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { - resetView(cm); + resetView(cm) } else { - display.viewFrom += lendiff; - display.viewTo += lendiff; + display.viewFrom += lendiff + display.viewTo += lendiff } } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap - resetView(cm); + resetView(cm) } else if (from <= display.viewFrom) { // Top overlap - var cut = viewCuttingPoint(cm, to, to + lendiff, 1); + var cut = viewCuttingPoint(cm, to, to + lendiff, 1) if (cut) { - display.view = display.view.slice(cut.index); - display.viewFrom = cut.lineN; - display.viewTo += lendiff; + display.view = display.view.slice(cut.index) + display.viewFrom = cut.lineN + display.viewTo += lendiff } else { - resetView(cm); + resetView(cm) } } else if (to >= display.viewTo) { // Bottom overlap - var cut = viewCuttingPoint(cm, from, from, -1); + var cut = viewCuttingPoint(cm, from, from, -1) if (cut) { - display.view = display.view.slice(0, cut.index); - display.viewTo = cut.lineN; + display.view = display.view.slice(0, cut.index) + display.viewTo = cut.lineN } else { - resetView(cm); + resetView(cm) } } else { // Gap in the middle - var cutTop = viewCuttingPoint(cm, from, from, -1); - var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); + var cutTop = viewCuttingPoint(cm, from, from, -1) + var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1) if (cutTop && cutBot) { display.view = display.view.slice(0, cutTop.index) .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) - .concat(display.view.slice(cutBot.index)); - display.viewTo += lendiff; + .concat(display.view.slice(cutBot.index)) + display.viewTo += lendiff } else { - resetView(cm); + resetView(cm) } } - var ext = display.externalMeasured; + var ext = display.externalMeasured if (ext) { if (to < ext.lineN) - ext.lineN += lendiff; + ext.lineN += lendiff else if (from < ext.lineN + ext.size) - display.externalMeasured = null; + display.externalMeasured = null } } // Register a change to a single line. Type must be one of "text", // "gutter", "class", "widget" export function regLineChange(cm, line, type) { - cm.curOp.viewChanged = true; - var display = cm.display, ext = cm.display.externalMeasured; + cm.curOp.viewChanged = true + var display = cm.display, ext = cm.display.externalMeasured if (ext && line >= ext.lineN && line < ext.lineN + ext.size) - display.externalMeasured = null; + display.externalMeasured = null - if (line < display.viewFrom || line >= display.viewTo) return; - var lineView = display.view[findViewIndex(cm, line)]; - if (lineView.node == null) return; - var arr = lineView.changes || (lineView.changes = []); - if (indexOf(arr, type) == -1) arr.push(type); + if (line < display.viewFrom || line >= display.viewTo) return + var lineView = display.view[findViewIndex(cm, line)] + if (lineView.node == null) return + var arr = lineView.changes || (lineView.changes = []) + if (indexOf(arr, type) == -1) arr.push(type) } // Clear the view. export function resetView(cm) { - cm.display.viewFrom = cm.display.viewTo = cm.doc.first; - cm.display.view = []; - cm.display.viewOffset = 0; + cm.display.viewFrom = cm.display.viewTo = cm.doc.first + cm.display.view = [] + cm.display.viewOffset = 0 } function viewCuttingPoint(cm, oldN, newN, dir) { - var index = findViewIndex(cm, oldN), diff, view = cm.display.view; + var index = findViewIndex(cm, oldN), diff, view = cm.display.view if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) - return {index: index, lineN: newN}; + return {index: index, lineN: newN} for (var i = 0, n = cm.display.viewFrom; i < index; i++) - n += view[i].size; + n += view[i].size if (n != oldN) { if (dir > 0) { - if (index == view.length - 1) return null; - diff = (n + view[index].size) - oldN; - index++; + if (index == view.length - 1) return null + diff = (n + view[index].size) - oldN + index++ } else { - diff = n - oldN; + diff = n - oldN } - oldN += diff; newN += diff; + oldN += diff; newN += diff } while (visualLineNo(cm.doc, newN) != newN) { - if (index == (dir < 0 ? 0 : view.length - 1)) return null; - newN += dir * view[index - (dir < 0 ? 1 : 0)].size; - index += dir; + if (index == (dir < 0 ? 0 : view.length - 1)) return null + newN += dir * view[index - (dir < 0 ? 1 : 0)].size + index += dir } - return {index: index, lineN: newN}; + return {index: index, lineN: newN} } // Force the view to cover a given range, adding empty view element // or clipping off existing ones as needed. export function adjustView(cm, from, to) { - var display = cm.display, view = display.view; + var display = cm.display, view = display.view if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { - display.view = buildViewArray(cm, from, to); - display.viewFrom = from; + display.view = buildViewArray(cm, from, to) + display.viewFrom = from } else { if (display.viewFrom > from) - display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); + display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view) else if (display.viewFrom < from) - display.view = display.view.slice(findViewIndex(cm, from)); - display.viewFrom = from; + display.view = display.view.slice(findViewIndex(cm, from)) + display.viewFrom = from if (display.viewTo < to) - display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); + display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)) else if (display.viewTo > to) - display.view = display.view.slice(0, findViewIndex(cm, to)); + display.view = display.view.slice(0, findViewIndex(cm, to)) } - display.viewTo = to; + display.viewTo = to } // Count the number of lines in the view whose DOM representation is // out of date (or nonexistent). export function countDirtyView(cm) { - var view = cm.display.view, dirty = 0; + var view = cm.display.view, dirty = 0 for (var i = 0; i < view.length; i++) { - var lineView = view[i]; - if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty; + var lineView = view[i] + if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty } - return dirty; + return dirty } diff --git a/src/edit/CodeMirror.js b/src/edit/CodeMirror.js index 7bd6a60a50..ee549d54c8 100644 --- a/src/edit/CodeMirror.js +++ b/src/edit/CodeMirror.js @@ -1,52 +1,52 @@ -import { Display } from "../display/Display"; -import { onFocus, onBlur } from "../display/focus"; -import { setGuttersForLineNumbers, updateGutters } from "../display/gutters"; -import { maybeUpdateLineNumberWidth } from "../display/line_numbers"; -import { endOperation, operation, startOperation } from "../display/operations"; -import { initScrollbars } from "../display/scrollbars"; -import { onScrollWheel, setScrollLeft, setScrollTop } from "../display/scroll_events"; -import { clipPos, Pos } from "../line/pos"; -import { posFromMouse } from "../measurement/position_measurement"; -import { eventInWidget } from "../measurement/widgets"; -import Doc from "../model/Doc"; -import { attachDoc } from "../model/document_data"; -import { Range } from "../model/selection"; -import { extendSelection } from "../model/selection_updates"; -import { captureRightClick, ie, ie_version, mobile, webkit } from "../util/browser"; -import { e_preventDefault, e_stop, on, signal, signalDOMEvent } from "../util/event"; -import { bind, copyObj, Delayed } from "../util/misc"; - -import { clearDragCursor, onDragOver, onDragStart, onDrop } from "./drop_events"; -import { ensureGlobalHandlers } from "./global_events"; -import { onKeyDown, onKeyPress, onKeyUp } from "./key_events"; -import { clickInGutter, onContextMenu, onMouseDown } from "./mouse_events"; -import { themeChanged } from "./utils"; -import { defaults, optionHandlers, Init } from "./options"; +import { Display } from "../display/Display" +import { onFocus, onBlur } from "../display/focus" +import { setGuttersForLineNumbers, updateGutters } from "../display/gutters" +import { maybeUpdateLineNumberWidth } from "../display/line_numbers" +import { endOperation, operation, startOperation } from "../display/operations" +import { initScrollbars } from "../display/scrollbars" +import { onScrollWheel, setScrollLeft, setScrollTop } from "../display/scroll_events" +import { clipPos, Pos } from "../line/pos" +import { posFromMouse } from "../measurement/position_measurement" +import { eventInWidget } from "../measurement/widgets" +import Doc from "../model/Doc" +import { attachDoc } from "../model/document_data" +import { Range } from "../model/selection" +import { extendSelection } from "../model/selection_updates" +import { captureRightClick, ie, ie_version, mobile, webkit } from "../util/browser" +import { e_preventDefault, e_stop, on, signal, signalDOMEvent } from "../util/event" +import { bind, copyObj, Delayed } from "../util/misc" + +import { clearDragCursor, onDragOver, onDragStart, onDrop } from "./drop_events" +import { ensureGlobalHandlers } from "./global_events" +import { onKeyDown, onKeyPress, onKeyUp } from "./key_events" +import { clickInGutter, onContextMenu, onMouseDown } from "./mouse_events" +import { themeChanged } from "./utils" +import { defaults, optionHandlers, Init } from "./options" // A CodeMirror instance represents an editor. This is the object // that user code is usually dealing with. export function CodeMirror(place, options) { - if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); + if (!(this instanceof CodeMirror)) return new CodeMirror(place, options) - this.options = options = options ? copyObj(options) : {}; + this.options = options = options ? copyObj(options) : {} // Determine effective options based on given values and defaults. - copyObj(defaults, options, false); - setGuttersForLineNumbers(options); - - var doc = options.value; - if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator); - this.doc = doc; - - var input = new CodeMirror.inputStyles[options.inputStyle](this); - var display = this.display = new Display(place, doc, input); - display.wrapper.CodeMirror = this; - updateGutters(this); - themeChanged(this); + copyObj(defaults, options, false) + setGuttersForLineNumbers(options) + + var doc = options.value + if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator) + this.doc = doc + + var input = new CodeMirror.inputStyles[options.inputStyle](this) + var display = this.display = new Display(place, doc, input) + display.wrapper.CodeMirror = this + updateGutters(this) + themeChanged(this) if (options.lineWrapping) - this.display.wrapper.className += " CodeMirror-wrap"; - if (options.autofocus && !mobile) display.input.focus(); - initScrollbars(this); + this.display.wrapper.className += " CodeMirror-wrap" + if (options.autofocus && !mobile) display.input.focus() + initScrollbars(this) this.state = { keyMaps: [], // stores maps added by addKeyMap @@ -62,152 +62,152 @@ export function CodeMirror(place, options) { highlight: new Delayed(), // stores highlight worker timeout keySeq: null, // Unfinished key sequence specialChars: null - }; + } - var cm = this; + var cm = this // Override magic textarea content restore that IE sometimes does // on our hidden textarea on reload - if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20); + if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true) }, 20) - registerEventHandlers(this); - ensureGlobalHandlers(); + registerEventHandlers(this) + ensureGlobalHandlers() - startOperation(this); - this.curOp.forceUpdate = true; - attachDoc(this, doc); + startOperation(this) + this.curOp.forceUpdate = true + attachDoc(this, doc) if ((options.autofocus && !mobile) || cm.hasFocus()) - setTimeout(bind(onFocus, this), 20); + setTimeout(bind(onFocus, this), 20) else - onBlur(this); + onBlur(this) for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) - optionHandlers[opt](this, options[opt], Init); - maybeUpdateLineNumberWidth(this); - if (options.finishInit) options.finishInit(this); - for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); - endOperation(this); + optionHandlers[opt](this, options[opt], Init) + maybeUpdateLineNumberWidth(this) + if (options.finishInit) options.finishInit(this) + for (var i = 0; i < initHooks.length; ++i) initHooks[i](this) + endOperation(this) // Suppress optimizelegibility in Webkit, since it breaks text // measuring on line wrapping boundaries. if (webkit && options.lineWrapping && getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") - display.lineDiv.style.textRendering = "auto"; + display.lineDiv.style.textRendering = "auto" } // The default configuration options. -CodeMirror.defaults = defaults; +CodeMirror.defaults = defaults // Functions to run when options are changed. -CodeMirror.optionHandlers = optionHandlers; +CodeMirror.optionHandlers = optionHandlers -export default CodeMirror; +export default CodeMirror // Attach the necessary event handlers when initializing the editor function registerEventHandlers(cm) { - var d = cm.display; - on(d.scroller, "mousedown", operation(cm, onMouseDown)); + var d = cm.display + on(d.scroller, "mousedown", operation(cm, onMouseDown)) // Older IE's will not fire a second mousedown for a double click if (ie && ie_version < 11) on(d.scroller, "dblclick", operation(cm, function(e) { - if (signalDOMEvent(cm, e)) return; - var pos = posFromMouse(cm, e); - if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; - e_preventDefault(e); - var word = cm.findWordAt(pos); - extendSelection(cm.doc, word.anchor, word.head); - })); + if (signalDOMEvent(cm, e)) return + var pos = posFromMouse(cm, e) + if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return + e_preventDefault(e) + var word = cm.findWordAt(pos) + extendSelection(cm.doc, word.anchor, word.head) + })) else - on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); }); + on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e) }) // Some browsers fire contextmenu *after* opening the menu, at // which point we can't mess with it anymore. Context menu is // handled in onMouseDown for these browsers. - if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); + if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e)}) // Used to suppress mouse event handling when a touch happens - var touchFinished, prevTouch = {end: 0}; + var touchFinished, prevTouch = {end: 0} function finishTouch() { if (d.activeTouch) { - touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000); - prevTouch = d.activeTouch; - prevTouch.end = +new Date; + touchFinished = setTimeout(function() {d.activeTouch = null}, 1000) + prevTouch = d.activeTouch + prevTouch.end = +new Date } } function isMouseLikeTouchEvent(e) { - if (e.touches.length != 1) return false; - var touch = e.touches[0]; - return touch.radiusX <= 1 && touch.radiusY <= 1; + if (e.touches.length != 1) return false + var touch = e.touches[0] + return touch.radiusX <= 1 && touch.radiusY <= 1 } function farAway(touch, other) { - if (other.left == null) return true; - var dx = other.left - touch.left, dy = other.top - touch.top; - return dx * dx + dy * dy > 20 * 20; + if (other.left == null) return true + var dx = other.left - touch.left, dy = other.top - touch.top + return dx * dx + dy * dy > 20 * 20 } on(d.scroller, "touchstart", function(e) { if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) { - clearTimeout(touchFinished); - var now = +new Date; + clearTimeout(touchFinished) + var now = +new Date d.activeTouch = {start: now, moved: false, - prev: now - prevTouch.end <= 300 ? prevTouch : null}; + prev: now - prevTouch.end <= 300 ? prevTouch : null} if (e.touches.length == 1) { - d.activeTouch.left = e.touches[0].pageX; - d.activeTouch.top = e.touches[0].pageY; + d.activeTouch.left = e.touches[0].pageX + d.activeTouch.top = e.touches[0].pageY } } - }); + }) on(d.scroller, "touchmove", function() { - if (d.activeTouch) d.activeTouch.moved = true; - }); + if (d.activeTouch) d.activeTouch.moved = true + }) on(d.scroller, "touchend", function(e) { - var touch = d.activeTouch; + var touch = d.activeTouch if (touch && !eventInWidget(d, e) && touch.left != null && !touch.moved && new Date - touch.start < 300) { - var pos = cm.coordsChar(d.activeTouch, "page"), range; + var pos = cm.coordsChar(d.activeTouch, "page"), range if (!touch.prev || farAway(touch, touch.prev)) // Single tap - range = new Range(pos, pos); + range = new Range(pos, pos) else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap - range = cm.findWordAt(pos); + range = cm.findWordAt(pos) else // Triple tap - range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); - cm.setSelection(range.anchor, range.head); - cm.focus(); - e_preventDefault(e); + range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) + cm.setSelection(range.anchor, range.head) + cm.focus() + e_preventDefault(e) } - finishTouch(); - }); - on(d.scroller, "touchcancel", finishTouch); + finishTouch() + }) + on(d.scroller, "touchcancel", finishTouch) // Sync scrolling between fake scrollbars and real scrollable // area, ensure viewport is updated when scrolling. on(d.scroller, "scroll", function() { if (d.scroller.clientHeight) { - setScrollTop(cm, d.scroller.scrollTop); - setScrollLeft(cm, d.scroller.scrollLeft, true); - signal(cm, "scroll", cm); + setScrollTop(cm, d.scroller.scrollTop) + setScrollLeft(cm, d.scroller.scrollLeft, true) + signal(cm, "scroll", cm) } - }); + }) // Listen to wheel events in order to try and update the viewport on time. - on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); - on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); + on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e)}) + on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e)}) // Prevent wrapper from ever scrolling - on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); + on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0 }) d.dragFunctions = { - enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);}, - over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }}, - start: function(e){onDragStart(cm, e);}, + enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e)}, + over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e) }}, + start: function(e){onDragStart(cm, e)}, drop: operation(cm, onDrop), - leave: function(e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }} - }; - - var inp = d.input.getField(); - on(inp, "keyup", function(e) { onKeyUp.call(cm, e); }); - on(inp, "keydown", operation(cm, onKeyDown)); - on(inp, "keypress", operation(cm, onKeyPress)); - on(inp, "focus", function(e) { onFocus(cm, e); }); - on(inp, "blur", function (e) { onBlur(cm, e); }); + leave: function(e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm) }} + } + + var inp = d.input.getField() + on(inp, "keyup", function(e) { onKeyUp.call(cm, e) }) + on(inp, "keydown", operation(cm, onKeyDown)) + on(inp, "keypress", operation(cm, onKeyPress)) + on(inp, "focus", function(e) { onFocus(cm, e) }) + on(inp, "blur", function (e) { onBlur(cm, e) }) } -var initHooks = []; -CodeMirror.defineInitHook = function(f) {initHooks.push(f);}; +var initHooks = [] +CodeMirror.defineInitHook = function(f) {initHooks.push(f)} diff --git a/src/edit/commands.js b/src/edit/commands.js index 3e8735ec13..2d670ab516 100644 --- a/src/edit/commands.js +++ b/src/edit/commands.js @@ -1,156 +1,156 @@ -import { deleteNearSelection } from "./deleteNearSelection"; -import { runInOp } from "../display/operations"; -import { ensureCursorVisible } from "../display/scrolling"; -import { clipPos, Pos } from "../line/pos"; -import { collapsedSpanAtEnd, visualLine } from "../line/spans"; -import { getLine, lineNo } from "../line/utils_line"; -import { Range } from "../model/selection"; -import { selectAll } from "../model/selection_updates"; -import { countColumn, sel_dontScroll, sel_move, spaceStr } from "../util/misc"; -import { getOrder, lineLeft, lineRight } from "../util/bidi"; +import { deleteNearSelection } from "./deleteNearSelection" +import { runInOp } from "../display/operations" +import { ensureCursorVisible } from "../display/scrolling" +import { clipPos, Pos } from "../line/pos" +import { collapsedSpanAtEnd, visualLine } from "../line/spans" +import { getLine, lineNo } from "../line/utils_line" +import { Range } from "../model/selection" +import { selectAll } from "../model/selection_updates" +import { countColumn, sel_dontScroll, sel_move, spaceStr } from "../util/misc" +import { getOrder, lineLeft, lineRight } from "../util/bidi" // Commands are parameter-less actions that can be performed on an // editor, mostly used for keybindings. export var commands = { selectAll: selectAll, singleSelection: function(cm) { - cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); + cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll) }, killLine: function(cm) { deleteNearSelection(cm, function(range) { if (range.empty()) { - var len = getLine(cm.doc, range.head.line).text.length; + var len = getLine(cm.doc, range.head.line).text.length if (range.head.ch == len && range.head.line < cm.lastLine()) - return {from: range.head, to: Pos(range.head.line + 1, 0)}; + return {from: range.head, to: Pos(range.head.line + 1, 0)} else - return {from: range.head, to: Pos(range.head.line, len)}; + return {from: range.head, to: Pos(range.head.line, len)} } else { - return {from: range.from(), to: range.to()}; + return {from: range.from(), to: range.to()} } - }); + }) }, deleteLine: function(cm) { deleteNearSelection(cm, function(range) { return {from: Pos(range.from().line, 0), - to: clipPos(cm.doc, Pos(range.to().line + 1, 0))}; - }); + to: clipPos(cm.doc, Pos(range.to().line + 1, 0))} + }) }, delLineLeft: function(cm) { deleteNearSelection(cm, function(range) { - return {from: Pos(range.from().line, 0), to: range.from()}; - }); + return {from: Pos(range.from().line, 0), to: range.from()} + }) }, delWrappedLineLeft: function(cm) { deleteNearSelection(cm, function(range) { - var top = cm.charCoords(range.head, "div").top + 5; - var leftPos = cm.coordsChar({left: 0, top: top}, "div"); - return {from: leftPos, to: range.from()}; - }); + var top = cm.charCoords(range.head, "div").top + 5 + var leftPos = cm.coordsChar({left: 0, top: top}, "div") + return {from: leftPos, to: range.from()} + }) }, delWrappedLineRight: function(cm) { deleteNearSelection(cm, function(range) { - var top = cm.charCoords(range.head, "div").top + 5; - var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); - return {from: range.from(), to: rightPos }; - }); - }, - undo: function(cm) {cm.undo();}, - redo: function(cm) {cm.redo();}, - undoSelection: function(cm) {cm.undoSelection();}, - redoSelection: function(cm) {cm.redoSelection();}, - goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));}, - goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));}, + var top = cm.charCoords(range.head, "div").top + 5 + var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") + return {from: range.from(), to: rightPos } + }) + }, + undo: function(cm) {cm.undo()}, + redo: function(cm) {cm.redo()}, + undoSelection: function(cm) {cm.undoSelection()}, + redoSelection: function(cm) {cm.redoSelection()}, + goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0))}, + goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()))}, goLineStart: function(cm) { - cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); }, - {origin: "+move", bias: 1}); + cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line) }, + {origin: "+move", bias: 1}) }, goLineStartSmart: function(cm) { cm.extendSelectionsBy(function(range) { - return lineStartSmart(cm, range.head); - }, {origin: "+move", bias: 1}); + return lineStartSmart(cm, range.head) + }, {origin: "+move", bias: 1}) }, goLineEnd: function(cm) { - cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); }, - {origin: "+move", bias: -1}); + cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line) }, + {origin: "+move", bias: -1}) }, goLineRight: function(cm) { cm.extendSelectionsBy(function(range) { - var top = cm.charCoords(range.head, "div").top + 5; - return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); - }, sel_move); + var top = cm.charCoords(range.head, "div").top + 5 + return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") + }, sel_move) }, goLineLeft: function(cm) { cm.extendSelectionsBy(function(range) { - var top = cm.charCoords(range.head, "div").top + 5; - return cm.coordsChar({left: 0, top: top}, "div"); - }, sel_move); + var top = cm.charCoords(range.head, "div").top + 5 + return cm.coordsChar({left: 0, top: top}, "div") + }, sel_move) }, goLineLeftSmart: function(cm) { cm.extendSelectionsBy(function(range) { - var top = cm.charCoords(range.head, "div").top + 5; - var pos = cm.coordsChar({left: 0, top: top}, "div"); - if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head); - return pos; - }, sel_move); - }, - goLineUp: function(cm) {cm.moveV(-1, "line");}, - goLineDown: function(cm) {cm.moveV(1, "line");}, - goPageUp: function(cm) {cm.moveV(-1, "page");}, - goPageDown: function(cm) {cm.moveV(1, "page");}, - goCharLeft: function(cm) {cm.moveH(-1, "char");}, - goCharRight: function(cm) {cm.moveH(1, "char");}, - goColumnLeft: function(cm) {cm.moveH(-1, "column");}, - goColumnRight: function(cm) {cm.moveH(1, "column");}, - goWordLeft: function(cm) {cm.moveH(-1, "word");}, - goGroupRight: function(cm) {cm.moveH(1, "group");}, - goGroupLeft: function(cm) {cm.moveH(-1, "group");}, - goWordRight: function(cm) {cm.moveH(1, "word");}, - delCharBefore: function(cm) {cm.deleteH(-1, "char");}, - delCharAfter: function(cm) {cm.deleteH(1, "char");}, - delWordBefore: function(cm) {cm.deleteH(-1, "word");}, - delWordAfter: function(cm) {cm.deleteH(1, "word");}, - delGroupBefore: function(cm) {cm.deleteH(-1, "group");}, - delGroupAfter: function(cm) {cm.deleteH(1, "group");}, - indentAuto: function(cm) {cm.indentSelection("smart");}, - indentMore: function(cm) {cm.indentSelection("add");}, - indentLess: function(cm) {cm.indentSelection("subtract");}, - insertTab: function(cm) {cm.replaceSelection("\t");}, + var top = cm.charCoords(range.head, "div").top + 5 + var pos = cm.coordsChar({left: 0, top: top}, "div") + if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head) + return pos + }, sel_move) + }, + goLineUp: function(cm) {cm.moveV(-1, "line")}, + goLineDown: function(cm) {cm.moveV(1, "line")}, + goPageUp: function(cm) {cm.moveV(-1, "page")}, + goPageDown: function(cm) {cm.moveV(1, "page")}, + goCharLeft: function(cm) {cm.moveH(-1, "char")}, + goCharRight: function(cm) {cm.moveH(1, "char")}, + goColumnLeft: function(cm) {cm.moveH(-1, "column")}, + goColumnRight: function(cm) {cm.moveH(1, "column")}, + goWordLeft: function(cm) {cm.moveH(-1, "word")}, + goGroupRight: function(cm) {cm.moveH(1, "group")}, + goGroupLeft: function(cm) {cm.moveH(-1, "group")}, + goWordRight: function(cm) {cm.moveH(1, "word")}, + delCharBefore: function(cm) {cm.deleteH(-1, "char")}, + delCharAfter: function(cm) {cm.deleteH(1, "char")}, + delWordBefore: function(cm) {cm.deleteH(-1, "word")}, + delWordAfter: function(cm) {cm.deleteH(1, "word")}, + delGroupBefore: function(cm) {cm.deleteH(-1, "group")}, + delGroupAfter: function(cm) {cm.deleteH(1, "group")}, + indentAuto: function(cm) {cm.indentSelection("smart")}, + indentMore: function(cm) {cm.indentSelection("add")}, + indentLess: function(cm) {cm.indentSelection("subtract")}, + insertTab: function(cm) {cm.replaceSelection("\t")}, insertSoftTab: function(cm) { - var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; + var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize for (var i = 0; i < ranges.length; i++) { - var pos = ranges[i].from(); - var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); - spaces.push(spaceStr(tabSize - col % tabSize)); + var pos = ranges[i].from() + var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize) + spaces.push(spaceStr(tabSize - col % tabSize)) } - cm.replaceSelections(spaces); + cm.replaceSelections(spaces) }, defaultTab: function(cm) { - if (cm.somethingSelected()) cm.indentSelection("add"); - else cm.execCommand("insertTab"); + if (cm.somethingSelected()) cm.indentSelection("add") + else cm.execCommand("insertTab") }, transposeChars: function(cm) { runInOp(cm, function() { - var ranges = cm.listSelections(), newSel = []; + var ranges = cm.listSelections(), newSel = [] for (var i = 0; i < ranges.length; i++) { - var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; + var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text if (line) { - if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1); + if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1) if (cur.ch > 0) { - cur = new Pos(cur.line, cur.ch + 1); + cur = new Pos(cur.line, cur.ch + 1) cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), - Pos(cur.line, cur.ch - 2), cur, "+transpose"); + Pos(cur.line, cur.ch - 2), cur, "+transpose") } else if (cur.line > cm.doc.first) { - var prev = getLine(cm.doc, cur.line - 1).text; + var prev = getLine(cm.doc, cur.line - 1).text if (prev) cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + prev.charAt(prev.length - 1), - Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose"); + Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose") } } - newSel.push(new Range(cur, cur)); + newSel.push(new Range(cur, cur)) } - cm.setSelections(newSel); - }); + cm.setSelections(newSel) + }) }, newlineAndIndent: function(cm) { runInOp(cm, function() { @@ -160,40 +160,40 @@ export var commands = { sels = cm.listSelections() for (var i = 0; i < sels.length; i++) cm.indentLine(sels[i].from().line, null, true) - ensureCursorVisible(cm); - }); + ensureCursorVisible(cm) + }) }, openLine: function(cm) {cm.replaceSelection("\n", "start")}, - toggleOverwrite: function(cm) {cm.toggleOverwrite();} -}; + toggleOverwrite: function(cm) {cm.toggleOverwrite()} +} function lineStart(cm, lineN) { - var line = getLine(cm.doc, lineN); - var visual = visualLine(line); - if (visual != line) lineN = lineNo(visual); - var order = getOrder(visual); - var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); - return Pos(lineN, ch); + var line = getLine(cm.doc, lineN) + var visual = visualLine(line) + if (visual != line) lineN = lineNo(visual) + var order = getOrder(visual) + var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual) + return Pos(lineN, ch) } function lineEnd(cm, lineN) { - var merged, line = getLine(cm.doc, lineN); + var merged, line = getLine(cm.doc, lineN) while (merged = collapsedSpanAtEnd(line)) { - line = merged.find(1, true).line; - lineN = null; + line = merged.find(1, true).line + lineN = null } - var order = getOrder(line); - var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); - return Pos(lineN == null ? lineNo(line) : lineN, ch); + var order = getOrder(line) + var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line) + return Pos(lineN == null ? lineNo(line) : lineN, ch) } function lineStartSmart(cm, pos) { - var start = lineStart(cm, pos.line); - var line = getLine(cm.doc, start.line); - var order = getOrder(line); + var start = lineStart(cm, pos.line) + var line = getLine(cm.doc, start.line) + var order = getOrder(line) if (!order || order[0].level == 0) { - var firstNonWS = Math.max(0, line.text.search(/\S/)); - var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; - return Pos(start.line, inWS ? 0 : firstNonWS); + var firstNonWS = Math.max(0, line.text.search(/\S/)) + var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch + return Pos(start.line, inWS ? 0 : firstNonWS) } - return start; + return start } diff --git a/src/edit/deleteNearSelection.js b/src/edit/deleteNearSelection.js index dd1369026c..00b4aa08b9 100644 --- a/src/edit/deleteNearSelection.js +++ b/src/edit/deleteNearSelection.js @@ -1,30 +1,30 @@ -import { runInOp } from "../display/operations"; -import { ensureCursorVisible } from "../display/scrolling"; -import { cmp } from "../line/pos"; -import { replaceRange } from "../model/changes"; -import { lst } from "../util/misc"; +import { runInOp } from "../display/operations" +import { ensureCursorVisible } from "../display/scrolling" +import { cmp } from "../line/pos" +import { replaceRange } from "../model/changes" +import { lst } from "../util/misc" // Helper for deleting text near the selection(s), used to implement // backspace, delete, and similar functionality. export function deleteNearSelection(cm, compute) { - var ranges = cm.doc.sel.ranges, kill = []; + var ranges = cm.doc.sel.ranges, kill = [] // Build up a set of ranges to kill first, merging overlapping // ranges. for (var i = 0; i < ranges.length; i++) { - var toKill = compute(ranges[i]); + var toKill = compute(ranges[i]) while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { - var replaced = kill.pop(); + var replaced = kill.pop() if (cmp(replaced.from, toKill.from) < 0) { - toKill.from = replaced.from; - break; + toKill.from = replaced.from + break } } - kill.push(toKill); + kill.push(toKill) } // Next, remove those actual ranges. runInOp(cm, function() { for (var i = kill.length - 1; i >= 0; i--) - replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); - ensureCursorVisible(cm); - }); + replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete") + ensureCursorVisible(cm) + }) } diff --git a/src/edit/drop_events.js b/src/edit/drop_events.js index fac58a266e..d2aeaa7cef 100644 --- a/src/edit/drop_events.js +++ b/src/edit/drop_events.js @@ -1,74 +1,74 @@ -import { drawSelectionCursor } from "../display/selection"; -import { operation } from "../display/operations"; -import { clipPos } from "../line/pos"; -import { posFromMouse } from "../measurement/position_measurement"; -import { eventInWidget } from "../measurement/widgets"; -import { makeChange, replaceRange } from "../model/changes"; -import { changeEnd } from "../model/change_measurement"; -import { simpleSelection } from "../model/selection"; -import { setSelectionNoUndo, setSelectionReplaceHistory } from "../model/selection_updates"; -import { ie, presto, safari } from "../util/browser"; -import { elt, removeChildrenAndAdd } from "../util/dom"; -import { e_preventDefault, e_stop, signalDOMEvent } from "../util/event"; -import { indexOf } from "../util/misc"; +import { drawSelectionCursor } from "../display/selection" +import { operation } from "../display/operations" +import { clipPos } from "../line/pos" +import { posFromMouse } from "../measurement/position_measurement" +import { eventInWidget } from "../measurement/widgets" +import { makeChange, replaceRange } from "../model/changes" +import { changeEnd } from "../model/change_measurement" +import { simpleSelection } from "../model/selection" +import { setSelectionNoUndo, setSelectionReplaceHistory } from "../model/selection_updates" +import { ie, presto, safari } from "../util/browser" +import { elt, removeChildrenAndAdd } from "../util/dom" +import { e_preventDefault, e_stop, signalDOMEvent } from "../util/event" +import { indexOf } from "../util/misc" // Kludge to work around strange IE behavior where it'll sometimes // re-fire a series of drag-related events right after the drop (#1551) -var lastDrop = 0; +var lastDrop = 0 export function onDrop(e) { - var cm = this; - clearDragCursor(cm); + var cm = this + clearDragCursor(cm) if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) - return; - e_preventDefault(e); - if (ie) lastDrop = +new Date; - var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; - if (!pos || cm.isReadOnly()) return; + return + e_preventDefault(e) + if (ie) lastDrop = +new Date + var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files + if (!pos || cm.isReadOnly()) return // Might be a file drop, in which case we simply extract the text // and insert it. if (files && files.length && window.FileReader && window.File) { - var n = files.length, text = Array(n), read = 0; + var n = files.length, text = Array(n), read = 0 var loadFile = function(file, i) { if (cm.options.allowDropFileTypes && indexOf(cm.options.allowDropFileTypes, file.type) == -1) - return; + return - var reader = new FileReader; + var reader = new FileReader reader.onload = operation(cm, function() { - var content = reader.result; - if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = ""; - text[i] = content; + var content = reader.result + if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "" + text[i] = content if (++read == n) { - pos = clipPos(cm.doc, pos); + pos = clipPos(cm.doc, pos) var change = {from: pos, to: pos, text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), - origin: "paste"}; - makeChange(cm.doc, change); - setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); + origin: "paste"} + makeChange(cm.doc, change) + setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))) } - }); - reader.readAsText(file); - }; - for (var i = 0; i < n; ++i) loadFile(files[i], i); + }) + reader.readAsText(file) + } + for (var i = 0; i < n; ++i) loadFile(files[i], i) } else { // Normal drop // Don't do a replace if the drop happened inside of the selected text. if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { - cm.state.draggingText(e); + cm.state.draggingText(e) // Ensure the editor is re-focused - setTimeout(function() {cm.display.input.focus();}, 20); - return; + setTimeout(function() {cm.display.input.focus()}, 20) + return } try { - var text = e.dataTransfer.getData("Text"); + var text = e.dataTransfer.getData("Text") if (text) { if (cm.state.draggingText && !cm.state.draggingText.copy) - var selected = cm.listSelections(); - setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); + var selected = cm.listSelections() + setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)) if (selected) for (var i = 0; i < selected.length; ++i) - replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag"); - cm.replaceSelection(text, "around", "paste"); - cm.display.input.focus(); + replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag") + cm.replaceSelection(text, "around", "paste") + cm.display.input.focus() } } catch(e){} @@ -76,43 +76,43 @@ export function onDrop(e) { } export function onDragStart(cm, e) { - if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } - if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; + if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return } + if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return - e.dataTransfer.setData("Text", cm.getSelection()); + e.dataTransfer.setData("Text", cm.getSelection()) e.dataTransfer.effectAllowed = "copyMove" // Use dummy image instead of default browsers image. // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. if (e.dataTransfer.setDragImage && !safari) { - var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); - img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; + var img = elt("img", null, null, "position: fixed; left: 0; top: 0;") + img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" if (presto) { - img.width = img.height = 1; - cm.display.wrapper.appendChild(img); + img.width = img.height = 1 + cm.display.wrapper.appendChild(img) // Force a relayout, or Opera won't use our image for some obscure reason - img._top = img.offsetTop; + img._top = img.offsetTop } - e.dataTransfer.setDragImage(img, 0, 0); - if (presto) img.parentNode.removeChild(img); + e.dataTransfer.setDragImage(img, 0, 0) + if (presto) img.parentNode.removeChild(img) } } export function onDragOver(cm, e) { - var pos = posFromMouse(cm, e); - if (!pos) return; - var frag = document.createDocumentFragment(); - drawSelectionCursor(cm, pos, frag); + var pos = posFromMouse(cm, e) + if (!pos) return + var frag = document.createDocumentFragment() + drawSelectionCursor(cm, pos, frag) if (!cm.display.dragCursor) { - cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors"); - cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv); + cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors") + cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv) } - removeChildrenAndAdd(cm.display.dragCursor, frag); + removeChildrenAndAdd(cm.display.dragCursor, frag) } export function clearDragCursor(cm) { if (cm.display.dragCursor) { - cm.display.lineSpace.removeChild(cm.display.dragCursor); - cm.display.dragCursor = null; + cm.display.lineSpace.removeChild(cm.display.dragCursor) + cm.display.dragCursor = null } } diff --git a/src/edit/fromTextArea.js b/src/edit/fromTextArea.js index aa1a040fa9..dda26d4bff 100644 --- a/src/edit/fromTextArea.js +++ b/src/edit/fromTextArea.js @@ -1,59 +1,59 @@ -import { CodeMirror } from "./CodeMirror"; -import { activeElt } from "../util/dom"; -import { off, on } from "../util/event"; -import { copyObj } from "../util/misc"; +import { CodeMirror } from "./CodeMirror" +import { activeElt } from "../util/dom" +import { off, on } from "../util/event" +import { copyObj } from "../util/misc" export function fromTextArea(textarea, options) { - options = options ? copyObj(options) : {}; - options.value = textarea.value; + options = options ? copyObj(options) : {} + options.value = textarea.value if (!options.tabindex && textarea.tabIndex) - options.tabindex = textarea.tabIndex; + options.tabindex = textarea.tabIndex if (!options.placeholder && textarea.placeholder) - options.placeholder = textarea.placeholder; + options.placeholder = textarea.placeholder // Set autofocus to true if this textarea is focused, or if it has // autofocus and no other element is focused. if (options.autofocus == null) { - var hasFocus = activeElt(); + var hasFocus = activeElt() options.autofocus = hasFocus == textarea || - textarea.getAttribute("autofocus") != null && hasFocus == document.body; + textarea.getAttribute("autofocus") != null && hasFocus == document.body } - function save() {textarea.value = cm.getValue();} + function save() {textarea.value = cm.getValue()} if (textarea.form) { - on(textarea.form, "submit", save); + on(textarea.form, "submit", save) // Deplorable hack to make the submit method do the right thing. if (!options.leaveSubmitMethodAlone) { - var form = textarea.form, realSubmit = form.submit; + var form = textarea.form, realSubmit = form.submit try { var wrappedSubmit = form.submit = function() { - save(); - form.submit = realSubmit; - form.submit(); - form.submit = wrappedSubmit; - }; + save() + form.submit = realSubmit + form.submit() + form.submit = wrappedSubmit + } } catch(e) {} } } options.finishInit = function(cm) { - cm.save = save; - cm.getTextArea = function() { return textarea; }; + cm.save = save + cm.getTextArea = function() { return textarea } cm.toTextArea = function() { - cm.toTextArea = isNaN; // Prevent this from being ran twice - save(); - textarea.parentNode.removeChild(cm.getWrapperElement()); - textarea.style.display = ""; + cm.toTextArea = isNaN // Prevent this from being ran twice + save() + textarea.parentNode.removeChild(cm.getWrapperElement()) + textarea.style.display = "" if (textarea.form) { - off(textarea.form, "submit", save); + off(textarea.form, "submit", save) if (typeof textarea.form.submit == "function") - textarea.form.submit = realSubmit; + textarea.form.submit = realSubmit } - }; - }; + } + } - textarea.style.display = "none"; + textarea.style.display = "none" var cm = CodeMirror(function(node) { - textarea.parentNode.insertBefore(node, textarea.nextSibling); - }, options); - return cm; + textarea.parentNode.insertBefore(node, textarea.nextSibling) + }, options) + return cm } diff --git a/src/edit/global_events.js b/src/edit/global_events.js index b219285dfb..57542f2d32 100644 --- a/src/edit/global_events.js +++ b/src/edit/global_events.js @@ -1,46 +1,46 @@ -import { onBlur } from "../display/focus"; -import { on } from "../util/event"; +import { onBlur } from "../display/focus" +import { on } from "../util/event" // These must be handled carefully, because naively registering a // handler for each editor will cause the editors to never be // garbage collected. function forEachCodeMirror(f) { - if (!document.body.getElementsByClassName) return; - var byClass = document.body.getElementsByClassName("CodeMirror"); + if (!document.body.getElementsByClassName) return + var byClass = document.body.getElementsByClassName("CodeMirror") for (var i = 0; i < byClass.length; i++) { - var cm = byClass[i].CodeMirror; - if (cm) f(cm); + var cm = byClass[i].CodeMirror + if (cm) f(cm) } } -var globalsRegistered = false; +var globalsRegistered = false export function ensureGlobalHandlers() { - if (globalsRegistered) return; - registerGlobalHandlers(); - globalsRegistered = true; + if (globalsRegistered) return + registerGlobalHandlers() + globalsRegistered = true } function registerGlobalHandlers() { // When the window resizes, we need to refresh active editors. - var resizeTimer; + var resizeTimer on(window, "resize", function() { if (resizeTimer == null) resizeTimer = setTimeout(function() { - resizeTimer = null; - forEachCodeMirror(onResize); - }, 100); - }); + resizeTimer = null + forEachCodeMirror(onResize) + }, 100) + }) // When the window loses focus, we want to show the editor as blurred on(window, "blur", function() { - forEachCodeMirror(onBlur); - }); + forEachCodeMirror(onBlur) + }) } // Called when the window resizes function onResize(cm) { - var d = cm.display; + var d = cm.display if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) - return; + return // Might be a text scaling operation, clear size caches. - d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; - d.scrollbarsClipped = false; - cm.setSize(); + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null + d.scrollbarsClipped = false + cm.setSize() } diff --git a/src/edit/key_events.js b/src/edit/key_events.js index 92763037c9..9a4944414c 100644 --- a/src/edit/key_events.js +++ b/src/edit/key_events.js @@ -1,153 +1,153 @@ -import { signalLater } from "../util/operation_group"; -import { restartBlink } from "../display/selection"; -import { isModifierKey, keyName, lookupKey } from "../input/keymap"; -import { eventInWidget } from "../measurement/widgets"; -import { ie, ie_version, mac, presto } from "../util/browser"; -import { activeElt, addClass, rmClass } from "../util/dom"; -import { e_preventDefault, off, on, signalDOMEvent } from "../util/event"; -import { hasCopyEvent } from "../util/feature_detection"; -import { Delayed, Pass } from "../util/misc"; - -import { commands } from "./commands"; +import { signalLater } from "../util/operation_group" +import { restartBlink } from "../display/selection" +import { isModifierKey, keyName, lookupKey } from "../input/keymap" +import { eventInWidget } from "../measurement/widgets" +import { ie, ie_version, mac, presto } from "../util/browser" +import { activeElt, addClass, rmClass } from "../util/dom" +import { e_preventDefault, off, on, signalDOMEvent } from "../util/event" +import { hasCopyEvent } from "../util/feature_detection" +import { Delayed, Pass } from "../util/misc" + +import { commands } from "./commands" // Run a handler that was bound to a key. function doHandleBinding(cm, bound, dropShift) { if (typeof bound == "string") { - bound = commands[bound]; - if (!bound) return false; + bound = commands[bound] + if (!bound) return false } // Ensure previous input has been read, so that the handler sees a // consistent view of the document - cm.display.input.ensurePolled(); - var prevShift = cm.display.shift, done = false; + cm.display.input.ensurePolled() + var prevShift = cm.display.shift, done = false try { - if (cm.isReadOnly()) cm.state.suppressEdits = true; - if (dropShift) cm.display.shift = false; - done = bound(cm) != Pass; + if (cm.isReadOnly()) cm.state.suppressEdits = true + if (dropShift) cm.display.shift = false + done = bound(cm) != Pass } finally { - cm.display.shift = prevShift; - cm.state.suppressEdits = false; + cm.display.shift = prevShift + cm.state.suppressEdits = false } - return done; + return done } function lookupKeyForEditor(cm, name, handle) { for (var i = 0; i < cm.state.keyMaps.length; i++) { - var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); - if (result) return result; + var result = lookupKey(name, cm.state.keyMaps[i], handle, cm) + if (result) return result } return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) - || lookupKey(name, cm.options.keyMap, handle, cm); + || lookupKey(name, cm.options.keyMap, handle, cm) } -var stopSeq = new Delayed; +var stopSeq = new Delayed function dispatchKey(cm, name, e, handle) { - var seq = cm.state.keySeq; + var seq = cm.state.keySeq if (seq) { - if (isModifierKey(name)) return "handled"; + if (isModifierKey(name)) return "handled" stopSeq.set(50, function() { if (cm.state.keySeq == seq) { - cm.state.keySeq = null; - cm.display.input.reset(); + cm.state.keySeq = null + cm.display.input.reset() } - }); - name = seq + " " + name; + }) + name = seq + " " + name } - var result = lookupKeyForEditor(cm, name, handle); + var result = lookupKeyForEditor(cm, name, handle) if (result == "multi") - cm.state.keySeq = name; + cm.state.keySeq = name if (result == "handled") - signalLater(cm, "keyHandled", cm, name, e); + signalLater(cm, "keyHandled", cm, name, e) if (result == "handled" || result == "multi") { - e_preventDefault(e); - restartBlink(cm); + e_preventDefault(e) + restartBlink(cm) } if (seq && !result && /\'$/.test(name)) { - e_preventDefault(e); - return true; + e_preventDefault(e) + return true } - return !!result; + return !!result } // Handle a key from the keydown event. function handleKeyBinding(cm, e) { - var name = keyName(e, true); - if (!name) return false; + var name = keyName(e, true) + if (!name) return false if (e.shiftKey && !cm.state.keySeq) { // First try to resolve full name (including 'Shift-'). Failing // that, see if there is a cursor-motion command (starting with // 'go') bound to the keyname without 'Shift-'. - return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);}) + return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true)}) || dispatchKey(cm, name, e, function(b) { if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) - return doHandleBinding(cm, b); - }); + return doHandleBinding(cm, b) + }) } else { - return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); }); + return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b) }) } } // Handle a key from the keypress event function handleCharBinding(cm, e, ch) { return dispatchKey(cm, "'" + ch + "'", e, - function(b) { return doHandleBinding(cm, b, true); }); + function(b) { return doHandleBinding(cm, b, true) }) } -var lastStoppedKey = null; +var lastStoppedKey = null export function onKeyDown(e) { - var cm = this; - cm.curOp.focus = activeElt(); - if (signalDOMEvent(cm, e)) return; + var cm = this + cm.curOp.focus = activeElt() + if (signalDOMEvent(cm, e)) return // IE does strange things with escape. - if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false; - var code = e.keyCode; - cm.display.shift = code == 16 || e.shiftKey; - var handled = handleKeyBinding(cm, e); + if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false + var code = e.keyCode + cm.display.shift = code == 16 || e.shiftKey + var handled = handleKeyBinding(cm, e) if (presto) { - lastStoppedKey = handled ? code : null; + lastStoppedKey = handled ? code : null // Opera has no cut event... we try to at least catch the key combo if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) - cm.replaceSelection("", null, "cut"); + cm.replaceSelection("", null, "cut") } // Turn mouse into crosshair when Alt is held on Mac. if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) - showCrossHair(cm); + showCrossHair(cm) } function showCrossHair(cm) { - var lineDiv = cm.display.lineDiv; - addClass(lineDiv, "CodeMirror-crosshair"); + var lineDiv = cm.display.lineDiv + addClass(lineDiv, "CodeMirror-crosshair") function up(e) { if (e.keyCode == 18 || !e.altKey) { - rmClass(lineDiv, "CodeMirror-crosshair"); - off(document, "keyup", up); - off(document, "mouseover", up); + rmClass(lineDiv, "CodeMirror-crosshair") + off(document, "keyup", up) + off(document, "mouseover", up) } } - on(document, "keyup", up); - on(document, "mouseover", up); + on(document, "keyup", up) + on(document, "mouseover", up) } export function onKeyUp(e) { - if (e.keyCode == 16) this.doc.sel.shift = false; - signalDOMEvent(this, e); + if (e.keyCode == 16) this.doc.sel.shift = false + signalDOMEvent(this, e) } export function onKeyPress(e) { - var cm = this; - if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return; - var keyCode = e.keyCode, charCode = e.charCode; - if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} - if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return; - var ch = String.fromCharCode(charCode == null ? keyCode : charCode); + var cm = this + if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return + var keyCode = e.keyCode, charCode = e.charCode + if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return} + if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return + var ch = String.fromCharCode(charCode == null ? keyCode : charCode) // Some browsers fire keypress events for backspace - if (ch == "\x08") return; - if (handleCharBinding(cm, e, ch)) return; - cm.display.input.onKeyPress(e); + if (ch == "\x08") return + if (handleCharBinding(cm, e, ch)) return + cm.display.input.onKeyPress(e) } diff --git a/src/edit/legacy.js b/src/edit/legacy.js index 150f8a7225..bc3df6c8f1 100644 --- a/src/edit/legacy.js +++ b/src/edit/legacy.js @@ -1,62 +1,62 @@ -import { scrollbarModel } from "../display/scrollbars"; -import { wheelEventPixels } from "../display/scroll_events"; -import { keyMap, keyName, isModifierKey, lookupKey, normalizeKeyMap } from "../input/keymap"; -import { keyNames } from "../input/keynames"; -import { Line } from "../line/line_data"; -import { cmp, Pos } from "../line/pos"; -import { changeEnd } from "../model/change_measurement"; -import Doc from "../model/Doc"; -import { LineWidget } from "../model/line_widget"; -import { SharedTextMarker, TextMarker } from "../model/mark_text"; -import { copyState, extendMode, getMode, innerMode, mimeModes, modeExtensions, modes, resolveMode, startState } from "../modes"; -import { addClass, contains, rmClass } from "../util/dom"; -import { e_preventDefault, e_stop, e_stopPropagation, off, on, signal } from "../util/event"; -import { splitLinesAuto } from "../util/feature_detection"; -import { countColumn, findColumn, isWordCharBasic, Pass } from "../util/misc"; -import StringStream from "../util/StringStream"; +import { scrollbarModel } from "../display/scrollbars" +import { wheelEventPixels } from "../display/scroll_events" +import { keyMap, keyName, isModifierKey, lookupKey, normalizeKeyMap } from "../input/keymap" +import { keyNames } from "../input/keynames" +import { Line } from "../line/line_data" +import { cmp, Pos } from "../line/pos" +import { changeEnd } from "../model/change_measurement" +import Doc from "../model/Doc" +import { LineWidget } from "../model/line_widget" +import { SharedTextMarker, TextMarker } from "../model/mark_text" +import { copyState, extendMode, getMode, innerMode, mimeModes, modeExtensions, modes, resolveMode, startState } from "../modes" +import { addClass, contains, rmClass } from "../util/dom" +import { e_preventDefault, e_stop, e_stopPropagation, off, on, signal } from "../util/event" +import { splitLinesAuto } from "../util/feature_detection" +import { countColumn, findColumn, isWordCharBasic, Pass } from "../util/misc" +import StringStream from "../util/StringStream" -import { commands } from "./commands"; +import { commands } from "./commands" export function addLegacyProps(CodeMirror) { - CodeMirror.off = off; - CodeMirror.on = on; - CodeMirror.wheelEventPixels = wheelEventPixels; - CodeMirror.Doc = Doc; - CodeMirror.splitLines = splitLinesAuto; - CodeMirror.countColumn = countColumn; - CodeMirror.findColumn = findColumn; - CodeMirror.isWordChar = isWordCharBasic; - CodeMirror.Pass = Pass; - CodeMirror.signal = signal; - CodeMirror.Line = Line; - CodeMirror.changeEnd = changeEnd; - CodeMirror.scrollbarModel = scrollbarModel; - CodeMirror.Pos = Pos; - CodeMirror.cmpPos = cmp; - CodeMirror.modes = modes; - CodeMirror.mimeModes = mimeModes; - CodeMirror.resolveMode = resolveMode; - CodeMirror.getMode = getMode; - CodeMirror.modeExtensions = modeExtensions; - CodeMirror.extendMode = extendMode; - CodeMirror.copyState = copyState; - CodeMirror.startState = startState; - CodeMirror.innerMode = innerMode; - CodeMirror.commands = commands; - CodeMirror.keyMap = keyMap; - CodeMirror.keyName = keyName; - CodeMirror.isModifierKey = isModifierKey; - CodeMirror.lookupKey = lookupKey; - CodeMirror.normalizeKeyMap = normalizeKeyMap; - CodeMirror.StringStream = StringStream; - CodeMirror.SharedTextMarker = SharedTextMarker; - CodeMirror.TextMarker = TextMarker; - CodeMirror.LineWidget = LineWidget; - CodeMirror.e_preventDefault = e_preventDefault; - CodeMirror.e_stopPropagation = e_stopPropagation; - CodeMirror.e_stop = e_stop; - CodeMirror.addClass = addClass; - CodeMirror.contains = contains; - CodeMirror.rmClass = rmClass; - CodeMirror.keyNames = keyNames; + CodeMirror.off = off + CodeMirror.on = on + CodeMirror.wheelEventPixels = wheelEventPixels + CodeMirror.Doc = Doc + CodeMirror.splitLines = splitLinesAuto + CodeMirror.countColumn = countColumn + CodeMirror.findColumn = findColumn + CodeMirror.isWordChar = isWordCharBasic + CodeMirror.Pass = Pass + CodeMirror.signal = signal + CodeMirror.Line = Line + CodeMirror.changeEnd = changeEnd + CodeMirror.scrollbarModel = scrollbarModel + CodeMirror.Pos = Pos + CodeMirror.cmpPos = cmp + CodeMirror.modes = modes + CodeMirror.mimeModes = mimeModes + CodeMirror.resolveMode = resolveMode + CodeMirror.getMode = getMode + CodeMirror.modeExtensions = modeExtensions + CodeMirror.extendMode = extendMode + CodeMirror.copyState = copyState + CodeMirror.startState = startState + CodeMirror.innerMode = innerMode + CodeMirror.commands = commands + CodeMirror.keyMap = keyMap + CodeMirror.keyName = keyName + CodeMirror.isModifierKey = isModifierKey + CodeMirror.lookupKey = lookupKey + CodeMirror.normalizeKeyMap = normalizeKeyMap + CodeMirror.StringStream = StringStream + CodeMirror.SharedTextMarker = SharedTextMarker + CodeMirror.TextMarker = TextMarker + CodeMirror.LineWidget = LineWidget + CodeMirror.e_preventDefault = e_preventDefault + CodeMirror.e_stopPropagation = e_stopPropagation + CodeMirror.e_stop = e_stop + CodeMirror.addClass = addClass + CodeMirror.contains = contains + CodeMirror.rmClass = rmClass + CodeMirror.keyNames = keyNames } diff --git a/src/edit/main.js b/src/edit/main.js index a955aaa197..3f76d70207 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -1,71 +1,71 @@ // EDITOR CONSTRUCTOR -import { CodeMirror } from "./CodeMirror"; -export { CodeMirror } from "./CodeMirror"; +import { CodeMirror } from "./CodeMirror" +export { CodeMirror } from "./CodeMirror" -import { eventMixin } from "../util/event"; -import { indexOf } from "../util/misc"; +import { eventMixin } from "../util/event" +import { indexOf } from "../util/misc" -import { defineOptions } from "./options"; +import { defineOptions } from "./options" -defineOptions(CodeMirror); +defineOptions(CodeMirror) -import addEditorMethods from "./methods"; +import addEditorMethods from "./methods" -addEditorMethods(CodeMirror); +addEditorMethods(CodeMirror) -import Doc from "../model/Doc"; +import Doc from "../model/Doc" // Set up methods on CodeMirror's prototype to redirect to the editor's document. -var dontDelegate = "iter insert remove copy getEditor constructor".split(" "); +var dontDelegate = "iter insert remove copy getEditor constructor".split(" ") for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) CodeMirror.prototype[prop] = (function(method) { - return function() {return method.apply(this.doc, arguments);}; - })(Doc.prototype[prop]); + return function() {return method.apply(this.doc, arguments)} + })(Doc.prototype[prop]) -eventMixin(Doc); +eventMixin(Doc) // INPUT HANDLING -import ContentEditableInput from "../input/ContentEditableInput"; -import TextareaInput from "../input/TextareaInput"; -CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput}; +import ContentEditableInput from "../input/ContentEditableInput" +import TextareaInput from "../input/TextareaInput" +CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput} // MODE DEFINITION AND QUERYING -import { defineMIME, defineMode } from "../modes"; +import { defineMIME, defineMode } from "../modes" // Extra arguments are stored as the mode's dependencies, which is // used by (legacy) mechanisms like loadmode.js to automatically // load a mode. (Preferred mechanism is the require/define calls.) CodeMirror.defineMode = function(name/*, mode, …*/) { - if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; - defineMode.apply(this, arguments); -}; + if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name + defineMode.apply(this, arguments) +} -CodeMirror.defineMIME = defineMIME; +CodeMirror.defineMIME = defineMIME // Minimal default mode. CodeMirror.defineMode("null", function() { - return {token: function(stream) {stream.skipToEnd();}}; -}); -CodeMirror.defineMIME("text/plain", "null"); + return {token: function(stream) {stream.skipToEnd()}} +}) +CodeMirror.defineMIME("text/plain", "null") // EXTENSIONS CodeMirror.defineExtension = function(name, func) { - CodeMirror.prototype[name] = func; -}; + CodeMirror.prototype[name] = func +} CodeMirror.defineDocExtension = function(name, func) { - Doc.prototype[name] = func; -}; + Doc.prototype[name] = func +} -import { fromTextArea } from "./fromTextArea"; +import { fromTextArea } from "./fromTextArea" -CodeMirror.fromTextArea = fromTextArea; +CodeMirror.fromTextArea = fromTextArea -import { addLegacyProps } from "./legacy"; +import { addLegacyProps } from "./legacy" -addLegacyProps(CodeMirror); +addLegacyProps(CodeMirror) -CodeMirror.version = "5.19.1"; +CodeMirror.version = "5.19.1" diff --git a/src/edit/methods.js b/src/edit/methods.js index 84aaf397b0..828304d3dc 100644 --- a/src/edit/methods.js +++ b/src/edit/methods.js @@ -1,27 +1,27 @@ -import { deleteNearSelection } from "./deleteNearSelection"; -import { changeLine } from "../model/changes"; -import { commands } from "./commands"; -import { attachDoc } from "../model/document_data"; -import { activeElt, addClass, rmClass } from "../util/dom"; -import { eventMixin, signal } from "../util/event"; -import { getLineStyles, getStateBefore, takeToken } from "../line/highlight"; -import { indentLine } from "../input/indent"; -import { triggerElectric } from "../input/input"; -import { onKeyDown, onKeyPress, onKeyUp } from "./key_events"; -import { getKeyMap } from "../input/keymap"; -import { methodOp, operation, runInOp } from "../display/operations"; -import { clipLine, clipPos, cmp, Pos } from "../line/pos"; -import { charCoords, charWidth, clearCaches, clearLineMeasurementCache, coordsChar, cursorCoords, displayHeight, displayWidth, estimateLineHeights, fromCoordSystem, intoCoordSystem, scrollGap, textHeight } from "../measurement/position_measurement"; -import { Range } from "../model/selection"; -import { replaceOneSelection, skipAtomic } from "../model/selection_updates"; -import { addToScrollPos, calculateScrollPos, ensureCursorVisible, resolveScrollToPos, scrollIntoView } from "../display/scrolling"; -import { heightAtLine } from "../line/spans"; -import { updateGutterSpace } from "../display/update_display"; -import { lineLeft, lineRight, moveLogically, moveVisually } from "../util/bidi"; -import { indexOf, insertSorted, isEmpty, isWordChar, sel_dontScroll, sel_move } from "../util/misc"; -import { signalLater } from "../util/operation_group"; -import { getLine, isLine, lineAtHeight, lineNo } from "../line/utils_line"; -import { regChange, regLineChange } from "../display/view_tracking"; +import { deleteNearSelection } from "./deleteNearSelection" +import { changeLine } from "../model/changes" +import { commands } from "./commands" +import { attachDoc } from "../model/document_data" +import { activeElt, addClass, rmClass } from "../util/dom" +import { eventMixin, signal } from "../util/event" +import { getLineStyles, getStateBefore, takeToken } from "../line/highlight" +import { indentLine } from "../input/indent" +import { triggerElectric } from "../input/input" +import { onKeyDown, onKeyPress, onKeyUp } from "./key_events" +import { getKeyMap } from "../input/keymap" +import { methodOp, operation, runInOp } from "../display/operations" +import { clipLine, clipPos, cmp, Pos } from "../line/pos" +import { charCoords, charWidth, clearCaches, clearLineMeasurementCache, coordsChar, cursorCoords, displayHeight, displayWidth, estimateLineHeights, fromCoordSystem, intoCoordSystem, scrollGap, textHeight } from "../measurement/position_measurement" +import { Range } from "../model/selection" +import { replaceOneSelection, skipAtomic } from "../model/selection_updates" +import { addToScrollPos, calculateScrollPos, ensureCursorVisible, resolveScrollToPos, scrollIntoView } from "../display/scrolling" +import { heightAtLine } from "../line/spans" +import { updateGutterSpace } from "../display/update_display" +import { lineLeft, lineRight, moveLogically, moveVisually } from "../util/bidi" +import { indexOf, insertSorted, isEmpty, isWordChar, sel_dontScroll, sel_move } from "../util/misc" +import { signalLater } from "../util/operation_group" +import { getLine, isLine, lineAtHeight, lineNo } from "../line/utils_line" +import { regChange, regLineChange } from "../display/view_tracking" // The publicly visible API. Note that methodOp(f) means // 'wrap f in an operation, performed on its `this` parameter'. @@ -32,84 +32,84 @@ import { regChange, regLineChange } from "../display/view_tracking"; // convenience. export default function(CodeMirror) { - var optionHandlers = CodeMirror.optionHandlers; + var optionHandlers = CodeMirror.optionHandlers - var helpers = CodeMirror.helpers = {}; + var helpers = CodeMirror.helpers = {} CodeMirror.prototype = { constructor: CodeMirror, - focus: function(){window.focus(); this.display.input.focus();}, + focus: function(){window.focus(); this.display.input.focus()}, setOption: function(option, value) { - var options = this.options, old = options[option]; - if (options[option] == value && option != "mode") return; - options[option] = value; + var options = this.options, old = options[option] + if (options[option] == value && option != "mode") return + options[option] = value if (optionHandlers.hasOwnProperty(option)) - operation(this, optionHandlers[option])(this, value, old); + operation(this, optionHandlers[option])(this, value, old) }, - getOption: function(option) {return this.options[option];}, - getDoc: function() {return this.doc;}, + getOption: function(option) {return this.options[option]}, + getDoc: function() {return this.doc}, addKeyMap: function(map, bottom) { - this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); + this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)) }, removeKeyMap: function(map) { - var maps = this.state.keyMaps; + var maps = this.state.keyMaps for (var i = 0; i < maps.length; ++i) if (maps[i] == map || maps[i].name == map) { - maps.splice(i, 1); - return true; + maps.splice(i, 1) + return true } }, addOverlay: methodOp(function(spec, options) { - var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); - if (mode.startState) throw new Error("Overlays may not be stateful."); + var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec) + if (mode.startState) throw new Error("Overlays may not be stateful.") insertSorted(this.state.overlays, {mode: mode, modeSpec: spec, opaque: options && options.opaque, priority: (options && options.priority) || 0}, function(overlay) { return overlay.priority }) - this.state.modeGen++; - regChange(this); + this.state.modeGen++ + regChange(this) }), removeOverlay: methodOp(function(spec) { - var overlays = this.state.overlays; + var overlays = this.state.overlays for (var i = 0; i < overlays.length; ++i) { - var cur = overlays[i].modeSpec; + var cur = overlays[i].modeSpec if (cur == spec || typeof spec == "string" && cur.name == spec) { - overlays.splice(i, 1); - this.state.modeGen++; - regChange(this); - return; + overlays.splice(i, 1) + this.state.modeGen++ + regChange(this) + return } } }), indentLine: methodOp(function(n, dir, aggressive) { if (typeof dir != "string" && typeof dir != "number") { - if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; - else dir = dir ? "add" : "subtract"; + if (dir == null) dir = this.options.smartIndent ? "smart" : "prev" + else dir = dir ? "add" : "subtract" } - if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); + if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive) }), indentSelection: methodOp(function(how) { - var ranges = this.doc.sel.ranges, end = -1; + var ranges = this.doc.sel.ranges, end = -1 for (var i = 0; i < ranges.length; i++) { - var range = ranges[i]; + var range = ranges[i] if (!range.empty()) { - var from = range.from(), to = range.to(); - var start = Math.max(end, from.line); - end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; + var from = range.from(), to = range.to() + var start = Math.max(end, from.line) + end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1 for (var j = start; j < end; ++j) - indentLine(this, j, how); - var newRanges = this.doc.sel.ranges; + indentLine(this, j, how) + var newRanges = this.doc.sel.ranges if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) - replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); + replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll) } else if (range.head.line > end) { - indentLine(this, range.head.line, how, true); - end = range.head.line; - if (i == this.doc.sel.primIndex) ensureCursorVisible(this); + indentLine(this, range.head.line, how, true) + end = range.head.line + if (i == this.doc.sel.primIndex) ensureCursorVisible(this) } } }), @@ -117,178 +117,178 @@ export default function(CodeMirror) { // Fetch the parser token for a given character. Useful for hacks // that want to inspect the mode state (say, for completion). getTokenAt: function(pos, precise) { - return takeToken(this, pos, precise); + return takeToken(this, pos, precise) }, getLineTokens: function(line, precise) { - return takeToken(this, Pos(line), precise, true); + return takeToken(this, Pos(line), precise, true) }, getTokenTypeAt: function(pos) { - pos = clipPos(this.doc, pos); - var styles = getLineStyles(this, getLine(this.doc, pos.line)); - var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; - var type; - if (ch == 0) type = styles[2]; + pos = clipPos(this.doc, pos) + var styles = getLineStyles(this, getLine(this.doc, pos.line)) + var before = 0, after = (styles.length - 1) / 2, ch = pos.ch + var type + if (ch == 0) type = styles[2] else for (;;) { - var mid = (before + after) >> 1; - if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; - else if (styles[mid * 2 + 1] < ch) before = mid + 1; - else { type = styles[mid * 2 + 2]; break; } + var mid = (before + after) >> 1 + if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid + else if (styles[mid * 2 + 1] < ch) before = mid + 1 + else { type = styles[mid * 2 + 2]; break } } - var cut = type ? type.indexOf("cm-overlay ") : -1; - return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1); + var cut = type ? type.indexOf("cm-overlay ") : -1 + return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1) }, getModeAt: function(pos) { - var mode = this.doc.mode; - if (!mode.innerMode) return mode; - return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; + var mode = this.doc.mode + if (!mode.innerMode) return mode + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode }, getHelper: function(pos, type) { - return this.getHelpers(pos, type)[0]; + return this.getHelpers(pos, type)[0] }, getHelpers: function(pos, type) { - var found = []; - if (!helpers.hasOwnProperty(type)) return found; - var help = helpers[type], mode = this.getModeAt(pos); + var found = [] + if (!helpers.hasOwnProperty(type)) return found + var help = helpers[type], mode = this.getModeAt(pos) if (typeof mode[type] == "string") { - if (help[mode[type]]) found.push(help[mode[type]]); + if (help[mode[type]]) found.push(help[mode[type]]) } else if (mode[type]) { for (var i = 0; i < mode[type].length; i++) { - var val = help[mode[type][i]]; - if (val) found.push(val); + var val = help[mode[type][i]] + if (val) found.push(val) } } else if (mode.helperType && help[mode.helperType]) { - found.push(help[mode.helperType]); + found.push(help[mode.helperType]) } else if (help[mode.name]) { - found.push(help[mode.name]); + found.push(help[mode.name]) } for (var i = 0; i < help._global.length; i++) { - var cur = help._global[i]; + var cur = help._global[i] if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) - found.push(cur.val); + found.push(cur.val) } - return found; + return found }, getStateAfter: function(line, precise) { - var doc = this.doc; - line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); - return getStateBefore(this, line + 1, precise); + var doc = this.doc + line = clipLine(doc, line == null ? doc.first + doc.size - 1: line) + return getStateBefore(this, line + 1, precise) }, cursorCoords: function(start, mode) { - var pos, range = this.doc.sel.primary(); - if (start == null) pos = range.head; - else if (typeof start == "object") pos = clipPos(this.doc, start); - else pos = start ? range.from() : range.to(); - return cursorCoords(this, pos, mode || "page"); + var pos, range = this.doc.sel.primary() + if (start == null) pos = range.head + else if (typeof start == "object") pos = clipPos(this.doc, start) + else pos = start ? range.from() : range.to() + return cursorCoords(this, pos, mode || "page") }, charCoords: function(pos, mode) { - return charCoords(this, clipPos(this.doc, pos), mode || "page"); + return charCoords(this, clipPos(this.doc, pos), mode || "page") }, coordsChar: function(coords, mode) { - coords = fromCoordSystem(this, coords, mode || "page"); - return coordsChar(this, coords.left, coords.top); + coords = fromCoordSystem(this, coords, mode || "page") + return coordsChar(this, coords.left, coords.top) }, lineAtHeight: function(height, mode) { - height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top; - return lineAtHeight(this.doc, height + this.display.viewOffset); + height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top + return lineAtHeight(this.doc, height + this.display.viewOffset) }, heightAtLine: function(line, mode) { - var end = false, lineObj; + var end = false, lineObj if (typeof line == "number") { - var last = this.doc.first + this.doc.size - 1; - if (line < this.doc.first) line = this.doc.first; - else if (line > last) { line = last; end = true; } - lineObj = getLine(this.doc, line); + var last = this.doc.first + this.doc.size - 1 + if (line < this.doc.first) line = this.doc.first + else if (line > last) { line = last; end = true } + lineObj = getLine(this.doc, line) } else { - lineObj = line; + lineObj = line } return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top + - (end ? this.doc.height - heightAtLine(lineObj) : 0); + (end ? this.doc.height - heightAtLine(lineObj) : 0) }, - defaultTextHeight: function() { return textHeight(this.display); }, - defaultCharWidth: function() { return charWidth(this.display); }, + defaultTextHeight: function() { return textHeight(this.display) }, + defaultCharWidth: function() { return charWidth(this.display) }, setGutterMarker: methodOp(function(line, gutterID, value) { return changeLine(this.doc, line, "gutter", function(line) { - var markers = line.gutterMarkers || (line.gutterMarkers = {}); - markers[gutterID] = value; - if (!value && isEmpty(markers)) line.gutterMarkers = null; - return true; - }); + var markers = line.gutterMarkers || (line.gutterMarkers = {}) + markers[gutterID] = value + if (!value && isEmpty(markers)) line.gutterMarkers = null + return true + }) }), clearGutter: methodOp(function(gutterID) { - var cm = this, doc = cm.doc, i = doc.first; + var cm = this, doc = cm.doc, i = doc.first doc.iter(function(line) { if (line.gutterMarkers && line.gutterMarkers[gutterID]) { - line.gutterMarkers[gutterID] = null; - regLineChange(cm, i, "gutter"); - if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; + line.gutterMarkers[gutterID] = null + regLineChange(cm, i, "gutter") + if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null } - ++i; - }); + ++i + }) }), lineInfo: function(line) { if (typeof line == "number") { - if (!isLine(this.doc, line)) return null; - var n = line; - line = getLine(this.doc, line); - if (!line) return null; + if (!isLine(this.doc, line)) return null + var n = line + line = getLine(this.doc, line) + if (!line) return null } else { - var n = lineNo(line); - if (n == null) return null; + var n = lineNo(line) + if (n == null) return null } return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, - widgets: line.widgets}; + widgets: line.widgets} }, - getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};}, + getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}}, addWidget: function(pos, node, scroll, vert, horiz) { - var display = this.display; - pos = cursorCoords(this, clipPos(this.doc, pos)); - var top = pos.bottom, left = pos.left; - node.style.position = "absolute"; - node.setAttribute("cm-ignore-events", "true"); - this.display.input.setUneditable(node); - display.sizer.appendChild(node); + var display = this.display + pos = cursorCoords(this, clipPos(this.doc, pos)) + var top = pos.bottom, left = pos.left + node.style.position = "absolute" + node.setAttribute("cm-ignore-events", "true") + this.display.input.setUneditable(node) + display.sizer.appendChild(node) if (vert == "over") { - top = pos.top; + top = pos.top } else if (vert == "above" || vert == "near") { var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), - hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); + hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth) // Default to positioning above (if specified and possible); otherwise default to positioning below if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) - top = pos.top - node.offsetHeight; + top = pos.top - node.offsetHeight else if (pos.bottom + node.offsetHeight <= vspace) - top = pos.bottom; + top = pos.bottom if (left + node.offsetWidth > hspace) - left = hspace - node.offsetWidth; + left = hspace - node.offsetWidth } - node.style.top = top + "px"; - node.style.left = node.style.right = ""; + node.style.top = top + "px" + node.style.left = node.style.right = "" if (horiz == "right") { - left = display.sizer.clientWidth - node.offsetWidth; - node.style.right = "0px"; + left = display.sizer.clientWidth - node.offsetWidth + node.style.right = "0px" } else { - if (horiz == "left") left = 0; - else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2; - node.style.left = left + "px"; + if (horiz == "left") left = 0 + else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2 + node.style.left = left + "px" } if (scroll) - scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); + scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight) }, triggerOnKeyDown: methodOp(onKeyDown), @@ -297,199 +297,199 @@ export default function(CodeMirror) { execCommand: function(cmd) { if (commands.hasOwnProperty(cmd)) - return commands[cmd].call(null, this); + return commands[cmd].call(null, this) }, - triggerElectric: methodOp(function(text) { triggerElectric(this, text); }), + triggerElectric: methodOp(function(text) { triggerElectric(this, text) }), findPosH: function(from, amount, unit, visually) { - var dir = 1; - if (amount < 0) { dir = -1; amount = -amount; } + var dir = 1 + if (amount < 0) { dir = -1; amount = -amount } for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { - cur = findPosH(this.doc, cur, dir, unit, visually); - if (cur.hitSide) break; + cur = findPosH(this.doc, cur, dir, unit, visually) + if (cur.hitSide) break } - return cur; + return cur }, moveH: methodOp(function(dir, unit) { - var cm = this; + var cm = this cm.extendSelectionsBy(function(range) { if (cm.display.shift || cm.doc.extend || range.empty()) - return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually); + return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually) else - return dir < 0 ? range.from() : range.to(); - }, sel_move); + return dir < 0 ? range.from() : range.to() + }, sel_move) }), deleteH: methodOp(function(dir, unit) { - var sel = this.doc.sel, doc = this.doc; + var sel = this.doc.sel, doc = this.doc if (sel.somethingSelected()) - doc.replaceSelection("", null, "+delete"); + doc.replaceSelection("", null, "+delete") else deleteNearSelection(this, function(range) { - var other = findPosH(doc, range.head, dir, unit, false); - return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}; - }); + var other = findPosH(doc, range.head, dir, unit, false) + return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other} + }) }), findPosV: function(from, amount, unit, goalColumn) { - var dir = 1, x = goalColumn; - if (amount < 0) { dir = -1; amount = -amount; } + var dir = 1, x = goalColumn + if (amount < 0) { dir = -1; amount = -amount } for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { - var coords = cursorCoords(this, cur, "div"); - if (x == null) x = coords.left; - else coords.left = x; - cur = findPosV(this, coords, dir, unit); - if (cur.hitSide) break; + var coords = cursorCoords(this, cur, "div") + if (x == null) x = coords.left + else coords.left = x + cur = findPosV(this, coords, dir, unit) + if (cur.hitSide) break } - return cur; + return cur }, moveV: methodOp(function(dir, unit) { - var cm = this, doc = this.doc, goals = []; - var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected(); + var cm = this, doc = this.doc, goals = [] + var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected() doc.extendSelectionsBy(function(range) { if (collapse) - return dir < 0 ? range.from() : range.to(); - var headPos = cursorCoords(cm, range.head, "div"); - if (range.goalColumn != null) headPos.left = range.goalColumn; - goals.push(headPos.left); - var pos = findPosV(cm, headPos, dir, unit); + return dir < 0 ? range.from() : range.to() + var headPos = cursorCoords(cm, range.head, "div") + if (range.goalColumn != null) headPos.left = range.goalColumn + goals.push(headPos.left) + var pos = findPosV(cm, headPos, dir, unit) if (unit == "page" && range == doc.sel.primary()) - addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top); - return pos; - }, sel_move); + addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top) + return pos + }, sel_move) if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++) - doc.sel.ranges[i].goalColumn = goals[i]; + doc.sel.ranges[i].goalColumn = goals[i] }), // Find the word at the given position (as returned by coordsChar). findWordAt: function(pos) { - var doc = this.doc, line = getLine(doc, pos.line).text; - var start = pos.ch, end = pos.ch; + var doc = this.doc, line = getLine(doc, pos.line).text + var start = pos.ch, end = pos.ch if (line) { - var helper = this.getHelper(pos, "wordChars"); - if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; - var startChar = line.charAt(start); + var helper = this.getHelper(pos, "wordChars") + if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end + var startChar = line.charAt(start) var check = isWordChar(startChar, helper) - ? function(ch) { return isWordChar(ch, helper); } - : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} - : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; - while (start > 0 && check(line.charAt(start - 1))) --start; - while (end < line.length && check(line.charAt(end))) ++end; + ? function(ch) { return isWordChar(ch, helper) } + : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch)} + : function(ch) {return !/\s/.test(ch) && !isWordChar(ch)} + while (start > 0 && check(line.charAt(start - 1))) --start + while (end < line.length && check(line.charAt(end))) ++end } - return new Range(Pos(pos.line, start), Pos(pos.line, end)); + return new Range(Pos(pos.line, start), Pos(pos.line, end)) }, toggleOverwrite: function(value) { - if (value != null && value == this.state.overwrite) return; + if (value != null && value == this.state.overwrite) return if (this.state.overwrite = !this.state.overwrite) - addClass(this.display.cursorDiv, "CodeMirror-overwrite"); + addClass(this.display.cursorDiv, "CodeMirror-overwrite") else - rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); + rmClass(this.display.cursorDiv, "CodeMirror-overwrite") - signal(this, "overwriteToggle", this, this.state.overwrite); + signal(this, "overwriteToggle", this, this.state.overwrite) }, - hasFocus: function() { return this.display.input.getField() == activeElt(); }, - isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit); }, + hasFocus: function() { return this.display.input.getField() == activeElt() }, + isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) }, scrollTo: methodOp(function(x, y) { - if (x != null || y != null) resolveScrollToPos(this); - if (x != null) this.curOp.scrollLeft = x; - if (y != null) this.curOp.scrollTop = y; + if (x != null || y != null) resolveScrollToPos(this) + if (x != null) this.curOp.scrollLeft = x + if (y != null) this.curOp.scrollTop = y }), getScrollInfo: function() { - var scroller = this.display.scroller; + var scroller = this.display.scroller return {left: scroller.scrollLeft, top: scroller.scrollTop, height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, - clientHeight: displayHeight(this), clientWidth: displayWidth(this)}; + clientHeight: displayHeight(this), clientWidth: displayWidth(this)} }, scrollIntoView: methodOp(function(range, margin) { if (range == null) { - range = {from: this.doc.sel.primary().head, to: null}; - if (margin == null) margin = this.options.cursorScrollMargin; + range = {from: this.doc.sel.primary().head, to: null} + if (margin == null) margin = this.options.cursorScrollMargin } else if (typeof range == "number") { - range = {from: Pos(range, 0), to: null}; + range = {from: Pos(range, 0), to: null} } else if (range.from == null) { - range = {from: range, to: null}; + range = {from: range, to: null} } - if (!range.to) range.to = range.from; - range.margin = margin || 0; + if (!range.to) range.to = range.from + range.margin = margin || 0 if (range.from.line != null) { - resolveScrollToPos(this); - this.curOp.scrollToPos = range; + resolveScrollToPos(this) + this.curOp.scrollToPos = range } else { var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), Math.min(range.from.top, range.to.top) - range.margin, Math.max(range.from.right, range.to.right), - Math.max(range.from.bottom, range.to.bottom) + range.margin); - this.scrollTo(sPos.scrollLeft, sPos.scrollTop); + Math.max(range.from.bottom, range.to.bottom) + range.margin) + this.scrollTo(sPos.scrollLeft, sPos.scrollTop) } }), setSize: methodOp(function(width, height) { - var cm = this; + var cm = this function interpret(val) { - return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; + return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val } - if (width != null) cm.display.wrapper.style.width = interpret(width); - if (height != null) cm.display.wrapper.style.height = interpret(height); - if (cm.options.lineWrapping) clearLineMeasurementCache(this); - var lineNo = cm.display.viewFrom; + if (width != null) cm.display.wrapper.style.width = interpret(width) + if (height != null) cm.display.wrapper.style.height = interpret(height) + if (cm.options.lineWrapping) clearLineMeasurementCache(this) + var lineNo = cm.display.viewFrom cm.doc.iter(lineNo, cm.display.viewTo, function(line) { if (line.widgets) for (var i = 0; i < line.widgets.length; i++) - if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; } - ++lineNo; - }); - cm.curOp.forceUpdate = true; - signal(cm, "refresh", this); + if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break } + ++lineNo + }) + cm.curOp.forceUpdate = true + signal(cm, "refresh", this) }), - operation: function(f){return runInOp(this, f);}, + operation: function(f){return runInOp(this, f)}, refresh: methodOp(function() { - var oldHeight = this.display.cachedTextHeight; - regChange(this); - this.curOp.forceUpdate = true; - clearCaches(this); - this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop); - updateGutterSpace(this); + var oldHeight = this.display.cachedTextHeight + regChange(this) + this.curOp.forceUpdate = true + clearCaches(this) + this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop) + updateGutterSpace(this) if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) - estimateLineHeights(this); - signal(this, "refresh", this); + estimateLineHeights(this) + signal(this, "refresh", this) }), swapDoc: methodOp(function(doc) { - var old = this.doc; - old.cm = null; - attachDoc(this, doc); - clearCaches(this); - this.display.input.reset(); - this.scrollTo(doc.scrollLeft, doc.scrollTop); - this.curOp.forceScroll = true; - signalLater(this, "swapDoc", this, old); - return old; + var old = this.doc + old.cm = null + attachDoc(this, doc) + clearCaches(this) + this.display.input.reset() + this.scrollTo(doc.scrollLeft, doc.scrollTop) + this.curOp.forceScroll = true + signalLater(this, "swapDoc", this, old) + return old }), - getInputField: function(){return this.display.input.getField();}, - getWrapperElement: function(){return this.display.wrapper;}, - getScrollerElement: function(){return this.display.scroller;}, - getGutterElement: function(){return this.display.gutters;} - }; - eventMixin(CodeMirror); + getInputField: function(){return this.display.input.getField()}, + getWrapperElement: function(){return this.display.wrapper}, + getScrollerElement: function(){return this.display.scroller}, + getGutterElement: function(){return this.display.gutters} + } + eventMixin(CodeMirror) CodeMirror.registerHelper = function(type, name, value) { - if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []}; - helpers[type][name] = value; - }; + if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []} + helpers[type][name] = value + } CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { - CodeMirror.registerHelper(type, name, value); - helpers[type]._global.push({pred: predicate, val: value}); - }; + CodeMirror.registerHelper(type, name, value) + helpers[type]._global.push({pred: predicate, val: value}) + } } // Used for horizontal relative motion. Dir is -1 or 1 (left or @@ -502,23 +502,23 @@ export default function(CodeMirror) { // position. The resulting position will have a hitSide=true // property if it reached the end of the document. function findPosH(doc, pos, dir, unit, visually) { - var line = pos.line, ch = pos.ch, origDir = dir; - var lineObj = getLine(doc, line); + var line = pos.line, ch = pos.ch, origDir = dir + var lineObj = getLine(doc, line) function findNextLine() { - var l = line + dir; + var l = line + dir if (l < doc.first || l >= doc.first + doc.size) return false - line = l; - return lineObj = getLine(doc, l); + line = l + return lineObj = getLine(doc, l) } function moveOnce(boundToLine) { - var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true); + var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true) if (next == null) { if (!boundToLine && findNextLine()) { - if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); - else ch = dir < 0 ? lineObj.text.length : 0; + if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj) + else ch = dir < 0 ? lineObj.text.length : 0 } else return false - } else ch = next; - return true; + } else ch = next + return true } if (unit == "char") { @@ -526,48 +526,48 @@ function findPosH(doc, pos, dir, unit, visually) { } else if (unit == "column") { moveOnce(true) } else if (unit == "word" || unit == "group") { - var sawType = null, group = unit == "group"; - var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); + var sawType = null, group = unit == "group" + var helper = doc.cm && doc.cm.getHelper(pos, "wordChars") for (var first = true;; first = false) { - if (dir < 0 && !moveOnce(!first)) break; - var cur = lineObj.text.charAt(ch) || "\n"; + if (dir < 0 && !moveOnce(!first)) break + var cur = lineObj.text.charAt(ch) || "\n" var type = isWordChar(cur, helper) ? "w" : group && cur == "\n" ? "n" : !group || /\s/.test(cur) ? null - : "p"; - if (group && !first && !type) type = "s"; + : "p" + if (group && !first && !type) type = "s" if (sawType && sawType != type) { - if (dir < 0) {dir = 1; moveOnce();} - break; + if (dir < 0) {dir = 1; moveOnce()} + break } - if (type) sawType = type; - if (dir > 0 && !moveOnce(!first)) break; + if (type) sawType = type + if (dir > 0 && !moveOnce(!first)) break } } - var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true); - if (!cmp(pos, result)) result.hitSide = true; - return result; + var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true) + if (!cmp(pos, result)) result.hitSide = true + return result } // For relative vertical movement. Dir may be -1 or 1. Unit can be // "page" or "line". The resulting position will have a hitSide=true // property if it reached the end of the document. function findPosV(cm, pos, dir, unit) { - var doc = cm.doc, x = pos.left, y; + var doc = cm.doc, x = pos.left, y if (unit == "page") { - var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); - var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3); - y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount; + var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight) + var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3) + y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount } else if (unit == "line") { - y = dir > 0 ? pos.bottom + 3 : pos.top - 3; + y = dir > 0 ? pos.bottom + 3 : pos.top - 3 } for (;;) { - var target = coordsChar(cm, x, y); - if (!target.outside) break; - if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } - y += dir * 5; + var target = coordsChar(cm, x, y) + if (!target.outside) break + if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break } + y += dir * 5 } - return target; + return target } diff --git a/src/edit/mouse_events.js b/src/edit/mouse_events.js index ebda0c28a9..408cc497d1 100644 --- a/src/edit/mouse_events.js +++ b/src/edit/mouse_events.js @@ -1,17 +1,17 @@ -import { delayBlurEvent, ensureFocus } from "../display/focus"; -import { operation } from "../display/operations"; -import { visibleLines } from "../display/update_lines"; -import { clipPos, cmp, maxPos, minPos, Pos } from "../line/pos"; -import { getLine, lineAtHeight } from "../line/utils_line"; -import { posFromMouse } from "../measurement/position_measurement"; -import { eventInWidget } from "../measurement/widgets"; -import { normalizeSelection, Range, Selection } from "../model/selection"; -import { extendRange, extendSelection, replaceOneSelection, setSelection } from "../model/selection_updates"; -import { captureRightClick, chromeOS, ie, ie_version, mac, webkit } from "../util/browser"; -import { activeElt } from "../util/dom"; -import { e_button, e_defaultPrevented, e_preventDefault, e_target, hasHandler, off, on, signal, signalDOMEvent } from "../util/event"; -import { dragAndDrop } from "../util/feature_detection"; -import { bind, countColumn, findColumn, sel_mouse } from "../util/misc"; +import { delayBlurEvent, ensureFocus } from "../display/focus" +import { operation } from "../display/operations" +import { visibleLines } from "../display/update_lines" +import { clipPos, cmp, maxPos, minPos, Pos } from "../line/pos" +import { getLine, lineAtHeight } from "../line/utils_line" +import { posFromMouse } from "../measurement/position_measurement" +import { eventInWidget } from "../measurement/widgets" +import { normalizeSelection, Range, Selection } from "../model/selection" +import { extendRange, extendSelection, replaceOneSelection, setSelection } from "../model/selection_updates" +import { captureRightClick, chromeOS, ie, ie_version, mac, webkit } from "../util/browser" +import { activeElt } from "../util/dom" +import { e_button, e_defaultPrevented, e_preventDefault, e_target, hasHandler, off, on, signal, signalDOMEvent } from "../util/event" +import { dragAndDrop } from "../util/feature_detection" +import { bind, countColumn, findColumn, sel_mouse } from "../util/misc" // A mouse down can be a single click, double click, triple click, // start of selection drag, start of text drag, new cursor @@ -19,275 +19,275 @@ import { bind, countColumn, findColumn, sel_mouse } from "../util/misc"; // middle-click-paste. Or it might be a click on something we should // not interfere with, such as a scrollbar or widget. export function onMouseDown(e) { - var cm = this, display = cm.display; - if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return; - display.shift = e.shiftKey; + var cm = this, display = cm.display + if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return + display.shift = e.shiftKey if (eventInWidget(display, e)) { if (!webkit) { // Briefly turn off draggability, to allow widgets to do // normal dragging things. - display.scroller.draggable = false; - setTimeout(function(){display.scroller.draggable = true;}, 100); + display.scroller.draggable = false + setTimeout(function(){display.scroller.draggable = true}, 100) } - return; + return } - if (clickInGutter(cm, e)) return; - var start = posFromMouse(cm, e); - window.focus(); + if (clickInGutter(cm, e)) return + var start = posFromMouse(cm, e) + window.focus() switch (e_button(e)) { case 1: // #3261: make sure, that we're not starting a second selection if (cm.state.selectingText) - cm.state.selectingText(e); + cm.state.selectingText(e) else if (start) - leftButtonDown(cm, e, start); + leftButtonDown(cm, e, start) else if (e_target(e) == display.scroller) - e_preventDefault(e); - break; + e_preventDefault(e) + break case 2: - if (webkit) cm.state.lastMiddleDown = +new Date; - if (start) extendSelection(cm.doc, start); - setTimeout(function() {display.input.focus();}, 20); - e_preventDefault(e); - break; + if (webkit) cm.state.lastMiddleDown = +new Date + if (start) extendSelection(cm.doc, start) + setTimeout(function() {display.input.focus()}, 20) + e_preventDefault(e) + break case 3: - if (captureRightClick) onContextMenu(cm, e); - else delayBlurEvent(cm); - break; + if (captureRightClick) onContextMenu(cm, e) + else delayBlurEvent(cm) + break } } -var lastClick, lastDoubleClick; +var lastClick, lastDoubleClick function leftButtonDown(cm, e, start) { - if (ie) setTimeout(bind(ensureFocus, cm), 0); - else cm.curOp.focus = activeElt(); + if (ie) setTimeout(bind(ensureFocus, cm), 0) + else cm.curOp.focus = activeElt() - var now = +new Date, type; + var now = +new Date, type if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { - type = "triple"; + type = "triple" } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { - type = "double"; - lastDoubleClick = {time: now, pos: start}; + type = "double" + lastDoubleClick = {time: now, pos: start} } else { - type = "single"; - lastClick = {time: now, pos: start}; + type = "single" + lastClick = {time: now, pos: start} } - var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained; + var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() && type == "single" && (contained = sel.contains(start)) > -1 && (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) && (cmp(contained.to(), start) > 0 || start.xRel < 0)) - leftButtonStartDrag(cm, e, start, modifier); + leftButtonStartDrag(cm, e, start, modifier) else - leftButtonSelect(cm, e, start, type, modifier); + leftButtonSelect(cm, e, start, type, modifier) } // Start a text drag. When it ends, see if any dragging actually // happen, and treat as a click if it didn't. function leftButtonStartDrag(cm, e, start, modifier) { - var display = cm.display, startTime = +new Date; + var display = cm.display, startTime = +new Date var dragEnd = operation(cm, function(e2) { - if (webkit) display.scroller.draggable = false; - cm.state.draggingText = false; - off(document, "mouseup", dragEnd); - off(display.scroller, "drop", dragEnd); + if (webkit) display.scroller.draggable = false + cm.state.draggingText = false + off(document, "mouseup", dragEnd) + off(display.scroller, "drop", dragEnd) if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { - e_preventDefault(e2); + e_preventDefault(e2) if (!modifier && +new Date - 200 < startTime) - extendSelection(cm.doc, start); + extendSelection(cm.doc, start) // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) if (webkit || ie && ie_version == 9) - setTimeout(function() {document.body.focus(); display.input.focus();}, 20); + setTimeout(function() {document.body.focus(); display.input.focus()}, 20) else - display.input.focus(); + display.input.focus() } - }); + }) // Let the drag handler handle this. - if (webkit) display.scroller.draggable = true; - cm.state.draggingText = dragEnd; + if (webkit) display.scroller.draggable = true + cm.state.draggingText = dragEnd dragEnd.copy = mac ? e.altKey : e.ctrlKey // IE's approach to draggable - if (display.scroller.dragDrop) display.scroller.dragDrop(); - on(document, "mouseup", dragEnd); - on(display.scroller, "drop", dragEnd); + if (display.scroller.dragDrop) display.scroller.dragDrop() + on(document, "mouseup", dragEnd) + on(display.scroller, "drop", dragEnd) } // Normal selection, as opposed to text dragging. function leftButtonSelect(cm, e, start, type, addNew) { - var display = cm.display, doc = cm.doc; - e_preventDefault(e); + var display = cm.display, doc = cm.doc + e_preventDefault(e) - var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; + var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges if (addNew && !e.shiftKey) { - ourIndex = doc.sel.contains(start); + ourIndex = doc.sel.contains(start) if (ourIndex > -1) - ourRange = ranges[ourIndex]; + ourRange = ranges[ourIndex] else - ourRange = new Range(start, start); + ourRange = new Range(start, start) } else { - ourRange = doc.sel.primary(); - ourIndex = doc.sel.primIndex; + ourRange = doc.sel.primary() + ourIndex = doc.sel.primIndex } if (chromeOS ? e.shiftKey && e.metaKey : e.altKey) { - type = "rect"; - if (!addNew) ourRange = new Range(start, start); - start = posFromMouse(cm, e, true, true); - ourIndex = -1; + type = "rect" + if (!addNew) ourRange = new Range(start, start) + start = posFromMouse(cm, e, true, true) + ourIndex = -1 } else if (type == "double") { - var word = cm.findWordAt(start); + var word = cm.findWordAt(start) if (cm.display.shift || doc.extend) - ourRange = extendRange(doc, ourRange, word.anchor, word.head); + ourRange = extendRange(doc, ourRange, word.anchor, word.head) else - ourRange = word; + ourRange = word } else if (type == "triple") { - var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))); + var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))) if (cm.display.shift || doc.extend) - ourRange = extendRange(doc, ourRange, line.anchor, line.head); + ourRange = extendRange(doc, ourRange, line.anchor, line.head) else - ourRange = line; + ourRange = line } else { - ourRange = extendRange(doc, ourRange, start); + ourRange = extendRange(doc, ourRange, start) } if (!addNew) { - ourIndex = 0; - setSelection(doc, new Selection([ourRange], 0), sel_mouse); - startSel = doc.sel; + ourIndex = 0 + setSelection(doc, new Selection([ourRange], 0), sel_mouse) + startSel = doc.sel } else if (ourIndex == -1) { - ourIndex = ranges.length; + ourIndex = ranges.length setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), - {scroll: false, origin: "*mouse"}); + {scroll: false, origin: "*mouse"}) } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0), - {scroll: false, origin: "*mouse"}); - startSel = doc.sel; + {scroll: false, origin: "*mouse"}) + startSel = doc.sel } else { - replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); + replaceOneSelection(doc, ourIndex, ourRange, sel_mouse) } - var lastPos = start; + var lastPos = start function extendTo(pos) { - if (cmp(lastPos, pos) == 0) return; - lastPos = pos; + if (cmp(lastPos, pos) == 0) return + lastPos = pos if (type == "rect") { - var ranges = [], tabSize = cm.options.tabSize; - var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); - var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); - var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); + var ranges = [], tabSize = cm.options.tabSize + var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize) + var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize) + var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol) for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); line <= end; line++) { - var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); + var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize) if (left == right) - ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); + ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))) else if (text.length > leftPos) - ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); + ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))) } - if (!ranges.length) ranges.push(new Range(start, start)); + if (!ranges.length) ranges.push(new Range(start, start)) setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), - {origin: "*mouse", scroll: false}); - cm.scrollIntoView(pos); + {origin: "*mouse", scroll: false}) + cm.scrollIntoView(pos) } else { - var oldRange = ourRange; - var anchor = oldRange.anchor, head = pos; + var oldRange = ourRange + var anchor = oldRange.anchor, head = pos if (type != "single") { if (type == "double") - var range = cm.findWordAt(pos); + var range = cm.findWordAt(pos) else - var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))); + var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))) if (cmp(range.anchor, anchor) > 0) { - head = range.head; - anchor = minPos(oldRange.from(), range.anchor); + head = range.head + anchor = minPos(oldRange.from(), range.anchor) } else { - head = range.anchor; - anchor = maxPos(oldRange.to(), range.head); + head = range.anchor + anchor = maxPos(oldRange.to(), range.head) } } - var ranges = startSel.ranges.slice(0); - ranges[ourIndex] = new Range(clipPos(doc, anchor), head); - setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse); + var ranges = startSel.ranges.slice(0) + ranges[ourIndex] = new Range(clipPos(doc, anchor), head) + setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse) } } - var editorSize = display.wrapper.getBoundingClientRect(); + var editorSize = display.wrapper.getBoundingClientRect() // Used to ensure timeout re-tries don't fire when another extend // happened in the meantime (clearTimeout isn't reliable -- at // least on Chrome, the timeouts still happen even when cleared, // if the clear happens after their scheduled firing time). - var counter = 0; + var counter = 0 function extend(e) { - var curCount = ++counter; - var cur = posFromMouse(cm, e, true, type == "rect"); - if (!cur) return; + var curCount = ++counter + var cur = posFromMouse(cm, e, true, type == "rect") + if (!cur) return if (cmp(cur, lastPos) != 0) { - cm.curOp.focus = activeElt(); - extendTo(cur); - var visible = visibleLines(display, doc); + cm.curOp.focus = activeElt() + extendTo(cur) + var visible = visibleLines(display, doc) if (cur.line >= visible.to || cur.line < visible.from) - setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150); + setTimeout(operation(cm, function(){if (counter == curCount) extend(e)}), 150) } else { - var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; + var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0 if (outside) setTimeout(operation(cm, function() { - if (counter != curCount) return; - display.scroller.scrollTop += outside; - extend(e); - }), 50); + if (counter != curCount) return + display.scroller.scrollTop += outside + extend(e) + }), 50) } } function done(e) { - cm.state.selectingText = false; - counter = Infinity; - e_preventDefault(e); - display.input.focus(); - off(document, "mousemove", move); - off(document, "mouseup", up); - doc.history.lastSelOrigin = null; + cm.state.selectingText = false + counter = Infinity + e_preventDefault(e) + display.input.focus() + off(document, "mousemove", move) + off(document, "mouseup", up) + doc.history.lastSelOrigin = null } var move = operation(cm, function(e) { - if (!e_button(e)) done(e); - else extend(e); - }); - var up = operation(cm, done); - cm.state.selectingText = up; - on(document, "mousemove", move); - on(document, "mouseup", up); + if (!e_button(e)) done(e) + else extend(e) + }) + var up = operation(cm, done) + cm.state.selectingText = up + on(document, "mousemove", move) + on(document, "mouseup", up) } // Determines whether an event happened in the gutter, and fires the // handlers for the corresponding event. function gutterEvent(cm, e, type, prevent) { - try { var mX = e.clientX, mY = e.clientY; } - catch(e) { return false; } - if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; - if (prevent) e_preventDefault(e); + try { var mX = e.clientX, mY = e.clientY } + catch(e) { return false } + if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false + if (prevent) e_preventDefault(e) - var display = cm.display; - var lineBox = display.lineDiv.getBoundingClientRect(); + var display = cm.display + var lineBox = display.lineDiv.getBoundingClientRect() - if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e); - mY -= lineBox.top - display.viewOffset; + if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e) + mY -= lineBox.top - display.viewOffset for (var i = 0; i < cm.options.gutters.length; ++i) { - var g = display.gutters.childNodes[i]; + var g = display.gutters.childNodes[i] if (g && g.getBoundingClientRect().right >= mX) { - var line = lineAtHeight(cm.doc, mY); - var gutter = cm.options.gutters[i]; - signal(cm, type, cm, line, gutter, e); - return e_defaultPrevented(e); + var line = lineAtHeight(cm.doc, mY) + var gutter = cm.options.gutters[i] + signal(cm, type, cm, line, gutter, e) + return e_defaultPrevented(e) } } } export function clickInGutter(cm, e) { - return gutterEvent(cm, e, "gutterClick", true); + return gutterEvent(cm, e, "gutterClick", true) } // CONTEXT MENU HANDLING @@ -296,12 +296,12 @@ export function clickInGutter(cm, e) { // textarea (making it as unobtrusive as possible) to let the // right-click take effect on it. export function onContextMenu(cm, e) { - if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return; - if (signalDOMEvent(cm, e, "contextmenu")) return; - cm.display.input.onContextMenu(e); + if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return + if (signalDOMEvent(cm, e, "contextmenu")) return + cm.display.input.onContextMenu(e) } function contextMenuInGutter(cm, e) { - if (!hasHandler(cm, "gutterContextMenu")) return false; - return gutterEvent(cm, e, "gutterContextMenu", false); + if (!hasHandler(cm, "gutterContextMenu")) return false + return gutterEvent(cm, e, "gutterContextMenu", false) } diff --git a/src/edit/options.js b/src/edit/options.js index 308eb574f2..cf0d4d8185 100644 --- a/src/edit/options.js +++ b/src/edit/options.js @@ -1,196 +1,196 @@ -import { onBlur } from "../display/focus"; -import { setGuttersForLineNumbers, updateGutters } from "../display/gutters"; -import { alignHorizontally } from "../display/line_numbers"; -import { loadMode, resetModeState } from "../display/mode_state"; -import { initScrollbars, updateScrollbars } from "../display/scrollbars"; -import { updateSelection } from "../display/selection"; -import { regChange } from "../display/view_tracking"; -import { getKeyMap } from "../input/keymap"; -import { defaultSpecialCharPlaceholder } from "../line/line_data"; -import { Pos } from "../line/pos"; -import { findMaxLine } from "../line/spans"; -import { clearCaches, compensateForHScroll, estimateLineHeights } from "../measurement/position_measurement"; -import { replaceRange } from "../model/changes"; -import { mobile, windows } from "../util/browser"; -import { addClass, rmClass } from "../util/dom"; -import { off, on } from "../util/event"; - -import { themeChanged } from "./utils"; - -export var Init = {toString: function(){return "CodeMirror.Init";}}; - -export var defaults = {}; -export var optionHandlers = {}; +import { onBlur } from "../display/focus" +import { setGuttersForLineNumbers, updateGutters } from "../display/gutters" +import { alignHorizontally } from "../display/line_numbers" +import { loadMode, resetModeState } from "../display/mode_state" +import { initScrollbars, updateScrollbars } from "../display/scrollbars" +import { updateSelection } from "../display/selection" +import { regChange } from "../display/view_tracking" +import { getKeyMap } from "../input/keymap" +import { defaultSpecialCharPlaceholder } from "../line/line_data" +import { Pos } from "../line/pos" +import { findMaxLine } from "../line/spans" +import { clearCaches, compensateForHScroll, estimateLineHeights } from "../measurement/position_measurement" +import { replaceRange } from "../model/changes" +import { mobile, windows } from "../util/browser" +import { addClass, rmClass } from "../util/dom" +import { off, on } from "../util/event" + +import { themeChanged } from "./utils" + +export var Init = {toString: function(){return "CodeMirror.Init"}} + +export var defaults = {} +export var optionHandlers = {} export function defineOptions(CodeMirror) { - var optionHandlers = CodeMirror.optionHandlers; + var optionHandlers = CodeMirror.optionHandlers function option(name, deflt, handle, notOnInit) { - CodeMirror.defaults[name] = deflt; + CodeMirror.defaults[name] = deflt if (handle) optionHandlers[name] = - notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle; + notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old)} : handle } - CodeMirror.defineOption = option; + CodeMirror.defineOption = option // Passed to option handlers when there is no old value. - CodeMirror.Init = Init; + CodeMirror.Init = Init // These two are, on init, called from the constructor because they // have to be initialized before the editor can start at all. option("value", "", function(cm, val) { - cm.setValue(val); - }, true); + cm.setValue(val) + }, true) option("mode", null, function(cm, val) { - cm.doc.modeOption = val; - loadMode(cm); - }, true); + cm.doc.modeOption = val + loadMode(cm) + }, true) - option("indentUnit", 2, loadMode, true); - option("indentWithTabs", false); - option("smartIndent", true); + option("indentUnit", 2, loadMode, true) + option("indentWithTabs", false) + option("smartIndent", true) option("tabSize", 4, function(cm) { - resetModeState(cm); - clearCaches(cm); - regChange(cm); - }, true); + resetModeState(cm) + clearCaches(cm) + regChange(cm) + }, true) option("lineSeparator", null, function(cm, val) { - cm.doc.lineSep = val; - if (!val) return; - var newBreaks = [], lineNo = cm.doc.first; + cm.doc.lineSep = val + if (!val) return + var newBreaks = [], lineNo = cm.doc.first cm.doc.iter(function(line) { for (var pos = 0;;) { - var found = line.text.indexOf(val, pos); - if (found == -1) break; - pos = found + val.length; - newBreaks.push(Pos(lineNo, found)); + var found = line.text.indexOf(val, pos) + if (found == -1) break + pos = found + val.length + newBreaks.push(Pos(lineNo, found)) } - lineNo++; - }); + lineNo++ + }) for (var i = newBreaks.length - 1; i >= 0; i--) replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) - }); + }) option("specialChars", /[\u0000-\u001f\u007f\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) { - cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); - if (old != Init) cm.refresh(); - }); - option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true); - option("electricChars", true); + cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g") + if (old != Init) cm.refresh() + }) + option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh()}, true) + option("electricChars", true) option("inputStyle", mobile ? "contenteditable" : "textarea", function() { - throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME - }, true); + throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME + }, true) option("spellcheck", false, function(cm, val) { cm.getInputField().spellcheck = val - }, true); - option("rtlMoveVisually", !windows); - option("wholeLineUpdateBefore", true); + }, true) + option("rtlMoveVisually", !windows) + option("wholeLineUpdateBefore", true) option("theme", "default", function(cm) { - themeChanged(cm); - guttersChanged(cm); - }, true); + themeChanged(cm) + guttersChanged(cm) + }, true) option("keyMap", "default", function(cm, val, old) { - var next = getKeyMap(val); - var prev = old != Init && getKeyMap(old); - if (prev && prev.detach) prev.detach(cm, next); - if (next.attach) next.attach(cm, prev || null); - }); - option("extraKeys", null); - - option("lineWrapping", false, wrappingChanged, true); + var next = getKeyMap(val) + var prev = old != Init && getKeyMap(old) + if (prev && prev.detach) prev.detach(cm, next) + if (next.attach) next.attach(cm, prev || null) + }) + option("extraKeys", null) + + option("lineWrapping", false, wrappingChanged, true) option("gutters", [], function(cm) { - setGuttersForLineNumbers(cm.options); - guttersChanged(cm); - }, true); + setGuttersForLineNumbers(cm.options) + guttersChanged(cm) + }, true) option("fixedGutter", true, function(cm, val) { - cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; - cm.refresh(); - }, true); - option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true); + cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0" + cm.refresh() + }, true) + option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm)}, true) option("scrollbarStyle", "native", function(cm) { - initScrollbars(cm); - updateScrollbars(cm); - cm.display.scrollbars.setScrollTop(cm.doc.scrollTop); - cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft); - }, true); + initScrollbars(cm) + updateScrollbars(cm) + cm.display.scrollbars.setScrollTop(cm.doc.scrollTop) + cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft) + }, true) option("lineNumbers", false, function(cm) { - setGuttersForLineNumbers(cm.options); - guttersChanged(cm); - }, true); - option("firstLineNumber", 1, guttersChanged, true); - option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true); - option("showCursorWhenSelecting", false, updateSelection, true); + setGuttersForLineNumbers(cm.options) + guttersChanged(cm) + }, true) + option("firstLineNumber", 1, guttersChanged, true) + option("lineNumberFormatter", function(integer) {return integer}, guttersChanged, true) + option("showCursorWhenSelecting", false, updateSelection, true) - option("resetSelectionOnContextMenu", true); - option("lineWiseCopyCut", true); + option("resetSelectionOnContextMenu", true) + option("lineWiseCopyCut", true) option("readOnly", false, function(cm, val) { if (val == "nocursor") { - onBlur(cm); - cm.display.input.blur(); - cm.display.disabled = true; + onBlur(cm) + cm.display.input.blur() + cm.display.disabled = true } else { - cm.display.disabled = false; + cm.display.disabled = false } cm.display.input.readOnlyChanged(val) - }); - option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true); - option("dragDrop", true, dragDropChanged); - option("allowDropFileTypes", null); - - option("cursorBlinkRate", 530); - option("cursorScrollMargin", 0); - option("cursorHeight", 1, updateSelection, true); - option("singleCursorHeightPerLine", true, updateSelection, true); - option("workTime", 100); - option("workDelay", 100); - option("flattenSpans", true, resetModeState, true); - option("addModeClass", false, resetModeState, true); - option("pollInterval", 100); - option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;}); - option("historyEventDelay", 1250); - option("viewportMargin", 10, function(cm){cm.refresh();}, true); - option("maxHighlightLength", 10000, resetModeState, true); + }) + option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset()}, true) + option("dragDrop", true, dragDropChanged) + option("allowDropFileTypes", null) + + option("cursorBlinkRate", 530) + option("cursorScrollMargin", 0) + option("cursorHeight", 1, updateSelection, true) + option("singleCursorHeightPerLine", true, updateSelection, true) + option("workTime", 100) + option("workDelay", 100) + option("flattenSpans", true, resetModeState, true) + option("addModeClass", false, resetModeState, true) + option("pollInterval", 100) + option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val}) + option("historyEventDelay", 1250) + option("viewportMargin", 10, function(cm){cm.refresh()}, true) + option("maxHighlightLength", 10000, resetModeState, true) option("moveInputWithCursor", true, function(cm, val) { - if (!val) cm.display.input.resetPosition(); - }); + if (!val) cm.display.input.resetPosition() + }) option("tabindex", null, function(cm, val) { - cm.display.input.getField().tabIndex = val || ""; - }); - option("autofocus", null); + cm.display.input.getField().tabIndex = val || "" + }) + option("autofocus", null) } function guttersChanged(cm) { - updateGutters(cm); - regChange(cm); - setTimeout(function(){alignHorizontally(cm);}, 20); + updateGutters(cm) + regChange(cm) + setTimeout(function(){alignHorizontally(cm)}, 20) } function dragDropChanged(cm, value, old) { - var wasOn = old && old != Init; + var wasOn = old && old != Init if (!value != !wasOn) { - var funcs = cm.display.dragFunctions; - var toggle = value ? on : off; - toggle(cm.display.scroller, "dragstart", funcs.start); - toggle(cm.display.scroller, "dragenter", funcs.enter); - toggle(cm.display.scroller, "dragover", funcs.over); - toggle(cm.display.scroller, "dragleave", funcs.leave); - toggle(cm.display.scroller, "drop", funcs.drop); + var funcs = cm.display.dragFunctions + var toggle = value ? on : off + toggle(cm.display.scroller, "dragstart", funcs.start) + toggle(cm.display.scroller, "dragenter", funcs.enter) + toggle(cm.display.scroller, "dragover", funcs.over) + toggle(cm.display.scroller, "dragleave", funcs.leave) + toggle(cm.display.scroller, "drop", funcs.drop) } } function wrappingChanged(cm) { if (cm.options.lineWrapping) { - addClass(cm.display.wrapper, "CodeMirror-wrap"); - cm.display.sizer.style.minWidth = ""; - cm.display.sizerWidth = null; + addClass(cm.display.wrapper, "CodeMirror-wrap") + cm.display.sizer.style.minWidth = "" + cm.display.sizerWidth = null } else { - rmClass(cm.display.wrapper, "CodeMirror-wrap"); - findMaxLine(cm); + rmClass(cm.display.wrapper, "CodeMirror-wrap") + findMaxLine(cm) } - estimateLineHeights(cm); - regChange(cm); - clearCaches(cm); - setTimeout(function(){updateScrollbars(cm);}, 100); + estimateLineHeights(cm) + regChange(cm) + clearCaches(cm) + setTimeout(function(){updateScrollbars(cm)}, 100) } diff --git a/src/edit/utils.js b/src/edit/utils.js index cdef3156bb..61f795572d 100644 --- a/src/edit/utils.js +++ b/src/edit/utils.js @@ -1,7 +1,7 @@ -import { clearCaches } from "../measurement/position_measurement"; +import { clearCaches } from "../measurement/position_measurement" export function themeChanged(cm) { cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + - cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); - clearCaches(cm); + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-") + clearCaches(cm) } diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index 69d53c0cbe..51597d19fa 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -1,317 +1,317 @@ -import { operation, runInOp } from "../display/operations"; -import { prepareSelection } from "../display/selection"; -import { regChange } from "../display/view_tracking"; -import { applyTextInput, copyableRanges, disableBrowserMagic, handlePaste, hiddenTextarea, lastCopied, setLastCopied } from "./input"; -import { cmp, maxPos, minPos, Pos } from "../line/pos"; -import { getBetween, getLine, lineNo } from "../line/utils_line"; -import { findViewForLine, findViewIndex, mapFromLineView, nodeAndOffsetInLineMap } from "../measurement/position_measurement"; -import { replaceRange } from "../model/changes"; -import { simpleSelection } from "../model/selection"; -import { setSelection } from "../model/selection_updates"; -import { getBidiPartAt, getOrder } from "../util/bidi"; -import { gecko, ie_version } from "../util/browser"; -import { contains, range, removeChildrenAndAdd, selectInput } from "../util/dom"; -import { on, signalDOMEvent } from "../util/event"; -import { copyObj, Delayed, lst, nothing, sel_dontScroll } from "../util/misc"; +import { operation, runInOp } from "../display/operations" +import { prepareSelection } from "../display/selection" +import { regChange } from "../display/view_tracking" +import { applyTextInput, copyableRanges, disableBrowserMagic, handlePaste, hiddenTextarea, lastCopied, setLastCopied } from "./input" +import { cmp, maxPos, minPos, Pos } from "../line/pos" +import { getBetween, getLine, lineNo } from "../line/utils_line" +import { findViewForLine, findViewIndex, mapFromLineView, nodeAndOffsetInLineMap } from "../measurement/position_measurement" +import { replaceRange } from "../model/changes" +import { simpleSelection } from "../model/selection" +import { setSelection } from "../model/selection_updates" +import { getBidiPartAt, getOrder } from "../util/bidi" +import { gecko, ie_version } from "../util/browser" +import { contains, range, removeChildrenAndAdd, selectInput } from "../util/dom" +import { on, signalDOMEvent } from "../util/event" +import { copyObj, Delayed, lst, nothing, sel_dontScroll } from "../util/misc" // CONTENTEDITABLE INPUT STYLE export default function ContentEditableInput(cm) { - this.cm = cm; - this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; - this.polling = new Delayed(); - this.gracePeriod = false; + this.cm = cm + this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null + this.polling = new Delayed() + this.gracePeriod = false } ContentEditableInput.prototype = copyObj({ init: function(display) { - var input = this, cm = input.cm; - var div = input.div = display.lineDiv; - disableBrowserMagic(div, cm.options.spellcheck); + var input = this, cm = input.cm + var div = input.div = display.lineDiv + disableBrowserMagic(div, cm.options.spellcheck) on(div, "paste", function(e) { if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return // IE doesn't fire input events, so we schedule a read for the pasted content in this way if (ie_version <= 11) setTimeout(operation(cm, function() { - if (!input.pollContent()) regChange(cm); + if (!input.pollContent()) regChange(cm) }), 20) }) on(div, "compositionstart", function(e) { - var data = e.data; - input.composing = {sel: cm.doc.sel, data: data, startData: data}; - if (!data) return; - var prim = cm.doc.sel.primary(); - var line = cm.getLine(prim.head.line); - var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)); + var data = e.data + input.composing = {sel: cm.doc.sel, data: data, startData: data} + if (!data) return + var prim = cm.doc.sel.primary() + var line = cm.getLine(prim.head.line) + var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)) if (found > -1 && found <= prim.head.ch) input.composing.sel = simpleSelection(Pos(prim.head.line, found), - Pos(prim.head.line, found + data.length)); - }); + Pos(prim.head.line, found + data.length)) + }) on(div, "compositionupdate", function(e) { - input.composing.data = e.data; - }); + input.composing.data = e.data + }) on(div, "compositionend", function(e) { - var ours = input.composing; - if (!ours) return; + var ours = input.composing + if (!ours) return if (e.data != ours.startData && !/\u200b/.test(e.data)) - ours.data = e.data; + ours.data = e.data // Need a small delay to prevent other code (input event, // selection polling) from doing damage when fired right after // compositionend. setTimeout(function() { if (!ours.handled) - input.applyComposition(ours); + input.applyComposition(ours) if (input.composing == ours) - input.composing = null; - }, 50); - }); + input.composing = null + }, 50) + }) on(div, "touchstart", function() { - input.forceCompositionEnd(); - }); + input.forceCompositionEnd() + }) on(div, "input", function() { - if (input.composing) return; + if (input.composing) return if (cm.isReadOnly() || !input.pollContent()) - runInOp(input.cm, function() {regChange(cm);}); - }); + runInOp(input.cm, function() {regChange(cm)}) + }) function onCopyCut(e) { if (signalDOMEvent(cm, e)) return if (cm.somethingSelected()) { - setLastCopied({lineWise: false, text: cm.getSelections()}); - if (e.type == "cut") cm.replaceSelection("", null, "cut"); + setLastCopied({lineWise: false, text: cm.getSelections()}) + if (e.type == "cut") cm.replaceSelection("", null, "cut") } else if (!cm.options.lineWiseCopyCut) { - return; + return } else { - var ranges = copyableRanges(cm); - setLastCopied({lineWise: true, text: ranges.text}); + var ranges = copyableRanges(cm) + setLastCopied({lineWise: true, text: ranges.text}) if (e.type == "cut") { cm.operation(function() { - cm.setSelections(ranges.ranges, 0, sel_dontScroll); - cm.replaceSelection("", null, "cut"); - }); + cm.setSelections(ranges.ranges, 0, sel_dontScroll) + cm.replaceSelection("", null, "cut") + }) } } if (e.clipboardData) { - e.clipboardData.clearData(); + e.clipboardData.clearData() var content = lastCopied.text.join("\n") // iOS exposes the clipboard API, but seems to discard content inserted into it - e.clipboardData.setData("Text", content); + e.clipboardData.setData("Text", content) if (e.clipboardData.getData("Text") == content) { - e.preventDefault(); + e.preventDefault() return } } // Old-fashioned briefly-focus-a-textarea hack - var kludge = hiddenTextarea(), te = kludge.firstChild; - cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); - te.value = lastCopied.text.join("\n"); - var hadFocus = document.activeElement; - selectInput(te); + var kludge = hiddenTextarea(), te = kludge.firstChild + cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild) + te.value = lastCopied.text.join("\n") + var hadFocus = document.activeElement + selectInput(te) setTimeout(function() { - cm.display.lineSpace.removeChild(kludge); - hadFocus.focus(); + cm.display.lineSpace.removeChild(kludge) + hadFocus.focus() if (hadFocus == div) input.showPrimarySelection() - }, 50); + }, 50) } - on(div, "copy", onCopyCut); - on(div, "cut", onCopyCut); + on(div, "copy", onCopyCut) + on(div, "cut", onCopyCut) }, prepareSelection: function() { - var result = prepareSelection(this.cm, false); - result.focus = this.cm.state.focused; - return result; + var result = prepareSelection(this.cm, false) + result.focus = this.cm.state.focused + return result }, showSelection: function(info, takeFocus) { - if (!info || !this.cm.display.view.length) return; - if (info.focus || takeFocus) this.showPrimarySelection(); - this.showMultipleSelections(info); + if (!info || !this.cm.display.view.length) return + if (info.focus || takeFocus) this.showPrimarySelection() + this.showMultipleSelections(info) }, showPrimarySelection: function() { - var sel = window.getSelection(), prim = this.cm.doc.sel.primary(); - var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset); - var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset); + var sel = window.getSelection(), prim = this.cm.doc.sel.primary() + var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset) + var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset) if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && cmp(minPos(curAnchor, curFocus), prim.from()) == 0 && cmp(maxPos(curAnchor, curFocus), prim.to()) == 0) - return; + return - var start = posToDOM(this.cm, prim.from()); - var end = posToDOM(this.cm, prim.to()); - if (!start && !end) return; + var start = posToDOM(this.cm, prim.from()) + var end = posToDOM(this.cm, prim.to()) + if (!start && !end) return - var view = this.cm.display.view; - var old = sel.rangeCount && sel.getRangeAt(0); + var view = this.cm.display.view + var old = sel.rangeCount && sel.getRangeAt(0) if (!start) { - start = {node: view[0].measure.map[2], offset: 0}; + start = {node: view[0].measure.map[2], offset: 0} } else if (!end) { // FIXME dangerously hacky - var measure = view[view.length - 1].measure; - var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; - end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}; + var measure = view[view.length - 1].measure + var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map + end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]} } - try { var rng = range(start.node, start.offset, end.offset, end.node); } + try { var rng = range(start.node, start.offset, end.offset, end.node) } catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible if (rng) { if (!gecko && this.cm.state.focused) { - sel.collapse(start.node, start.offset); - if (!rng.collapsed) sel.addRange(rng); + sel.collapse(start.node, start.offset) + if (!rng.collapsed) sel.addRange(rng) } else { - sel.removeAllRanges(); - sel.addRange(rng); + sel.removeAllRanges() + sel.addRange(rng) } - if (old && sel.anchorNode == null) sel.addRange(old); - else if (gecko) this.startGracePeriod(); + if (old && sel.anchorNode == null) sel.addRange(old) + else if (gecko) this.startGracePeriod() } - this.rememberSelection(); + this.rememberSelection() }, startGracePeriod: function() { - var input = this; - clearTimeout(this.gracePeriod); + var input = this + clearTimeout(this.gracePeriod) this.gracePeriod = setTimeout(function() { - input.gracePeriod = false; + input.gracePeriod = false if (input.selectionChanged()) - input.cm.operation(function() { input.cm.curOp.selectionChanged = true; }); - }, 20); + input.cm.operation(function() { input.cm.curOp.selectionChanged = true }) + }, 20) }, showMultipleSelections: function(info) { - removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); - removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); + removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors) + removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection) }, rememberSelection: function() { - var sel = window.getSelection(); - this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset; - this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset; + var sel = window.getSelection() + this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset + this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset }, selectionInEditor: function() { - var sel = window.getSelection(); - if (!sel.rangeCount) return false; - var node = sel.getRangeAt(0).commonAncestorContainer; - return contains(this.div, node); + var sel = window.getSelection() + if (!sel.rangeCount) return false + var node = sel.getRangeAt(0).commonAncestorContainer + return contains(this.div, node) }, focus: function() { - if (this.cm.options.readOnly != "nocursor") this.div.focus(); + if (this.cm.options.readOnly != "nocursor") this.div.focus() }, - blur: function() { this.div.blur(); }, - getField: function() { return this.div; }, + blur: function() { this.div.blur() }, + getField: function() { return this.div }, - supportsTouch: function() { return true; }, + supportsTouch: function() { return true }, receivedFocus: function() { - var input = this; + var input = this if (this.selectionInEditor()) - this.pollSelection(); + this.pollSelection() else - runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; }); + runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true }) function poll() { if (input.cm.state.focused) { - input.pollSelection(); - input.polling.set(input.cm.options.pollInterval, poll); + input.pollSelection() + input.polling.set(input.cm.options.pollInterval, poll) } } - this.polling.set(this.cm.options.pollInterval, poll); + this.polling.set(this.cm.options.pollInterval, poll) }, selectionChanged: function() { - var sel = window.getSelection(); + var sel = window.getSelection() return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || - sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset; + sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset }, pollSelection: function() { if (!this.composing && !this.gracePeriod && this.selectionChanged()) { - var sel = window.getSelection(), cm = this.cm; - this.rememberSelection(); - var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); - var head = domToPos(cm, sel.focusNode, sel.focusOffset); + var sel = window.getSelection(), cm = this.cm + this.rememberSelection() + var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset) + var head = domToPos(cm, sel.focusNode, sel.focusOffset) if (anchor && head) runInOp(cm, function() { - setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll); - if (anchor.bad || head.bad) cm.curOp.selectionChanged = true; - }); + setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll) + if (anchor.bad || head.bad) cm.curOp.selectionChanged = true + }) } }, pollContent: function() { - var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary(); - var from = sel.from(), to = sel.to(); - if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false; + var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary() + var from = sel.from(), to = sel.to() + if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false - var fromIndex; + var fromIndex if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { - var fromLine = lineNo(display.view[0].line); - var fromNode = display.view[0].node; + var fromLine = lineNo(display.view[0].line) + var fromNode = display.view[0].node } else { - var fromLine = lineNo(display.view[fromIndex].line); - var fromNode = display.view[fromIndex - 1].node.nextSibling; + var fromLine = lineNo(display.view[fromIndex].line) + var fromNode = display.view[fromIndex - 1].node.nextSibling } - var toIndex = findViewIndex(cm, to.line); + var toIndex = findViewIndex(cm, to.line) if (toIndex == display.view.length - 1) { - var toLine = display.viewTo - 1; - var toNode = display.lineDiv.lastChild; + var toLine = display.viewTo - 1 + var toNode = display.lineDiv.lastChild } else { - var toLine = lineNo(display.view[toIndex + 1].line) - 1; - var toNode = display.view[toIndex + 1].node.previousSibling; + var toLine = lineNo(display.view[toIndex + 1].line) - 1 + var toNode = display.view[toIndex + 1].node.previousSibling } - var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); - var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); + var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)) + var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)) while (newText.length > 1 && oldText.length > 1) { - if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } - else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; } - else break; + if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine-- } + else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++ } + else break } - var cutFront = 0, cutEnd = 0; - var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length); + var cutFront = 0, cutEnd = 0 + var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length) while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) - ++cutFront; - var newBot = lst(newText), oldBot = lst(oldText); + ++cutFront + var newBot = lst(newText), oldBot = lst(oldText) var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), - oldBot.length - (oldText.length == 1 ? cutFront : 0)); + oldBot.length - (oldText.length == 1 ? cutFront : 0)) while (cutEnd < maxCutEnd && newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) - ++cutEnd; + ++cutEnd - newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd); - newText[0] = newText[0].slice(cutFront); + newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd) + newText[0] = newText[0].slice(cutFront) - var chFrom = Pos(fromLine, cutFront); - var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0); + var chFrom = Pos(fromLine, cutFront) + var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0) if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { - replaceRange(cm.doc, newText, chFrom, chTo, "+input"); - return true; + replaceRange(cm.doc, newText, chFrom, chTo, "+input") + return true } }, ensurePolled: function() { - this.forceCompositionEnd(); + this.forceCompositionEnd() }, reset: function() { - this.forceCompositionEnd(); + this.forceCompositionEnd() }, forceCompositionEnd: function() { - if (!this.composing || this.composing.handled) return; - this.applyComposition(this.composing); - this.composing.handled = true; - this.div.blur(); - this.div.focus(); + if (!this.composing || this.composing.handled) return + this.applyComposition(this.composing) + this.composing.handled = true + this.div.blur() + this.div.focus() }, applyComposition: function(composing) { if (this.cm.isReadOnly()) operation(this.cm, regChange)(this.cm) else if (composing.data && composing.data != composing.startData) - operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel); + operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel) }, setUneditable: function(node) { @@ -319,9 +319,9 @@ ContentEditableInput.prototype = copyObj({ }, onKeyPress: function(e) { - e.preventDefault(); + e.preventDefault() if (!this.cm.isReadOnly()) - operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); + operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0) }, readOnlyChanged: function(val) { @@ -332,137 +332,137 @@ ContentEditableInput.prototype = copyObj({ resetPosition: nothing, needsContentAttribute: true - }, ContentEditableInput.prototype); + }, ContentEditableInput.prototype) function posToDOM(cm, pos) { - var view = findViewForLine(cm, pos.line); - if (!view || view.hidden) return null; - var line = getLine(cm.doc, pos.line); - var info = mapFromLineView(view, line, pos.line); + var view = findViewForLine(cm, pos.line) + if (!view || view.hidden) return null + var line = getLine(cm.doc, pos.line) + var info = mapFromLineView(view, line, pos.line) - var order = getOrder(line), side = "left"; + var order = getOrder(line), side = "left" if (order) { - var partPos = getBidiPartAt(order, pos.ch); - side = partPos % 2 ? "right" : "left"; + var partPos = getBidiPartAt(order, pos.ch) + side = partPos % 2 ? "right" : "left" } - var result = nodeAndOffsetInLineMap(info.map, pos.ch, side); - result.offset = result.collapse == "right" ? result.end : result.start; - return result; + var result = nodeAndOffsetInLineMap(info.map, pos.ch, side) + result.offset = result.collapse == "right" ? result.end : result.start + return result } -function badPos(pos, bad) { if (bad) pos.bad = true; return pos; } +function badPos(pos, bad) { if (bad) pos.bad = true; return pos } function domTextBetween(cm, from, to, fromLine, toLine) { - var text = "", closing = false, lineSep = cm.doc.lineSeparator(); - function recognizeMarker(id) { return function(marker) { return marker.id == id; }; } + var text = "", closing = false, lineSep = cm.doc.lineSeparator() + function recognizeMarker(id) { return function(marker) { return marker.id == id } } function walk(node) { if (node.nodeType == 1) { - var cmText = node.getAttribute("cm-text"); + var cmText = node.getAttribute("cm-text") if (cmText != null) { - if (cmText == "") cmText = node.textContent.replace(/\u200b/g, ""); - text += cmText; - return; + if (cmText == "") cmText = node.textContent.replace(/\u200b/g, "") + text += cmText + return } - var markerID = node.getAttribute("cm-marker"), range; + var markerID = node.getAttribute("cm-marker"), range if (markerID) { - var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); + var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)) if (found.length && (range = found[0].find())) - text += getBetween(cm.doc, range.from, range.to).join(lineSep); - return; + text += getBetween(cm.doc, range.from, range.to).join(lineSep) + return } - if (node.getAttribute("contenteditable") == "false") return; + if (node.getAttribute("contenteditable") == "false") return for (var i = 0; i < node.childNodes.length; i++) - walk(node.childNodes[i]); + walk(node.childNodes[i]) if (/^(pre|div|p)$/i.test(node.nodeName)) - closing = true; + closing = true } else if (node.nodeType == 3) { - var val = node.nodeValue; - if (!val) return; + var val = node.nodeValue + if (!val) return if (closing) { - text += lineSep; - closing = false; + text += lineSep + closing = false } - text += val; + text += val } } for (;;) { - walk(from); - if (from == to) break; - from = from.nextSibling; + walk(from) + if (from == to) break + from = from.nextSibling } - return text; + return text } function domToPos(cm, node, offset) { - var lineNode; + var lineNode if (node == cm.display.lineDiv) { - lineNode = cm.display.lineDiv.childNodes[offset]; - if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true); - node = null; offset = 0; + lineNode = cm.display.lineDiv.childNodes[offset] + if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) + node = null; offset = 0 } else { for (lineNode = node;; lineNode = lineNode.parentNode) { - if (!lineNode || lineNode == cm.display.lineDiv) return null; - if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break; + if (!lineNode || lineNode == cm.display.lineDiv) return null + if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break } } for (var i = 0; i < cm.display.view.length; i++) { - var lineView = cm.display.view[i]; + var lineView = cm.display.view[i] if (lineView.node == lineNode) - return locateNodeInLineView(lineView, node, offset); + return locateNodeInLineView(lineView, node, offset) } } function locateNodeInLineView(lineView, node, offset) { - var wrapper = lineView.text.firstChild, bad = false; - if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true); + var wrapper = lineView.text.firstChild, bad = false + if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true) if (node == wrapper) { - bad = true; - node = wrapper.childNodes[offset]; - offset = 0; + bad = true + node = wrapper.childNodes[offset] + offset = 0 if (!node) { - var line = lineView.rest ? lst(lineView.rest) : lineView.line; - return badPos(Pos(lineNo(line), line.text.length), bad); + var line = lineView.rest ? lst(lineView.rest) : lineView.line + return badPos(Pos(lineNo(line), line.text.length), bad) } } - var textNode = node.nodeType == 3 ? node : null, topNode = node; + var textNode = node.nodeType == 3 ? node : null, topNode = node if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { - textNode = node.firstChild; - if (offset) offset = textNode.nodeValue.length; + textNode = node.firstChild + if (offset) offset = textNode.nodeValue.length } - while (topNode.parentNode != wrapper) topNode = topNode.parentNode; - var measure = lineView.measure, maps = measure.maps; + while (topNode.parentNode != wrapper) topNode = topNode.parentNode + var measure = lineView.measure, maps = measure.maps function find(textNode, topNode, offset) { for (var i = -1; i < (maps ? maps.length : 0); i++) { - var map = i < 0 ? measure.map : maps[i]; + var map = i < 0 ? measure.map : maps[i] for (var j = 0; j < map.length; j += 3) { - var curNode = map[j + 2]; + var curNode = map[j + 2] if (curNode == textNode || curNode == topNode) { - var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); - var ch = map[j] + offset; - if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)]; - return Pos(line, ch); + var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]) + var ch = map[j] + offset + if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)] + return Pos(line, ch) } } } } - var found = find(textNode, topNode, offset); - if (found) return badPos(found, bad); + var found = find(textNode, topNode, offset) + if (found) return badPos(found, bad) // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { - found = find(after, after.firstChild, 0); + found = find(after, after.firstChild, 0) if (found) - return badPos(Pos(found.line, found.ch - dist), bad); + return badPos(Pos(found.line, found.ch - dist), bad) else - dist += after.textContent.length; + dist += after.textContent.length } for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) { - found = find(before, before.firstChild, -1); + found = find(before, before.firstChild, -1) if (found) - return badPos(Pos(found.line, found.ch + dist), bad); + return badPos(Pos(found.line, found.ch + dist), bad) else - dist += before.textContent.length; + dist += before.textContent.length } } diff --git a/src/input/TextareaInput.js b/src/input/TextareaInput.js index 421ce17a06..4c08f37797 100644 --- a/src/input/TextareaInput.js +++ b/src/input/TextareaInput.js @@ -1,210 +1,210 @@ -import { operation, runInOp } from "../display/operations"; -import { prepareSelection } from "../display/selection"; -import { applyTextInput, copyableRanges, handlePaste, hiddenTextarea, lastCopied, setLastCopied } from "./input"; -import { cursorCoords, posFromMouse } from "../measurement/position_measurement"; -import { eventInWidget } from "../measurement/widgets"; -import { simpleSelection } from "../model/selection"; -import { selectAll, setSelection } from "../model/selection_updates"; -import { captureRightClick, ie, ie_version, ios, mac, mobile, presto, webkit } from "../util/browser"; -import { activeElt, removeChildrenAndAdd, selectInput } from "../util/dom"; -import { e_preventDefault, e_stop, off, on, signalDOMEvent } from "../util/event"; -import { hasCopyEvent, hasSelection } from "../util/feature_detection"; -import { copyObj, Delayed, nothing, sel_dontScroll } from "../util/misc"; +import { operation, runInOp } from "../display/operations" +import { prepareSelection } from "../display/selection" +import { applyTextInput, copyableRanges, handlePaste, hiddenTextarea, lastCopied, setLastCopied } from "./input" +import { cursorCoords, posFromMouse } from "../measurement/position_measurement" +import { eventInWidget } from "../measurement/widgets" +import { simpleSelection } from "../model/selection" +import { selectAll, setSelection } from "../model/selection_updates" +import { captureRightClick, ie, ie_version, ios, mac, mobile, presto, webkit } from "../util/browser" +import { activeElt, removeChildrenAndAdd, selectInput } from "../util/dom" +import { e_preventDefault, e_stop, off, on, signalDOMEvent } from "../util/event" +import { hasCopyEvent, hasSelection } from "../util/feature_detection" +import { copyObj, Delayed, nothing, sel_dontScroll } from "../util/misc" // TEXTAREA INPUT STYLE export default function TextareaInput(cm) { - this.cm = cm; + this.cm = cm // See input.poll and input.reset - this.prevInput = ""; + this.prevInput = "" // Flag that indicates whether we expect input to appear real soon // now (after some event like 'keypress' or 'input') and are // polling intensively. - this.pollingFast = false; + this.pollingFast = false // Self-resetting timeout for the poller - this.polling = new Delayed(); + this.polling = new Delayed() // Tracks when input.reset has punted to just putting a short // string into the textarea instead of the full selection. - this.inaccurateSelection = false; + this.inaccurateSelection = false // Used to work around IE issue with selection being forgotten when focus moves away from textarea - this.hasSelection = false; - this.composing = null; + this.hasSelection = false + this.composing = null } TextareaInput.prototype = copyObj({ init: function(display) { - var input = this, cm = this.cm; + var input = this, cm = this.cm // Wraps and hides input textarea - var div = this.wrapper = hiddenTextarea(); + var div = this.wrapper = hiddenTextarea() // The semihidden textarea that is focused when the editor is // focused, and receives input. - var te = this.textarea = div.firstChild; - display.wrapper.insertBefore(div, display.wrapper.firstChild); + var te = this.textarea = div.firstChild + display.wrapper.insertBefore(div, display.wrapper.firstChild) // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) - if (ios) te.style.width = "0px"; + if (ios) te.style.width = "0px" on(te, "input", function() { - if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null; - input.poll(); - }); + if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null + input.poll() + }) on(te, "paste", function(e) { if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return - cm.state.pasteIncoming = true; - input.fastPoll(); - }); + cm.state.pasteIncoming = true + input.fastPoll() + }) function prepareCopyCut(e) { if (signalDOMEvent(cm, e)) return if (cm.somethingSelected()) { - setLastCopied({lineWise: false, text: cm.getSelections()}); + setLastCopied({lineWise: false, text: cm.getSelections()}) if (input.inaccurateSelection) { - input.prevInput = ""; - input.inaccurateSelection = false; - te.value = lastCopied.text.join("\n"); - selectInput(te); + input.prevInput = "" + input.inaccurateSelection = false + te.value = lastCopied.text.join("\n") + selectInput(te) } } else if (!cm.options.lineWiseCopyCut) { - return; + return } else { - var ranges = copyableRanges(cm); - setLastCopied({lineWise: true, text: ranges.text}); + var ranges = copyableRanges(cm) + setLastCopied({lineWise: true, text: ranges.text}) if (e.type == "cut") { - cm.setSelections(ranges.ranges, null, sel_dontScroll); + cm.setSelections(ranges.ranges, null, sel_dontScroll) } else { - input.prevInput = ""; - te.value = ranges.text.join("\n"); - selectInput(te); + input.prevInput = "" + te.value = ranges.text.join("\n") + selectInput(te) } } - if (e.type == "cut") cm.state.cutIncoming = true; + if (e.type == "cut") cm.state.cutIncoming = true } - on(te, "cut", prepareCopyCut); - on(te, "copy", prepareCopyCut); + on(te, "cut", prepareCopyCut) + on(te, "copy", prepareCopyCut) on(display.scroller, "paste", function(e) { - if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return; - cm.state.pasteIncoming = true; - input.focus(); - }); + if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return + cm.state.pasteIncoming = true + input.focus() + }) // Prevent normal selection in the editor (we handle our own) on(display.lineSpace, "selectstart", function(e) { - if (!eventInWidget(display, e)) e_preventDefault(e); - }); + if (!eventInWidget(display, e)) e_preventDefault(e) + }) on(te, "compositionstart", function() { - var start = cm.getCursor("from"); + var start = cm.getCursor("from") if (input.composing) input.composing.range.clear() input.composing = { start: start, range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"}) - }; - }); + } + }) on(te, "compositionend", function() { if (input.composing) { - input.poll(); - input.composing.range.clear(); - input.composing = null; + input.poll() + input.composing.range.clear() + input.composing = null } - }); + }) }, prepareSelection: function() { // Redraw the selection and/or cursor - var cm = this.cm, display = cm.display, doc = cm.doc; - var result = prepareSelection(cm); + var cm = this.cm, display = cm.display, doc = cm.doc + var result = prepareSelection(cm) // Move the hidden textarea near the cursor to prevent scrolling artifacts if (cm.options.moveInputWithCursor) { - var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); - var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); + var headPos = cursorCoords(cm, doc.sel.primary().head, "div") + var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect() result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, - headPos.top + lineOff.top - wrapOff.top)); + headPos.top + lineOff.top - wrapOff.top)) result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, - headPos.left + lineOff.left - wrapOff.left)); + headPos.left + lineOff.left - wrapOff.left)) } - return result; + return result }, showSelection: function(drawn) { - var cm = this.cm, display = cm.display; - removeChildrenAndAdd(display.cursorDiv, drawn.cursors); - removeChildrenAndAdd(display.selectionDiv, drawn.selection); + var cm = this.cm, display = cm.display + removeChildrenAndAdd(display.cursorDiv, drawn.cursors) + removeChildrenAndAdd(display.selectionDiv, drawn.selection) if (drawn.teTop != null) { - this.wrapper.style.top = drawn.teTop + "px"; - this.wrapper.style.left = drawn.teLeft + "px"; + this.wrapper.style.top = drawn.teTop + "px" + this.wrapper.style.left = drawn.teLeft + "px" } }, // Reset the input to correspond to the selection (or to be empty, // when not typing and nothing is selected) reset: function(typing) { - if (this.contextMenuPending) return; - var minimal, selected, cm = this.cm, doc = cm.doc; + if (this.contextMenuPending) return + var minimal, selected, cm = this.cm, doc = cm.doc if (cm.somethingSelected()) { - this.prevInput = ""; - var range = doc.sel.primary(); + this.prevInput = "" + var range = doc.sel.primary() minimal = hasCopyEvent && - (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000); - var content = minimal ? "-" : selected || cm.getSelection(); - this.textarea.value = content; - if (cm.state.focused) selectInput(this.textarea); - if (ie && ie_version >= 9) this.hasSelection = content; + (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000) + var content = minimal ? "-" : selected || cm.getSelection() + this.textarea.value = content + if (cm.state.focused) selectInput(this.textarea) + if (ie && ie_version >= 9) this.hasSelection = content } else if (!typing) { - this.prevInput = this.textarea.value = ""; - if (ie && ie_version >= 9) this.hasSelection = null; + this.prevInput = this.textarea.value = "" + if (ie && ie_version >= 9) this.hasSelection = null } - this.inaccurateSelection = minimal; + this.inaccurateSelection = minimal }, - getField: function() { return this.textarea; }, + getField: function() { return this.textarea }, - supportsTouch: function() { return false; }, + supportsTouch: function() { return false }, focus: function() { if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { - try { this.textarea.focus(); } + try { this.textarea.focus() } catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM } }, - blur: function() { this.textarea.blur(); }, + blur: function() { this.textarea.blur() }, resetPosition: function() { - this.wrapper.style.top = this.wrapper.style.left = 0; + this.wrapper.style.top = this.wrapper.style.left = 0 }, - receivedFocus: function() { this.slowPoll(); }, + receivedFocus: function() { this.slowPoll() }, // Poll for input changes, using the normal rate of polling. This // runs as long as the editor is focused. slowPoll: function() { - var input = this; - if (input.pollingFast) return; + var input = this + if (input.pollingFast) return input.polling.set(this.cm.options.pollInterval, function() { - input.poll(); - if (input.cm.state.focused) input.slowPoll(); - }); + input.poll() + if (input.cm.state.focused) input.slowPoll() + }) }, // When an event has just come in that is likely to add or change // something in the input textarea, we poll faster, to ensure that // the change appears on the screen quickly. fastPoll: function() { - var missed = false, input = this; - input.pollingFast = true; + var missed = false, input = this + input.pollingFast = true function p() { - var changed = input.poll(); - if (!changed && !missed) {missed = true; input.polling.set(60, p);} - else {input.pollingFast = false; input.slowPoll();} + var changed = input.poll() + if (!changed && !missed) {missed = true; input.polling.set(60, p)} + else {input.pollingFast = false; input.slowPoll()} } - input.polling.set(20, p); + input.polling.set(20, p) }, // Read input from the textarea, and update the document to match. @@ -214,7 +214,7 @@ TextareaInput.prototype = copyObj({ // seen text (can be empty), which is stored in prevInput (we must // not reset the textarea when typing, because that breaks IME). poll: function() { - var cm = this.cm, input = this.textarea, prevInput = this.prevInput; + var cm = this.cm, input = this.textarea, prevInput = this.prevInput // Since this is called a *lot*, try to bail out as cheaply as // possible when it is clear that nothing happened. hasSelection // will be the case when there is a lot of text in the textarea, @@ -222,138 +222,138 @@ TextareaInput.prototype = copyObj({ if (this.contextMenuPending || !cm.state.focused || (hasSelection(input) && !prevInput && !this.composing) || cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) - return false; + return false - var text = input.value; + var text = input.value // If nothing changed, bail. - if (text == prevInput && !cm.somethingSelected()) return false; + if (text == prevInput && !cm.somethingSelected()) return false // Work around nonsensical selection resetting in IE9/10, and // inexplicable appearance of private area unicode characters on // some key combos in Mac (#2689). if (ie && ie_version >= 9 && this.hasSelection === text || mac && /[\uf700-\uf7ff]/.test(text)) { - cm.display.input.reset(); - return false; + cm.display.input.reset() + return false } if (cm.doc.sel == cm.display.selForContextMenu) { - var first = text.charCodeAt(0); - if (first == 0x200b && !prevInput) prevInput = "\u200b"; - if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); } + var first = text.charCodeAt(0) + if (first == 0x200b && !prevInput) prevInput = "\u200b" + if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") } } // Find the part of the input that is actually new - var same = 0, l = Math.min(prevInput.length, text.length); - while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; + var same = 0, l = Math.min(prevInput.length, text.length) + while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same - var self = this; + var self = this runInOp(cm, function() { applyTextInput(cm, text.slice(same), prevInput.length - same, - null, self.composing ? "*compose" : null); + null, self.composing ? "*compose" : null) // Don't leave long text in the textarea, since it makes further polling slow - if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = ""; - else self.prevInput = text; + if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = "" + else self.prevInput = text if (self.composing) { - self.composing.range.clear(); + self.composing.range.clear() self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"), - {className: "CodeMirror-composing"}); + {className: "CodeMirror-composing"}) } - }); - return true; + }) + return true }, ensurePolled: function() { - if (this.pollingFast && this.poll()) this.pollingFast = false; + if (this.pollingFast && this.poll()) this.pollingFast = false }, onKeyPress: function() { - if (ie && ie_version >= 9) this.hasSelection = null; - this.fastPoll(); + if (ie && ie_version >= 9) this.hasSelection = null + this.fastPoll() }, onContextMenu: function(e) { - var input = this, cm = input.cm, display = cm.display, te = input.textarea; - var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; - if (!pos || presto) return; // Opera is difficult. + var input = this, cm = input.cm, display = cm.display, te = input.textarea + var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop + if (!pos || presto) return // Opera is difficult. // Reset the current text selection only if the click is done outside of the selection // and 'resetSelectionOnContextMenu' option is true. - var reset = cm.options.resetSelectionOnContextMenu; + var reset = cm.options.resetSelectionOnContextMenu if (reset && cm.doc.sel.contains(pos) == -1) - operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); + operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll) - var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText; + var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText input.wrapper.style.cssText = "position: absolute" var wrapperBox = input.wrapper.getBoundingClientRect() te.style.cssText = "position: absolute; width: 30px; height: 30px; top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px; z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + - "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; - if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712) - display.input.focus(); - if (webkit) window.scrollTo(null, oldScrollY); - display.input.reset(); + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);" + if (webkit) var oldScrollY = window.scrollY // Work around Chrome issue (#2712) + display.input.focus() + if (webkit) window.scrollTo(null, oldScrollY) + display.input.reset() // Adds "Select all" to context menu in FF - if (!cm.somethingSelected()) te.value = input.prevInput = " "; - input.contextMenuPending = true; - display.selForContextMenu = cm.doc.sel; - clearTimeout(display.detectingSelectAll); + if (!cm.somethingSelected()) te.value = input.prevInput = " " + input.contextMenuPending = true + display.selForContextMenu = cm.doc.sel + clearTimeout(display.detectingSelectAll) // Select-all will be greyed out if there's nothing to select, so // this adds a zero-width space so that we can later check whether // it got selected. function prepareSelectAllHack() { if (te.selectionStart != null) { - var selected = cm.somethingSelected(); - var extval = "\u200b" + (selected ? te.value : ""); - te.value = "\u21da"; // Used to catch context-menu undo - te.value = extval; - input.prevInput = selected ? "" : "\u200b"; - te.selectionStart = 1; te.selectionEnd = extval.length; + var selected = cm.somethingSelected() + var extval = "\u200b" + (selected ? te.value : "") + te.value = "\u21da" // Used to catch context-menu undo + te.value = extval + input.prevInput = selected ? "" : "\u200b" + te.selectionStart = 1; te.selectionEnd = extval.length // Re-set this, in case some other handler touched the // selection in the meantime. - display.selForContextMenu = cm.doc.sel; + display.selForContextMenu = cm.doc.sel } } function rehide() { - input.contextMenuPending = false; + input.contextMenuPending = false input.wrapper.style.cssText = oldWrapperCSS - te.style.cssText = oldCSS; - if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); + te.style.cssText = oldCSS + if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos) // Try to detect the user choosing select-all if (te.selectionStart != null) { - if (!ie || (ie && ie_version < 9)) prepareSelectAllHack(); + if (!ie || (ie && ie_version < 9)) prepareSelectAllHack() var i = 0, poll = function() { if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && te.selectionEnd > 0 && input.prevInput == "\u200b") - operation(cm, selectAll)(cm); - else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); - else display.input.reset(); - }; - display.detectingSelectAll = setTimeout(poll, 200); + operation(cm, selectAll)(cm) + else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500) + else display.input.reset() + } + display.detectingSelectAll = setTimeout(poll, 200) } } - if (ie && ie_version >= 9) prepareSelectAllHack(); + if (ie && ie_version >= 9) prepareSelectAllHack() if (captureRightClick) { - e_stop(e); + e_stop(e) var mouseup = function() { - off(window, "mouseup", mouseup); - setTimeout(rehide, 20); - }; - on(window, "mouseup", mouseup); + off(window, "mouseup", mouseup) + setTimeout(rehide, 20) + } + on(window, "mouseup", mouseup) } else { - setTimeout(rehide, 50); + setTimeout(rehide, 50) } }, readOnlyChanged: function(val) { - if (!val) this.reset(); + if (!val) this.reset() }, setUneditable: nothing, needsContentAttribute: false -}, TextareaInput.prototype); +}, TextareaInput.prototype) diff --git a/src/input/indent.js b/src/input/indent.js index d814452e8b..f0fc78fd05 100644 --- a/src/input/indent.js +++ b/src/input/indent.js @@ -1,10 +1,10 @@ -import { getStateBefore } from "../line/highlight"; -import { Pos } from "../line/pos"; -import { getLine } from "../line/utils_line"; -import { replaceRange } from "../model/changes"; -import { Range } from "../model/selection"; -import { replaceOneSelection } from "../model/selection_updates"; -import { countColumn, Pass, spaceStr } from "../util/misc"; +import { getStateBefore } from "../line/highlight" +import { Pos } from "../line/pos" +import { getLine } from "../line/utils_line" +import { replaceRange } from "../model/changes" +import { Range } from "../model/selection" +import { replaceOneSelection } from "../model/selection_updates" +import { countColumn, Pass, spaceStr } from "../util/misc" // Indent the given line. The how parameter can be "smart", // "add"/null, "subtract", or "prev". When aggressive is false @@ -12,59 +12,59 @@ import { countColumn, Pass, spaceStr } from "../util/misc"; // lines are not indented, and places where the mode returns Pass // are left alone. export function indentLine(cm, n, how, aggressive) { - var doc = cm.doc, state; - if (how == null) how = "add"; + var doc = cm.doc, state + if (how == null) how = "add" if (how == "smart") { // Fall back to "prev" when the mode doesn't have an indentation // method. - if (!doc.mode.indent) how = "prev"; - else state = getStateBefore(cm, n); + if (!doc.mode.indent) how = "prev" + else state = getStateBefore(cm, n) } - var tabSize = cm.options.tabSize; - var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); - if (line.stateAfter) line.stateAfter = null; - var curSpaceString = line.text.match(/^\s*/)[0], indentation; + var tabSize = cm.options.tabSize + var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize) + if (line.stateAfter) line.stateAfter = null + var curSpaceString = line.text.match(/^\s*/)[0], indentation if (!aggressive && !/\S/.test(line.text)) { - indentation = 0; - how = "not"; + indentation = 0 + how = "not" } else if (how == "smart") { - indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); + indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text) if (indentation == Pass || indentation > 150) { - if (!aggressive) return; - how = "prev"; + if (!aggressive) return + how = "prev" } } if (how == "prev") { - if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize); - else indentation = 0; + if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize) + else indentation = 0 } else if (how == "add") { - indentation = curSpace + cm.options.indentUnit; + indentation = curSpace + cm.options.indentUnit } else if (how == "subtract") { - indentation = curSpace - cm.options.indentUnit; + indentation = curSpace - cm.options.indentUnit } else if (typeof how == "number") { - indentation = curSpace + how; + indentation = curSpace + how } - indentation = Math.max(0, indentation); + indentation = Math.max(0, indentation) - var indentString = "", pos = 0; + var indentString = "", pos = 0 if (cm.options.indentWithTabs) - for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} - if (pos < indentation) indentString += spaceStr(indentation - pos); + for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t"} + if (pos < indentation) indentString += spaceStr(indentation - pos) if (indentString != curSpaceString) { - replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); - line.stateAfter = null; - return true; + replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input") + line.stateAfter = null + return true } else { // Ensure that, if the cursor was in the whitespace at the start // of the line, it is moved to the end of that space. for (var i = 0; i < doc.sel.ranges.length; i++) { - var range = doc.sel.ranges[i]; + var range = doc.sel.ranges[i] if (range.head.line == n && range.head.ch < curSpaceString.length) { - var pos = Pos(n, curSpaceString.length); - replaceOneSelection(doc, i, new Range(pos, pos)); - break; + var pos = Pos(n, curSpaceString.length) + replaceOneSelection(doc, i, new Range(pos, pos)) + break } } } diff --git a/src/input/input.js b/src/input/input.js index b017934a2c..a084e08f8b 100644 --- a/src/input/input.js +++ b/src/input/input.js @@ -1,133 +1,133 @@ -import { runInOp } from "../display/operations"; -import { ensureCursorVisible } from "../display/scrolling"; -import { Pos } from "../line/pos"; -import { getLine } from "../line/utils_line"; -import { makeChange } from "../model/changes"; -import { ios, webkit } from "../util/browser"; -import { elt } from "../util/dom"; -import { lst, map } from "../util/misc"; -import { signalLater } from "../util/operation_group"; +import { runInOp } from "../display/operations" +import { ensureCursorVisible } from "../display/scrolling" +import { Pos } from "../line/pos" +import { getLine } from "../line/utils_line" +import { makeChange } from "../model/changes" +import { ios, webkit } from "../util/browser" +import { elt } from "../util/dom" +import { lst, map } from "../util/misc" +import { signalLater } from "../util/operation_group" -import { indentLine } from "./indent"; +import { indentLine } from "./indent" // This will be set to a {lineWise: bool, text: [string]} object, so // that, when pasting, we know what kind of selections the copied // text was made out of. -export var lastCopied = null; +export var lastCopied = null export function setLastCopied(newLastCopied) { - lastCopied = newLastCopied; + lastCopied = newLastCopied } export function applyTextInput(cm, inserted, deleted, sel, origin) { - var doc = cm.doc; - cm.display.shift = false; - if (!sel) sel = doc.sel; + var doc = cm.doc + cm.display.shift = false + if (!sel) sel = doc.sel - var paste = cm.state.pasteIncoming || origin == "paste"; + var paste = cm.state.pasteIncoming || origin == "paste" var textLines = doc.splitLines(inserted), multiPaste = null // When pasing N lines into N selections, insert one line per selection if (paste && sel.ranges.length > 1) { if (lastCopied && lastCopied.text.join("\n") == inserted) { if (sel.ranges.length % lastCopied.text.length == 0) { - multiPaste = []; + multiPaste = [] for (var i = 0; i < lastCopied.text.length; i++) - multiPaste.push(doc.splitLines(lastCopied.text[i])); + multiPaste.push(doc.splitLines(lastCopied.text[i])) } } else if (textLines.length == sel.ranges.length) { - multiPaste = map(textLines, function(l) { return [l]; }); + multiPaste = map(textLines, function(l) { return [l] }) } } // Normal behavior is to insert the new text into every selection for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range = sel.ranges[i]; - var from = range.from(), to = range.to(); + var range = sel.ranges[i] + var from = range.from(), to = range.to() if (range.empty()) { if (deleted && deleted > 0) // Handle deletion - from = Pos(from.line, from.ch - deleted); + from = Pos(from.line, from.ch - deleted) else if (cm.state.overwrite && !paste) // Handle overwrite - to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); + to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)) else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted) from = to = Pos(from.line, 0) } - var updateInput = cm.curOp.updateInput; + var updateInput = cm.curOp.updateInput var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, - origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")}; - makeChange(cm.doc, changeEvent); - signalLater(cm, "inputRead", cm, changeEvent); + origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")} + makeChange(cm.doc, changeEvent) + signalLater(cm, "inputRead", cm, changeEvent) } if (inserted && !paste) - triggerElectric(cm, inserted); + triggerElectric(cm, inserted) - ensureCursorVisible(cm); - cm.curOp.updateInput = updateInput; - cm.curOp.typing = true; - cm.state.pasteIncoming = cm.state.cutIncoming = false; + ensureCursorVisible(cm) + cm.curOp.updateInput = updateInput + cm.curOp.typing = true + cm.state.pasteIncoming = cm.state.cutIncoming = false } export function handlePaste(e, cm) { - var pasted = e.clipboardData && e.clipboardData.getData("Text"); + var pasted = e.clipboardData && e.clipboardData.getData("Text") if (pasted) { - e.preventDefault(); + e.preventDefault() if (!cm.isReadOnly() && !cm.options.disableInput) - runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); }); - return true; + runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste") }) + return true } } export function triggerElectric(cm, inserted) { // When an 'electric' character is inserted, immediately trigger a reindent - if (!cm.options.electricChars || !cm.options.smartIndent) return; - var sel = cm.doc.sel; + if (!cm.options.electricChars || !cm.options.smartIndent) return + var sel = cm.doc.sel for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range = sel.ranges[i]; - if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue; - var mode = cm.getModeAt(range.head); - var indented = false; + var range = sel.ranges[i] + if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue + var mode = cm.getModeAt(range.head) + var indented = false if (mode.electricChars) { for (var j = 0; j < mode.electricChars.length; j++) if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { - indented = indentLine(cm, range.head.line, "smart"); - break; + indented = indentLine(cm, range.head.line, "smart") + break } } else if (mode.electricInput) { if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) - indented = indentLine(cm, range.head.line, "smart"); + indented = indentLine(cm, range.head.line, "smart") } - if (indented) signalLater(cm, "electricInput", cm, range.head.line); + if (indented) signalLater(cm, "electricInput", cm, range.head.line) } } export function copyableRanges(cm) { - var text = [], ranges = []; + var text = [], ranges = [] for (var i = 0; i < cm.doc.sel.ranges.length; i++) { - var line = cm.doc.sel.ranges[i].head.line; - var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}; - ranges.push(lineRange); - text.push(cm.getRange(lineRange.anchor, lineRange.head)); + var line = cm.doc.sel.ranges[i].head.line + var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)} + ranges.push(lineRange) + text.push(cm.getRange(lineRange.anchor, lineRange.head)) } - return {text: text, ranges: ranges}; + return {text: text, ranges: ranges} } export function disableBrowserMagic(field, spellcheck) { - field.setAttribute("autocorrect", "off"); - field.setAttribute("autocapitalize", "off"); - field.setAttribute("spellcheck", !!spellcheck); + field.setAttribute("autocorrect", "off") + field.setAttribute("autocapitalize", "off") + field.setAttribute("spellcheck", !!spellcheck) } export function hiddenTextarea() { - var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none"); - var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); + var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none") + var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;") // The textarea is kept positioned near the cursor to prevent the // fact that it'll be scrolled into view on input from scrolling // our fake cursor out of view. On webkit, when wrap=off, paste is // very slow. So make the area wide instead. - if (webkit) te.style.width = "1000px"; - else te.setAttribute("wrap", "off"); + if (webkit) te.style.width = "1000px" + else te.setAttribute("wrap", "off") // If border: 0; -- iOS fails to open keyboard (issue #1287) - if (ios) te.style.border = "1px solid black"; - disableBrowserMagic(te); - return div; + if (ios) te.style.border = "1px solid black" + disableBrowserMagic(te) + return div } diff --git a/src/input/keymap.js b/src/input/keymap.js index 7b2879247e..0f5941e81a 100644 --- a/src/input/keymap.js +++ b/src/input/keymap.js @@ -1,9 +1,9 @@ -import { flipCtrlCmd, mac, presto } from "../util/browser"; -import { map } from "../util/misc"; +import { flipCtrlCmd, mac, presto } from "../util/browser" +import { map } from "../util/misc" -import { keyNames } from "./keynames"; +import { keyNames } from "./keynames" -export var keyMap = {}; +export var keyMap = {} keyMap.basic = { "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", @@ -12,7 +12,7 @@ keyMap.basic = { "Tab": "defaultTab", "Shift-Tab": "indentAuto", "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", "Esc": "singleSelection" -}; +} // Note that the save and find-related commands aren't defined by // default. User code or addons can define them. Unknown commands // are simply ignored. @@ -25,7 +25,7 @@ keyMap.pcDefault = { "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", fallthrough: "basic" -}; +} // Very basic readline/emacs-style bindings, which are standard on Mac. keyMap.emacsy = { "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", @@ -33,7 +33,7 @@ keyMap.emacsy = { "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars", "Ctrl-O": "openLine" -}; +} keyMap.macDefault = { "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", @@ -43,27 +43,27 @@ keyMap.macDefault = { "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", fallthrough: ["basic", "emacsy"] -}; -keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; +} +keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault // KEYMAP DISPATCH function normalizeKeyName(name) { - var parts = name.split(/-(?!$)/), name = parts[parts.length - 1]; - var alt, ctrl, shift, cmd; + var parts = name.split(/-(?!$)/), name = parts[parts.length - 1] + var alt, ctrl, shift, cmd for (var i = 0; i < parts.length - 1; i++) { - var mod = parts[i]; - if (/^(cmd|meta|m)$/i.test(mod)) cmd = true; - else if (/^a(lt)?$/i.test(mod)) alt = true; - else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true; - else if (/^s(hift)$/i.test(mod)) shift = true; - else throw new Error("Unrecognized modifier name: " + mod); + var mod = parts[i] + if (/^(cmd|meta|m)$/i.test(mod)) cmd = true + else if (/^a(lt)?$/i.test(mod)) alt = true + else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true + else if (/^s(hift)$/i.test(mod)) shift = true + else throw new Error("Unrecognized modifier name: " + mod) } - if (alt) name = "Alt-" + name; - if (ctrl) name = "Ctrl-" + name; - if (cmd) name = "Cmd-" + name; - if (shift) name = "Shift-" + name; - return name; + if (alt) name = "Alt-" + name + if (ctrl) name = "Ctrl-" + name + if (cmd) name = "Cmd-" + name + if (shift) name = "Shift-" + name + return name } // This is a kludge to keep keymaps mostly working as raw objects @@ -72,45 +72,45 @@ function normalizeKeyName(name) { // new normalized keymap, and then updates the old object to reflect // this. export function normalizeKeyMap(keymap) { - var copy = {}; + var copy = {} for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) { - var value = keymap[keyname]; - if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue; - if (value == "...") { delete keymap[keyname]; continue; } + var value = keymap[keyname] + if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue + if (value == "...") { delete keymap[keyname]; continue } - var keys = map(keyname.split(" "), normalizeKeyName); + var keys = map(keyname.split(" "), normalizeKeyName) for (var i = 0; i < keys.length; i++) { - var val, name; + var val, name if (i == keys.length - 1) { - name = keys.join(" "); - val = value; + name = keys.join(" ") + val = value } else { - name = keys.slice(0, i + 1).join(" "); - val = "..."; + name = keys.slice(0, i + 1).join(" ") + val = "..." } - var prev = copy[name]; - if (!prev) copy[name] = val; - else if (prev != val) throw new Error("Inconsistent bindings for " + name); + var prev = copy[name] + if (!prev) copy[name] = val + else if (prev != val) throw new Error("Inconsistent bindings for " + name) } - delete keymap[keyname]; + delete keymap[keyname] } - for (var prop in copy) keymap[prop] = copy[prop]; - return keymap; + for (var prop in copy) keymap[prop] = copy[prop] + return keymap } export function lookupKey(key, map, handle, context) { - map = getKeyMap(map); - var found = map.call ? map.call(key, context) : map[key]; - if (found === false) return "nothing"; - if (found === "...") return "multi"; - if (found != null && handle(found)) return "handled"; + map = getKeyMap(map) + var found = map.call ? map.call(key, context) : map[key] + if (found === false) return "nothing" + if (found === "...") return "multi" + if (found != null && handle(found)) return "handled" if (map.fallthrough) { if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") - return lookupKey(key, map.fallthrough, handle, context); + return lookupKey(key, map.fallthrough, handle, context) for (var i = 0; i < map.fallthrough.length; i++) { - var result = lookupKey(key, map.fallthrough[i], handle, context); - if (result) return result; + var result = lookupKey(key, map.fallthrough[i], handle, context) + if (result) return result } } } @@ -118,22 +118,22 @@ export function lookupKey(key, map, handle, context) { // Modifier key presses don't count as 'real' key presses for the // purpose of keymap fallthrough. export function isModifierKey(value) { - var name = typeof value == "string" ? value : keyNames[value.keyCode]; - return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; + var name = typeof value == "string" ? value : keyNames[value.keyCode] + return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod" } // Look up the name of a key as indicated by an event object. export function keyName(event, noShift) { - if (presto && event.keyCode == 34 && event["char"]) return false; - var base = keyNames[event.keyCode], name = base; - if (name == null || event.altGraphKey) return false; - if (event.altKey && base != "Alt") name = "Alt-" + name; - if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name; - if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name; - if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name; - return name; + if (presto && event.keyCode == 34 && event["char"]) return false + var base = keyNames[event.keyCode], name = base + if (name == null || event.altGraphKey) return false + if (event.altKey && base != "Alt") name = "Alt-" + name + if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name + if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name + if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name + return name } export function getKeyMap(val) { - return typeof val == "string" ? keyMap[val] : val; + return typeof val == "string" ? keyMap[val] : val } diff --git a/src/input/keynames.js b/src/input/keynames.js index 5956093e82..8cf11f38cd 100644 --- a/src/input/keynames.js +++ b/src/input/keynames.js @@ -7,11 +7,11 @@ export var keyNames = { 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" -}; +} // Number keys -for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); +for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i) // Alphabetic keys -for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); +for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i) // Function keys -for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; +for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i diff --git a/src/line/highlight.js b/src/line/highlight.js index eada1a0671..0632be6e3e 100644 --- a/src/line/highlight.js +++ b/src/line/highlight.js @@ -1,9 +1,9 @@ -import { countColumn } from "../util/misc"; -import { copyState, innerMode, startState } from "../modes"; -import StringStream from "../util/StringStream"; +import { countColumn } from "../util/misc" +import { copyState, innerMode, startState } from "../modes" +import StringStream from "../util/StringStream" -import { getLine, lineNo } from "./utils_line"; -import { clipPos } from "./pos"; +import { getLine, lineNo } from "./utils_line" +import { clipPos } from "./pos" // Compute a style array (an array starting with a mode generation // -- for invalidation -- followed by pairs of end positions and @@ -12,98 +12,98 @@ import { clipPos } from "./pos"; export 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], lineClasses = {}; + var st = [cm.state.modeGen], lineClasses = {} // Compute the base array of styles runMode(cm, line.text, cm.doc.mode, state, function(end, style) { - st.push(end, style); - }, lineClasses, forceToEnd); + st.push(end, style) + }, lineClasses, forceToEnd) // Run overlays, adjust style array. for (var o = 0; o < cm.state.overlays.length; ++o) { - var overlay = cm.state.overlays[o], i = 1, at = 0; + var overlay = cm.state.overlays[o], i = 1, at = 0 runMode(cm, line.text, overlay.mode, true, function(end, style) { - var start = i; + var start = i // Ensure there's a token end at the current position, and that i points at it while (at < end) { - var i_end = st[i]; + var i_end = st[i] if (i_end > end) - st.splice(i, 1, end, st[i+1], i_end); - i += 2; - at = Math.min(end, i_end); + st.splice(i, 1, end, st[i+1], i_end) + i += 2 + at = Math.min(end, i_end) } - if (!style) return; + if (!style) return if (overlay.opaque) { - st.splice(start, i - start, end, "cm-overlay " + style); - i = start + 2; + st.splice(start, i - start, end, "cm-overlay " + style) + i = start + 2 } else { for (; start < i; start += 2) { - var cur = st[start+1]; - st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style; + var cur = st[start+1] + st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style } } - }, lineClasses); + }, lineClasses) } - return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}; + return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null} } export function getLineStyles(cm, line, updateFrontier) { if (!line.styles || line.styles[0] != cm.state.modeGen) { - var state = getStateBefore(cm, lineNo(line)); - var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state); - line.stateAfter = state; - line.styles = result.styles; - if (result.classes) line.styleClasses = result.classes; - else if (line.styleClasses) line.styleClasses = null; - if (updateFrontier === cm.doc.frontier) cm.doc.frontier++; + var state = getStateBefore(cm, lineNo(line)) + var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state) + line.stateAfter = state + line.styles = result.styles + if (result.classes) line.styleClasses = result.classes + else if (line.styleClasses) line.styleClasses = null + if (updateFrontier === cm.doc.frontier) cm.doc.frontier++ } - return line.styles; + return line.styles } export function getStateBefore(cm, n, precise) { - var doc = cm.doc, display = cm.display; - if (!doc.mode.startState) return true; - var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter; - if (!state) state = startState(doc.mode); - else state = copyState(doc.mode, state); + var doc = cm.doc, display = cm.display + if (!doc.mode.startState) return true + var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter + if (!state) state = startState(doc.mode) + else state = copyState(doc.mode, state) doc.iter(pos, n, function(line) { - processLine(cm, line.text, state); - var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo; - line.stateAfter = save ? copyState(doc.mode, state) : null; - ++pos; - }); - if (precise) doc.frontier = pos; - return state; + processLine(cm, line.text, state) + var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo + line.stateAfter = save ? copyState(doc.mode, state) : null + ++pos + }) + if (precise) doc.frontier = pos + return state } // Lightweight form of highlight -- proceed over this line and // update state, but don't save a style array. Used for lines that // aren't currently visible. export function processLine(cm, text, state, startAt) { - var mode = cm.doc.mode; - var stream = new StringStream(text, cm.options.tabSize); - stream.start = stream.pos = startAt || 0; - if (text == "") callBlankLine(mode, state); + var mode = cm.doc.mode + var stream = new StringStream(text, cm.options.tabSize) + stream.start = stream.pos = startAt || 0 + if (text == "") callBlankLine(mode, state) while (!stream.eol()) { - readToken(mode, stream, state); - stream.start = stream.pos; + readToken(mode, stream, state) + stream.start = stream.pos } } function callBlankLine(mode, state) { - if (mode.blankLine) return mode.blankLine(state); - if (!mode.innerMode) return; - var inner = innerMode(mode, state); - if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); + if (mode.blankLine) return mode.blankLine(state) + if (!mode.innerMode) return + var inner = innerMode(mode, state) + if (inner.mode.blankLine) return inner.mode.blankLine(inner.state) } export function readToken(mode, stream, state, inner) { for (var i = 0; i < 10; i++) { - if (inner) inner[0] = innerMode(mode, state).mode; - var style = mode.token(stream, state); - if (stream.pos > stream.start) return style; + if (inner) inner[0] = innerMode(mode, state).mode + var style = mode.token(stream, state) + if (stream.pos > stream.start) return style } - throw new Error("Mode " + mode.name + " failed to advance stream."); + throw new Error("Mode " + mode.name + " failed to advance stream.") } // Utility for getTokenAt and getLineTokens @@ -112,73 +112,73 @@ export function takeToken(cm, pos, precise, asArray) { return {start: stream.start, end: stream.pos, string: stream.current(), type: style || null, - state: copy ? copyState(doc.mode, state) : state}; + state: copy ? copyState(doc.mode, state) : state} } - var doc = cm.doc, mode = doc.mode, style; - pos = clipPos(doc, pos); - var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise); - var stream = new StringStream(line.text, cm.options.tabSize), tokens; - if (asArray) tokens = []; + var doc = cm.doc, mode = doc.mode, style + pos = clipPos(doc, pos) + var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise) + var stream = new StringStream(line.text, cm.options.tabSize), tokens + if (asArray) tokens = [] while ((asArray || stream.pos < pos.ch) && !stream.eol()) { - stream.start = stream.pos; - style = readToken(mode, stream, state); - if (asArray) tokens.push(getObj(true)); + stream.start = stream.pos + style = readToken(mode, stream, state) + if (asArray) tokens.push(getObj(true)) } - return asArray ? tokens : getObj(); + return asArray ? tokens : getObj() } function extractLineClasses(type, output) { if (type) for (;;) { - var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); - if (!lineClass) break; - type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); - var prop = lineClass[1] ? "bgClass" : "textClass"; + var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/) + if (!lineClass) break + type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length) + var prop = lineClass[1] ? "bgClass" : "textClass" if (output[prop] == null) - output[prop] = lineClass[2]; + output[prop] = lineClass[2] else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) - output[prop] += " " + lineClass[2]; + output[prop] += " " + lineClass[2] } - return type; + return type } // Run the given mode's parser over a line, calling f for each token. function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { - var flattenSpans = mode.flattenSpans; - if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; - var curStart = 0, curStyle = null; - var stream = new StringStream(text, cm.options.tabSize), style; - var inner = cm.options.addModeClass && [null]; - if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); + var flattenSpans = mode.flattenSpans + if (flattenSpans == null) flattenSpans = cm.options.flattenSpans + var curStart = 0, curStyle = null + var stream = new StringStream(text, cm.options.tabSize), style + var inner = cm.options.addModeClass && [null] + if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses) 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; + flattenSpans = false + if (forceToEnd) processLine(cm, text, state, stream.pos) + stream.pos = text.length + style = null } else { - style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses); + style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses) } if (inner) { - var mName = inner[0].name; - if (mName) style = "m-" + (style ? mName + " " + style : mName); + var mName = inner[0].name + if (mName) style = "m-" + (style ? mName + " " + style : mName) } if (!flattenSpans || curStyle != style) { while (curStart < stream.start) { - curStart = Math.min(stream.start, curStart + 5000); - f(curStart, curStyle); + curStart = Math.min(stream.start, curStart + 5000) + f(curStart, curStyle) } - curStyle = style; + curStyle = style } - stream.start = stream.pos; + stream.start = stream.pos } while (curStart < stream.pos) { // Webkit seems to refuse to render text nodes longer than 57444 // characters, and returns inaccurate measurements in nodes // starting around 5000 chars. - var pos = Math.min(stream.pos, curStart + 5000); - f(pos, curStyle); - curStart = pos; + var pos = Math.min(stream.pos, curStart + 5000) + f(pos, curStyle) + curStart = pos } } @@ -188,17 +188,17 @@ function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { // smallest indentation, which tends to need the least context to // parse correctly. function findStartLine(cm, n, precise) { - var minindent, minline, doc = cm.doc; - var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); + var minindent, minline, doc = cm.doc + var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100) for (var search = n; search > lim; --search) { - if (search <= doc.first) return doc.first; - var line = getLine(doc, search - 1); - if (line.stateAfter && (!precise || search <= doc.frontier)) return search; - var indented = countColumn(line.text, null, cm.options.tabSize); + if (search <= doc.first) return doc.first + var line = getLine(doc, search - 1) + if (line.stateAfter && (!precise || search <= doc.frontier)) return search + var indented = countColumn(line.text, null, cm.options.tabSize) if (minline == null || minindent > indented) { - minline = search - 1; - minindent = indented; + minline = search - 1 + minindent = indented } } - return minline; + return minline } diff --git a/src/line/line_data.js b/src/line/line_data.js index 018bd0e297..688aa1bdd2 100644 --- a/src/line/line_data.js +++ b/src/line/line_data.js @@ -1,55 +1,55 @@ -import { getOrder } from "../util/bidi"; -import { ie, ie_version, webkit } from "../util/browser"; -import { elt, joinClasses } from "../util/dom"; -import { eventMixin, signal } from "../util/event"; -import { hasBadBidiRects, zeroWidthElement } from "../util/feature_detection"; -import { lst, spaceStr } from "../util/misc"; +import { getOrder } from "../util/bidi" +import { ie, ie_version, webkit } from "../util/browser" +import { elt, joinClasses } from "../util/dom" +import { eventMixin, signal } from "../util/event" +import { hasBadBidiRects, zeroWidthElement } from "../util/feature_detection" +import { lst, spaceStr } from "../util/misc" -import { getLineStyles } from "./highlight"; -import { attachMarkedSpans, compareCollapsedMarkers, detachMarkedSpans, lineIsHidden, visualLineContinued } from "./spans"; -import { getLine, lineNo, updateLineHeight } from "./utils_line"; +import { getLineStyles } from "./highlight" +import { attachMarkedSpans, compareCollapsedMarkers, detachMarkedSpans, lineIsHidden, visualLineContinued } from "./spans" +import { getLine, lineNo, updateLineHeight } from "./utils_line" // LINE DATA STRUCTURE // Line objects. These hold state related to a line, including // highlighting info (the styles array). export function Line(text, markedSpans, estimateHeight) { - this.text = text; - attachMarkedSpans(this, markedSpans); - this.height = estimateHeight ? estimateHeight(this) : 1; + this.text = text + attachMarkedSpans(this, markedSpans) + this.height = estimateHeight ? estimateHeight(this) : 1 } -eventMixin(Line); -Line.prototype.lineNo = function() { return lineNo(this); }; +eventMixin(Line) +Line.prototype.lineNo = function() { return lineNo(this) } // Change the content (text, markers) of a line. Automatically // invalidates cached information and tries to re-estimate the // line's height. export function updateLine(line, text, markedSpans, estimateHeight) { - line.text = text; - if (line.stateAfter) line.stateAfter = null; - if (line.styles) line.styles = null; - if (line.order != null) line.order = null; - detachMarkedSpans(line); - attachMarkedSpans(line, markedSpans); - var estHeight = estimateHeight ? estimateHeight(line) : 1; - if (estHeight != line.height) updateLineHeight(line, estHeight); + line.text = text + if (line.stateAfter) line.stateAfter = null + if (line.styles) line.styles = null + if (line.order != null) line.order = null + detachMarkedSpans(line) + attachMarkedSpans(line, markedSpans) + var estHeight = estimateHeight ? estimateHeight(line) : 1 + if (estHeight != line.height) updateLineHeight(line, estHeight) } // Detach a line from the document tree and its markers. export function cleanUpLine(line) { - line.parent = null; - detachMarkedSpans(line); + line.parent = null + detachMarkedSpans(line) } // Convert a style as returned by a mode (either null, or a string // containing one or more styles) to a CSS style. This is cached, // and also looks for line-wide styles. -var styleToClassCache = {}, styleToClassCacheWithMode = {}; +var styleToClassCache = {}, styleToClassCacheWithMode = {} function interpretTokenStyle(style, options) { - if (!style || /^\s*$/.test(style)) return null; - var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; + if (!style || /^\s*$/.test(style)) return null + var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache return cache[style] || - (cache[style] = style.replace(/\S+/g, "cm-$&")); + (cache[style] = style.replace(/\S+/g, "cm-$&")) } // Render the DOM representation of the text of a line. Also builds @@ -61,43 +61,43 @@ export function buildLineContent(cm, lineView) { // The padding-right forces the element to have a 'border', which // is needed on Webkit to be able to get line-level bounding // rectangles for it (in measureChar). - var content = elt("span", null, null, webkit ? "padding-right: .1px" : null); + var content = elt("span", null, null, webkit ? "padding-right: .1px" : null) var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content, col: 0, pos: 0, cm: cm, trailingSpace: false, - splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")}; - lineView.measure = {}; + splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")} + lineView.measure = {} // Iterate over the logical lines that make up this visual line. for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { - var line = i ? lineView.rest[i - 1] : lineView.line, order; - builder.pos = 0; - builder.addToken = buildToken; + var line = i ? lineView.rest[i - 1] : lineView.line, order + builder.pos = 0 + builder.addToken = buildToken // Optionally wire in some hacks into the token-rendering // algorithm, to deal with browser quirks. if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) - builder.addToken = buildTokenBadBidi(builder.addToken, order); - builder.map = []; - var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line); - insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)); + builder.addToken = buildTokenBadBidi(builder.addToken, order) + builder.map = [] + var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line) + insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)) if (line.styleClasses) { if (line.styleClasses.bgClass) - builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); + builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "") if (line.styleClasses.textClass) - builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); + builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "") } // Ensure at least a single node is present, for measuring. if (builder.map.length == 0) - builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); + builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))) // Store the map and a cache object for the current logical line if (i == 0) { - lineView.measure.map = builder.map; - lineView.measure.cache = {}; + lineView.measure.map = builder.map + lineView.measure.cache = {} } else { - (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map); - (lineView.measure.caches || (lineView.measure.caches = [])).push({}); + (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map) + ;(lineView.measure.caches || (lineView.measure.caches = [])).push({}) } } @@ -105,82 +105,82 @@ export function buildLineContent(cm, lineView) { if (webkit) { var last = builder.content.lastChild if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab"))) - builder.content.className = "cm-tab-wrap-hack"; + builder.content.className = "cm-tab-wrap-hack" } - signal(cm, "renderLine", cm, lineView.line, builder.pre); + signal(cm, "renderLine", cm, lineView.line, builder.pre) if (builder.pre.className) - builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); + builder.textClass = joinClasses(builder.pre.className, builder.textClass || "") - return builder; + return builder } export function defaultSpecialCharPlaceholder(ch) { - var token = elt("span", "\u2022", "cm-invalidchar"); - token.title = "\\u" + ch.charCodeAt(0).toString(16); - token.setAttribute("aria-label", token.title); - return token; + var token = elt("span", "\u2022", "cm-invalidchar") + token.title = "\\u" + ch.charCodeAt(0).toString(16) + token.setAttribute("aria-label", token.title) + return token } // Build up the DOM representation for a single token, and add it to // the line map. Takes care to render special characters separately. function buildToken(builder, text, style, startStyle, endStyle, title, css) { - if (!text) return; + if (!text) return var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text - var special = builder.cm.state.specialChars, mustWrap = false; + var special = builder.cm.state.specialChars, mustWrap = false if (!special.test(text)) { - builder.col += text.length; - var content = document.createTextNode(displayText); - builder.map.push(builder.pos, builder.pos + text.length, content); - if (ie && ie_version < 9) mustWrap = true; - builder.pos += text.length; + builder.col += text.length + var content = document.createTextNode(displayText) + builder.map.push(builder.pos, builder.pos + text.length, content) + if (ie && ie_version < 9) mustWrap = true + builder.pos += text.length } else { - var content = document.createDocumentFragment(), pos = 0; + var content = document.createDocumentFragment(), pos = 0 while (true) { - special.lastIndex = pos; - var m = special.exec(text); - var skipped = m ? m.index - pos : text.length - pos; + special.lastIndex = pos + var m = special.exec(text) + var skipped = m ? m.index - pos : text.length - pos if (skipped) { - var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); - if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); - else content.appendChild(txt); - builder.map.push(builder.pos, builder.pos + skipped, txt); - builder.col += skipped; - builder.pos += skipped; + var txt = document.createTextNode(displayText.slice(pos, pos + skipped)) + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])) + else content.appendChild(txt) + builder.map.push(builder.pos, builder.pos + skipped, txt) + builder.col += skipped + builder.pos += skipped } - if (!m) break; - pos += skipped + 1; + if (!m) break + pos += skipped + 1 if (m[0] == "\t") { - var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; - var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); - txt.setAttribute("role", "presentation"); - txt.setAttribute("cm-text", "\t"); - builder.col += tabWidth; + var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize + var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")) + txt.setAttribute("role", "presentation") + txt.setAttribute("cm-text", "\t") + builder.col += tabWidth } else if (m[0] == "\r" || m[0] == "\n") { - var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")); - txt.setAttribute("cm-text", m[0]); - builder.col += 1; + var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")) + txt.setAttribute("cm-text", m[0]) + builder.col += 1 } else { - var txt = builder.cm.options.specialCharPlaceholder(m[0]); - txt.setAttribute("cm-text", m[0]); - if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); - else content.appendChild(txt); - builder.col += 1; + var txt = builder.cm.options.specialCharPlaceholder(m[0]) + txt.setAttribute("cm-text", m[0]) + if (ie && ie_version < 9) content.appendChild(elt("span", [txt])) + else content.appendChild(txt) + builder.col += 1 } - builder.map.push(builder.pos, builder.pos + 1, txt); - builder.pos++; + builder.map.push(builder.pos, builder.pos + 1, txt) + builder.pos++ } } builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32 if (style || startStyle || endStyle || mustWrap || css) { - var fullStyle = style || ""; - if (startStyle) fullStyle += startStyle; - if (endStyle) fullStyle += endStyle; - var token = elt("span", [content], fullStyle, css); - if (title) token.title = title; - return builder.content.appendChild(token); + var fullStyle = style || "" + if (startStyle) fullStyle += startStyle + if (endStyle) fullStyle += endStyle + var token = elt("span", [content], fullStyle, css) + if (title) token.title = title + return builder.content.appendChild(token) } - builder.content.appendChild(content); + builder.content.appendChild(content) } function splitSpaces(text, trailingBefore) { @@ -200,105 +200,105 @@ function splitSpaces(text, trailingBefore) { // right-to-left text. function buildTokenBadBidi(inner, order) { return function(builder, text, style, startStyle, endStyle, title, css) { - style = style ? style + " cm-force-border" : "cm-force-border"; - var start = builder.pos, end = start + text.length; + style = style ? style + " cm-force-border" : "cm-force-border" + var start = builder.pos, end = start + text.length for (;;) { // Find the part that overlaps with the start of this text for (var i = 0; i < order.length; i++) { - var part = order[i]; - if (part.to > start && part.from <= start) break; + var part = order[i] + if (part.to > start && part.from <= start) break } - if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css); - inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css); - startStyle = null; - text = text.slice(part.to - start); - start = part.to; + if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css) + inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css) + startStyle = null + text = text.slice(part.to - start) + start = part.to } - }; + } } function buildCollapsedSpan(builder, size, marker, ignoreWidget) { - var widget = !ignoreWidget && marker.widgetNode; - if (widget) builder.map.push(builder.pos, builder.pos + size, widget); + var widget = !ignoreWidget && marker.widgetNode + if (widget) builder.map.push(builder.pos, builder.pos + size, widget) if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { if (!widget) - widget = builder.content.appendChild(document.createElement("span")); - widget.setAttribute("cm-marker", marker.id); + widget = builder.content.appendChild(document.createElement("span")) + widget.setAttribute("cm-marker", marker.id) } if (widget) { - builder.cm.display.input.setUneditable(widget); - builder.content.appendChild(widget); + builder.cm.display.input.setUneditable(widget) + builder.content.appendChild(widget) } - builder.pos += size; + builder.pos += size builder.trailingSpace = false } // Outputs a number of spans to make up a line, taking highlighting // and marked text into account. function insertLineContent(line, builder, styles) { - var spans = line.markedSpans, allText = line.text, at = 0; + var spans = line.markedSpans, allText = line.text, at = 0 if (!spans) { for (var i = 1; i < styles.length; i+=2) - builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options)); - return; + builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options)) + return } - var len = allText.length, pos = 0, i = 1, text = "", style, css; - var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; + var len = allText.length, pos = 0, i = 1, text = "", style, css + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed for (;;) { if (nextChange == pos) { // Update current marker set - spanStyle = spanEndStyle = spanStartStyle = title = css = ""; - collapsed = null; nextChange = Infinity; + spanStyle = spanEndStyle = spanStartStyle = title = css = "" + collapsed = null; nextChange = Infinity var foundBookmarks = [], endStyles for (var j = 0; j < spans.length; ++j) { - var sp = spans[j], m = sp.marker; + var sp = spans[j], m = sp.marker if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { - foundBookmarks.push(m); + foundBookmarks.push(m) } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { if (sp.to != null && sp.to != pos && nextChange > sp.to) { - nextChange = sp.to; - spanEndStyle = ""; + nextChange = sp.to + spanEndStyle = "" } - if (m.className) spanStyle += " " + m.className; - if (m.css) css = (css ? css + ";" : "") + m.css; - if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; + if (m.className) spanStyle += " " + m.className + if (m.css) css = (css ? css + ";" : "") + m.css + if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to) - if (m.title && !title) title = m.title; + if (m.title && !title) title = m.title if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) - collapsed = sp; + collapsed = sp } else if (sp.from > pos && nextChange > sp.from) { - nextChange = sp.from; + nextChange = sp.from } } if (endStyles) for (var j = 0; j < endStyles.length; j += 2) if (endStyles[j + 1] == nextChange) spanEndStyle += " " + endStyles[j] if (!collapsed || collapsed.from == pos) for (var j = 0; j < foundBookmarks.length; ++j) - buildCollapsedSpan(builder, 0, foundBookmarks[j]); + buildCollapsedSpan(builder, 0, foundBookmarks[j]) if (collapsed && (collapsed.from || 0) == pos) { buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, - collapsed.marker, collapsed.from == null); - if (collapsed.to == null) return; - if (collapsed.to == pos) collapsed = false; + collapsed.marker, collapsed.from == null) + if (collapsed.to == null) return + if (collapsed.to == pos) collapsed = false } } - if (pos >= len) break; + if (pos >= len) break - var upto = Math.min(len, nextChange); + var upto = Math.min(len, nextChange) while (true) { if (text) { - var end = pos + text.length; + var end = pos + text.length if (!collapsed) { - var tokenText = end > upto ? text.slice(0, upto - pos) : text; + var tokenText = end > upto ? text.slice(0, upto - pos) : text builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, - spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css); + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css) } - if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} - pos = end; - spanStartStyle = ""; + if (end >= upto) {text = text.slice(upto - pos); pos = upto; break} + pos = end + spanStartStyle = "" } - text = allText.slice(at, at = styles[i++]); - style = interpretTokenStyle(styles[i++], builder.cm.options); + text = allText.slice(at, at = styles[i++]) + style = interpretTokenStyle(styles[i++], builder.cm.options) } } } @@ -309,22 +309,22 @@ function insertLineContent(line, builder, styles) { // logical lines, if those are connected by collapsed ranges. export function LineView(doc, line, lineN) { // The starting line - this.line = line; + this.line = line // Continuing lines, if any - this.rest = visualLineContinued(line); + this.rest = visualLineContinued(line) // Number of logical lines in this visual line - this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; - this.node = this.text = null; - this.hidden = lineIsHidden(doc, line); + this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1 + this.node = this.text = null + this.hidden = lineIsHidden(doc, line) } // Create a range of LineView objects for the given lines. export function buildViewArray(cm, from, to) { - var array = [], nextPos; + var array = [], nextPos for (var pos = from; pos < to; pos = nextPos) { - var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); - nextPos = pos + view.size; - array.push(view); + var view = new LineView(cm.doc, getLine(cm.doc, pos), pos) + nextPos = pos + view.size + array.push(view) } - return array; + return array } diff --git a/src/line/pos.js b/src/line/pos.js index e81eb58493..b5d2513abe 100644 --- a/src/line/pos.js +++ b/src/line/pos.js @@ -1,35 +1,35 @@ -import { getLine } from "./utils_line"; +import { getLine } from "./utils_line" // A Pos instance represents a position within the text. export function Pos (line, ch) { - if (!(this instanceof Pos)) return new Pos(line, ch); - this.line = line; this.ch = ch; + if (!(this instanceof Pos)) return new Pos(line, ch) + this.line = line; this.ch = ch } // Compare two positions, return 0 if they are the same, a negative // number when a is less, and a positive number otherwise. -export function cmp(a, b) { return a.line - b.line || a.ch - b.ch; } +export function cmp(a, b) { return a.line - b.line || a.ch - b.ch } -export function copyPos(x) {return Pos(x.line, x.ch);} -export function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; } -export function minPos(a, b) { return cmp(a, b) < 0 ? a : b; } +export function copyPos(x) {return Pos(x.line, x.ch)} +export function maxPos(a, b) { return cmp(a, b) < 0 ? b : a } +export function minPos(a, b) { return cmp(a, b) < 0 ? a : b } // Most of the external API clips given positions to make sure they // actually exist within the document. -export function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));} +export function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))} export function clipPos(doc, pos) { - if (pos.line < doc.first) return Pos(doc.first, 0); - var last = doc.first + doc.size - 1; - if (pos.line > last) return Pos(last, getLine(doc, last).text.length); - return clipToLen(pos, getLine(doc, pos.line).text.length); + if (pos.line < doc.first) return Pos(doc.first, 0) + var last = doc.first + doc.size - 1 + if (pos.line > last) return Pos(last, getLine(doc, last).text.length) + return clipToLen(pos, getLine(doc, pos.line).text.length) } function clipToLen(pos, linelen) { - var ch = pos.ch; - if (ch == null || ch > linelen) return Pos(pos.line, linelen); - else if (ch < 0) return Pos(pos.line, 0); - else return pos; + var ch = pos.ch + if (ch == null || ch > linelen) return Pos(pos.line, linelen) + else if (ch < 0) return Pos(pos.line, 0) + else return pos } export function clipPosArray(doc, array) { - for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]); - return out; + for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]) + return out } diff --git a/src/line/saw_special_spans.js b/src/line/saw_special_spans.js index 4c1f8e0bf0..0cf5ff320b 100644 --- a/src/line/saw_special_spans.js +++ b/src/line/saw_special_spans.js @@ -1,10 +1,10 @@ // Optimize some code when these features are not used. -export var sawReadOnlySpans = false, sawCollapsedSpans = false; +export var sawReadOnlySpans = false, sawCollapsedSpans = false export function seeReadOnlySpans() { - sawReadOnlySpans = true; + sawReadOnlySpans = true } export function seeCollapsedSpans() { - sawCollapsedSpans = true; + sawCollapsedSpans = true } diff --git a/src/line/spans.js b/src/line/spans.js index d114d8943f..fd9bd55408 100644 --- a/src/line/spans.js +++ b/src/line/spans.js @@ -1,34 +1,34 @@ -import { indexOf, lst } from "../util/misc"; +import { indexOf, lst } from "../util/misc" -import { cmp } from "./pos"; -import { sawCollapsedSpans } from "./saw_special_spans"; -import { getLine, isLine, lineNo } from "./utils_line"; +import { cmp } from "./pos" +import { sawCollapsedSpans } from "./saw_special_spans" +import { getLine, isLine, lineNo } from "./utils_line" // TEXTMARKER SPANS export function MarkedSpan(marker, from, to) { - this.marker = marker; - this.from = from; this.to = to; + this.marker = marker + this.from = from; this.to = to } // Search an array of spans for a span matching the given marker. export function getMarkedSpanFor(spans, marker) { if (spans) for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; - if (span.marker == marker) return span; + var span = spans[i] + if (span.marker == marker) return span } } // Remove a span from an array, returning undefined if no spans are // left (we don't store arrays for lines without spans). export function removeMarkedSpan(spans, span) { for (var r, i = 0; i < spans.length; ++i) - if (spans[i] != span) (r || (r = [])).push(spans[i]); - return r; + if (spans[i] != span) (r || (r = [])).push(spans[i]) + return r } // Add a span to a line. export function addMarkedSpan(line, span) { - line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; - span.marker.attachLine(line); + line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span] + span.marker.attachLine(line) } // Used for the algorithm that adjusts markers for a change in the @@ -37,26 +37,26 @@ export function addMarkedSpan(line, span) { // undefined if nothing remains). function markedSpansBefore(old, startCh, isInsert) { 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); + var span = old[i], marker = span.marker + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh) if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); - (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh) + ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)) } } - return nw; + return nw } function markedSpansAfter(old, endCh, isInsert) { if (old) for (var i = 0, nw; i < old.length; ++i) { - var span = old[i], marker = span.marker; - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); + var span = old[i], marker = span.marker + var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh) if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { - var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); - (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, - span.to == null ? null : span.to - endCh)); + var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh) + ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, + span.to == null ? null : span.to - endCh)) } } - return nw; + return nw } // Given a change object, compute the new set of marker spans that @@ -66,171 +66,171 @@ function markedSpansAfter(old, endCh, isInsert) { // spans partially within the change. Returns an array of span // arrays with one element for each line in (after) the change. export function stretchSpansOverChange(doc, change) { - if (change.full) return null; - var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; - var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; - if (!oldFirst && !oldLast) return null; + if (change.full) return null + var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans + var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans + if (!oldFirst && !oldLast) return null - var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; + var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0 // Get the spans that 'stick out' on both sides - var first = markedSpansBefore(oldFirst, startCh, isInsert); - var last = markedSpansAfter(oldLast, endCh, isInsert); + var first = markedSpansBefore(oldFirst, startCh, isInsert) + var last = markedSpansAfter(oldLast, endCh, isInsert) // Next, merge those two ends - var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); + var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0) if (first) { // Fix up .to properties of first for (var i = 0; i < first.length; ++i) { - var span = first[i]; + var span = first[i] if (span.to == null) { - var found = getMarkedSpanFor(last, span.marker); - if (!found) span.to = startCh; - else if (sameLine) span.to = found.to == null ? null : found.to + offset; + var found = getMarkedSpanFor(last, span.marker) + if (!found) span.to = startCh + else if (sameLine) span.to = found.to == null ? null : found.to + offset } } } if (last) { // Fix up .from in last (or move them into first in case of sameLine) for (var i = 0; i < last.length; ++i) { - var span = last[i]; - if (span.to != null) span.to += offset; + var span = last[i] + if (span.to != null) span.to += offset if (span.from == null) { - var found = getMarkedSpanFor(first, span.marker); + var found = getMarkedSpanFor(first, span.marker) if (!found) { - span.from = offset; - if (sameLine) (first || (first = [])).push(span); + span.from = offset + if (sameLine) (first || (first = [])).push(span) } } else { - span.from += offset; - if (sameLine) (first || (first = [])).push(span); + span.from += offset + if (sameLine) (first || (first = [])).push(span) } } } // Make sure we didn't create any zero-length spans - if (first) first = clearEmptySpans(first); - if (last && last != first) last = clearEmptySpans(last); + if (first) first = clearEmptySpans(first) + if (last && last != first) last = clearEmptySpans(last) - var newMarkers = [first]; + var newMarkers = [first] if (!sameLine) { // Fill gap with whole-line-spans - var gap = change.text.length - 2, gapMarkers; + var gap = change.text.length - 2, gapMarkers if (gap > 0 && first) for (var i = 0; i < first.length; ++i) if (first[i].to == null) - (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)); + (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)) for (var i = 0; i < gap; ++i) - newMarkers.push(gapMarkers); - newMarkers.push(last); + newMarkers.push(gapMarkers) + newMarkers.push(last) } - return newMarkers; + return newMarkers } // Remove spans that are empty and don't have a clearWhenEmpty // option of false. function clearEmptySpans(spans) { for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; + var span = spans[i] if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) - spans.splice(i--, 1); + spans.splice(i--, 1) } - if (!spans.length) return null; - return spans; + if (!spans.length) return null + return spans } // Used to 'clip' out readOnly ranges when making a change. export function removeReadOnlyRanges(doc, from, to) { - var markers = null; + var markers = null doc.iter(from.line, to.line + 1, function(line) { if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { - var mark = line.markedSpans[i].marker; + var mark = line.markedSpans[i].marker if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) - (markers || (markers = [])).push(mark); + (markers || (markers = [])).push(mark) } - }); - if (!markers) return null; - var parts = [{from: from, to: to}]; + }) + if (!markers) return null + var parts = [{from: from, to: to}] for (var i = 0; i < markers.length; ++i) { - var mk = markers[i], m = mk.find(0); + var mk = markers[i], m = mk.find(0) for (var j = 0; j < parts.length; ++j) { - var p = parts[j]; - if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue; - var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); + var p = parts[j] + if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue + var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to) if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) - newParts.push({from: p.from, to: m.from}); + newParts.push({from: p.from, to: m.from}) if (dto > 0 || !mk.inclusiveRight && !dto) - newParts.push({from: m.to, to: p.to}); - parts.splice.apply(parts, newParts); - j += newParts.length - 1; + newParts.push({from: m.to, to: p.to}) + parts.splice.apply(parts, newParts) + j += newParts.length - 1 } } - return parts; + return parts } // Connect or disconnect spans from a line. export function detachMarkedSpans(line) { - var spans = line.markedSpans; - if (!spans) return; + var spans = line.markedSpans + if (!spans) return for (var i = 0; i < spans.length; ++i) - spans[i].marker.detachLine(line); - line.markedSpans = null; + spans[i].marker.detachLine(line) + line.markedSpans = null } export function attachMarkedSpans(line, spans) { - if (!spans) return; + if (!spans) return for (var i = 0; i < spans.length; ++i) - spans[i].marker.attachLine(line); - line.markedSpans = spans; + spans[i].marker.attachLine(line) + line.markedSpans = spans } // Helpers used when computing which overlapping collapsed span // counts as the larger one. -function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; } -function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; } +function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 } +function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 } // Returns a number indicating which of two overlapping collapsed // spans is larger (and thus includes the other). Falls back to // comparing ids when the spans cover exactly the same range. export function compareCollapsedMarkers(a, b) { - var lenDiff = a.lines.length - b.lines.length; - if (lenDiff != 0) return lenDiff; - var aPos = a.find(), bPos = b.find(); - var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); - if (fromCmp) return -fromCmp; - var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); - if (toCmp) return toCmp; - return b.id - a.id; + var lenDiff = a.lines.length - b.lines.length + if (lenDiff != 0) return lenDiff + var aPos = a.find(), bPos = b.find() + var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b) + if (fromCmp) return -fromCmp + var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b) + if (toCmp) return toCmp + return b.id - a.id } // Find out whether a line ends or starts in a collapsed span. If // so, return the marker for that span. function collapsedSpanAtSide(line, start) { - var sps = sawCollapsedSpans && line.markedSpans, found; + var sps = sawCollapsedSpans && line.markedSpans, found if (sps) for (var sp, i = 0; i < sps.length; ++i) { - sp = sps[i]; + sp = sps[i] if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && (!found || compareCollapsedMarkers(found, sp.marker) < 0)) - found = sp.marker; + found = sp.marker } - return found; + return found } -export function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); } -export function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); } +export function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) } +export function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) } // Test whether there exists a collapsed span that partially // overlaps (covers the start or end, but not both) of a new span. // Such overlap is not allowed. export function conflictingCollapsedRange(doc, lineNo, from, to, marker) { - var line = getLine(doc, lineNo); - var sps = sawCollapsedSpans && line.markedSpans; + var line = getLine(doc, lineNo) + var sps = sawCollapsedSpans && line.markedSpans if (sps) for (var i = 0; i < sps.length; ++i) { - var sp = sps[i]; - if (!sp.marker.collapsed) continue; - var found = sp.marker.find(0); - var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); - var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); - if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue; + var sp = sps[i] + if (!sp.marker.collapsed) continue + var found = sp.marker.find(0) + var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker) + var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker) + if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) || fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0)) - return true; + return true } } @@ -239,124 +239,124 @@ export function conflictingCollapsedRange(doc, lineNo, from, to, marker) { // visual line. This finds the start of the visual line that the // given line is part of (usually that is the line itself). export function visualLine(line) { - var merged; + var merged while (merged = collapsedSpanAtStart(line)) - line = merged.find(-1, true).line; - return line; + line = merged.find(-1, true).line + return line } // Returns an array of logical lines that continue the visual line // started by the argument, or undefined if there are no such lines. export function visualLineContinued(line) { - var merged, lines; + var merged, lines while (merged = collapsedSpanAtEnd(line)) { - line = merged.find(1, true).line; - (lines || (lines = [])).push(line); + line = merged.find(1, true).line + ;(lines || (lines = [])).push(line) } - return lines; + return lines } // Get the line number of the start of the visual line that the // given line number is part of. export function visualLineNo(doc, lineN) { - var line = getLine(doc, lineN), vis = visualLine(line); - if (line == vis) return lineN; - return lineNo(vis); + var line = getLine(doc, lineN), vis = visualLine(line) + if (line == vis) return lineN + return lineNo(vis) } // Get the line number of the start of the next visual line after // the given line. export function visualLineEndNo(doc, lineN) { - if (lineN > doc.lastLine()) return lineN; - var line = getLine(doc, lineN), merged; - if (!lineIsHidden(doc, line)) return lineN; + if (lineN > doc.lastLine()) return lineN + var line = getLine(doc, lineN), merged + if (!lineIsHidden(doc, line)) return lineN while (merged = collapsedSpanAtEnd(line)) - line = merged.find(1, true).line; - return lineNo(line) + 1; + line = merged.find(1, true).line + return lineNo(line) + 1 } // Compute whether a line is hidden. Lines count as hidden when they // are part of a visual line that starts with another line, or when // they are entirely covered by collapsed, non-widget span. export function lineIsHidden(doc, line) { - var sps = sawCollapsedSpans && line.markedSpans; + var sps = sawCollapsedSpans && line.markedSpans if (sps) for (var sp, i = 0; i < sps.length; ++i) { - sp = sps[i]; - if (!sp.marker.collapsed) continue; - if (sp.from == null) return true; - if (sp.marker.widgetNode) continue; + sp = sps[i] + if (!sp.marker.collapsed) continue + if (sp.from == null) return true + if (sp.marker.widgetNode) continue if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) - return true; + return true } } function lineIsHiddenInner(doc, line, span) { if (span.to == null) { - var end = span.marker.find(1, true); - return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)); + var end = span.marker.find(1, true) + return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)) } if (span.marker.inclusiveRight && span.to == line.text.length) - return true; + return true for (var sp, i = 0; i < line.markedSpans.length; ++i) { - sp = line.markedSpans[i]; + sp = line.markedSpans[i] if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && (sp.to == null || sp.to != span.from) && (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && - lineIsHiddenInner(doc, line, sp)) return true; + lineIsHiddenInner(doc, line, sp)) return true } } // Find the height above the given line. export function heightAtLine(lineObj) { - lineObj = visualLine(lineObj); + lineObj = visualLine(lineObj) - var h = 0, chunk = lineObj.parent; + var h = 0, chunk = lineObj.parent for (var i = 0; i < chunk.lines.length; ++i) { - var line = chunk.lines[i]; - if (line == lineObj) break; - else h += line.height; + var line = chunk.lines[i] + if (line == lineObj) break + else h += line.height } for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { for (var i = 0; i < p.children.length; ++i) { - var cur = p.children[i]; - if (cur == chunk) break; - else h += cur.height; + var cur = p.children[i] + if (cur == chunk) break + else h += cur.height } } - return h; + return h } // Compute the character length of a line, taking into account // collapsed ranges (see markText) that might hide parts, and join // other lines onto it. export function lineLength(line) { - if (line.height == 0) return 0; - var len = line.text.length, merged, cur = line; + if (line.height == 0) return 0 + var len = line.text.length, merged, cur = line while (merged = collapsedSpanAtStart(cur)) { - var found = merged.find(0, true); - cur = found.from.line; - len += found.from.ch - found.to.ch; + var found = merged.find(0, true) + cur = found.from.line + len += found.from.ch - found.to.ch } - cur = line; + cur = line while (merged = collapsedSpanAtEnd(cur)) { - var found = merged.find(0, true); - len -= cur.text.length - found.from.ch; - cur = found.to.line; - len += cur.text.length - found.to.ch; + var found = merged.find(0, true) + len -= cur.text.length - found.from.ch + cur = found.to.line + len += cur.text.length - found.to.ch } - return len; + return len } // Find the longest line in the document. export function findMaxLine(cm) { - var d = cm.display, doc = cm.doc; - d.maxLine = getLine(doc, doc.first); - d.maxLineLength = lineLength(d.maxLine); - d.maxLineChanged = true; + var d = cm.display, doc = cm.doc + d.maxLine = getLine(doc, doc.first) + d.maxLineLength = lineLength(d.maxLine) + d.maxLineChanged = true doc.iter(function(line) { - var len = lineLength(line); + var len = lineLength(line) if (len > d.maxLineLength) { - d.maxLineLength = len; - d.maxLine = line; + d.maxLineLength = len + d.maxLine = line } - }); + }) } diff --git a/src/line/utils_line.js b/src/line/utils_line.js index b194ff38b6..4e10a1d8d8 100644 --- a/src/line/utils_line.js +++ b/src/line/utils_line.js @@ -1,83 +1,83 @@ -import { indexOf } from "../util/misc"; +import { indexOf } from "../util/misc" // Find the line object corresponding to the given line number. export function getLine(doc, n) { - n -= doc.first; - if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document."); + n -= doc.first + if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.") for (var chunk = doc; !chunk.lines;) { for (var i = 0;; ++i) { - var child = chunk.children[i], sz = child.chunkSize(); - if (n < sz) { chunk = child; break; } - n -= sz; + var child = chunk.children[i], sz = child.chunkSize() + if (n < sz) { chunk = child; break } + n -= sz } } - return chunk.lines[n]; + return chunk.lines[n] } // Get the part of a document between two positions, as an array of // strings. export function getBetween(doc, start, end) { - var out = [], n = start.line; + var out = [], n = start.line doc.iter(start.line, end.line + 1, function(line) { - var text = line.text; - if (n == end.line) text = text.slice(0, end.ch); - if (n == start.line) text = text.slice(start.ch); - out.push(text); - ++n; - }); - return out; + var text = line.text + if (n == end.line) text = text.slice(0, end.ch) + if (n == start.line) text = text.slice(start.ch) + out.push(text) + ++n + }) + return out } // Get the lines between from and to, as array of strings. export function getLines(doc, from, to) { - var out = []; - doc.iter(from, to, function(line) { out.push(line.text); }); - return out; + var out = [] + doc.iter(from, to, function(line) { out.push(line.text) }) + return out } // Update the height of a line, propagating the height change // upwards to parent nodes. export function updateLineHeight(line, height) { - var diff = height - line.height; - if (diff) for (var n = line; n; n = n.parent) n.height += diff; + var diff = height - line.height + if (diff) for (var n = line; n; n = n.parent) n.height += diff } // Given a line object, find its line number by walking up through // its parent links. export function lineNo(line) { - if (line.parent == null) return null; - var cur = line.parent, no = indexOf(cur.lines, 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) { for (var i = 0;; ++i) { - if (chunk.children[i] == cur) break; - no += chunk.children[i].chunkSize(); + if (chunk.children[i] == cur) break + no += chunk.children[i].chunkSize() } } - return no + cur.first; + return no + cur.first } // Find the line at the given vertical position, using the height // information in the document tree. export function lineAtHeight(chunk, h) { - var n = chunk.first; + var n = chunk.first outer: do { for (var i = 0; i < chunk.children.length; ++i) { - var child = chunk.children[i], ch = child.height; - if (h < ch) { chunk = child; continue outer; } - h -= ch; - n += child.chunkSize(); + var child = chunk.children[i], ch = child.height + if (h < ch) { chunk = child; continue outer } + h -= ch + n += child.chunkSize() } - return n; - } while (!chunk.lines); + return n + } while (!chunk.lines) for (var i = 0; i < chunk.lines.length; ++i) { - var line = chunk.lines[i], lh = line.height; - if (h < lh) break; - h -= lh; + var line = chunk.lines[i], lh = line.height + if (h < lh) break + h -= lh } - return n + i; + return n + i } -export function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;} +export function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size} export function lineNumberFor(options, i) { - return String(options.lineNumberFormatter(i + options.firstLineNumber)); + return String(options.lineNumberFormatter(i + options.firstLineNumber)) } diff --git a/src/measurement/position_measurement.js b/src/measurement/position_measurement.js index b479e25090..75011a34d3 100644 --- a/src/measurement/position_measurement.js +++ b/src/measurement/position_measurement.js @@ -1,36 +1,36 @@ -import { buildLineContent, LineView } from "../line/line_data"; -import { clipPos, Pos } from "../line/pos"; -import { collapsedSpanAtEnd, heightAtLine, lineIsHidden, visualLine } from "../line/spans"; -import { getLine, lineAtHeight, lineNo, updateLineHeight } from "../line/utils_line"; -import { bidiLeft, bidiRight, bidiOther, getBidiPartAt, getOrder, lineLeft, lineRight, moveVisually } from "../util/bidi"; -import { ie, ie_version } from "../util/browser"; -import { elt, removeChildren, range, removeChildrenAndAdd } from "../util/dom"; -import { e_target } from "../util/event"; -import { hasBadZoomedRects } from "../util/feature_detection"; -import { countColumn, isExtendingChar, scrollerGap } from "../util/misc"; - -import { updateLineForChanges } from "./update_line"; -import { widgetHeight } from "./widgets"; +import { buildLineContent, LineView } from "../line/line_data" +import { clipPos, Pos } from "../line/pos" +import { collapsedSpanAtEnd, heightAtLine, lineIsHidden, visualLine } from "../line/spans" +import { getLine, lineAtHeight, lineNo, updateLineHeight } from "../line/utils_line" +import { bidiLeft, bidiRight, bidiOther, getBidiPartAt, getOrder, lineLeft, lineRight, moveVisually } from "../util/bidi" +import { ie, ie_version } from "../util/browser" +import { elt, removeChildren, range, removeChildrenAndAdd } from "../util/dom" +import { e_target } from "../util/event" +import { hasBadZoomedRects } from "../util/feature_detection" +import { countColumn, isExtendingChar, scrollerGap } from "../util/misc" + +import { updateLineForChanges } from "./update_line" +import { widgetHeight } from "./widgets" // POSITION MEASUREMENT -export function paddingTop(display) {return display.lineSpace.offsetTop;} -export function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;} +export function paddingTop(display) {return display.lineSpace.offsetTop} +export function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight} export function paddingH(display) { - if (display.cachedPaddingH) return display.cachedPaddingH; - var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); - var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; - var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; - if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data; - return data; + if (display.cachedPaddingH) return display.cachedPaddingH + var e = removeChildrenAndAdd(display.measure, elt("pre", "x")) + var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle + var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)} + if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data + return data } -export function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; } +export function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth } export function displayWidth(cm) { - return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth; + return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth } export function displayHeight(cm) { - return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight; + return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight } // Ensure the lineView.wrapping.heights array is populated. This is @@ -38,20 +38,20 @@ export function displayHeight(cm) { // line. When lineWrapping is on, there might be more than one // height. function ensureLineHeights(cm, lineView, rect) { - var wrapping = cm.options.lineWrapping; - var curWidth = wrapping && displayWidth(cm); + var wrapping = cm.options.lineWrapping + var curWidth = wrapping && displayWidth(cm) if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { - var heights = lineView.measure.heights = []; + var heights = lineView.measure.heights = [] if (wrapping) { - lineView.measure.width = curWidth; - var rects = lineView.text.firstChild.getClientRects(); + lineView.measure.width = curWidth + var rects = lineView.text.firstChild.getClientRects() for (var i = 0; i < rects.length - 1; i++) { - var cur = rects[i], next = rects[i + 1]; + var cur = rects[i], next = rects[i + 1] if (Math.abs(cur.bottom - next.bottom) > 2) - heights.push((cur.bottom + next.top) / 2 - rect.top); + heights.push((cur.bottom + next.top) / 2 - rect.top) } } - heights.push(rect.bottom - rect.top); + heights.push(rect.bottom - rect.top) } } @@ -60,41 +60,41 @@ function ensureLineHeights(cm, lineView, rect) { // contain multiple lines when collapsed ranges are present.) export function mapFromLineView(lineView, line, lineN) { if (lineView.line == line) - return {map: lineView.measure.map, cache: lineView.measure.cache}; + return {map: lineView.measure.map, cache: lineView.measure.cache} for (var i = 0; i < lineView.rest.length; i++) if (lineView.rest[i] == line) - return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]}; + return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} for (var i = 0; i < lineView.rest.length; i++) if (lineNo(lineView.rest[i]) > lineN) - return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true}; + return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true} } // Render a line into the hidden node display.externalMeasured. Used // when measurement is needed for a line that's not in the viewport. function updateExternalMeasurement(cm, line) { - line = visualLine(line); - var lineN = lineNo(line); - var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); - view.lineN = lineN; - var built = view.built = buildLineContent(cm, view); - view.text = built.pre; - removeChildrenAndAdd(cm.display.lineMeasure, built.pre); - return view; + line = visualLine(line) + var lineN = lineNo(line) + var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN) + view.lineN = lineN + var built = view.built = buildLineContent(cm, view) + view.text = built.pre + removeChildrenAndAdd(cm.display.lineMeasure, built.pre) + return view } // Get a {top, bottom, left, right} box (in line-local coordinates) // for a given character. export function measureChar(cm, line, ch, bias) { - return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias); + return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias) } // Find a line view that corresponds to the given line number. export function findViewForLine(cm, lineN) { if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) - return cm.display.view[findViewIndex(cm, lineN)]; - var ext = cm.display.externalMeasured; + return cm.display.view[findViewIndex(cm, lineN)] + var ext = cm.display.externalMeasured if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) - return ext; + return ext } // Measurement can be split in two steps, the set-up work that @@ -103,84 +103,84 @@ export function findViewForLine(cm, lineN) { // measurements in a row, can thus ensure that the set-up work is // only done once. function prepareMeasureForLine(cm, line) { - var lineN = lineNo(line); - var view = findViewForLine(cm, lineN); + var lineN = lineNo(line) + var view = findViewForLine(cm, lineN) if (view && !view.text) { - view = null; + view = null } else if (view && view.changes) { - updateLineForChanges(cm, view, lineN, getDimensions(cm)); - cm.curOp.forceUpdate = true; + updateLineForChanges(cm, view, lineN, getDimensions(cm)) + cm.curOp.forceUpdate = true } if (!view) - view = updateExternalMeasurement(cm, line); + view = updateExternalMeasurement(cm, line) - var info = mapFromLineView(view, line, lineN); + var info = mapFromLineView(view, line, lineN) return { line: line, view: view, rect: null, map: info.map, cache: info.cache, before: info.before, hasHeights: false - }; + } } // Given a prepared measurement object, measures the position of an // actual character (or fetches it from the cache). function measureCharPrepared(cm, prepared, ch, bias, varHeight) { - if (prepared.before) ch = -1; - var key = ch + (bias || ""), found; + if (prepared.before) ch = -1 + var key = ch + (bias || ""), found if (prepared.cache.hasOwnProperty(key)) { - found = prepared.cache[key]; + found = prepared.cache[key] } else { if (!prepared.rect) - prepared.rect = prepared.view.text.getBoundingClientRect(); + prepared.rect = prepared.view.text.getBoundingClientRect() if (!prepared.hasHeights) { - ensureLineHeights(cm, prepared.view, prepared.rect); - prepared.hasHeights = true; + ensureLineHeights(cm, prepared.view, prepared.rect) + prepared.hasHeights = true } - found = measureCharInner(cm, prepared, ch, bias); - if (!found.bogus) prepared.cache[key] = found; + found = measureCharInner(cm, prepared, ch, bias) + if (!found.bogus) prepared.cache[key] = found } return {left: found.left, right: found.right, top: varHeight ? found.rtop : found.top, - bottom: varHeight ? found.rbottom : found.bottom}; + bottom: varHeight ? found.rbottom : found.bottom} } -var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; +var nullRect = {left: 0, right: 0, top: 0, bottom: 0} export function nodeAndOffsetInLineMap(map, ch, bias) { - var node, start, end, collapse; + var node, start, end, collapse // First, search the line map for the text node corresponding to, // or closest to, the target character. for (var i = 0; i < map.length; i += 3) { - var mStart = map[i], mEnd = map[i + 1]; + var mStart = map[i], mEnd = map[i + 1] if (ch < mStart) { - start = 0; end = 1; - collapse = "left"; + start = 0; end = 1 + collapse = "left" } else if (ch < mEnd) { - start = ch - mStart; - end = start + 1; + start = ch - mStart + end = start + 1 } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { - end = mEnd - mStart; - start = end - 1; - if (ch >= mEnd) collapse = "right"; + end = mEnd - mStart + start = end - 1 + if (ch >= mEnd) collapse = "right" } if (start != null) { - node = map[i + 2]; + node = map[i + 2] if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) - collapse = bias; + collapse = bias if (bias == "left" && start == 0) while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { - node = map[(i -= 3) + 2]; - collapse = "left"; + node = map[(i -= 3) + 2] + collapse = "left" } if (bias == "right" && start == mEnd - mStart) while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { - node = map[(i += 3) + 2]; - collapse = "right"; + node = map[(i += 3) + 2] + collapse = "right" } - break; + break } } - return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}; + return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd} } function getUsefulRect(rects, bias) { @@ -194,53 +194,53 @@ function getUsefulRect(rects, bias) { } function measureCharInner(cm, prepared, ch, bias) { - var place = nodeAndOffsetInLineMap(prepared.map, ch, bias); - var node = place.node, start = place.start, end = place.end, collapse = place.collapse; + var place = nodeAndOffsetInLineMap(prepared.map, ch, bias) + var node = place.node, start = place.start, end = place.end, collapse = place.collapse - var rect; + var rect if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned - while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start; - while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end; + while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start + while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) - rect = node.parentNode.getBoundingClientRect(); + rect = node.parentNode.getBoundingClientRect() else rect = getUsefulRect(range(node, start, end).getClientRects(), bias) - if (rect.left || rect.right || start == 0) break; - end = start; - start = start - 1; - collapse = "right"; + if (rect.left || rect.right || start == 0) break + end = start + start = start - 1 + collapse = "right" } - if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect); + if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect) } else { // If it is a widget, simply get the box for the whole widget. - if (start > 0) collapse = bias = "right"; - var rects; + if (start > 0) collapse = bias = "right" + var rects if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) - rect = rects[bias == "right" ? rects.length - 1 : 0]; + rect = rects[bias == "right" ? rects.length - 1 : 0] else - rect = node.getBoundingClientRect(); + rect = node.getBoundingClientRect() } if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { - var rSpan = node.parentNode.getClientRects()[0]; + var rSpan = node.parentNode.getClientRects()[0] if (rSpan) - rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; + rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom} else - rect = nullRect; + rect = nullRect } - var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; - var mid = (rtop + rbot) / 2; - var heights = prepared.view.measure.heights; + var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top + var mid = (rtop + rbot) / 2 + var heights = prepared.view.measure.heights for (var i = 0; i < heights.length - 1; i++) - if (mid < heights[i]) break; - var top = i ? heights[i - 1] : 0, bot = heights[i]; + if (mid < heights[i]) break + var top = i ? heights[i - 1] : 0, bot = heights[i] var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, - top: top, bottom: bot}; - if (!rect.left && !rect.right) result.bogus = true; - if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } + top: top, bottom: bot} + if (!rect.left && !rect.right) result.bogus = true + if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot } - return result; + return result } // Work around problem with bounding client rects on ranges being @@ -248,38 +248,38 @@ function measureCharInner(cm, prepared, ch, bias) { function maybeUpdateRectForZooming(measure, rect) { if (!window.screen || screen.logicalXDPI == null || screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) - return rect; - var scaleX = screen.logicalXDPI / screen.deviceXDPI; - var scaleY = screen.logicalYDPI / screen.deviceYDPI; + return rect + var scaleX = screen.logicalXDPI / screen.deviceXDPI + var scaleY = screen.logicalYDPI / screen.deviceYDPI return {left: rect.left * scaleX, right: rect.right * scaleX, - top: rect.top * scaleY, bottom: rect.bottom * scaleY}; + top: rect.top * scaleY, bottom: rect.bottom * scaleY} } export function clearLineMeasurementCacheFor(lineView) { if (lineView.measure) { - lineView.measure.cache = {}; - lineView.measure.heights = null; + lineView.measure.cache = {} + lineView.measure.heights = null if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) - lineView.measure.caches[i] = {}; + lineView.measure.caches[i] = {} } } export function clearLineMeasurementCache(cm) { - cm.display.externalMeasure = null; - removeChildren(cm.display.lineMeasure); + cm.display.externalMeasure = null + removeChildren(cm.display.lineMeasure) for (var i = 0; i < cm.display.view.length; i++) - clearLineMeasurementCacheFor(cm.display.view[i]); + clearLineMeasurementCacheFor(cm.display.view[i]) } export function clearCaches(cm) { - clearLineMeasurementCache(cm); - cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; - if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; - cm.display.lineNumChars = null; + clearLineMeasurementCache(cm) + cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null + if (!cm.options.lineWrapping) cm.display.maxLineChanged = true + cm.display.lineNumChars = null } -function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } -function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } +function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft } +function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop } // Converts a {top, bottom, left, right} box from line-local // coordinates into another coordinate system. Context may be one of @@ -287,89 +287,89 @@ function pageScrollY() { return window.pageYOffset || (document.documentElement // or "page". export function intoCoordSystem(cm, lineObj, rect, context) { if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { - var size = widgetHeight(lineObj.widgets[i]); - rect.top += size; rect.bottom += size; + var size = widgetHeight(lineObj.widgets[i]) + rect.top += size; rect.bottom += size } - if (context == "line") return rect; - if (!context) context = "local"; - var yOff = heightAtLine(lineObj); - if (context == "local") yOff += paddingTop(cm.display); - else yOff -= cm.display.viewOffset; + if (context == "line") return rect + if (!context) context = "local" + var yOff = heightAtLine(lineObj) + if (context == "local") yOff += paddingTop(cm.display) + else yOff -= cm.display.viewOffset if (context == "page" || context == "window") { - var lOff = cm.display.lineSpace.getBoundingClientRect(); - yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); - var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); - rect.left += xOff; rect.right += xOff; + var lOff = cm.display.lineSpace.getBoundingClientRect() + yOff += lOff.top + (context == "window" ? 0 : pageScrollY()) + var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()) + rect.left += xOff; rect.right += xOff } - rect.top += yOff; rect.bottom += yOff; - return rect; + rect.top += yOff; rect.bottom += yOff + return rect } // Coverts a box from "div" coords to another coordinate system. // Context may be "window", "page", "div", or "local"./null. export function fromCoordSystem(cm, coords, context) { - if (context == "div") return coords; - var left = coords.left, top = coords.top; + if (context == "div") return coords + var left = coords.left, top = coords.top // First move into "page" coordinate system if (context == "page") { - left -= pageScrollX(); - top -= pageScrollY(); + left -= pageScrollX() + top -= pageScrollY() } else if (context == "local" || !context) { - var localBox = cm.display.sizer.getBoundingClientRect(); - left += localBox.left; - top += localBox.top; + var localBox = cm.display.sizer.getBoundingClientRect() + left += localBox.left + top += localBox.top } - var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); - return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}; + var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect() + return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top} } export function charCoords(cm, pos, context, lineObj, bias) { - if (!lineObj) lineObj = getLine(cm.doc, pos.line); - return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context); + if (!lineObj) lineObj = getLine(cm.doc, pos.line) + return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context) } // Returns a box for a given cursor position, which may have an // 'other' property containing the position of the secondary cursor // on a bidi boundary. export function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { - lineObj = lineObj || getLine(cm.doc, pos.line); - if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj); + lineObj = lineObj || getLine(cm.doc, pos.line) + if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj) function get(ch, right) { - var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); - if (right) m.left = m.right; else m.right = m.left; - return intoCoordSystem(cm, lineObj, m, context); + var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight) + if (right) m.left = m.right; else m.right = m.left + return intoCoordSystem(cm, lineObj, m, context) } function getBidi(ch, partPos) { - var part = order[partPos], right = part.level % 2; + var part = order[partPos], right = part.level % 2 if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { - part = order[--partPos]; - ch = bidiRight(part) - (part.level % 2 ? 0 : 1); - right = true; + part = order[--partPos] + ch = bidiRight(part) - (part.level % 2 ? 0 : 1) + right = true } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { - part = order[++partPos]; - ch = bidiLeft(part) - part.level % 2; - right = false; + part = order[++partPos] + ch = bidiLeft(part) - part.level % 2 + right = false } - if (right && ch == part.to && ch > part.from) return get(ch - 1); - return get(ch, right); + if (right && ch == part.to && ch > part.from) return get(ch - 1) + return get(ch, right) } - var order = getOrder(lineObj), ch = pos.ch; - if (!order) return get(ch); - var partPos = getBidiPartAt(order, ch); - var val = getBidi(ch, partPos); - if (bidiOther != null) val.other = getBidi(ch, bidiOther); - return val; + var order = getOrder(lineObj), ch = pos.ch + if (!order) return get(ch) + var partPos = getBidiPartAt(order, ch) + var val = getBidi(ch, partPos) + if (bidiOther != null) val.other = getBidi(ch, bidiOther) + return val } // Used to cheaply estimate the coordinates for a position. Used for // intermediate scroll updates. export function estimateCoords(cm, pos) { - var left = 0, pos = clipPos(cm.doc, pos); - if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch; - var lineObj = getLine(cm.doc, pos.line); - var top = heightAtLine(lineObj) + paddingTop(cm.display); - return {left: left, right: left, top: top, bottom: top + lineObj.height}; + var left = 0, pos = clipPos(cm.doc, pos) + if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch + var lineObj = getLine(cm.doc, pos.line) + var top = heightAtLine(lineObj) + paddingTop(cm.display) + return {left: left, right: left, top: top, bottom: top + lineObj.height} } // Positions returned by coordsChar contain some extra information. @@ -379,170 +379,170 @@ export function estimateCoords(cm, pos) { // is true, that means the coordinates lie outside the line's // vertical range. function PosWithInfo(line, ch, outside, xRel) { - var pos = Pos(line, ch); - pos.xRel = xRel; - if (outside) pos.outside = true; - return pos; + var pos = Pos(line, ch) + pos.xRel = xRel + if (outside) pos.outside = true + return pos } // Compute the character position closest to the given coordinates. // Input must be lineSpace-local ("div" coordinate system). export function coordsChar(cm, x, y) { - var doc = cm.doc; - y += cm.display.viewOffset; - if (y < 0) return PosWithInfo(doc.first, 0, true, -1); - var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; + var doc = cm.doc + y += cm.display.viewOffset + if (y < 0) return PosWithInfo(doc.first, 0, true, -1) + var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1 if (lineN > last) - return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1); - if (x < 0) x = 0; + return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1) + if (x < 0) x = 0 - var lineObj = getLine(doc, lineN); + var lineObj = getLine(doc, lineN) for (;;) { - var found = coordsCharInner(cm, lineObj, lineN, x, y); - var merged = collapsedSpanAtEnd(lineObj); - var mergedPos = merged && merged.find(0, true); + var found = coordsCharInner(cm, lineObj, lineN, x, y) + var merged = collapsedSpanAtEnd(lineObj) + var mergedPos = merged && merged.find(0, true) if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) - lineN = lineNo(lineObj = mergedPos.to.line); + lineN = lineNo(lineObj = mergedPos.to.line) else - return found; + return found } } function coordsCharInner(cm, lineObj, lineNo, x, y) { - var innerOff = y - heightAtLine(lineObj); - var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth; - var preparedMeasure = prepareMeasureForLine(cm, lineObj); + var innerOff = y - heightAtLine(lineObj) + var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth + var preparedMeasure = prepareMeasureForLine(cm, lineObj) function getX(ch) { - var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure); - wrongLine = true; - if (innerOff > sp.bottom) return sp.left - adjust; - else if (innerOff < sp.top) return sp.left + adjust; - else wrongLine = false; - return sp.left; + var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure) + wrongLine = true + if (innerOff > sp.bottom) return sp.left - adjust + else if (innerOff < sp.top) return sp.left + adjust + else wrongLine = false + return sp.left } - var bidi = getOrder(lineObj), dist = lineObj.text.length; - var from = lineLeft(lineObj), to = lineRight(lineObj); - var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; + var bidi = getOrder(lineObj), dist = lineObj.text.length + var from = lineLeft(lineObj), to = lineRight(lineObj) + var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine - if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1); + if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1) // Do a binary search between these bounds. for (;;) { if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { - var ch = x < fromX || x - fromX <= toX - x ? from : to; + var ch = x < fromX || x - fromX <= toX - x ? from : to var outside = ch == from ? fromOutside : toOutside - var xDiff = x - (ch == from ? fromX : toX); + var xDiff = x - (ch == from ? fromX : toX) // This is a kludge to handle the case where the coordinates // are after a line-wrapped line. We should replace it with a // more general handling of cursor positions around line // breaks. (Issue #4078) if (toOutside && !bidi && !/\s/.test(lineObj.text.charAt(ch)) && xDiff > 0 && ch < lineObj.text.length && preparedMeasure.view.measure.heights.length > 1) { - var charSize = measureCharPrepared(cm, preparedMeasure, ch, "right"); + var charSize = measureCharPrepared(cm, preparedMeasure, ch, "right") if (innerOff <= charSize.bottom && innerOff >= charSize.top && Math.abs(x - charSize.right) < xDiff) { outside = false ch++ xDiff = x - charSize.right } } - while (isExtendingChar(lineObj.text.charAt(ch))) ++ch; - var pos = PosWithInfo(lineNo, ch, outside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0); - return pos; + while (isExtendingChar(lineObj.text.charAt(ch))) ++ch + var pos = PosWithInfo(lineNo, ch, outside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0) + return pos } - var step = Math.ceil(dist / 2), middle = from + step; + var step = Math.ceil(dist / 2), middle = from + step if (bidi) { - middle = from; - for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1); + middle = from + for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1) } - var middleX = getX(middle); - if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;} - else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;} + var middleX = getX(middle) + if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step} + else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step} } } -var measureText; +var measureText // Compute the default text height. export function textHeight(display) { - if (display.cachedTextHeight != null) return display.cachedTextHeight; + if (display.cachedTextHeight != null) return display.cachedTextHeight if (measureText == null) { - measureText = elt("pre"); + measureText = elt("pre") // Measure a bunch of lines, for browsers that compute // fractional heights. for (var i = 0; i < 49; ++i) { - measureText.appendChild(document.createTextNode("x")); - measureText.appendChild(elt("br")); + measureText.appendChild(document.createTextNode("x")) + measureText.appendChild(elt("br")) } - measureText.appendChild(document.createTextNode("x")); + measureText.appendChild(document.createTextNode("x")) } - removeChildrenAndAdd(display.measure, measureText); - var height = measureText.offsetHeight / 50; - if (height > 3) display.cachedTextHeight = height; - removeChildren(display.measure); - return height || 1; + removeChildrenAndAdd(display.measure, measureText) + var height = measureText.offsetHeight / 50 + if (height > 3) display.cachedTextHeight = height + removeChildren(display.measure) + return height || 1 } // Compute the default character width. export function charWidth(display) { - if (display.cachedCharWidth != null) return display.cachedCharWidth; - var anchor = elt("span", "xxxxxxxxxx"); - var pre = elt("pre", [anchor]); - removeChildrenAndAdd(display.measure, pre); - var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; - if (width > 2) display.cachedCharWidth = width; - return width || 10; + if (display.cachedCharWidth != null) return display.cachedCharWidth + var anchor = elt("span", "xxxxxxxxxx") + var pre = elt("pre", [anchor]) + removeChildrenAndAdd(display.measure, pre) + var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10 + if (width > 2) display.cachedCharWidth = width + return width || 10 } // Do a bulk-read of the DOM positions and sizes needed to draw the // view, so that we don't interleave reading and writing to the DOM. export function getDimensions(cm) { - var d = cm.display, left = {}, width = {}; - var gutterLeft = d.gutters.clientLeft; + var d = cm.display, left = {}, width = {} + var gutterLeft = d.gutters.clientLeft for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { - left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft; - width[cm.options.gutters[i]] = n.clientWidth; + left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft + width[cm.options.gutters[i]] = n.clientWidth } return {fixedPos: compensateForHScroll(d), gutterTotalWidth: d.gutters.offsetWidth, gutterLeft: left, gutterWidth: width, - wrapperWidth: d.wrapper.clientWidth}; + wrapperWidth: d.wrapper.clientWidth} } // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, // but using getBoundingClientRect to get a sub-pixel-accurate // result. export function compensateForHScroll(display) { - return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left; + return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left } // Returns a function that estimates the height of a line, to use as // first approximation until the line becomes visible (and is thus // properly measurable). export function estimateHeight(cm) { - var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; - var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); + var th = textHeight(cm.display), wrapping = cm.options.lineWrapping + var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3) return function(line) { - if (lineIsHidden(cm.doc, line)) return 0; + if (lineIsHidden(cm.doc, line)) return 0 - var widgetsHeight = 0; + var widgetsHeight = 0 if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { - if (line.widgets[i].height) widgetsHeight += line.widgets[i].height; + if (line.widgets[i].height) widgetsHeight += line.widgets[i].height } if (wrapping) - return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th; + return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th else - return widgetsHeight + th; - }; + return widgetsHeight + th + } } export function estimateLineHeights(cm) { - var doc = cm.doc, est = estimateHeight(cm); + var doc = cm.doc, est = estimateHeight(cm) doc.iter(function(line) { - var estHeight = est(line); - if (estHeight != line.height) updateLineHeight(line, estHeight); - }); + var estHeight = est(line) + if (estHeight != line.height) updateLineHeight(line, estHeight) + }) } // Given a mouse event, find the corresponding position. If liberal @@ -551,30 +551,30 @@ export function estimateLineHeights(cm) { // selections, and tries to estimate a character position even for // coordinates beyond the right of the text. export function posFromMouse(cm, e, liberal, forRect) { - var display = cm.display; - if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null; + var display = cm.display + if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null - var x, y, space = display.lineSpace.getBoundingClientRect(); + var x, y, space = display.lineSpace.getBoundingClientRect() // Fails unpredictably on IE[67] when mouse is dragged around quickly. - try { x = e.clientX - space.left; y = e.clientY - space.top; } - catch (e) { return null; } - var coords = coordsChar(cm, x, y), line; + try { x = e.clientX - space.left; y = e.clientY - space.top } + catch (e) { return null } + var coords = coordsChar(cm, x, y), line if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { - var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; - coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); + var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length + coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)) } - return coords; + return coords } // Find the view element corresponding to a given line. Return null // when the line isn't visible. export function findViewIndex(cm, n) { - if (n >= cm.display.viewTo) return null; - n -= cm.display.viewFrom; - if (n < 0) return null; - var view = cm.display.view; + if (n >= cm.display.viewTo) return null + n -= cm.display.viewFrom + if (n < 0) return null + var view = cm.display.view for (var i = 0; i < view.length; i++) { - n -= view[i].size; - if (n < 0) return i; + n -= view[i].size + if (n < 0) return i } } diff --git a/src/measurement/update_line.js b/src/measurement/update_line.js index 5cac95db3e..a80d8c508c 100644 --- a/src/measurement/update_line.js +++ b/src/measurement/update_line.js @@ -1,189 +1,189 @@ -import { buildLineContent } from "../line/line_data"; -import { lineNumberFor } from "../line/utils_line"; -import { ie, ie_version } from "../util/browser"; -import { elt } from "../util/dom"; -import { signalLater } from "../util/operation_group"; +import { buildLineContent } from "../line/line_data" +import { lineNumberFor } from "../line/utils_line" +import { ie, ie_version } from "../util/browser" +import { elt } from "../util/dom" +import { signalLater } from "../util/operation_group" // When an aspect of a line changes, a string is added to // lineView.changes. This updates the relevant part of the line's // DOM structure. export function updateLineForChanges(cm, lineView, lineN, dims) { for (var j = 0; j < lineView.changes.length; j++) { - var type = lineView.changes[j]; - if (type == "text") updateLineText(cm, lineView); - else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims); - else if (type == "class") updateLineClasses(lineView); - else if (type == "widget") updateLineWidgets(cm, lineView, dims); + var type = lineView.changes[j] + if (type == "text") updateLineText(cm, lineView) + else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims) + else if (type == "class") updateLineClasses(lineView) + else if (type == "widget") updateLineWidgets(cm, lineView, dims) } - lineView.changes = null; + lineView.changes = null } // Lines with gutter elements, widgets or a background class need to // be wrapped, and have the extra elements added to the wrapper div function ensureLineWrapped(lineView) { if (lineView.node == lineView.text) { - lineView.node = elt("div", null, null, "position: relative"); + lineView.node = elt("div", null, null, "position: relative") if (lineView.text.parentNode) - lineView.text.parentNode.replaceChild(lineView.node, lineView.text); - lineView.node.appendChild(lineView.text); - if (ie && ie_version < 8) lineView.node.style.zIndex = 2; + lineView.text.parentNode.replaceChild(lineView.node, lineView.text) + lineView.node.appendChild(lineView.text) + if (ie && ie_version < 8) lineView.node.style.zIndex = 2 } - return lineView.node; + return lineView.node } function updateLineBackground(lineView) { - var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; - if (cls) cls += " CodeMirror-linebackground"; + var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass + if (cls) cls += " CodeMirror-linebackground" if (lineView.background) { - if (cls) lineView.background.className = cls; - else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } + if (cls) lineView.background.className = cls + else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null } } else if (cls) { - var wrap = ensureLineWrapped(lineView); - lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); + var wrap = ensureLineWrapped(lineView) + lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild) } } // Wrapper around buildLineContent which will reuse the structure // in display.externalMeasured when possible. function getLineContent(cm, lineView) { - var ext = cm.display.externalMeasured; + var ext = cm.display.externalMeasured if (ext && ext.line == lineView.line) { - cm.display.externalMeasured = null; - lineView.measure = ext.measure; - return ext.built; + cm.display.externalMeasured = null + lineView.measure = ext.measure + return ext.built } - return buildLineContent(cm, lineView); + return buildLineContent(cm, lineView) } // Redraw the line's text. Interacts with the background and text // classes because the mode may output tokens that influence these // classes. function updateLineText(cm, lineView) { - var cls = lineView.text.className; - var built = getLineContent(cm, lineView); - if (lineView.text == lineView.node) lineView.node = built.pre; - lineView.text.parentNode.replaceChild(built.pre, lineView.text); - lineView.text = built.pre; + var cls = lineView.text.className + var built = getLineContent(cm, lineView) + if (lineView.text == lineView.node) lineView.node = built.pre + lineView.text.parentNode.replaceChild(built.pre, lineView.text) + lineView.text = built.pre if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { - lineView.bgClass = built.bgClass; - lineView.textClass = built.textClass; - updateLineClasses(lineView); + lineView.bgClass = built.bgClass + lineView.textClass = built.textClass + updateLineClasses(lineView) } else if (cls) { - lineView.text.className = cls; + lineView.text.className = cls } } function updateLineClasses(lineView) { - updateLineBackground(lineView); + updateLineBackground(lineView) if (lineView.line.wrapClass) - ensureLineWrapped(lineView).className = lineView.line.wrapClass; + ensureLineWrapped(lineView).className = lineView.line.wrapClass else if (lineView.node != lineView.text) - lineView.node.className = ""; - var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; - lineView.text.className = textClass || ""; + lineView.node.className = "" + var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass + lineView.text.className = textClass || "" } function updateLineGutter(cm, lineView, lineN, dims) { if (lineView.gutter) { - lineView.node.removeChild(lineView.gutter); - lineView.gutter = null; + lineView.node.removeChild(lineView.gutter) + lineView.gutter = null } if (lineView.gutterBackground) { - lineView.node.removeChild(lineView.gutterBackground); - lineView.gutterBackground = null; + lineView.node.removeChild(lineView.gutterBackground) + lineView.gutterBackground = null } if (lineView.line.gutterClass) { - var wrap = ensureLineWrapped(lineView); + var wrap = ensureLineWrapped(lineView) lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass, "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + - "px; width: " + dims.gutterTotalWidth + "px"); - wrap.insertBefore(lineView.gutterBackground, lineView.text); + "px; width: " + dims.gutterTotalWidth + "px") + wrap.insertBefore(lineView.gutterBackground, lineView.text) } - var markers = lineView.line.gutterMarkers; + var markers = lineView.line.gutterMarkers if (cm.options.lineNumbers || markers) { - var wrap = ensureLineWrapped(lineView); + var wrap = ensureLineWrapped(lineView) var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + - (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"); - cm.display.input.setUneditable(gutterWrap); - wrap.insertBefore(gutterWrap, lineView.text); + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px") + cm.display.input.setUneditable(gutterWrap) + wrap.insertBefore(gutterWrap, lineView.text) if (lineView.line.gutterClass) - gutterWrap.className += " " + lineView.line.gutterClass; + gutterWrap.className += " " + lineView.line.gutterClass if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) lineView.lineNumber = gutterWrap.appendChild( elt("div", lineNumberFor(cm.options, lineN), "CodeMirror-linenumber CodeMirror-gutter-elt", "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " - + cm.display.lineNumInnerWidth + "px")); + + cm.display.lineNumInnerWidth + "px")) if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) { - var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]; + var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id] if (found) gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + - dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")); + dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")) } } } function updateLineWidgets(cm, lineView, dims) { - if (lineView.alignable) lineView.alignable = null; + if (lineView.alignable) lineView.alignable = null for (var node = lineView.node.firstChild, next; node; node = next) { - var next = node.nextSibling; + var next = node.nextSibling if (node.className == "CodeMirror-linewidget") - lineView.node.removeChild(node); + lineView.node.removeChild(node) } - insertLineWidgets(cm, lineView, dims); + insertLineWidgets(cm, lineView, dims) } // Build a line's DOM representation from scratch export function buildLineElement(cm, lineView, lineN, dims) { - var built = getLineContent(cm, lineView); - lineView.text = lineView.node = built.pre; - if (built.bgClass) lineView.bgClass = built.bgClass; - if (built.textClass) lineView.textClass = built.textClass; + var built = getLineContent(cm, lineView) + lineView.text = lineView.node = built.pre + if (built.bgClass) lineView.bgClass = built.bgClass + if (built.textClass) lineView.textClass = built.textClass - updateLineClasses(lineView); - updateLineGutter(cm, lineView, lineN, dims); - insertLineWidgets(cm, lineView, dims); - return lineView.node; + updateLineClasses(lineView) + updateLineGutter(cm, lineView, lineN, dims) + insertLineWidgets(cm, lineView, dims) + return lineView.node } // A lineView may contain multiple logical lines (when merged by // collapsed spans). The widgets for all of them need to be drawn. function insertLineWidgets(cm, lineView, dims) { - insertLineWidgetsFor(cm, lineView.line, lineView, dims, true); + insertLineWidgetsFor(cm, lineView.line, lineView, dims, true) if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) - insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); + insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false) } function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { - if (!line.widgets) return; - var wrap = ensureLineWrapped(lineView); + if (!line.widgets) return + var wrap = ensureLineWrapped(lineView) for (var i = 0, ws = line.widgets; i < ws.length; ++i) { - var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); - if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true"); - positionLineWidget(widget, node, lineView, dims); - cm.display.input.setUneditable(node); + var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget") + if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true") + positionLineWidget(widget, node, lineView, dims) + cm.display.input.setUneditable(node) if (allowAbove && widget.above) - wrap.insertBefore(node, lineView.gutter || lineView.text); + wrap.insertBefore(node, lineView.gutter || lineView.text) else - wrap.appendChild(node); - signalLater(widget, "redraw"); + wrap.appendChild(node) + signalLater(widget, "redraw") } } function positionLineWidget(widget, node, lineView, dims) { if (widget.noHScroll) { - (lineView.alignable || (lineView.alignable = [])).push(node); - var width = dims.wrapperWidth; - node.style.left = dims.fixedPos + "px"; + (lineView.alignable || (lineView.alignable = [])).push(node) + var width = dims.wrapperWidth + node.style.left = dims.fixedPos + "px" if (!widget.coverGutter) { - width -= dims.gutterTotalWidth; - node.style.paddingLeft = dims.gutterTotalWidth + "px"; + width -= dims.gutterTotalWidth + node.style.paddingLeft = dims.gutterTotalWidth + "px" } - node.style.width = width + "px"; + node.style.width = width + "px" } if (widget.coverGutter) { - node.style.zIndex = 5; - node.style.position = "relative"; - if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"; + node.style.zIndex = 5 + node.style.position = "relative" + if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px" } } diff --git a/src/measurement/widgets.js b/src/measurement/widgets.js index 283740e2c0..f20d313e6d 100644 --- a/src/measurement/widgets.js +++ b/src/measurement/widgets.js @@ -1,19 +1,19 @@ -import { contains, elt, removeChildrenAndAdd } from "../util/dom"; -import { e_target } from "../util/event"; +import { contains, elt, removeChildrenAndAdd } from "../util/dom" +import { e_target } from "../util/event" export function widgetHeight(widget) { - if (widget.height != null) return widget.height; - var cm = widget.doc.cm; - if (!cm) return 0; + if (widget.height != null) return widget.height + var cm = widget.doc.cm + if (!cm) return 0 if (!contains(document.body, widget.node)) { - var parentStyle = "position: relative;"; + var parentStyle = "position: relative;" if (widget.coverGutter) - parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; + parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;" if (widget.noHScroll) - parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; - removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); + parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;" + removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)) } - return widget.height = widget.node.parentNode.offsetHeight; + return widget.height = widget.node.parentNode.offsetHeight } // Return true when the given mouse event happened in a widget @@ -21,6 +21,6 @@ export function eventInWidget(display, e) { for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || (n.parentNode == display.sizer && n != display.mover)) - return true; + return true } } diff --git a/src/model/Doc.js b/src/model/Doc.js index 68d38c90d9..ba004631d3 100644 --- a/src/model/Doc.js +++ b/src/model/Doc.js @@ -1,47 +1,47 @@ -import CodeMirror from "../edit/CodeMirror"; -import { docMethodOp } from "../display/operations"; -import { Line } from "../line/line_data"; -import { clipPos, clipPosArray, Pos } from "../line/pos"; -import { visualLine } from "../line/spans"; -import { getBetween, getLine, getLines, isLine, lineNo } from "../line/utils_line"; -import { classTest } from "../util/dom"; -import { splitLinesAuto } from "../util/feature_detection"; -import { createObj, map, sel_dontScroll } from "../util/misc"; -import { ensureCursorVisible } from "../display/scrolling"; +import CodeMirror from "../edit/CodeMirror" +import { docMethodOp } from "../display/operations" +import { Line } from "../line/line_data" +import { clipPos, clipPosArray, Pos } from "../line/pos" +import { visualLine } from "../line/spans" +import { getBetween, getLine, getLines, isLine, lineNo } from "../line/utils_line" +import { classTest } from "../util/dom" +import { splitLinesAuto } from "../util/feature_detection" +import { createObj, map, sel_dontScroll } from "../util/misc" +import { ensureCursorVisible } from "../display/scrolling" -import { changeLine, makeChange, makeChangeFromHistory, replaceRange } from "./changes"; -import { computeReplacedSel } from "./change_measurement"; -import { BranchChunk, LeafChunk } from "./chunk"; -import { linkedDocs, updateDoc } from "./document_data"; -import { copyHistoryArray, History } from "./history"; -import { addLineWidget } from "./line_widget"; -import { copySharedMarkers, detachSharedMarkers, findSharedMarkers, markText } from "./mark_text"; -import { normalizeSelection, Range, simpleSelection } from "./selection"; -import { extendSelection, extendSelections, setSelection, setSelectionReplaceHistory, setSimpleSelection } from "./selection_updates"; +import { changeLine, makeChange, makeChangeFromHistory, replaceRange } from "./changes" +import { computeReplacedSel } from "./change_measurement" +import { BranchChunk, LeafChunk } from "./chunk" +import { linkedDocs, updateDoc } from "./document_data" +import { copyHistoryArray, History } from "./history" +import { addLineWidget } from "./line_widget" +import { copySharedMarkers, detachSharedMarkers, findSharedMarkers, markText } from "./mark_text" +import { normalizeSelection, Range, simpleSelection } from "./selection" +import { extendSelection, extendSelections, setSelection, setSelectionReplaceHistory, setSimpleSelection } from "./selection_updates" -var nextDocId = 0; +var nextDocId = 0 var Doc = function(text, mode, firstLine, lineSep) { - if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep); - if (firstLine == null) firstLine = 0; + if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep) + if (firstLine == null) firstLine = 0 - BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); - this.first = firstLine; - this.scrollTop = this.scrollLeft = 0; - this.cantEdit = false; - this.cleanGeneration = 1; - this.frontier = firstLine; - var start = Pos(firstLine, 0); - this.sel = simpleSelection(start); - this.history = new History(null); - this.id = ++nextDocId; - this.modeOption = mode; - this.lineSep = lineSep; - this.extend = false; + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]) + this.first = firstLine + this.scrollTop = this.scrollLeft = 0 + this.cantEdit = false + this.cleanGeneration = 1 + this.frontier = firstLine + var start = Pos(firstLine, 0) + this.sel = simpleSelection(start) + this.history = new History(null) + this.id = ++nextDocId + this.modeOption = mode + this.lineSep = lineSep + this.extend = false - if (typeof text == "string") text = this.splitLines(text); - updateDoc(this, {from: start, to: start, text: text}); - setSelection(this, simpleSelection(start), sel_dontScroll); -}; + if (typeof text == "string") text = this.splitLines(text) + updateDoc(this, {from: start, to: start, text: text}) + setSelection(this, simpleSelection(start), sel_dontScroll) +} Doc.prototype = createObj(BranchChunk.prototype, { constructor: Doc, @@ -50,335 +50,335 @@ Doc.prototype = createObj(BranchChunk.prototype, { // three, it iterates over the range given by the first two (with // the second being non-inclusive). iter: function(from, to, op) { - if (op) this.iterN(from - this.first, to - from, op); - else this.iterN(this.first, this.first + this.size, from); + if (op) this.iterN(from - this.first, to - from, op) + else this.iterN(this.first, this.first + this.size, from) }, // Non-public interface for adding and removing lines. insert: function(at, lines) { - var height = 0; - for (var i = 0; i < lines.length; ++i) height += lines[i].height; - this.insertInner(at - this.first, lines, height); + var height = 0 + for (var i = 0; i < lines.length; ++i) height += lines[i].height + this.insertInner(at - this.first, lines, height) }, - remove: function(at, n) { this.removeInner(at - this.first, n); }, + remove: function(at, n) { this.removeInner(at - this.first, n) }, // From here, the methods are part of the public interface. Most // are also available from CodeMirror (editor) instances. getValue: function(lineSep) { - var lines = getLines(this, this.first, this.first + this.size); - if (lineSep === false) return lines; - return lines.join(lineSep || this.lineSeparator()); + var lines = getLines(this, this.first, this.first + this.size) + if (lineSep === false) return lines + return lines.join(lineSep || this.lineSeparator()) }, setValue: docMethodOp(function(code) { - var top = Pos(this.first, 0), last = this.first + this.size - 1; + var top = Pos(this.first, 0), last = this.first + this.size - 1 makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), - text: this.splitLines(code), origin: "setValue", full: true}, true); - setSelection(this, simpleSelection(top)); + text: this.splitLines(code), origin: "setValue", full: true}, true) + setSelection(this, simpleSelection(top)) }), replaceRange: function(code, from, to, origin) { - from = clipPos(this, from); - to = to ? clipPos(this, to) : from; - replaceRange(this, code, from, to, origin); + from = clipPos(this, from) + to = to ? clipPos(this, to) : from + replaceRange(this, code, from, to, origin) }, getRange: function(from, to, lineSep) { - var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); - if (lineSep === false) return lines; - return lines.join(lineSep || this.lineSeparator()); + var lines = getBetween(this, clipPos(this, from), clipPos(this, to)) + if (lineSep === false) return lines + return lines.join(lineSep || this.lineSeparator()) }, - getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, + getLine: function(line) {var l = this.getLineHandle(line); return l && l.text}, - getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, - getLineNumber: function(line) {return lineNo(line);}, + getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line)}, + getLineNumber: function(line) {return lineNo(line)}, getLineHandleVisualStart: function(line) { - if (typeof line == "number") line = getLine(this, line); - return visualLine(line); + if (typeof line == "number") line = getLine(this, line) + return visualLine(line) }, - lineCount: function() {return this.size;}, - firstLine: function() {return this.first;}, - lastLine: function() {return this.first + this.size - 1;}, + lineCount: function() {return this.size}, + firstLine: function() {return this.first}, + lastLine: function() {return this.first + this.size - 1}, - clipPos: function(pos) {return clipPos(this, pos);}, + clipPos: function(pos) {return clipPos(this, pos)}, getCursor: function(start) { - var range = this.sel.primary(), pos; - if (start == null || start == "head") pos = range.head; - else if (start == "anchor") pos = range.anchor; - else if (start == "end" || start == "to" || start === false) pos = range.to(); - else pos = range.from(); - return pos; + var range = this.sel.primary(), pos + if (start == null || start == "head") pos = range.head + else if (start == "anchor") pos = range.anchor + else if (start == "end" || start == "to" || start === false) pos = range.to() + else pos = range.from() + return pos }, - listSelections: function() { return this.sel.ranges; }, - somethingSelected: function() {return this.sel.somethingSelected();}, + listSelections: function() { return this.sel.ranges }, + somethingSelected: function() {return this.sel.somethingSelected()}, setCursor: docMethodOp(function(line, ch, options) { - setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); + setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options) }), setSelection: docMethodOp(function(anchor, head, options) { - setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); + setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options) }), extendSelection: docMethodOp(function(head, other, options) { - extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); + extendSelection(this, clipPos(this, head), other && clipPos(this, other), options) }), extendSelections: docMethodOp(function(heads, options) { - extendSelections(this, clipPosArray(this, heads), options); + extendSelections(this, clipPosArray(this, heads), options) }), extendSelectionsBy: docMethodOp(function(f, options) { - var heads = map(this.sel.ranges, f); - extendSelections(this, clipPosArray(this, heads), options); + var heads = map(this.sel.ranges, f) + extendSelections(this, clipPosArray(this, heads), options) }), setSelections: docMethodOp(function(ranges, primary, options) { - if (!ranges.length) return; + if (!ranges.length) return for (var i = 0, out = []; i < ranges.length; i++) out[i] = new Range(clipPos(this, ranges[i].anchor), - clipPos(this, ranges[i].head)); - if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex); - setSelection(this, normalizeSelection(out, primary), options); + clipPos(this, ranges[i].head)) + if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex) + setSelection(this, normalizeSelection(out, primary), options) }), addSelection: docMethodOp(function(anchor, head, options) { - var ranges = this.sel.ranges.slice(0); - ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); - setSelection(this, normalizeSelection(ranges, ranges.length - 1), options); + var ranges = this.sel.ranges.slice(0) + ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))) + setSelection(this, normalizeSelection(ranges, ranges.length - 1), options) }), getSelection: function(lineSep) { - var ranges = this.sel.ranges, lines; + var ranges = this.sel.ranges, lines for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this, ranges[i].from(), ranges[i].to()); - lines = lines ? lines.concat(sel) : sel; + var sel = getBetween(this, ranges[i].from(), ranges[i].to()) + lines = lines ? lines.concat(sel) : sel } - if (lineSep === false) return lines; - else return lines.join(lineSep || this.lineSeparator()); + if (lineSep === false) return lines + else return lines.join(lineSep || this.lineSeparator()) }, getSelections: function(lineSep) { - var parts = [], ranges = this.sel.ranges; + var parts = [], ranges = this.sel.ranges for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this, ranges[i].from(), ranges[i].to()); - if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator()); - parts[i] = sel; + var sel = getBetween(this, ranges[i].from(), ranges[i].to()) + if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator()) + parts[i] = sel } - return parts; + return parts }, replaceSelection: function(code, collapse, origin) { - var dup = []; + var dup = [] for (var i = 0; i < this.sel.ranges.length; i++) - dup[i] = code; - this.replaceSelections(dup, collapse, origin || "+input"); + dup[i] = code + this.replaceSelections(dup, collapse, origin || "+input") }, replaceSelections: docMethodOp(function(code, collapse, origin) { - var changes = [], sel = this.sel; + var changes = [], sel = this.sel for (var i = 0; i < sel.ranges.length; i++) { - var range = sel.ranges[i]; - changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin}; + var range = sel.ranges[i] + changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin} } - var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); + var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse) for (var i = changes.length - 1; i >= 0; i--) - makeChange(this, changes[i]); - if (newSel) setSelectionReplaceHistory(this, newSel); - else if (this.cm) ensureCursorVisible(this.cm); + makeChange(this, changes[i]) + if (newSel) setSelectionReplaceHistory(this, newSel) + else if (this.cm) ensureCursorVisible(this.cm) }), - undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}), - redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}), - undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}), - redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}), + undo: docMethodOp(function() {makeChangeFromHistory(this, "undo")}), + redo: docMethodOp(function() {makeChangeFromHistory(this, "redo")}), + undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true)}), + redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true)}), - setExtending: function(val) {this.extend = val;}, - getExtending: function() {return this.extend;}, + setExtending: function(val) {this.extend = val}, + getExtending: function() {return this.extend}, historySize: function() { - var hist = this.history, done = 0, undone = 0; - for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done; - for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone; - return {undo: done, redo: undone}; + var hist = this.history, done = 0, undone = 0 + for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done + for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone + return {undo: done, redo: undone} }, - clearHistory: function() {this.history = new History(this.history.maxGeneration);}, + clearHistory: function() {this.history = new History(this.history.maxGeneration)}, markClean: function() { - this.cleanGeneration = this.changeGeneration(true); + this.cleanGeneration = this.changeGeneration(true) }, changeGeneration: function(forceSplit) { if (forceSplit) - this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; - return this.history.generation; + this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null + return this.history.generation }, isClean: function (gen) { - return this.history.generation == (gen || this.cleanGeneration); + return this.history.generation == (gen || this.cleanGeneration) }, getHistory: function() { return {done: copyHistoryArray(this.history.done), - undone: copyHistoryArray(this.history.undone)}; + undone: copyHistoryArray(this.history.undone)} }, setHistory: function(histData) { - var hist = this.history = new History(this.history.maxGeneration); - hist.done = copyHistoryArray(histData.done.slice(0), null, true); - hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); + var hist = this.history = new History(this.history.maxGeneration) + hist.done = copyHistoryArray(histData.done.slice(0), null, true) + hist.undone = copyHistoryArray(histData.undone.slice(0), null, true) }, addLineClass: docMethodOp(function(handle, where, cls) { return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" - : where == "gutter" ? "gutterClass" : "wrapClass"; - if (!line[prop]) line[prop] = cls; - else if (classTest(cls).test(line[prop])) return false; - else line[prop] += " " + cls; - return true; - }); + : where == "gutter" ? "gutterClass" : "wrapClass" + if (!line[prop]) line[prop] = cls + else if (classTest(cls).test(line[prop])) return false + else line[prop] += " " + cls + return true + }) }), removeLineClass: docMethodOp(function(handle, where, cls) { return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" - : where == "gutter" ? "gutterClass" : "wrapClass"; - var cur = line[prop]; - if (!cur) return false; - else if (cls == null) line[prop] = null; + : where == "gutter" ? "gutterClass" : "wrapClass" + var cur = line[prop] + if (!cur) return false + else if (cls == null) line[prop] = null else { - var found = cur.match(classTest(cls)); - if (!found) return false; - var end = found.index + found[0].length; - line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; + var found = cur.match(classTest(cls)) + if (!found) return false + var end = found.index + found[0].length + line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null } - return true; - }); + return true + }) }), addLineWidget: docMethodOp(function(handle, node, options) { - return addLineWidget(this, handle, node, options); + return addLineWidget(this, handle, node, options) }), - removeLineWidget: function(widget) { widget.clear(); }, + removeLineWidget: function(widget) { widget.clear() }, markText: function(from, to, options) { - return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range"); + return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range") }, setBookmark: function(pos, options) { var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), insertLeft: options && options.insertLeft, clearWhenEmpty: false, shared: options && options.shared, - handleMouseEvents: options && options.handleMouseEvents}; - pos = clipPos(this, pos); - return markText(this, pos, pos, realOpts, "bookmark"); + handleMouseEvents: options && options.handleMouseEvents} + pos = clipPos(this, pos) + return markText(this, pos, pos, realOpts, "bookmark") }, findMarksAt: function(pos) { - pos = clipPos(this, pos); - var markers = [], spans = getLine(this, pos.line).markedSpans; + pos = clipPos(this, pos) + var markers = [], spans = getLine(this, pos.line).markedSpans if (spans) for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; + var span = spans[i] if ((span.from == null || span.from <= pos.ch) && (span.to == null || span.to >= pos.ch)) - markers.push(span.marker.parent || span.marker); + markers.push(span.marker.parent || span.marker) } - return markers; + return markers }, findMarks: function(from, to, filter) { - from = clipPos(this, from); to = clipPos(this, to); - var found = [], lineNo = from.line; + from = clipPos(this, from); to = clipPos(this, to) + var found = [], lineNo = from.line this.iter(from.line, to.line + 1, function(line) { - var spans = line.markedSpans; + var spans = line.markedSpans if (spans) for (var i = 0; i < spans.length; i++) { - var span = spans[i]; + var span = spans[i] if (!(span.to != null && lineNo == from.line && from.ch >= span.to || span.from == null && lineNo != from.line || span.from != null && lineNo == to.line && span.from >= to.ch) && (!filter || filter(span.marker))) - found.push(span.marker.parent || span.marker); + found.push(span.marker.parent || span.marker) } - ++lineNo; - }); - return found; + ++lineNo + }) + return found }, getAllMarks: function() { - var markers = []; + var markers = [] this.iter(function(line) { - var sps = line.markedSpans; + var sps = line.markedSpans if (sps) for (var i = 0; i < sps.length; ++i) - if (sps[i].from != null) markers.push(sps[i].marker); - }); - return markers; + if (sps[i].from != null) markers.push(sps[i].marker) + }) + return markers }, posFromIndex: function(off) { - var ch, lineNo = this.first, sepSize = this.lineSeparator().length; + var ch, lineNo = this.first, sepSize = this.lineSeparator().length this.iter(function(line) { - var sz = line.text.length + sepSize; - if (sz > off) { ch = off; return true; } - off -= sz; - ++lineNo; - }); - return clipPos(this, Pos(lineNo, ch)); + var sz = line.text.length + sepSize + if (sz > off) { ch = off; return true } + off -= sz + ++lineNo + }) + return clipPos(this, Pos(lineNo, ch)) }, indexFromPos: function (coords) { - coords = clipPos(this, coords); - var index = coords.ch; - if (coords.line < this.first || coords.ch < 0) return 0; - var sepSize = this.lineSeparator().length; + coords = clipPos(this, coords) + var index = coords.ch + if (coords.line < this.first || coords.ch < 0) return 0 + var sepSize = this.lineSeparator().length this.iter(this.first, coords.line, function (line) { - index += line.text.length + sepSize; - }); - return index; + index += line.text.length + sepSize + }) + return index }, copy: function(copyHistory) { var doc = new Doc(getLines(this, this.first, this.first + this.size), - this.modeOption, this.first, this.lineSep); - doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; - doc.sel = this.sel; - doc.extend = false; + this.modeOption, this.first, this.lineSep) + doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft + doc.sel = this.sel + doc.extend = false if (copyHistory) { - doc.history.undoDepth = this.history.undoDepth; - doc.setHistory(this.getHistory()); + doc.history.undoDepth = this.history.undoDepth + doc.setHistory(this.getHistory()) } - return doc; + return doc }, linkedDoc: function(options) { - if (!options) options = {}; - var from = this.first, to = this.first + this.size; - if (options.from != null && options.from > from) from = options.from; - if (options.to != null && options.to < to) to = options.to; - var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep); - if (options.sharedHist) copy.history = this.history; - (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); - copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; - copySharedMarkers(copy, findSharedMarkers(this)); - return copy; + if (!options) options = {} + var from = this.first, to = this.first + this.size + if (options.from != null && options.from > from) from = options.from + if (options.to != null && options.to < to) to = options.to + var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep) + if (options.sharedHist) copy.history = this.history + ;(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}) + copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}] + copySharedMarkers(copy, findSharedMarkers(this)) + return copy }, unlinkDoc: function(other) { - if (other instanceof CodeMirror) other = other.doc; + if (other instanceof CodeMirror) other = other.doc if (this.linked) for (var i = 0; i < this.linked.length; ++i) { - var link = this.linked[i]; - if (link.doc != other) continue; - this.linked.splice(i, 1); - other.unlinkDoc(this); - detachSharedMarkers(findSharedMarkers(this)); - break; + var link = this.linked[i] + if (link.doc != other) continue + this.linked.splice(i, 1) + other.unlinkDoc(this) + detachSharedMarkers(findSharedMarkers(this)) + break } // If the histories were shared, split them again if (other.history == this.history) { - var splitIds = [other.id]; - linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true); - other.history = new History(null); - other.history.done = copyHistoryArray(this.history.done, splitIds); - other.history.undone = copyHistoryArray(this.history.undone, splitIds); + var splitIds = [other.id] + linkedDocs(other, function(doc) {splitIds.push(doc.id)}, true) + other.history = new History(null) + other.history.done = copyHistoryArray(this.history.done, splitIds) + other.history.undone = copyHistoryArray(this.history.undone, splitIds) } }, - iterLinkedDocs: function(f) {linkedDocs(this, f);}, + iterLinkedDocs: function(f) {linkedDocs(this, f)}, - getMode: function() {return this.mode;}, - getEditor: function() {return this.cm;}, + getMode: function() {return this.mode}, + getEditor: function() {return this.cm}, splitLines: function(str) { - if (this.lineSep) return str.split(this.lineSep); - return splitLinesAuto(str); + if (this.lineSep) return str.split(this.lineSep) + return splitLinesAuto(str) }, - lineSeparator: function() { return this.lineSep || "\n"; } -}); + lineSeparator: function() { return this.lineSep || "\n" } +}) // Public alias. -Doc.prototype.eachLine = Doc.prototype.iter; +Doc.prototype.eachLine = Doc.prototype.iter -export default Doc; +export default Doc diff --git a/src/model/change_measurement.js b/src/model/change_measurement.js index cb2bb2d1d8..ac14fa5458 100644 --- a/src/model/change_measurement.js +++ b/src/model/change_measurement.js @@ -1,61 +1,61 @@ -import { cmp, Pos } from "../line/pos"; -import { lst } from "../util/misc"; +import { cmp, Pos } from "../line/pos" +import { lst } from "../util/misc" -import { normalizeSelection, Range, Selection } from "./selection"; +import { normalizeSelection, Range, Selection } from "./selection" // Compute the position of the end of a change (its 'to' property // refers to the pre-change end). export function changeEnd(change) { - if (!change.text) return change.to; + if (!change.text) return change.to return Pos(change.from.line + change.text.length - 1, - lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); + lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)) } // Adjust a position to refer to the post-change position of the // same text, or the end of the change if the change covers it. function adjustForChange(pos, change) { - if (cmp(pos, change.from) < 0) return pos; - if (cmp(pos, change.to) <= 0) return changeEnd(change); + if (cmp(pos, change.from) < 0) return pos + if (cmp(pos, change.to) <= 0) return changeEnd(change) - var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; - if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch; - return Pos(line, ch); + var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch + if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch + return Pos(line, ch) } export function computeSelAfterChange(doc, change) { - var out = []; + var out = [] for (var i = 0; i < doc.sel.ranges.length; i++) { - var range = doc.sel.ranges[i]; + var range = doc.sel.ranges[i] out.push(new Range(adjustForChange(range.anchor, change), - adjustForChange(range.head, change))); + adjustForChange(range.head, change))) } - return normalizeSelection(out, doc.sel.primIndex); + return normalizeSelection(out, doc.sel.primIndex) } function offsetPos(pos, old, nw) { if (pos.line == old.line) - return Pos(nw.line, pos.ch - old.ch + nw.ch); + return Pos(nw.line, pos.ch - old.ch + nw.ch) else - return Pos(nw.line + (pos.line - old.line), pos.ch); + return Pos(nw.line + (pos.line - old.line), pos.ch) } // Used by replaceSelections to allow moving the selection to the // start or around the replaced test. Hint may be "start" or "around". export function computeReplacedSel(doc, changes, hint) { - var out = []; - var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; + var out = [] + var oldPrev = Pos(doc.first, 0), newPrev = oldPrev for (var i = 0; i < changes.length; i++) { - var change = changes[i]; - var from = offsetPos(change.from, oldPrev, newPrev); - var to = offsetPos(changeEnd(change), oldPrev, newPrev); - oldPrev = change.to; - newPrev = to; + var change = changes[i] + var from = offsetPos(change.from, oldPrev, newPrev) + var to = offsetPos(changeEnd(change), oldPrev, newPrev) + oldPrev = change.to + newPrev = to if (hint == "around") { - var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; - out[i] = new Range(inv ? to : from, inv ? from : to); + var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0 + out[i] = new Range(inv ? to : from, inv ? from : to) } else { - out[i] = new Range(from, from); + out[i] = new Range(from, from) } } - return new Selection(out, doc.sel.primIndex); + return new Selection(out, doc.sel.primIndex) } diff --git a/src/model/changes.js b/src/model/changes.js index 01526d2943..6a8606afcb 100644 --- a/src/model/changes.js +++ b/src/model/changes.js @@ -1,20 +1,20 @@ -import { startWorker } from "../display/highlight_worker"; -import { operation } from "../display/operations"; -import { regChange, regLineChange } from "../display/view_tracking"; -import { clipLine, clipPos, cmp, Pos } from "../line/pos"; -import { sawReadOnlySpans } from "../line/saw_special_spans"; -import { lineLength, removeReadOnlyRanges, stretchSpansOverChange, visualLine } from "../line/spans"; -import { getBetween, getLine, lineNo } from "../line/utils_line"; -import { estimateHeight } from "../measurement/position_measurement"; -import { hasHandler, signal, signalCursorActivity } from "../util/event"; -import { indexOf, lst, map, sel_dontScroll } from "../util/misc"; -import { signalLater } from "../util/operation_group"; - -import { changeEnd, computeSelAfterChange } from "./change_measurement"; -import { isWholeLineUpdate, linkedDocs, updateDoc } from "./document_data"; -import { addChangeToHistory, historyChangeFromChange, mergeOldSpans, pushSelectionToHistory } from "./history"; -import { Range, Selection } from "./selection"; -import { setSelection, setSelectionNoUndo } from "./selection_updates"; +import { startWorker } from "../display/highlight_worker" +import { operation } from "../display/operations" +import { regChange, regLineChange } from "../display/view_tracking" +import { clipLine, clipPos, cmp, Pos } from "../line/pos" +import { sawReadOnlySpans } from "../line/saw_special_spans" +import { lineLength, removeReadOnlyRanges, stretchSpansOverChange, visualLine } from "../line/spans" +import { getBetween, getLine, lineNo } from "../line/utils_line" +import { estimateHeight } from "../measurement/position_measurement" +import { hasHandler, signal, signalCursorActivity } from "../util/event" +import { indexOf, lst, map, sel_dontScroll } from "../util/misc" +import { signalLater } from "../util/operation_group" + +import { changeEnd, computeSelAfterChange } from "./change_measurement" +import { isWholeLineUpdate, linkedDocs, updateDoc } from "./document_data" +import { addChangeToHistory, historyChangeFromChange, mergeOldSpans, pushSelectionToHistory } from "./history" +import { Range, Selection } from "./selection" +import { setSelection, setSelectionNoUndo } from "./selection_updates" // UPDATING @@ -26,140 +26,140 @@ function filterChange(doc, change, update) { to: change.to, text: change.text, origin: change.origin, - cancel: function() { this.canceled = true; } - }; + cancel: function() { this.canceled = true } + } if (update) obj.update = function(from, to, text, origin) { - if (from) this.from = clipPos(doc, from); - if (to) this.to = clipPos(doc, to); - if (text) this.text = text; - if (origin !== undefined) this.origin = origin; - }; - signal(doc, "beforeChange", doc, obj); - if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); - - if (obj.canceled) return null; - return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}; + if (from) this.from = clipPos(doc, from) + if (to) this.to = clipPos(doc, to) + if (text) this.text = text + if (origin !== undefined) this.origin = origin + } + signal(doc, "beforeChange", doc, obj) + if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj) + + if (obj.canceled) return null + return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin} } // Apply a change to a document, and add it to the document's // history, and propagating it to all linked documents. export function makeChange(doc, change, ignoreReadOnly) { if (doc.cm) { - if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly); - if (doc.cm.state.suppressEdits) return; + if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) + if (doc.cm.state.suppressEdits) return } if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { - change = filterChange(doc, change, true); - if (!change) return; + change = filterChange(doc, change, true) + if (!change) return } // Possibly split or suppress the update based on the presence // of read-only spans in its range. - var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); + var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to) if (split) { for (var i = split.length - 1; i >= 0; --i) - makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}); + makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}) } else { - makeChangeInner(doc, change); + makeChangeInner(doc, change) } } function makeChangeInner(doc, change) { - if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return; - var selAfter = computeSelAfterChange(doc, change); - addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); + if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return + var selAfter = computeSelAfterChange(doc, change) + addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN) - makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); - var rebased = []; + makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)) + var rebased = [] linkedDocs(doc, function(doc, sharedHist) { if (!sharedHist && indexOf(rebased, doc.history) == -1) { - rebaseHist(doc.history, change); - rebased.push(doc.history); + rebaseHist(doc.history, change) + rebased.push(doc.history) } - makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); - }); + makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)) + }) } // Revert a change stored in a document's history. export function makeChangeFromHistory(doc, type, allowSelectionOnly) { - if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) return; + if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) return - var hist = doc.history, event, selAfter = doc.sel; - var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; + var hist = doc.history, event, selAfter = doc.sel + var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done // Verify that there is a useable event (so that ctrl-z won't // needlessly clear selection events) for (var i = 0; i < source.length; i++) { - event = source[i]; + event = source[i] if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) - break; + break } - if (i == source.length) return; - hist.lastOrigin = hist.lastSelOrigin = null; + if (i == source.length) return + hist.lastOrigin = hist.lastSelOrigin = null for (;;) { - event = source.pop(); + event = source.pop() if (event.ranges) { - pushSelectionToHistory(event, dest); + pushSelectionToHistory(event, dest) if (allowSelectionOnly && !event.equals(doc.sel)) { - setSelection(doc, event, {clearRedo: false}); - return; + setSelection(doc, event, {clearRedo: false}) + return } - selAfter = event; + selAfter = event } - else break; + else break } // Build up a reverse change object to add to the opposite history // stack (redo when undoing, and vice versa). - var antiChanges = []; - pushSelectionToHistory(selAfter, dest); - dest.push({changes: antiChanges, generation: hist.generation}); - hist.generation = event.generation || ++hist.maxGeneration; + var antiChanges = [] + pushSelectionToHistory(selAfter, dest) + dest.push({changes: antiChanges, generation: hist.generation}) + hist.generation = event.generation || ++hist.maxGeneration - var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); + var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange") for (var i = event.changes.length - 1; i >= 0; --i) { - var change = event.changes[i]; - change.origin = type; + var change = event.changes[i] + change.origin = type if (filter && !filterChange(doc, change, false)) { - source.length = 0; - return; + source.length = 0 + return } - antiChanges.push(historyChangeFromChange(doc, change)); + antiChanges.push(historyChangeFromChange(doc, change)) - var after = i ? computeSelAfterChange(doc, change) : lst(source); - makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); - if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); - var rebased = []; + var after = i ? computeSelAfterChange(doc, change) : lst(source) + makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)) + if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}) + var rebased = [] // Propagate to the linked documents linkedDocs(doc, function(doc, sharedHist) { if (!sharedHist && indexOf(rebased, doc.history) == -1) { - rebaseHist(doc.history, change); - rebased.push(doc.history); + rebaseHist(doc.history, change) + rebased.push(doc.history) } - makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); - }); + makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)) + }) } } // Sub-views need their line numbers shifted when text is added // above or below them in the parent document. function shiftDoc(doc, distance) { - if (distance == 0) return; - doc.first += distance; + if (distance == 0) return + doc.first += distance doc.sel = new Selection(map(doc.sel.ranges, function(range) { return new Range(Pos(range.anchor.line + distance, range.anchor.ch), - Pos(range.head.line + distance, range.head.ch)); - }), doc.sel.primIndex); + Pos(range.head.line + distance, range.head.ch)) + }), doc.sel.primIndex) if (doc.cm) { - regChange(doc.cm, doc.first, doc.first - distance, distance); + regChange(doc.cm, doc.first, doc.first - distance, distance) for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) - regLineChange(doc.cm, l, "gutter"); + regLineChange(doc.cm, l, "gutter") } } @@ -167,111 +167,111 @@ function shiftDoc(doc, distance) { // (not linked ones). function makeChangeSingleDoc(doc, change, selAfter, spans) { if (doc.cm && !doc.cm.curOp) - return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans); + return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) if (change.to.line < doc.first) { - shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); - return; + shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)) + return } - if (change.from.line > doc.lastLine()) return; + if (change.from.line > doc.lastLine()) return // Clip the change to the size of this doc if (change.from.line < doc.first) { - var shift = change.text.length - 1 - (doc.first - change.from.line); - shiftDoc(doc, shift); + var shift = change.text.length - 1 - (doc.first - change.from.line) + shiftDoc(doc, shift) change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), - text: [lst(change.text)], origin: change.origin}; + text: [lst(change.text)], origin: change.origin} } - var last = doc.lastLine(); + var last = doc.lastLine() if (change.to.line > last) { change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), - text: [change.text[0]], origin: change.origin}; + text: [change.text[0]], origin: change.origin} } - change.removed = getBetween(doc, change.from, change.to); + change.removed = getBetween(doc, change.from, change.to) - if (!selAfter) selAfter = computeSelAfterChange(doc, change); - if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans); - else updateDoc(doc, change, spans); - setSelectionNoUndo(doc, selAfter, sel_dontScroll); + if (!selAfter) selAfter = computeSelAfterChange(doc, change) + if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans) + else updateDoc(doc, change, spans) + setSelectionNoUndo(doc, selAfter, sel_dontScroll) } // Handle the interaction of a change to a document with the editor // that this document is part of. function makeChangeSingleDocInEditor(cm, change, spans) { - var doc = cm.doc, display = cm.display, from = change.from, to = change.to; + var doc = cm.doc, display = cm.display, from = change.from, to = change.to - var recomputeMaxLength = false, checkWidthStart = from.line; + var recomputeMaxLength = false, checkWidthStart = from.line if (!cm.options.lineWrapping) { - checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); + checkWidthStart = lineNo(visualLine(getLine(doc, from.line))) doc.iter(checkWidthStart, to.line + 1, function(line) { if (line == display.maxLine) { - recomputeMaxLength = true; - return true; + recomputeMaxLength = true + return true } - }); + }) } if (doc.sel.contains(change.from, change.to) > -1) - signalCursorActivity(cm); + signalCursorActivity(cm) - updateDoc(doc, change, spans, estimateHeight(cm)); + updateDoc(doc, change, spans, estimateHeight(cm)) if (!cm.options.lineWrapping) { doc.iter(checkWidthStart, from.line + change.text.length, function(line) { - var len = lineLength(line); + var len = lineLength(line) if (len > display.maxLineLength) { - display.maxLine = line; - display.maxLineLength = len; - display.maxLineChanged = true; - recomputeMaxLength = false; + display.maxLine = line + display.maxLineLength = len + display.maxLineChanged = true + recomputeMaxLength = false } - }); - if (recomputeMaxLength) cm.curOp.updateMaxLine = true; + }) + if (recomputeMaxLength) cm.curOp.updateMaxLine = true } // Adjust frontier, schedule worker - doc.frontier = Math.min(doc.frontier, from.line); - startWorker(cm, 400); + doc.frontier = Math.min(doc.frontier, from.line) + startWorker(cm, 400) - var lendiff = change.text.length - (to.line - from.line) - 1; + var lendiff = change.text.length - (to.line - from.line) - 1 // Remember that these lines changed, for updating the display if (change.full) - regChange(cm); + regChange(cm) else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) - regLineChange(cm, from.line, "text"); + regLineChange(cm, from.line, "text") else - regChange(cm, from.line, to.line + 1, lendiff); + regChange(cm, from.line, to.line + 1, lendiff) - var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); + var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change") if (changeHandler || changesHandler) { var obj = { from: from, to: to, text: change.text, removed: change.removed, origin: change.origin - }; - if (changeHandler) signalLater(cm, "change", cm, obj); - if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); + } + if (changeHandler) signalLater(cm, "change", cm, obj) + if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj) } - cm.display.selForContextMenu = null; + cm.display.selForContextMenu = null } export function replaceRange(doc, code, from, to, origin) { - if (!to) to = from; - if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } - if (typeof code == "string") code = doc.splitLines(code); - makeChange(doc, {from: from, to: to, text: code, origin: origin}); + if (!to) to = from + if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp } + if (typeof code == "string") code = doc.splitLines(code) + makeChange(doc, {from: from, to: to, text: code, origin: origin}) } // Rebasing/resetting history to deal with externally-sourced changes function rebaseHistSelSingle(pos, from, to, diff) { if (to < pos.line) { - pos.line += diff; + pos.line += diff } else if (from < pos.line) { - pos.line = from; - pos.ch = 0; + pos.line = from + pos.ch = 0 } } @@ -284,46 +284,46 @@ function rebaseHistSelSingle(pos, from, to, diff) { // shared position objects being unsafely updated. function rebaseHistArray(array, from, to, diff) { for (var i = 0; i < array.length; ++i) { - var sub = array[i], ok = true; + var sub = array[i], ok = true if (sub.ranges) { - if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } + if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true } for (var j = 0; j < sub.ranges.length; j++) { - rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); - rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); + rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff) + rebaseHistSelSingle(sub.ranges[j].head, from, to, diff) } - continue; + continue } for (var j = 0; j < sub.changes.length; ++j) { - var cur = sub.changes[j]; + var cur = sub.changes[j] if (to < cur.from.line) { - cur.from = Pos(cur.from.line + diff, cur.from.ch); - cur.to = Pos(cur.to.line + diff, cur.to.ch); + cur.from = Pos(cur.from.line + diff, cur.from.ch) + cur.to = Pos(cur.to.line + diff, cur.to.ch) } else if (from <= cur.to.line) { - ok = false; - break; + ok = false + break } } if (!ok) { - array.splice(0, i + 1); - i = 0; + array.splice(0, i + 1) + i = 0 } } } function rebaseHist(hist, change) { - var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; - rebaseHistArray(hist.done, from, to, diff); - rebaseHistArray(hist.undone, from, to, diff); + var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1 + rebaseHistArray(hist.done, from, to, diff) + rebaseHistArray(hist.undone, from, to, diff) } // Utility for applying a change to a line by handle or number, // returning the number and optionally registering the line as // changed. export function changeLine(doc, handle, changeType, op) { - var no = handle, line = handle; - if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); - else no = lineNo(handle); - if (no == null) return null; - if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType); - return line; + var no = handle, line = handle + if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)) + else no = lineNo(handle) + if (no == null) return null + if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType) + return line } diff --git a/src/model/chunk.js b/src/model/chunk.js index 28fd4153b5..0aee95fe2f 100644 --- a/src/model/chunk.js +++ b/src/model/chunk.js @@ -1,6 +1,6 @@ -import { cleanUpLine } from "../line/line_data"; -import { indexOf } from "../util/misc"; -import { signalLater } from "../util/operation_group"; +import { cleanUpLine } from "../line/line_data" +import { indexOf } from "../util/misc" +import { signalLater } from "../util/operation_group" // The document is represented as a BTree consisting of leaves, with // chunk of lines in them, and branches, with up to ten leaves or @@ -16,142 +16,142 @@ import { signalLater } from "../util/operation_group"; // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html export function LeafChunk(lines) { - this.lines = lines; - this.parent = null; + this.lines = lines + this.parent = null for (var i = 0, height = 0; i < lines.length; ++i) { - lines[i].parent = this; - height += lines[i].height; + lines[i].parent = this + height += lines[i].height } - this.height = height; + this.height = height } LeafChunk.prototype = { - chunkSize: function() { return this.lines.length; }, + chunkSize: function() { return this.lines.length }, // Remove the n lines at offset 'at'. removeInner: function(at, n) { for (var i = at, e = at + n; i < e; ++i) { - var line = this.lines[i]; - this.height -= line.height; - cleanUpLine(line); - signalLater(line, "delete"); + var line = this.lines[i] + this.height -= line.height + cleanUpLine(line) + signalLater(line, "delete") } - this.lines.splice(at, n); + this.lines.splice(at, n) }, // Helper used to collapse a small branch into a single leaf. collapse: function(lines) { - lines.push.apply(lines, this.lines); + lines.push.apply(lines, this.lines) }, // Insert the given array of lines at offset 'at', count them as // having the given height. insertInner: function(at, lines, height) { - this.height += height; - this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); - for (var i = 0; i < lines.length; ++i) lines[i].parent = this; + this.height += height + this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)) + for (var i = 0; i < lines.length; ++i) lines[i].parent = this }, // Used to iterate over a part of the tree. iterN: function(at, n, op) { for (var e = at + n; at < e; ++at) - if (op(this.lines[at])) return true; + if (op(this.lines[at])) return true } -}; +} export function BranchChunk(children) { - this.children = children; - var size = 0, height = 0; + this.children = children + var size = 0, height = 0 for (var i = 0; i < children.length; ++i) { - var ch = children[i]; - size += ch.chunkSize(); height += ch.height; - ch.parent = this; + var ch = children[i] + size += ch.chunkSize(); height += ch.height + ch.parent = this } - this.size = size; - this.height = height; - this.parent = null; + this.size = size + this.height = height + this.parent = null } BranchChunk.prototype = { - chunkSize: function() { return this.size; }, + chunkSize: function() { return this.size }, removeInner: function(at, n) { - this.size -= n; + this.size -= n for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize(); + var child = this.children[i], sz = child.chunkSize() if (at < sz) { - var rm = Math.min(n, sz - at), oldHeight = child.height; - child.removeInner(at, rm); - this.height -= oldHeight - child.height; - if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } - if ((n -= rm) == 0) break; - at = 0; - } else at -= sz; + var rm = Math.min(n, sz - at), oldHeight = child.height + child.removeInner(at, rm) + this.height -= oldHeight - child.height + if (sz == rm) { this.children.splice(i--, 1); child.parent = null } + if ((n -= rm) == 0) break + at = 0 + } else at -= sz } // If the result is smaller than 25 lines, ensure that it is a // single leaf node. if (this.size - n < 25 && (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { - var lines = []; - this.collapse(lines); - this.children = [new LeafChunk(lines)]; - this.children[0].parent = this; + var lines = [] + this.collapse(lines) + this.children = [new LeafChunk(lines)] + this.children[0].parent = this } }, collapse: function(lines) { - for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines); + for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines) }, insertInner: function(at, lines, height) { - this.size += lines.length; - this.height += height; + this.size += lines.length + this.height += height for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize(); + var child = this.children[i], sz = child.chunkSize() if (at <= sz) { - child.insertInner(at, lines, height); + child.insertInner(at, lines, height) if (child.lines && child.lines.length > 50) { // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced. // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest. var remaining = child.lines.length % 25 + 25 for (var pos = remaining; pos < child.lines.length;) { - var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)); - child.height -= leaf.height; - this.children.splice(++i, 0, leaf); - leaf.parent = this; + var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)) + child.height -= leaf.height + this.children.splice(++i, 0, leaf) + leaf.parent = this } - child.lines = child.lines.slice(0, remaining); - this.maybeSpill(); + child.lines = child.lines.slice(0, remaining) + this.maybeSpill() } - break; + break } - at -= sz; + at -= sz } }, // When a node has grown, check whether it should be split. maybeSpill: function() { - if (this.children.length <= 10) return; - var me = this; + if (this.children.length <= 10) return + var me = this do { - var spilled = me.children.splice(me.children.length - 5, 5); - var sibling = new BranchChunk(spilled); + var spilled = me.children.splice(me.children.length - 5, 5) + var sibling = new BranchChunk(spilled) if (!me.parent) { // Become the parent node - var copy = new BranchChunk(me.children); - copy.parent = me; - me.children = [copy, sibling]; - me = copy; + var copy = new BranchChunk(me.children) + copy.parent = me + me.children = [copy, sibling] + me = copy } else { - me.size -= sibling.size; - me.height -= sibling.height; - var myIndex = indexOf(me.parent.children, me); - me.parent.children.splice(myIndex + 1, 0, sibling); + me.size -= sibling.size + me.height -= sibling.height + var myIndex = indexOf(me.parent.children, me) + me.parent.children.splice(myIndex + 1, 0, sibling) } - sibling.parent = me.parent; - } while (me.children.length > 10); - me.parent.maybeSpill(); + sibling.parent = me.parent + } while (me.children.length > 10) + me.parent.maybeSpill() }, iterN: function(at, n, op) { for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize(); + var child = this.children[i], sz = child.chunkSize() if (at < sz) { - var used = Math.min(n, sz - at); - if (child.iterN(at, used, op)) return true; - if ((n -= used) == 0) break; - at = 0; - } else at -= sz; + var used = Math.min(n, sz - at) + if (child.iterN(at, used, op)) return true + if ((n -= used) == 0) break + at = 0 + } else at -= sz } } -}; +} diff --git a/src/model/document_data.js b/src/model/document_data.js index 62ee034adf..8e423bafd3 100644 --- a/src/model/document_data.js +++ b/src/model/document_data.js @@ -1,11 +1,11 @@ -import { loadMode } from "../display/mode_state"; -import { regChange } from "../display/view_tracking"; -import { Line, updateLine } from "../line/line_data"; -import { findMaxLine } from "../line/spans"; -import { getLine } from "../line/utils_line"; -import { estimateLineHeights } from "../measurement/position_measurement"; -import { lst } from "../util/misc"; -import { signalLater } from "../util/operation_group"; +import { loadMode } from "../display/mode_state" +import { regChange } from "../display/view_tracking" +import { Line, updateLine } from "../line/line_data" +import { findMaxLine } from "../line/spans" +import { getLine } from "../line/utils_line" +import { estimateLineHeights } from "../measurement/position_measurement" +import { lst } from "../util/misc" +import { signalLater } from "../util/operation_group" // DOCUMENT DATA STRUCTURE @@ -14,84 +14,84 @@ import { signalLater } from "../util/operation_group"; // widgets and marker elements with the text behave more intuitive. export function isWholeLineUpdate(doc, change) { return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && - (!doc.cm || doc.cm.options.wholeLineUpdateBefore); + (!doc.cm || doc.cm.options.wholeLineUpdateBefore) } // Perform a change on the document data structure. export function updateDoc(doc, change, markedSpans, estimateHeight) { - function spansFor(n) {return markedSpans ? markedSpans[n] : null;} + function spansFor(n) {return markedSpans ? markedSpans[n] : null} function update(line, text, spans) { - updateLine(line, text, spans, estimateHeight); - signalLater(line, "change", line, change); + updateLine(line, text, spans, estimateHeight) + signalLater(line, "change", line, change) } function linesFor(start, end) { for (var i = start, result = []; i < end; ++i) - result.push(new Line(text[i], spansFor(i), estimateHeight)); - return result; + result.push(new Line(text[i], spansFor(i), estimateHeight)) + return result } - var from = change.from, to = change.to, text = change.text; - var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); - var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; + var from = change.from, to = change.to, text = change.text + var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line) + var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line // Adjust the line structure if (change.full) { - doc.insert(0, linesFor(0, text.length)); - doc.remove(text.length, doc.size - text.length); + doc.insert(0, linesFor(0, text.length)) + doc.remove(text.length, doc.size - text.length) } else if (isWholeLineUpdate(doc, change)) { // This is a whole-line replace. Treated specially to make // sure line objects move the way they are supposed to. - var added = linesFor(0, text.length - 1); - update(lastLine, lastLine.text, lastSpans); - if (nlines) doc.remove(from.line, nlines); - if (added.length) doc.insert(from.line, added); + var added = linesFor(0, text.length - 1) + update(lastLine, lastLine.text, lastSpans) + if (nlines) doc.remove(from.line, nlines) + if (added.length) doc.insert(from.line, added) } else if (firstLine == lastLine) { if (text.length == 1) { - update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); + update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans) } else { - var added = linesFor(1, text.length - 1); - added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); - update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); - doc.insert(from.line + 1, added); + var added = linesFor(1, text.length - 1) + added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)) + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)) + doc.insert(from.line + 1, added) } } else if (text.length == 1) { - update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); - doc.remove(from.line + 1, nlines); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)) + doc.remove(from.line + 1, nlines) } else { - update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); - update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); - var added = linesFor(1, text.length - 1); - if (nlines > 1) doc.remove(from.line + 1, nlines - 1); - doc.insert(from.line + 1, added); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)) + update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans) + var added = linesFor(1, text.length - 1) + if (nlines > 1) doc.remove(from.line + 1, nlines - 1) + doc.insert(from.line + 1, added) } - signalLater(doc, "change", doc, change); + signalLater(doc, "change", doc, change) } // Call f for all linked documents. export function linkedDocs(doc, f, sharedHistOnly) { function propagate(doc, skip, sharedHist) { if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { - var rel = doc.linked[i]; - if (rel.doc == skip) continue; - var shared = sharedHist && rel.sharedHist; - if (sharedHistOnly && !shared) continue; - f(rel.doc, shared); - propagate(rel.doc, doc, shared); + var rel = doc.linked[i] + if (rel.doc == skip) continue + var shared = sharedHist && rel.sharedHist + if (sharedHistOnly && !shared) continue + f(rel.doc, shared) + propagate(rel.doc, doc, shared) } } - propagate(doc, null, true); + propagate(doc, null, true) } // Attach a document to an editor. export function attachDoc(cm, doc) { - if (doc.cm) throw new Error("This document is already in use."); - cm.doc = doc; - doc.cm = cm; - estimateLineHeights(cm); - loadMode(cm); - if (!cm.options.lineWrapping) findMaxLine(cm); - cm.options.mode = doc.modeOption; - regChange(cm); + if (doc.cm) throw new Error("This document is already in use.") + cm.doc = doc + doc.cm = cm + estimateLineHeights(cm) + loadMode(cm) + if (!cm.options.lineWrapping) findMaxLine(cm) + cm.options.mode = doc.modeOption + regChange(cm) } diff --git a/src/model/history.js b/src/model/history.js index 8e34427330..8cc77b1ab0 100644 --- a/src/model/history.js +++ b/src/model/history.js @@ -1,44 +1,44 @@ -import { cmp, copyPos } from "../line/pos"; -import { stretchSpansOverChange } from "../line/spans"; -import { getBetween } from "../line/utils_line"; -import { signal } from "../util/event"; -import { indexOf, lst } from "../util/misc"; +import { cmp, copyPos } from "../line/pos" +import { stretchSpansOverChange } from "../line/spans" +import { getBetween } from "../line/utils_line" +import { signal } from "../util/event" +import { indexOf, lst } from "../util/misc" -import { changeEnd } from "./change_measurement"; -import { linkedDocs } from "./document_data"; -import { Selection } from "./selection"; +import { changeEnd } from "./change_measurement" +import { linkedDocs } from "./document_data" +import { Selection } from "./selection" export function History(startGen) { // Arrays of change events and selections. Doing something adds an // event to done and clears undo. Undoing moves events from done // to undone, redoing moves them in the other direction. - this.done = []; this.undone = []; - this.undoDepth = Infinity; + this.done = []; this.undone = [] + this.undoDepth = Infinity // Used to track when changes can be merged into a single undo // event - this.lastModTime = this.lastSelTime = 0; - this.lastOp = this.lastSelOp = null; - this.lastOrigin = this.lastSelOrigin = null; + this.lastModTime = this.lastSelTime = 0 + this.lastOp = this.lastSelOp = null + this.lastOrigin = this.lastSelOrigin = null // Used by the isClean() method - this.generation = this.maxGeneration = startGen || 1; + this.generation = this.maxGeneration = startGen || 1 } // Create a history change event from an updateDoc-style change // object. export function historyChangeFromChange(doc, change) { - var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; - attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); - linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true); - return histChange; + var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)} + attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1) + linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1)}, true) + return histChange } // Pop all selection events off the end of a history array. Stop at // a change event. function clearSelectionEvents(array) { while (array.length) { - var last = lst(array); - if (last.ranges) array.pop(); - else break; + var last = lst(array) + if (last.ranges) array.pop() + else break } } @@ -46,13 +46,13 @@ function clearSelectionEvents(array) { // events that are in the way. function lastChangeEvent(hist, force) { if (force) { - clearSelectionEvents(hist.done); - return lst(hist.done); + clearSelectionEvents(hist.done) + return lst(hist.done) } else if (hist.done.length && !lst(hist.done).ranges) { - return lst(hist.done); + return lst(hist.done) } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { - hist.done.pop(); - return lst(hist.done); + hist.done.pop() + return lst(hist.done) } } @@ -60,9 +60,9 @@ function lastChangeEvent(hist, force) { // a single operation, or are close together with an origin that // allows merging (starting with "+") into a single event. export function addChangeToHistory(doc, change, selAfter, opId) { - var hist = doc.history; - hist.undone.length = 0; - var time = +new Date, cur; + var hist = doc.history + hist.undone.length = 0 + var time = +new Date, cur if ((hist.lastOp == opId || hist.lastOrigin == change.origin && change.origin && @@ -70,44 +70,44 @@ export function addChangeToHistory(doc, change, selAfter, opId) { change.origin.charAt(0) == "*")) && (cur = lastChangeEvent(hist, hist.lastOp == opId))) { // Merge this change into the last event - var last = lst(cur.changes); + var last = lst(cur.changes) if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { // Optimized case for simple insertion -- don't want to add // new changesets for every character typed - last.to = changeEnd(change); + last.to = changeEnd(change) } else { // Add new sub-event - cur.changes.push(historyChangeFromChange(doc, change)); + cur.changes.push(historyChangeFromChange(doc, change)) } } else { // Can not be merged, start a new event. - var before = lst(hist.done); + var before = lst(hist.done) if (!before || !before.ranges) - pushSelectionToHistory(doc.sel, hist.done); + pushSelectionToHistory(doc.sel, hist.done) cur = {changes: [historyChangeFromChange(doc, change)], - generation: hist.generation}; - hist.done.push(cur); + generation: hist.generation} + hist.done.push(cur) while (hist.done.length > hist.undoDepth) { - hist.done.shift(); - if (!hist.done[0].ranges) hist.done.shift(); + hist.done.shift() + if (!hist.done[0].ranges) hist.done.shift() } } - hist.done.push(selAfter); - hist.generation = ++hist.maxGeneration; - hist.lastModTime = hist.lastSelTime = time; - hist.lastOp = hist.lastSelOp = opId; - hist.lastOrigin = hist.lastSelOrigin = change.origin; + hist.done.push(selAfter) + hist.generation = ++hist.maxGeneration + hist.lastModTime = hist.lastSelTime = time + hist.lastOp = hist.lastSelOp = opId + hist.lastOrigin = hist.lastSelOrigin = change.origin - if (!last) signal(doc, "historyAdded"); + if (!last) signal(doc, "historyAdded") } function selectionEventCanBeMerged(doc, origin, prev, sel) { - var ch = origin.charAt(0); + var ch = origin.charAt(0) return ch == "*" || ch == "+" && prev.ranges.length == sel.ranges.length && prev.somethingSelected() == sel.somethingSelected() && - new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500); + new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500) } // Called whenever the selection changes, sets the new selection as @@ -115,7 +115,7 @@ function selectionEventCanBeMerged(doc, origin, prev, sel) { // selection into the 'done' array when it was significantly // different (in number of selected ranges, emptiness, or time). export function addSelectionToHistory(doc, sel, opId, options) { - var hist = doc.history, origin = options && options.origin; + var hist = doc.history, origin = options && options.origin // A new event is started when the previous origin does not match // the current, or the origins don't allow matching. Origins @@ -125,51 +125,51 @@ export function addSelectionToHistory(doc, sel, opId, options) { (origin && hist.lastSelOrigin == origin && (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) - hist.done[hist.done.length - 1] = sel; + hist.done[hist.done.length - 1] = sel else - pushSelectionToHistory(sel, hist.done); + pushSelectionToHistory(sel, hist.done) - hist.lastSelTime = +new Date; - hist.lastSelOrigin = origin; - hist.lastSelOp = opId; + hist.lastSelTime = +new Date + hist.lastSelOrigin = origin + hist.lastSelOp = opId if (options && options.clearRedo !== false) - clearSelectionEvents(hist.undone); + clearSelectionEvents(hist.undone) } export function pushSelectionToHistory(sel, dest) { - var top = lst(dest); + var top = lst(dest) if (!(top && top.ranges && top.equals(sel))) - dest.push(sel); + dest.push(sel) } // Used to store marked span information in the history. function attachLocalSpans(doc, change, from, to) { - var existing = change["spans_" + doc.id], n = 0; + var existing = change["spans_" + doc.id], n = 0 doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) { if (line.markedSpans) - (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; - ++n; - }); + (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans + ++n + }) } // When un/re-doing restores text containing marked spans, those // that have been explicitly cleared should not be restored. function removeClearedSpans(spans) { - if (!spans) return null; + if (!spans) return null for (var i = 0, out; i < spans.length; ++i) { - if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); } - else if (out) out.push(spans[i]); + if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i) } + else if (out) out.push(spans[i]) } - return !out ? spans : out.length ? out : null; + return !out ? spans : out.length ? out : null } // Retrieve and filter the old marked spans stored in a change event. function getOldSpans(doc, change) { - var found = change["spans_" + doc.id]; - if (!found) return null; + var found = change["spans_" + doc.id] + if (!found) return null for (var i = 0, nw = []; i < change.text.length; ++i) - nw.push(removeClearedSpans(found[i])); - return nw; + nw.push(removeClearedSpans(found[i])) + return nw } // Used for un/re-doing changes from the history. Combines the @@ -177,48 +177,48 @@ function getOldSpans(doc, change) { // existed in the history (so that deleting around a span and then // undoing brings back the span). export function mergeOldSpans(doc, change) { - var old = getOldSpans(doc, change); - var stretched = stretchSpansOverChange(doc, change); - if (!old) return stretched; - if (!stretched) return old; + var old = getOldSpans(doc, change) + var stretched = stretchSpansOverChange(doc, change) + if (!old) return stretched + if (!stretched) return old for (var i = 0; i < old.length; ++i) { - var oldCur = old[i], stretchCur = stretched[i]; + var oldCur = old[i], stretchCur = stretched[i] if (oldCur && stretchCur) { spans: for (var j = 0; j < stretchCur.length; ++j) { - var span = stretchCur[j]; + var span = stretchCur[j] for (var k = 0; k < oldCur.length; ++k) - if (oldCur[k].marker == span.marker) continue spans; - oldCur.push(span); + if (oldCur[k].marker == span.marker) continue spans + oldCur.push(span) } } else if (stretchCur) { - old[i] = stretchCur; + old[i] = stretchCur } } - return old; + return old } // Used both to provide a JSON-safe object in .getHistory, and, when // detaching a document, to split the history in two export function copyHistoryArray(events, newGroup, instantiateSel) { for (var i = 0, copy = []; i < events.length; ++i) { - var event = events[i]; + var event = events[i] if (event.ranges) { - copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); - continue; + copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event) + continue } - var changes = event.changes, newChanges = []; - copy.push({changes: newChanges}); + var changes = event.changes, newChanges = [] + copy.push({changes: newChanges}) for (var j = 0; j < changes.length; ++j) { - var change = changes[j], m; - newChanges.push({from: change.from, to: change.to, text: change.text}); + var change = changes[j], m + newChanges.push({from: change.from, to: change.to, text: change.text}) if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { if (indexOf(newGroup, Number(m[1])) > -1) { - lst(newChanges)[prop] = change[prop]; - delete change[prop]; + lst(newChanges)[prop] = change[prop] + delete change[prop] } } } } - return copy; + return copy } diff --git a/src/model/line_widget.js b/src/model/line_widget.js index 241327ce77..b3b422aafb 100644 --- a/src/model/line_widget.js +++ b/src/model/line_widget.js @@ -1,67 +1,67 @@ -import { runInOp } from "../display/operations"; -import { addToScrollPos } from "../display/scrolling"; -import { regLineChange } from "../display/view_tracking"; -import { heightAtLine, lineIsHidden } from "../line/spans"; -import { lineNo, updateLineHeight } from "../line/utils_line"; -import { widgetHeight } from "../measurement/widgets"; -import { changeLine } from "./changes"; -import { eventMixin } from "../util/event"; +import { runInOp } from "../display/operations" +import { addToScrollPos } from "../display/scrolling" +import { regLineChange } from "../display/view_tracking" +import { heightAtLine, lineIsHidden } from "../line/spans" +import { lineNo, updateLineHeight } from "../line/utils_line" +import { widgetHeight } from "../measurement/widgets" +import { changeLine } from "./changes" +import { eventMixin } from "../util/event" // Line widgets are block elements displayed above or below a line. export function LineWidget(doc, node, options) { if (options) for (var opt in options) if (options.hasOwnProperty(opt)) - this[opt] = options[opt]; - this.doc = doc; - this.node = node; + this[opt] = options[opt] + this.doc = doc + this.node = node } -eventMixin(LineWidget); +eventMixin(LineWidget) function adjustScrollWhenAboveVisible(cm, line, diff) { if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) - addToScrollPos(cm, null, diff); + addToScrollPos(cm, null, diff) } LineWidget.prototype.clear = function() { - var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); - if (no == null || !ws) return; - for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); - if (!ws.length) line.widgets = null; - var height = widgetHeight(this); - updateLineHeight(line, Math.max(0, line.height - height)); + var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line) + if (no == null || !ws) return + for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1) + if (!ws.length) line.widgets = null + var height = widgetHeight(this) + updateLineHeight(line, Math.max(0, line.height - height)) if (cm) runInOp(cm, function() { - adjustScrollWhenAboveVisible(cm, line, -height); - regLineChange(cm, no, "widget"); - }); -}; + adjustScrollWhenAboveVisible(cm, line, -height) + regLineChange(cm, no, "widget") + }) +} LineWidget.prototype.changed = function() { - var oldH = this.height, cm = this.doc.cm, line = this.line; - this.height = null; - var diff = widgetHeight(this) - oldH; - if (!diff) return; - updateLineHeight(line, line.height + diff); + var oldH = this.height, cm = this.doc.cm, line = this.line + this.height = null + var diff = widgetHeight(this) - oldH + if (!diff) return + updateLineHeight(line, line.height + diff) if (cm) runInOp(cm, function() { - cm.curOp.forceUpdate = true; - adjustScrollWhenAboveVisible(cm, line, diff); - }); -}; + cm.curOp.forceUpdate = true + adjustScrollWhenAboveVisible(cm, line, diff) + }) +} export function addLineWidget(doc, handle, node, options) { - var widget = new LineWidget(doc, node, options); - var cm = doc.cm; - if (cm && widget.noHScroll) cm.display.alignWidgets = true; + var widget = new LineWidget(doc, node, options) + var cm = doc.cm + if (cm && widget.noHScroll) cm.display.alignWidgets = true changeLine(doc, handle, "widget", function(line) { - var widgets = line.widgets || (line.widgets = []); - if (widget.insertAt == null) widgets.push(widget); - else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); - widget.line = line; + var widgets = line.widgets || (line.widgets = []) + if (widget.insertAt == null) widgets.push(widget) + else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget) + widget.line = line if (cm && !lineIsHidden(doc, line)) { - var aboveVisible = heightAtLine(line) < doc.scrollTop; - updateLineHeight(line, line.height + widgetHeight(widget)); - if (aboveVisible) addToScrollPos(cm, null, widget.height); - cm.curOp.forceUpdate = true; + var aboveVisible = heightAtLine(line) < doc.scrollTop + updateLineHeight(line, line.height + widgetHeight(widget)) + if (aboveVisible) addToScrollPos(cm, null, widget.height) + cm.curOp.forceUpdate = true } - return true; - }); - return widget; + return true + }) + return widget } diff --git a/src/model/mark_text.js b/src/model/mark_text.js index 7a334e5352..c103a57481 100644 --- a/src/model/mark_text.js +++ b/src/model/mark_text.js @@ -1,19 +1,19 @@ -import { elt } from "../util/dom"; -import { eventMixin, hasHandler, on } from "../util/event"; -import { endOperation, operation, runInOp, startOperation } from "../display/operations"; -import { clipPos, cmp, Pos } from "../line/pos"; -import { lineNo, updateLineHeight } from "../line/utils_line"; -import { clearLineMeasurementCacheFor, findViewForLine, textHeight } from "../measurement/position_measurement"; -import { seeReadOnlySpans, seeCollapsedSpans } from "../line/saw_special_spans"; -import { addMarkedSpan, conflictingCollapsedRange, getMarkedSpanFor, lineIsHidden, lineLength, MarkedSpan, removeMarkedSpan, visualLine } from "../line/spans"; -import { copyObj, indexOf, lst } from "../util/misc"; -import { signalLater } from "../util/operation_group"; -import { widgetHeight } from "../measurement/widgets"; -import { regChange, regLineChange } from "../display/view_tracking"; +import { elt } from "../util/dom" +import { eventMixin, hasHandler, on } from "../util/event" +import { endOperation, operation, runInOp, startOperation } from "../display/operations" +import { clipPos, cmp, Pos } from "../line/pos" +import { lineNo, updateLineHeight } from "../line/utils_line" +import { clearLineMeasurementCacheFor, findViewForLine, textHeight } from "../measurement/position_measurement" +import { seeReadOnlySpans, seeCollapsedSpans } from "../line/saw_special_spans" +import { addMarkedSpan, conflictingCollapsedRange, getMarkedSpanFor, lineIsHidden, lineLength, MarkedSpan, removeMarkedSpan, visualLine } from "../line/spans" +import { copyObj, indexOf, lst } from "../util/misc" +import { signalLater } from "../util/operation_group" +import { widgetHeight } from "../measurement/widgets" +import { regChange, regLineChange } from "../display/view_tracking" -import { linkedDocs } from "./document_data"; -import { addChangeToHistory } from "./history"; -import { reCheckSelection } from "./selection_updates"; +import { linkedDocs } from "./document_data" +import { addChangeToHistory } from "./history" +import { reCheckSelection } from "./selection_updates" // TEXTMARKERS @@ -27,58 +27,58 @@ import { reCheckSelection } from "./selection_updates"; // marker continues beyond the start/end of the line. Markers have // links back to the lines they currently touch. -var nextMarkerId = 0; +var nextMarkerId = 0 export function TextMarker(doc, type) { - this.lines = []; - this.type = type; - this.doc = doc; - this.id = ++nextMarkerId; + this.lines = [] + this.type = type + this.doc = doc + this.id = ++nextMarkerId } -eventMixin(TextMarker); +eventMixin(TextMarker) // Clear the marker. TextMarker.prototype.clear = function() { - if (this.explicitlyCleared) return; - var cm = this.doc.cm, withOp = cm && !cm.curOp; - if (withOp) startOperation(cm); + if (this.explicitlyCleared) return + var cm = this.doc.cm, withOp = cm && !cm.curOp + if (withOp) startOperation(cm) if (hasHandler(this, "clear")) { - var found = this.find(); - if (found) signalLater(this, "clear", found.from, found.to); + var found = this.find() + if (found) signalLater(this, "clear", found.from, found.to) } - var min = null, max = null; + var min = null, max = null for (var i = 0; i < this.lines.length; ++i) { - var line = this.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this); - if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text"); + var line = this.lines[i] + var span = getMarkedSpanFor(line.markedSpans, this) + if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text") else if (cm) { - if (span.to != null) max = lineNo(line); - if (span.from != null) min = lineNo(line); + if (span.to != null) max = lineNo(line) + if (span.from != null) min = lineNo(line) } - line.markedSpans = removeMarkedSpan(line.markedSpans, span); + line.markedSpans = removeMarkedSpan(line.markedSpans, span) if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) - updateLineHeight(line, textHeight(cm.display)); + updateLineHeight(line, textHeight(cm.display)) } if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { - var visual = visualLine(this.lines[i]), len = lineLength(visual); + var visual = visualLine(this.lines[i]), len = lineLength(visual) if (len > cm.display.maxLineLength) { - cm.display.maxLine = visual; - cm.display.maxLineLength = len; - cm.display.maxLineChanged = true; + cm.display.maxLine = visual + cm.display.maxLineLength = len + cm.display.maxLineChanged = true } } - if (min != null && cm && this.collapsed) regChange(cm, min, max + 1); - this.lines.length = 0; - this.explicitlyCleared = true; + if (min != null && cm && this.collapsed) regChange(cm, min, max + 1) + this.lines.length = 0 + this.explicitlyCleared = true if (this.atomic && this.doc.cantEdit) { - this.doc.cantEdit = false; - if (cm) reCheckSelection(cm.doc); + this.doc.cantEdit = false + if (cm) reCheckSelection(cm.doc) } - if (cm) signalLater(cm, "markerCleared", cm, this); - if (withOp) endOperation(cm); - if (this.parent) this.parent.clear(); -}; + if (cm) signalLater(cm, "markerCleared", cm, this) + if (withOp) endOperation(cm) + if (this.parent) this.parent.clear() +} // Find the position of the marker in the document. Returns a {from, // to} object by default. Side can be passed to get a specific side @@ -86,135 +86,135 @@ TextMarker.prototype.clear = function() { // Pos objects returned contain a line object, rather than a line // number (used to prevent looking up the same line twice). TextMarker.prototype.find = function(side, lineObj) { - if (side == null && this.type == "bookmark") side = 1; - var from, to; + if (side == null && this.type == "bookmark") side = 1 + var from, to for (var i = 0; i < this.lines.length; ++i) { - var line = this.lines[i]; - var span = getMarkedSpanFor(line.markedSpans, this); + var line = this.lines[i] + var span = getMarkedSpanFor(line.markedSpans, this) if (span.from != null) { - from = Pos(lineObj ? line : lineNo(line), span.from); - if (side == -1) return from; + from = Pos(lineObj ? line : lineNo(line), span.from) + if (side == -1) return from } if (span.to != null) { - to = Pos(lineObj ? line : lineNo(line), span.to); - if (side == 1) return to; + to = Pos(lineObj ? line : lineNo(line), span.to) + if (side == 1) return to } } - return from && {from: from, to: to}; -}; + return from && {from: from, to: to} +} // Signals that the marker's widget changed, and surrounding layout // should be recomputed. TextMarker.prototype.changed = function() { - var pos = this.find(-1, true), widget = this, cm = this.doc.cm; - if (!pos || !cm) return; + var pos = this.find(-1, true), widget = this, cm = this.doc.cm + if (!pos || !cm) return runInOp(cm, function() { - var line = pos.line, lineN = lineNo(pos.line); - var view = findViewForLine(cm, lineN); + var line = pos.line, lineN = lineNo(pos.line) + var view = findViewForLine(cm, lineN) if (view) { - clearLineMeasurementCacheFor(view); - cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; + clearLineMeasurementCacheFor(view) + cm.curOp.selectionChanged = cm.curOp.forceUpdate = true } - cm.curOp.updateMaxLine = true; + cm.curOp.updateMaxLine = true if (!lineIsHidden(widget.doc, line) && widget.height != null) { - var oldHeight = widget.height; - widget.height = null; - var dHeight = widgetHeight(widget) - oldHeight; + var oldHeight = widget.height + widget.height = null + var dHeight = widgetHeight(widget) - oldHeight if (dHeight) - updateLineHeight(line, line.height + dHeight); + updateLineHeight(line, line.height + dHeight) } - }); -}; + }) +} TextMarker.prototype.attachLine = function(line) { if (!this.lines.length && this.doc.cm) { - var op = this.doc.cm.curOp; + var op = this.doc.cm.curOp if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) - (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); + (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this) } - this.lines.push(line); -}; + this.lines.push(line) +} TextMarker.prototype.detachLine = function(line) { - this.lines.splice(indexOf(this.lines, line), 1); + this.lines.splice(indexOf(this.lines, line), 1) if (!this.lines.length && this.doc.cm) { - var op = this.doc.cm.curOp; - (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); + var op = this.doc.cm.curOp + ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this) } -}; +} // Collapsed markers have unique ids, in order to be able to order // them, which is needed for uniquely determining an outer marker // when they overlap (they may nest, but not partially overlap). -var nextMarkerId = 0; +var nextMarkerId = 0 // Create a marker, wire it up to the right lines, and export function markText(doc, from, to, options, type) { // Shared markers (across linked documents) are handled separately // (markTextShared will call out to this again, once per // document). - if (options && options.shared) return markTextShared(doc, from, to, options, type); + if (options && options.shared) return markTextShared(doc, from, to, options, type) // Ensure we are in an operation. - if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); + if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type) - var marker = new TextMarker(doc, type), diff = cmp(from, to); - if (options) copyObj(options, marker, false); + var marker = new TextMarker(doc, type), diff = cmp(from, to) + if (options) copyObj(options, marker, false) // Don't connect empty markers unless clearWhenEmpty is false if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) - return marker; + return marker if (marker.replacedWith) { // Showing up as a widget implies collapsed (widget replaces text) - marker.collapsed = true; - marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget"); - if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true"); - if (options.insertLeft) marker.widgetNode.insertLeft = true; + marker.collapsed = true + marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget") + if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true") + if (options.insertLeft) marker.widgetNode.insertLeft = true } if (marker.collapsed) { if (conflictingCollapsedRange(doc, from.line, from, to, marker) || from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) - throw new Error("Inserting collapsed marker partially overlapping an existing one"); - seeCollapsedSpans(); + throw new Error("Inserting collapsed marker partially overlapping an existing one") + seeCollapsedSpans() } if (marker.addToHistory) - addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); + addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN) - var curLine = from.line, cm = doc.cm, updateMaxLine; + var curLine = from.line, cm = doc.cm, updateMaxLine doc.iter(curLine, to.line + 1, function(line) { if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) - updateMaxLine = true; - if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0); + updateMaxLine = true + if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0) addMarkedSpan(line, new MarkedSpan(marker, curLine == from.line ? from.ch : null, - curLine == to.line ? to.ch : null)); - ++curLine; - }); + curLine == to.line ? to.ch : null)) + ++curLine + }) // lineIsHidden depends on the presence of the spans, so needs a second pass if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) { - if (lineIsHidden(doc, line)) updateLineHeight(line, 0); - }); + if (lineIsHidden(doc, line)) updateLineHeight(line, 0) + }) - if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); }); + if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear() }) if (marker.readOnly) { - seeReadOnlySpans(); + seeReadOnlySpans() if (doc.history.done.length || doc.history.undone.length) - doc.clearHistory(); + doc.clearHistory() } if (marker.collapsed) { - marker.id = ++nextMarkerId; - marker.atomic = true; + marker.id = ++nextMarkerId + marker.atomic = true } if (cm) { // Sync editor state - if (updateMaxLine) cm.curOp.updateMaxLine = true; + if (updateMaxLine) cm.curOp.updateMaxLine = true if (marker.collapsed) - regChange(cm, from.line, to.line + 1); + regChange(cm, from.line, to.line + 1) else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) - for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text"); - if (marker.atomic) reCheckSelection(cm.doc); - signalLater(cm, "markerAdded", cm, marker); + for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text") + if (marker.atomic) reCheckSelection(cm.doc) + signalLater(cm, "markerAdded", cm, marker) } - return marker; + return marker } // SHARED TEXTMARKERS @@ -223,65 +223,65 @@ export function markText(doc, from, to, options, type) { // implemented as a meta-marker-object controlling multiple normal // markers. export function SharedTextMarker(markers, primary) { - this.markers = markers; - this.primary = primary; + this.markers = markers + this.primary = primary for (var i = 0; i < markers.length; ++i) - markers[i].parent = this; + markers[i].parent = this } -eventMixin(SharedTextMarker); +eventMixin(SharedTextMarker) SharedTextMarker.prototype.clear = function() { - if (this.explicitlyCleared) return; - this.explicitlyCleared = true; + if (this.explicitlyCleared) return + this.explicitlyCleared = true for (var i = 0; i < this.markers.length; ++i) - this.markers[i].clear(); - signalLater(this, "clear"); -}; + this.markers[i].clear() + signalLater(this, "clear") +} SharedTextMarker.prototype.find = function(side, lineObj) { - return this.primary.find(side, lineObj); -}; + return this.primary.find(side, lineObj) +} function markTextShared(doc, from, to, options, type) { - options = copyObj(options); - options.shared = false; - var markers = [markText(doc, from, to, options, type)], primary = markers[0]; - var widget = options.widgetNode; + options = copyObj(options) + options.shared = false + var markers = [markText(doc, from, to, options, type)], primary = markers[0] + var widget = options.widgetNode linkedDocs(doc, function(doc) { - if (widget) options.widgetNode = widget.cloneNode(true); - markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); + if (widget) options.widgetNode = widget.cloneNode(true) + markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)) for (var i = 0; i < doc.linked.length; ++i) - if (doc.linked[i].isParent) return; - primary = lst(markers); - }); - return new SharedTextMarker(markers, primary); + if (doc.linked[i].isParent) return + primary = lst(markers) + }) + return new SharedTextMarker(markers, primary) } export function findSharedMarkers(doc) { return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), - function(m) { return m.parent; }); + function(m) { return m.parent }) } export function copySharedMarkers(doc, markers) { for (var i = 0; i < markers.length; i++) { - var marker = markers[i], pos = marker.find(); - var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); + var marker = markers[i], pos = marker.find() + var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to) if (cmp(mFrom, mTo)) { - var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); - marker.markers.push(subMark); - subMark.parent = marker; + var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type) + marker.markers.push(subMark) + subMark.parent = marker } } } export function detachSharedMarkers(markers) { for (var i = 0; i < markers.length; i++) { - var marker = markers[i], linked = [marker.primary.doc]; - linkedDocs(marker.primary.doc, function(d) { linked.push(d); }); + var marker = markers[i], linked = [marker.primary.doc] + linkedDocs(marker.primary.doc, function(d) { linked.push(d) }) for (var j = 0; j < marker.markers.length; j++) { - var subMarker = marker.markers[j]; + var subMarker = marker.markers[j] if (indexOf(linked, subMarker.doc) == -1) { - subMarker.parent = null; - marker.markers.splice(j--, 1); + subMarker.parent = null + marker.markers.splice(j--, 1) } } } diff --git a/src/model/selection.js b/src/model/selection.js index ce3c228c8b..c75fcd6186 100644 --- a/src/model/selection.js +++ b/src/model/selection.js @@ -1,5 +1,5 @@ -import { cmp, copyPos, maxPos, minPos } from "../line/pos"; -import { indexOf } from "../util/misc"; +import { cmp, copyPos, maxPos, minPos } from "../line/pos" +import { indexOf } from "../util/misc" // Selection objects are immutable. A new one is created every time // the selection changes. A selection is one or more non-overlapping @@ -7,73 +7,73 @@ import { indexOf } from "../util/misc"; // which one is the primary selection (the one that's scrolled into // view, that getCursor returns, etc). export function Selection(ranges, primIndex) { - this.ranges = ranges; - this.primIndex = primIndex; + this.ranges = ranges + this.primIndex = primIndex } Selection.prototype = { - primary: function() { return this.ranges[this.primIndex]; }, + primary: function() { return this.ranges[this.primIndex] }, equals: function(other) { - if (other == this) return true; - if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false; + if (other == this) return true + if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false for (var i = 0; i < this.ranges.length; i++) { - var here = this.ranges[i], there = other.ranges[i]; - if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false; + var here = this.ranges[i], there = other.ranges[i] + if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false } - return true; + return true }, deepCopy: function() { for (var out = [], i = 0; i < this.ranges.length; i++) - out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); - return new Selection(out, this.primIndex); + out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)) + return new Selection(out, this.primIndex) }, somethingSelected: function() { for (var i = 0; i < this.ranges.length; i++) - if (!this.ranges[i].empty()) return true; - return false; + if (!this.ranges[i].empty()) return true + return false }, contains: function(pos, end) { - if (!end) end = pos; + if (!end) end = pos for (var i = 0; i < this.ranges.length; i++) { - var range = this.ranges[i]; + var range = this.ranges[i] if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) - return i; + return i } - return -1; + return -1 } -}; +} export function Range(anchor, head) { - this.anchor = anchor; this.head = head; + this.anchor = anchor; this.head = head } Range.prototype = { - from: function() { return minPos(this.anchor, this.head); }, - to: function() { return maxPos(this.anchor, this.head); }, + from: function() { return minPos(this.anchor, this.head) }, + to: function() { return maxPos(this.anchor, this.head) }, empty: function() { - return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch; + return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch } -}; +} // Take an unsorted, potentially overlapping set of ranges, and // build a selection out of it. 'Consumes' ranges array (modifying // it). export function normalizeSelection(ranges, primIndex) { - var prim = ranges[primIndex]; - ranges.sort(function(a, b) { return cmp(a.from(), b.from()); }); - primIndex = indexOf(ranges, prim); + var prim = ranges[primIndex] + ranges.sort(function(a, b) { return cmp(a.from(), b.from()) }) + primIndex = indexOf(ranges, prim) for (var i = 1; i < ranges.length; i++) { - var cur = ranges[i], prev = ranges[i - 1]; + var cur = ranges[i], prev = ranges[i - 1] if (cmp(prev.to(), cur.from()) >= 0) { - var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); - var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; - if (i <= primIndex) --primIndex; - ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); + var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()) + var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head + if (i <= primIndex) --primIndex + ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)) } } - return new Selection(ranges, primIndex); + return new Selection(ranges, primIndex) } export function simpleSelection(anchor, head) { - return new Selection([new Range(anchor, head || anchor)], 0); + return new Selection([new Range(anchor, head || anchor)], 0) } diff --git a/src/model/selection_updates.js b/src/model/selection_updates.js index e105afa9e0..640af1f249 100644 --- a/src/model/selection_updates.js +++ b/src/model/selection_updates.js @@ -1,12 +1,12 @@ -import { signalLater } from "../util/operation_group"; -import { ensureCursorVisible } from "../display/scrolling"; -import { clipPos, cmp, Pos } from "../line/pos"; -import { getLine } from "../line/utils_line"; -import { hasHandler, signal, signalCursorActivity } from "../util/event"; -import { lst, sel_dontScroll } from "../util/misc"; +import { signalLater } from "../util/operation_group" +import { ensureCursorVisible } from "../display/scrolling" +import { clipPos, cmp, Pos } from "../line/pos" +import { getLine } from "../line/utils_line" +import { hasHandler, signal, signalCursorActivity } from "../util/event" +import { lst, sel_dontScroll } from "../util/misc" -import { addSelectionToHistory } from "./history"; -import { normalizeSelection, Range, Selection, simpleSelection } from "./selection"; +import { addSelectionToHistory } from "./history" +import { normalizeSelection, Range, Selection, simpleSelection } from "./selection" // The 'scroll' parameter given to many of these indicated whether // the new cursor position should be scrolled into view after @@ -18,46 +18,46 @@ import { normalizeSelection, Range, Selection, simpleSelection } from "./selecti // Used for cursor motion and such. export function extendRange(doc, range, head, other) { if (doc.cm && doc.cm.display.shift || doc.extend) { - var anchor = range.anchor; + var anchor = range.anchor if (other) { - var posBefore = cmp(head, anchor) < 0; + var posBefore = cmp(head, anchor) < 0 if (posBefore != (cmp(other, anchor) < 0)) { - anchor = head; - head = other; + anchor = head + head = other } else if (posBefore != (cmp(head, other) < 0)) { - head = other; + head = other } } - return new Range(anchor, head); + return new Range(anchor, head) } else { - return new Range(other || head, head); + return new Range(other || head, head) } } // Extend the primary selection range, discard the rest. export function extendSelection(doc, head, other, options) { - setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options); + setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options) } // Extend all selections (pos is an array of selections with length // equal the number of selections) export function extendSelections(doc, heads, options) { for (var out = [], i = 0; i < doc.sel.ranges.length; i++) - out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null); - var newSel = normalizeSelection(out, doc.sel.primIndex); - setSelection(doc, newSel, options); + out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null) + var newSel = normalizeSelection(out, doc.sel.primIndex) + setSelection(doc, newSel, options) } // Updates a single range in the selection. export function replaceOneSelection(doc, i, range, options) { - var ranges = doc.sel.ranges.slice(0); - ranges[i] = range; - setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options); + var ranges = doc.sel.ranges.slice(0) + ranges[i] = range + setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options) } // Reset the selection to a single range. export function setSimpleSelection(doc, anchor, head, options) { - setSelection(doc, simpleSelection(anchor, head), options); + setSelection(doc, simpleSelection(anchor, head), options) } // Give beforeSelectionChange handlers a change to influence a @@ -66,140 +66,140 @@ function filterSelectionChange(doc, sel, options) { var obj = { ranges: sel.ranges, update: function(ranges) { - this.ranges = []; + this.ranges = [] for (var i = 0; i < ranges.length; i++) this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), - clipPos(doc, ranges[i].head)); + clipPos(doc, ranges[i].head)) }, origin: options && options.origin - }; - signal(doc, "beforeSelectionChange", doc, obj); - if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); - if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1); - else return sel; + } + signal(doc, "beforeSelectionChange", doc, obj) + if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj) + if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1) + else return sel } export function setSelectionReplaceHistory(doc, sel, options) { - var done = doc.history.done, last = lst(done); + var done = doc.history.done, last = lst(done) if (last && last.ranges) { - done[done.length - 1] = sel; - setSelectionNoUndo(doc, sel, options); + done[done.length - 1] = sel + setSelectionNoUndo(doc, sel, options) } else { - setSelection(doc, sel, options); + setSelection(doc, sel, options) } } // Set a new selection. export function setSelection(doc, sel, options) { - setSelectionNoUndo(doc, sel, options); - addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); + setSelectionNoUndo(doc, sel, options) + addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options) } export function setSelectionNoUndo(doc, sel, options) { if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) - sel = filterSelectionChange(doc, sel, options); + sel = filterSelectionChange(doc, sel, options) var bias = options && options.bias || - (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); - setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); + (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1) + setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)) if (!(options && options.scroll === false) && doc.cm) - ensureCursorVisible(doc.cm); + ensureCursorVisible(doc.cm) } function setSelectionInner(doc, sel) { - if (sel.equals(doc.sel)) return; + if (sel.equals(doc.sel)) return - doc.sel = sel; + doc.sel = sel if (doc.cm) { - doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; - signalCursorActivity(doc.cm); + doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true + signalCursorActivity(doc.cm) } - signalLater(doc, "cursorActivity", doc); + signalLater(doc, "cursorActivity", doc) } // Verify that the selection does not partially select any atomic // marked ranges. export function reCheckSelection(doc) { - setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll); + setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll) } // Return a selection that does not partially select any atomic // ranges. function skipAtomicInSelection(doc, sel, bias, mayClear) { - var out; + var out for (var i = 0; i < sel.ranges.length; i++) { - var range = sel.ranges[i]; - var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i]; - var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear); - var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear); + var range = sel.ranges[i] + var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i] + var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear) + var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear) if (out || newAnchor != range.anchor || newHead != range.head) { - if (!out) out = sel.ranges.slice(0, i); - out[i] = new Range(newAnchor, newHead); + if (!out) out = sel.ranges.slice(0, i) + out[i] = new Range(newAnchor, newHead) } } - return out ? normalizeSelection(out, sel.primIndex) : sel; + return out ? normalizeSelection(out, sel.primIndex) : sel } function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { - var line = getLine(doc, pos.line); + var line = getLine(doc, pos.line) if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { - var sp = line.markedSpans[i], m = sp.marker; + var sp = line.markedSpans[i], m = sp.marker if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) { if (mayClear) { - signal(m, "beforeCursorEnter"); + signal(m, "beforeCursorEnter") if (m.explicitlyCleared) { - if (!line.markedSpans) break; - else {--i; continue;} + if (!line.markedSpans) break + else {--i; continue} } } - if (!m.atomic) continue; + if (!m.atomic) continue if (oldPos) { - var near = m.find(dir < 0 ? 1 : -1), diff; + var near = m.find(dir < 0 ? 1 : -1), diff if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) - near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); + near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null) if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) - return skipAtomicInner(doc, near, pos, dir, mayClear); + return skipAtomicInner(doc, near, pos, dir, mayClear) } - var far = m.find(dir < 0 ? -1 : 1); + var far = m.find(dir < 0 ? -1 : 1) if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) - far = movePos(doc, far, dir, far.line == pos.line ? line : null); - return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null; + far = movePos(doc, far, dir, far.line == pos.line ? line : null) + return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null } } - return pos; + return pos } // Ensure a given position is not inside an atomic range. export function skipAtomic(doc, pos, oldPos, bias, mayClear) { - var dir = bias || 1; + var dir = bias || 1 var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) || skipAtomicInner(doc, pos, oldPos, -dir, mayClear) || - (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)); + (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)) if (!found) { - doc.cantEdit = true; - return Pos(doc.first, 0); + doc.cantEdit = true + return Pos(doc.first, 0) } - return found; + return found } function movePos(doc, pos, dir, line) { if (dir < 0 && pos.ch == 0) { - if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1)); - else return null; + if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1)) + else return null } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) { - if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0); - else return null; + if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0) + else return null } else { - return new Pos(pos.line, pos.ch + dir); + return new Pos(pos.line, pos.ch + dir) } } export function selectAll(cm) { - cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll); + cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll) } diff --git a/src/modes.js b/src/modes.js index ed5e918039..15d16cefcb 100644 --- a/src/modes.js +++ b/src/modes.js @@ -1,95 +1,95 @@ -import { copyObj, createObj } from "./util/misc"; +import { copyObj, createObj } from "./util/misc" // Known modes, by name and by MIME -export var modes = {}, mimeModes = {}; +export var modes = {}, mimeModes = {} // Extra arguments are stored as the mode's dependencies, which is // used by (legacy) mechanisms like loadmode.js to automatically // load a mode. (Preferred mechanism is the require/define calls.) export function defineMode(name, mode) { if (arguments.length > 2) - mode.dependencies = Array.prototype.slice.call(arguments, 2); - modes[name] = mode; + mode.dependencies = Array.prototype.slice.call(arguments, 2) + modes[name] = mode } export function defineMIME(mime, spec) { - mimeModes[mime] = spec; + mimeModes[mime] = spec } // Given a MIME type, a {name, ...options} config object, or a name // string, return a mode config object. export function resolveMode(spec) { if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { - spec = mimeModes[spec]; + spec = mimeModes[spec] } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { - var found = mimeModes[spec.name]; - if (typeof found == "string") found = {name: found}; - spec = createObj(found, spec); - spec.name = found.name; + var found = mimeModes[spec.name] + if (typeof found == "string") found = {name: found} + spec = createObj(found, spec) + spec.name = found.name } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { - return resolveMode("application/xml"); + return resolveMode("application/xml") } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) { - return resolveMode("application/json"); + return resolveMode("application/json") } - if (typeof spec == "string") return {name: spec}; - else return spec || {name: "null"}; + if (typeof spec == "string") return {name: spec} + else return spec || {name: "null"} } // Given a mode spec (anything that resolveMode accepts), find and // initialize an actual mode object. export function getMode(options, spec) { - var spec = resolveMode(spec); - var mfactory = modes[spec.name]; - if (!mfactory) return getMode(options, "text/plain"); - var modeObj = mfactory(options, spec); + var spec = resolveMode(spec) + var mfactory = modes[spec.name] + if (!mfactory) return getMode(options, "text/plain") + var modeObj = mfactory(options, spec) if (modeExtensions.hasOwnProperty(spec.name)) { - var exts = modeExtensions[spec.name]; + var exts = modeExtensions[spec.name] for (var prop in exts) { - if (!exts.hasOwnProperty(prop)) continue; - if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; - modeObj[prop] = exts[prop]; + if (!exts.hasOwnProperty(prop)) continue + if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop] + modeObj[prop] = exts[prop] } } - modeObj.name = spec.name; - if (spec.helperType) modeObj.helperType = spec.helperType; + modeObj.name = spec.name + if (spec.helperType) modeObj.helperType = spec.helperType if (spec.modeProps) for (var prop in spec.modeProps) - modeObj[prop] = spec.modeProps[prop]; + modeObj[prop] = spec.modeProps[prop] - return modeObj; + return modeObj } // This can be used to attach properties to mode objects from // outside the actual mode definition. -export var modeExtensions = {}; +export var modeExtensions = {} export function extendMode(mode, properties) { - var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); - copyObj(properties, exts); + var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}) + copyObj(properties, exts) } export function copyState(mode, state) { - if (state === true) return state; - if (mode.copyState) return mode.copyState(state); - var nstate = {}; + if (state === true) return state + if (mode.copyState) return mode.copyState(state) + var nstate = {} for (var n in state) { - var val = state[n]; - if (val instanceof Array) val = val.concat([]); - nstate[n] = val; + var val = state[n] + if (val instanceof Array) val = val.concat([]) + nstate[n] = val } - return nstate; + return nstate } // Given a mode and a state (for that mode), find the inner mode and // state at the position that the state refers to. export function innerMode(mode, state) { while (mode.innerMode) { - var info = mode.innerMode(state); - if (!info || info.mode == mode) break; - state = info.state; - mode = info.mode; + var info = mode.innerMode(state) + if (!info || info.mode == mode) break + state = info.state + mode = info.mode } - return info || {mode: mode, state: state}; + return info || {mode: mode, state: state} } export function startState(mode, a1, a2) { - return mode.startState ? mode.startState(a1, a2) : true; + return mode.startState ? mode.startState(a1, a2) : true } diff --git a/src/util/StringStream.js b/src/util/StringStream.js index f07357befc..d04807426c 100644 --- a/src/util/StringStream.js +++ b/src/util/StringStream.js @@ -1,4 +1,4 @@ -import { countColumn } from "./misc"; +import { countColumn } from "./misc" // STRING STREAM @@ -6,75 +6,75 @@ import { countColumn } from "./misc"; // parsers more succinct. var StringStream = function(string, tabSize) { - this.pos = this.start = 0; - this.string = string; - this.tabSize = tabSize || 8; - this.lastColumnPos = this.lastColumnValue = 0; - this.lineStart = 0; -}; + this.pos = this.start = 0 + this.string = string + this.tabSize = tabSize || 8 + this.lastColumnPos = this.lastColumnValue = 0 + this.lineStart = 0 +} StringStream.prototype = { - eol: function() {return this.pos >= this.string.length;}, - sol: function() {return this.pos == this.lineStart;}, - peek: function() {return this.string.charAt(this.pos) || undefined;}, + eol: function() {return this.pos >= this.string.length}, + sol: function() {return this.pos == this.lineStart}, + peek: function() {return this.string.charAt(this.pos) || undefined}, next: function() { if (this.pos < this.string.length) - return this.string.charAt(this.pos++); + return this.string.charAt(this.pos++) }, eat: function(match) { - var ch = this.string.charAt(this.pos); - if (typeof match == "string") var ok = ch == match; - else var ok = ch && (match.test ? match.test(ch) : match(ch)); - if (ok) {++this.pos; return ch;} + var ch = this.string.charAt(this.pos) + if (typeof match == "string") var ok = ch == match + else var ok = ch && (match.test ? match.test(ch) : match(ch)) + if (ok) {++this.pos; return ch} }, eatWhile: function(match) { - var start = this.pos; + var start = this.pos while (this.eat(match)){} - return this.pos > start; + return this.pos > start }, eatSpace: function() { - var start = this.pos; - while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; - return this.pos > start; + var start = this.pos + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos + return this.pos > start }, - skipToEnd: function() {this.pos = this.string.length;}, + skipToEnd: function() {this.pos = this.string.length}, skipTo: function(ch) { - var found = this.string.indexOf(ch, this.pos); - if (found > -1) {this.pos = found; return true;} + var found = this.string.indexOf(ch, this.pos) + if (found > -1) {this.pos = found; return true} }, - backUp: function(n) {this.pos -= n;}, + backUp: function(n) {this.pos -= n}, column: function() { if (this.lastColumnPos < this.start) { - this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); - this.lastColumnPos = this.start; + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue) + this.lastColumnPos = this.start } - return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) }, indentation: function() { return countColumn(this.string, null, this.tabSize) - - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); + (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) }, match: function(pattern, consume, caseInsensitive) { if (typeof pattern == "string") { - var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; - var substr = this.string.substr(this.pos, pattern.length); + var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str} + var substr = this.string.substr(this.pos, pattern.length) if (cased(substr) == cased(pattern)) { - if (consume !== false) this.pos += pattern.length; - return true; + if (consume !== false) this.pos += pattern.length + return true } } else { - var match = this.string.slice(this.pos).match(pattern); - if (match && match.index > 0) return null; - if (match && consume !== false) this.pos += match[0].length; - return match; + var match = this.string.slice(this.pos).match(pattern) + if (match && match.index > 0) return null + if (match && consume !== false) this.pos += match[0].length + return match } }, - current: function(){return this.string.slice(this.start, this.pos);}, + current: function(){return this.string.slice(this.start, this.pos)}, hideFirstChars: function(n, inner) { - this.lineStart += n; - try { return inner(); } - finally { this.lineStart -= n; } + this.lineStart += n + try { return inner() } + finally { this.lineStart -= n } } -}; +} -export default StringStream; +export default StringStream diff --git a/src/util/bidi.js b/src/util/bidi.js index 776319d022..f12dccf50b 100644 --- a/src/util/bidi.js +++ b/src/util/bidi.js @@ -1,63 +1,63 @@ -import { isExtendingChar, lst } from "./misc"; +import { isExtendingChar, lst } from "./misc" // BIDI HELPERS export function iterateBidiSections(order, from, to, f) { - if (!order) return f(from, to, "ltr"); - var found = false; + if (!order) return f(from, to, "ltr") + var found = false for (var i = 0; i < order.length; ++i) { - var part = order[i]; + var part = order[i] if (part.from < to && part.to > from || from == to && part.to == from) { - f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); - found = true; + f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr") + found = true } } - if (!found) f(from, to, "ltr"); + if (!found) f(from, to, "ltr") } -export function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } -export function bidiRight(part) { return part.level % 2 ? part.from : part.to; } +export function bidiLeft(part) { return part.level % 2 ? part.to : part.from } +export function bidiRight(part) { return part.level % 2 ? part.from : part.to } -export function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; } +export function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0 } export function lineRight(line) { - var order = getOrder(line); - if (!order) return line.text.length; - return bidiRight(lst(order)); + var order = getOrder(line) + if (!order) return line.text.length + return bidiRight(lst(order)) } function compareBidiLevel(order, a, b) { - var linedir = order[0].level; - if (a == linedir) return true; - if (b == linedir) return false; - return a < b; + var linedir = order[0].level + if (a == linedir) return true + if (b == linedir) return false + return a < b } -export var bidiOther = null; +export var bidiOther = null export function getBidiPartAt(order, pos) { - bidiOther = null; + bidiOther = null for (var i = 0, found; i < order.length; ++i) { - var cur = order[i]; - if (cur.from < pos && cur.to > pos) return i; + var cur = order[i] + if (cur.from < pos && cur.to > pos) return i if ((cur.from == pos || cur.to == pos)) { if (found == null) { - found = i; + found = i } else if (compareBidiLevel(order, cur.level, order[found].level)) { - if (cur.from != cur.to) bidiOther = found; - return i; + if (cur.from != cur.to) bidiOther = found + return i } else { - if (cur.from != cur.to) bidiOther = i; - return found; + if (cur.from != cur.to) bidiOther = i + return found } } } - return found; + return found } function moveInLine(line, pos, dir, byUnit) { - if (!byUnit) return pos + dir; - do pos += dir; - while (pos > 0 && isExtendingChar(line.text.charAt(pos))); - return pos; + if (!byUnit) return pos + dir + do pos += dir + while (pos > 0 && isExtendingChar(line.text.charAt(pos))) + return pos } // This is needed in order to move 'visually' through bi-directional @@ -66,32 +66,32 @@ function moveInLine(line, pos, dir, byUnit) { // LTR text touch each other. This often requires the cursor offset // to move more than one unit, in order to visually move one unit. export function moveVisually(line, start, dir, byUnit) { - var bidi = getOrder(line); - if (!bidi) return moveLogically(line, start, dir, byUnit); - var pos = getBidiPartAt(bidi, start), part = bidi[pos]; - var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); + var bidi = getOrder(line) + if (!bidi) return moveLogically(line, start, dir, byUnit) + var pos = getBidiPartAt(bidi, start), part = bidi[pos] + var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit) for (;;) { - if (target > part.from && target < part.to) return target; + if (target > part.from && target < part.to) return target if (target == part.from || target == part.to) { - if (getBidiPartAt(bidi, target) == pos) return target; - part = bidi[pos += dir]; - return (dir > 0) == part.level % 2 ? part.to : part.from; + if (getBidiPartAt(bidi, target) == pos) return target + part = bidi[pos += dir] + return (dir > 0) == part.level % 2 ? part.to : part.from } else { - part = bidi[pos += dir]; - if (!part) return null; + part = bidi[pos += dir] + if (!part) return null if ((dir > 0) == part.level % 2) - target = moveInLine(line, part.to, -1, byUnit); + target = moveInLine(line, part.to, -1, byUnit) else - target = moveInLine(line, part.from, 1, byUnit); + target = moveInLine(line, part.from, 1, byUnit) } } } export function moveLogically(line, start, dir, byUnit) { - var target = start + dir; - if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir; - return target < 0 || target > line.text.length ? null : target; + var target = start + dir + if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir + return target < 0 || target > line.text.length ? null : target } // Bidirectional ordering algorithm @@ -119,43 +119,43 @@ export function moveLogically(line, start, dir, byUnit) { // objects) in the order in which they occur visually. export var bidiOrdering = (function() { // Character types for codepoints 0 to 0xff - var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; + var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN" // Character types for codepoints 0x600 to 0x6ff - var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"; + var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm" function charType(code) { - if (code <= 0xf7) return lowTypes.charAt(code); - else if (0x590 <= code && code <= 0x5f4) return "R"; - else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600); - else if (0x6ee <= code && code <= 0x8ac) return "r"; - else if (0x2000 <= code && code <= 0x200b) return "w"; - else if (code == 0x200c) return "b"; - else return "L"; + if (code <= 0xf7) return lowTypes.charAt(code) + else if (0x590 <= code && code <= 0x5f4) return "R" + else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600) + else if (0x6ee <= code && code <= 0x8ac) return "r" + else if (0x2000 <= code && code <= 0x200b) return "w" + else if (code == 0x200c) return "b" + else return "L" } - var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; - var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; + var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/ + var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/ // Browsers seem to always treat the boundaries of block elements as being L. - var outerType = "L"; + var outerType = "L" function BidiSpan(level, from, to) { - this.level = level; - this.from = from; this.to = to; + this.level = level + this.from = from; this.to = to } return function(str) { - if (!bidiRE.test(str)) return false; - var len = str.length, types = []; + if (!bidiRE.test(str)) return false + var len = str.length, types = [] for (var i = 0, type; i < len; ++i) - types.push(type = charType(str.charCodeAt(i))); + types.push(type = charType(str.charCodeAt(i))) // W1. Examine each non-spacing mark (NSM) in the level run, and // change the type of the NSM to the type of the previous // character. If the NSM is at the start of the level run, it will // get the type of sor. for (var i = 0, prev = outerType; i < len; ++i) { - var type = types[i]; - if (type == "m") types[i] = prev; - else prev = type; + var type = types[i] + if (type == "m") types[i] = prev + else prev = type } // W2. Search backwards from each instance of a European number @@ -164,20 +164,20 @@ export var bidiOrdering = (function() { // number. // W3. Change all ALs to R. for (var i = 0, cur = outerType; i < len; ++i) { - var type = types[i]; - if (type == "1" && cur == "r") types[i] = "n"; - else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; } + var type = types[i] + if (type == "1" && cur == "r") types[i] = "n" + else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R" } } // W4. A single European separator between two European numbers // changes to a European number. A single common separator between // two numbers of the same type changes to that type. for (var i = 1, prev = types[0]; i < len - 1; ++i) { - var type = types[i]; - if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1"; + var type = types[i] + if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1" else if (type == "," && prev == types[i+1] && - (prev == "1" || prev == "n")) types[i] = prev; - prev = type; + (prev == "1" || prev == "n")) types[i] = prev + prev = type } // W5. A sequence of European terminators adjacent to European @@ -185,13 +185,13 @@ export var bidiOrdering = (function() { // W6. Otherwise, separators and terminators change to Other // Neutral. for (var i = 0; i < len; ++i) { - var type = types[i]; - if (type == ",") types[i] = "N"; + var type = types[i] + if (type == ",") types[i] = "N" else if (type == "%") { for (var end = i + 1; end < len && types[end] == "%"; ++end) {} - var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; - for (var j = i; j < end; ++j) types[j] = replace; - i = end - 1; + var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N" + for (var j = i; j < end; ++j) types[j] = replace + i = end - 1 } } @@ -199,9 +199,9 @@ export var bidiOrdering = (function() { // until the first strong type (R, L, or sor) is found. If an L is // found, then change the type of the European number to L. for (var i = 0, cur = outerType; i < len; ++i) { - var type = types[i]; - if (cur == "L" && type == "1") types[i] = "L"; - else if (isStrong.test(type)) cur = type; + var type = types[i] + if (cur == "L" && type == "1") types[i] = "L" + else if (isStrong.test(type)) cur = type } // N1. A sequence of neutrals takes the direction of the @@ -213,11 +213,11 @@ export var bidiOrdering = (function() { for (var i = 0; i < len; ++i) { if (isNeutral.test(types[i])) { for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {} - var before = (i ? types[i-1] : outerType) == "L"; - var after = (end < len ? types[end] : outerType) == "L"; - var replace = before || after ? "L" : "R"; - for (var j = i; j < end; ++j) types[j] = replace; - i = end - 1; + var before = (i ? types[i-1] : outerType) == "L" + var after = (end < len ? types[end] : outerType) == "L" + var replace = before || after ? "L" : "R" + for (var j = i; j < end; ++j) types[j] = replace + i = end - 1 } } @@ -226,49 +226,49 @@ export var bidiOrdering = (function() { // levels (0, 1, 2) in an implementation that doesn't take // explicit embedding into account, we can build up the order on // the fly, without following the level-based algorithm. - var order = [], m; + var order = [], m for (var i = 0; i < len;) { if (countsAsLeft.test(types[i])) { - var start = i; + var start = i for (++i; i < len && countsAsLeft.test(types[i]); ++i) {} - order.push(new BidiSpan(0, start, i)); + order.push(new BidiSpan(0, start, i)) } else { - var pos = i, at = order.length; + var pos = i, at = order.length for (++i; i < len && types[i] != "L"; ++i) {} for (var j = pos; j < i;) { if (countsAsNum.test(types[j])) { - if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)); - var nstart = j; + if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)) + var nstart = j for (++j; j < i && countsAsNum.test(types[j]); ++j) {} - order.splice(at, 0, new BidiSpan(2, nstart, j)); - pos = j; - } else ++j; + order.splice(at, 0, new BidiSpan(2, nstart, j)) + pos = j + } else ++j } - if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i)); + if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i)) } } if (order[0].level == 1 && (m = str.match(/^\s+/))) { - order[0].from = m[0].length; - order.unshift(new BidiSpan(0, 0, m[0].length)); + order[0].from = m[0].length + order.unshift(new BidiSpan(0, 0, m[0].length)) } if (lst(order).level == 1 && (m = str.match(/\s+$/))) { - lst(order).to -= m[0].length; - order.push(new BidiSpan(0, len - m[0].length, len)); + lst(order).to -= m[0].length + order.push(new BidiSpan(0, len - m[0].length, len)) } if (order[0].level == 2) - order.unshift(new BidiSpan(1, order[0].to, order[0].to)); + order.unshift(new BidiSpan(1, order[0].to, order[0].to)) if (order[0].level != lst(order).level) - order.push(new BidiSpan(order[0].level, len, len)); + order.push(new BidiSpan(order[0].level, len, len)) - return order; - }; -})(); + return order + } +})() // Get the bidi ordering for the given line (and cache it). Returns // false for lines that are fully left-to-right, and an array of // BidiSpan objects otherwise. export function getOrder(line) { - var order = line.order; - if (order == null) order = line.order = bidiOrdering(line.text); - return order; + var order = line.order + if (order == null) order = line.order = bidiOrdering(line.text) + return order } diff --git a/src/util/browser.js b/src/util/browser.js index 7941f930d7..ae48fb5c65 100644 --- a/src/util/browser.js +++ b/src/util/browser.js @@ -1,31 +1,31 @@ // Kludges for bugs and behavior differences that can't be feature // detected are enabled based on userAgent etc sniffing. -var userAgent = navigator.userAgent; -var platform = navigator.platform; +var userAgent = navigator.userAgent +var platform = navigator.platform -export var gecko = /gecko\/\d/i.test(userAgent); -var ie_upto10 = /MSIE \d/.test(userAgent); -var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent); -export var ie = ie_upto10 || ie_11up; -export var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); -export var webkit = /WebKit\//.test(userAgent); -var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent); -export var chrome = /Chrome\//.test(userAgent); -export var presto = /Opera\//.test(userAgent); -export var safari = /Apple Computer/.test(navigator.vendor); -export var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent); -export var phantom = /PhantomJS/.test(userAgent); +export var gecko = /gecko\/\d/i.test(userAgent) +var ie_upto10 = /MSIE \d/.test(userAgent) +var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent) +export var ie = ie_upto10 || ie_11up +export var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]) +export var webkit = /WebKit\//.test(userAgent) +var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent) +export var chrome = /Chrome\//.test(userAgent) +export var presto = /Opera\//.test(userAgent) +export var safari = /Apple Computer/.test(navigator.vendor) +export var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent) +export var phantom = /PhantomJS/.test(userAgent) -export var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent); +export var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent) // This is woefully incomplete. Suggestions for alternative methods welcome. -export var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent); -export var mac = ios || /Mac/.test(platform); -export var chromeOS = /\bCrOS\b/.test(userAgent); -export var windows = /win/i.test(platform); +export var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent) +export var mac = ios || /Mac/.test(platform) +export var chromeOS = /\bCrOS\b/.test(userAgent) +export var windows = /win/i.test(platform) -var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/); -if (presto_version) presto_version = Number(presto_version[1]); -if (presto_version && presto_version >= 15) { presto = false; webkit = true; } +var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/) +if (presto_version) presto_version = Number(presto_version[1]) +if (presto_version && presto_version >= 15) { presto = false; webkit = true } // Some browsers use the wrong event properties to signal cmd/ctrl on OS X -export var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); -export var captureRightClick = gecko || (ie && ie_version >= 9); +export var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)) +export var captureRightClick = gecko || (ie && ie_version >= 9) diff --git a/src/util/dom.js b/src/util/dom.js index 478402e668..df2cfd0aac 100644 --- a/src/util/dom.js +++ b/src/util/dom.js @@ -1,89 +1,89 @@ -import { ie, ie_version, ios } from "./browser"; +import { ie, ie_version, ios } from "./browser" -export function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); } +export function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") } export var rmClass = function(node, cls) { - var current = node.className; - var match = classTest(cls).exec(current); + var current = node.className + var match = classTest(cls).exec(current) if (match) { - var after = current.slice(match.index + match[0].length); - node.className = current.slice(0, match.index) + (after ? match[1] + after : ""); + var after = current.slice(match.index + match[0].length) + node.className = current.slice(0, match.index) + (after ? match[1] + after : "") } -}; +} export function removeChildren(e) { for (var count = e.childNodes.length; count > 0; --count) - e.removeChild(e.firstChild); - return e; + e.removeChild(e.firstChild) + return e } export function removeChildrenAndAdd(parent, e) { - return removeChildren(parent).appendChild(e); + return removeChildren(parent).appendChild(e) } export function elt(tag, content, className, style) { - var e = document.createElement(tag); - if (className) e.className = className; - if (style) e.style.cssText = style; - if (typeof content == "string") e.appendChild(document.createTextNode(content)); - else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); - return e; + var e = document.createElement(tag) + if (className) e.className = className + if (style) e.style.cssText = style + if (typeof content == "string") e.appendChild(document.createTextNode(content)) + else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]) + return e } -export var range; +export var range if (document.createRange) range = function(node, start, end, endNode) { - var r = document.createRange(); - r.setEnd(endNode || node, end); - r.setStart(node, start); - return r; -}; + var r = document.createRange() + r.setEnd(endNode || node, end) + r.setStart(node, start) + return r +} else range = function(node, start, end) { - var r = document.body.createTextRange(); - try { r.moveToElementText(node.parentNode); } - catch(e) { return r; } - r.collapse(true); - r.moveEnd("character", end); - r.moveStart("character", start); - return r; -}; + var r = document.body.createTextRange() + try { r.moveToElementText(node.parentNode) } + catch(e) { return r } + r.collapse(true) + r.moveEnd("character", end) + r.moveStart("character", start) + return r +} export function contains(parent, child) { if (child.nodeType == 3) // Android browser always returns false when child is a textnode - child = child.parentNode; + child = child.parentNode if (parent.contains) - return parent.contains(child); + return parent.contains(child) do { - if (child.nodeType == 11) child = child.host; - if (child == parent) return true; - } while (child = child.parentNode); + if (child.nodeType == 11) child = child.host + if (child == parent) return true + } while (child = child.parentNode) } export var activeElt = function() { - var activeElement = document.activeElement; + var activeElement = document.activeElement while (activeElement && activeElement.root && activeElement.root.activeElement) - activeElement = activeElement.root.activeElement; - return activeElement; + activeElement = activeElement.root.activeElement + return activeElement } // Older versions of IE throws unspecified error when touching // document.activeElement in some cases (during loading, in iframe) if (ie && ie_version < 11) activeElt = function() { - try { return document.activeElement; } - catch(e) { return document.body; } -}; + try { return document.activeElement } + catch(e) { return document.body } +} export function addClass(node, cls) { - var current = node.className; - if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls; + var current = node.className + if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls } export function joinClasses(a, b) { - var as = a.split(" "); + var as = a.split(" ") for (var i = 0; i < as.length; i++) - if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; - return b; + if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i] + return b } -export var selectInput = function(node) { node.select(); }; +export var selectInput = function(node) { node.select() } if (ios) // Mobile Safari apparently has a bug where select() is broken. - selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; + selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length } else if (ie) // Suppress mysterious IE10 errors - selectInput = function(node) { try { node.select(); } catch(_e) {} }; + selectInput = function(node) { try { node.select() } catch(_e) {} } diff --git a/src/util/event.js b/src/util/event.js index 4c479cbd25..b2137583fb 100644 --- a/src/util/event.js +++ b/src/util/event.js @@ -1,5 +1,5 @@ -import { mac } from "./browser"; -import { indexOf } from "./misc"; +import { mac } from "./browser" +import { indexOf } from "./misc" // EVENT HANDLING @@ -8,15 +8,15 @@ import { indexOf } from "./misc"; export var on = function(emitter, type, f) { if (emitter.addEventListener) - emitter.addEventListener(type, f, false); + emitter.addEventListener(type, f, false) else if (emitter.attachEvent) - emitter.attachEvent("on" + type, f); + emitter.attachEvent("on" + type, f) else { - var map = emitter._handlers || (emitter._handlers = {}); - var arr = map[type] || (map[type] = []); - arr.push(f); + var map = emitter._handlers || (emitter._handlers = {}) + var arr = map[type] || (map[type] = []) + arr.push(f) } -}; +} var noHandlers = [] export function getHandlers(emitter, type, copy) { @@ -27,21 +27,21 @@ export function getHandlers(emitter, type, copy) { export function off(emitter, type, f) { if (emitter.removeEventListener) - emitter.removeEventListener(type, f, false); + emitter.removeEventListener(type, f, false) else if (emitter.detachEvent) - emitter.detachEvent("on" + type, f); + emitter.detachEvent("on" + type, f) else { var handlers = getHandlers(emitter, type, false) for (var i = 0; i < handlers.length; ++i) - if (handlers[i] == f) { handlers.splice(i, 1); break; } + if (handlers[i] == f) { handlers.splice(i, 1); break } } } export function signal(emitter, type /*, values...*/) { var handlers = getHandlers(emitter, type, true) - if (!handlers.length) return; - var args = Array.prototype.slice.call(arguments, 2); - for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args); + if (!handlers.length) return + var args = Array.prototype.slice.call(arguments, 2) + for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args) } // The DOM events that CodeMirror handles can be overridden by @@ -49,17 +49,17 @@ export function signal(emitter, type /*, values...*/) { // and preventDefault-ing the event in that handler. export function signalDOMEvent(cm, e, override) { if (typeof e == "string") - e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; - signal(cm, override || e.type, cm, e); - return e_defaultPrevented(e) || e.codemirrorIgnore; + e = {type: e, preventDefault: function() { this.defaultPrevented = true }} + signal(cm, override || e.type, cm, e) + return e_defaultPrevented(e) || e.codemirrorIgnore } export function signalCursorActivity(cm) { - var arr = cm._handlers && cm._handlers.cursorActivity; - if (!arr) return; - var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); + var arr = cm._handlers && cm._handlers.cursorActivity + if (!arr) return + var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []) for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) - set.push(arr[i]); + set.push(arr[i]) } export function hasHandler(emitter, type) { @@ -69,34 +69,34 @@ export function hasHandler(emitter, type) { // Add on and off methods to a constructor's prototype, to make // registering events on such objects more convenient. export function eventMixin(ctor) { - ctor.prototype.on = function(type, f) {on(this, type, f);}; - ctor.prototype.off = function(type, f) {off(this, type, f);}; + ctor.prototype.on = function(type, f) {on(this, type, f)} + ctor.prototype.off = function(type, f) {off(this, type, f)} } // Due to the fact that we still support jurassic IE versions, some // compatibility wrappers are needed. export function e_preventDefault(e) { - if (e.preventDefault) e.preventDefault(); - else e.returnValue = false; + if (e.preventDefault) e.preventDefault() + else e.returnValue = false } export function e_stopPropagation(e) { - if (e.stopPropagation) e.stopPropagation(); - else e.cancelBubble = true; + if (e.stopPropagation) e.stopPropagation() + else e.cancelBubble = true } export function e_defaultPrevented(e) { - return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false; + return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false } -export function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);} +export function e_stop(e) {e_preventDefault(e); e_stopPropagation(e)} -export function e_target(e) {return e.target || e.srcElement;} +export function e_target(e) {return e.target || e.srcElement} export function e_button(e) { - var b = e.which; + var b = e.which if (b == null) { - if (e.button & 1) b = 1; - else if (e.button & 2) b = 3; - else if (e.button & 4) b = 2; + if (e.button & 1) b = 1 + else if (e.button & 2) b = 3 + else if (e.button & 4) b = 2 } - if (mac && e.ctrlKey && b == 1) b = 3; - return b; + if (mac && e.ctrlKey && b == 1) b = 3 + return b } diff --git a/src/util/feature_detection.js b/src/util/feature_detection.js index bce86ad220..1e9baf41e5 100644 --- a/src/util/feature_detection.js +++ b/src/util/feature_detection.js @@ -1,83 +1,83 @@ -import { elt, range, removeChildren, removeChildrenAndAdd } from "./dom"; -import { ie, ie_version } from "./browser"; +import { elt, range, removeChildren, removeChildrenAndAdd } from "./dom" +import { ie, ie_version } from "./browser" // Detect drag-and-drop export var dragAndDrop = function() { // There is *some* kind of drag-and-drop support in IE6-8, but I // couldn't get it to work yet. - if (ie && ie_version < 9) return false; - var div = elt('div'); - return "draggable" in div || "dragDrop" in div; -}(); + if (ie && ie_version < 9) return false + var div = elt('div') + return "draggable" in div || "dragDrop" in div +}() -var zwspSupported; +var zwspSupported export function zeroWidthElement(measure) { if (zwspSupported == null) { - var test = elt("span", "\u200b"); - removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); + var test = elt("span", "\u200b") + removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])) if (measure.firstChild.offsetHeight != 0) - zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); + zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8) } var node = zwspSupported ? elt("span", "\u200b") : - elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); - node.setAttribute("cm-text", ""); - return node; + elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px") + node.setAttribute("cm-text", "") + return node } // Feature-detect IE's crummy client rect reporting for bidi text -var badBidiRects; +var badBidiRects export function hasBadBidiRects(measure) { - if (badBidiRects != null) return badBidiRects; - var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); - var r0 = range(txt, 0, 1).getBoundingClientRect(); - var r1 = range(txt, 1, 2).getBoundingClientRect(); - removeChildren(measure); - if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780) - return badBidiRects = (r1.right - r0.right < 3); + if (badBidiRects != null) return badBidiRects + var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")) + var r0 = range(txt, 0, 1).getBoundingClientRect() + var r1 = range(txt, 1, 2).getBoundingClientRect() + removeChildren(measure) + if (!r0 || r0.left == r0.right) return false // Safari returns null in some cases (#2780) + return badBidiRects = (r1.right - r0.right < 3) } // See if "".split is the broken IE version, if so, provide an // alternative way to split lines. export var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function(string) { - var pos = 0, result = [], l = string.length; + var pos = 0, result = [], l = string.length while (pos <= l) { - var nl = string.indexOf("\n", pos); - if (nl == -1) nl = string.length; - var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); - var rt = line.indexOf("\r"); + var nl = string.indexOf("\n", pos) + if (nl == -1) nl = string.length + var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl) + var rt = line.indexOf("\r") if (rt != -1) { - result.push(line.slice(0, rt)); - pos += rt + 1; + result.push(line.slice(0, rt)) + pos += rt + 1 } else { - result.push(line); - pos = nl + 1; + result.push(line) + pos = nl + 1 } } - return result; -} : function(string){return string.split(/\r\n?|\n/);}; + return result +} : function(string){return string.split(/\r\n?|\n/)} export var hasSelection = window.getSelection ? function(te) { - try { return te.selectionStart != te.selectionEnd; } - catch(e) { return false; } + try { return te.selectionStart != te.selectionEnd } + catch(e) { return false } } : function(te) { - try {var range = te.ownerDocument.selection.createRange();} + try {var range = te.ownerDocument.selection.createRange()} catch(e) {} - if (!range || range.parentElement() != te) return false; - return range.compareEndPoints("StartToEnd", range) != 0; -}; + if (!range || range.parentElement() != te) return false + return range.compareEndPoints("StartToEnd", range) != 0 +} export var hasCopyEvent = (function() { - var e = elt("div"); - if ("oncopy" in e) return true; - e.setAttribute("oncopy", "return;"); - return typeof e.oncopy == "function"; -})(); + var e = elt("div") + if ("oncopy" in e) return true + e.setAttribute("oncopy", "return;") + return typeof e.oncopy == "function" +})() -var badZoomedRects = null; +var badZoomedRects = null export function hasBadZoomedRects(measure) { - if (badZoomedRects != null) return badZoomedRects; - var node = removeChildrenAndAdd(measure, elt("span", "x")); - var normal = node.getBoundingClientRect(); - var fromRange = range(node, 0, 1).getBoundingClientRect(); - return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1; + if (badZoomedRects != null) return badZoomedRects + var node = removeChildrenAndAdd(measure, elt("span", "x")) + var normal = node.getBoundingClientRect() + var fromRange = range(node, 0, 1).getBoundingClientRect() + return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1 } diff --git a/src/util/misc.js b/src/util/misc.js index a98a18832b..a6e3340db1 100644 --- a/src/util/misc.js +++ b/src/util/misc.js @@ -1,84 +1,84 @@ export function bind(f) { - var args = Array.prototype.slice.call(arguments, 1); - return function(){return f.apply(null, args);}; + var args = Array.prototype.slice.call(arguments, 1) + return function(){return f.apply(null, args)} } export function copyObj(obj, target, overwrite) { - if (!target) target = {}; + if (!target) target = {} for (var prop in obj) if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) - target[prop] = obj[prop]; - return target; + target[prop] = obj[prop] + return target } // Counts the column offset in a string, taking tabs into account. // Used mostly to find indentation. export function countColumn(string, end, tabSize, startIndex, startValue) { if (end == null) { - end = string.search(/[^\s\u00a0]/); - if (end == -1) end = string.length; + end = string.search(/[^\s\u00a0]/) + if (end == -1) end = string.length } for (var i = startIndex || 0, n = startValue || 0;;) { - var nextTab = string.indexOf("\t", i); + var nextTab = string.indexOf("\t", i) if (nextTab < 0 || nextTab >= end) - return n + (end - i); - n += nextTab - i; - n += tabSize - (n % tabSize); - i = nextTab + 1; + return n + (end - i) + n += nextTab - i + n += tabSize - (n % tabSize) + i = nextTab + 1 } } -export function Delayed() {this.id = null;} +export function Delayed() {this.id = null} Delayed.prototype.set = function(ms, f) { - clearTimeout(this.id); - this.id = setTimeout(f, ms); -}; + clearTimeout(this.id) + this.id = setTimeout(f, ms) +} export function indexOf(array, elt) { for (var i = 0; i < array.length; ++i) - if (array[i] == elt) return i; - return -1; + if (array[i] == elt) return i + return -1 } // Number of pixels added to scroller and sizer to hide scrollbar -export var scrollerGap = 30; +export var scrollerGap = 30 // Returned or thrown by various protocols to signal 'I'm not // handling this'. -export var Pass = {toString: function(){return "CodeMirror.Pass";}}; +export var Pass = {toString: function(){return "CodeMirror.Pass"}} // Reused option objects for setSelection & friends -export var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"}; +export var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"} // The inverse of countColumn -- find the offset that corresponds to // a particular column. export function findColumn(string, goal, tabSize) { for (var pos = 0, col = 0;;) { - var nextTab = string.indexOf("\t", pos); - if (nextTab == -1) nextTab = string.length; - var skipped = nextTab - pos; + var nextTab = string.indexOf("\t", pos) + if (nextTab == -1) nextTab = string.length + var skipped = nextTab - pos if (nextTab == string.length || col + skipped >= goal) - return pos + Math.min(skipped, goal - col); - col += nextTab - pos; - col += tabSize - (col % tabSize); - pos = nextTab + 1; - if (col >= goal) return pos; + return pos + Math.min(skipped, goal - col) + col += nextTab - pos + col += tabSize - (col % tabSize) + pos = nextTab + 1 + if (col >= goal) return pos } } -var spaceStrs = [""]; +var spaceStrs = [""] export function spaceStr(n) { while (spaceStrs.length <= n) - spaceStrs.push(lst(spaceStrs) + " "); - return spaceStrs[n]; + spaceStrs.push(lst(spaceStrs) + " ") + return spaceStrs[n] } -export function lst(arr) { return arr[arr.length-1]; } +export function lst(arr) { return arr[arr.length-1] } export function map(array, f) { - var out = []; - for (var i = 0; i < array.length; i++) out[i] = f(array[i], i); - return out; + var out = [] + for (var i = 0; i < array.length; i++) out[i] = f(array[i], i) + return out } export function insertSorted(array, value, score) { @@ -90,31 +90,31 @@ export function insertSorted(array, value, score) { export function nothing() {} export function createObj(base, props) { - var inst; + var inst if (Object.create) { - inst = Object.create(base); + inst = Object.create(base) } else { - nothing.prototype = base; - inst = new nothing(); + nothing.prototype = base + inst = new nothing() } - if (props) copyObj(props, inst); - return inst; + if (props) copyObj(props, inst) + return inst } -var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; +var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/ export function isWordCharBasic(ch) { return /\w/.test(ch) || ch > "\x80" && - (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); + (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)) } export function isWordChar(ch, helper) { - if (!helper) return isWordCharBasic(ch); - if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true; - return helper.test(ch); + if (!helper) return isWordCharBasic(ch) + if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true + return helper.test(ch) } export function isEmpty(obj) { - for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; - return true; + for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false + return true } // Extending unicode characters. A series of a non-extending char + @@ -122,5 +122,5 @@ export function isEmpty(obj) { // as editing and measuring is concerned. This is not fully correct, // since some scripts/fonts/browsers also treat other configurations // of code points as a group. -var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; -export function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); } +var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/ +export function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) } diff --git a/src/util/operation_group.js b/src/util/operation_group.js index 478f07283e..d48f6eb32a 100644 --- a/src/util/operation_group.js +++ b/src/util/operation_group.js @@ -1,46 +1,46 @@ -import { getHandlers } from "./event"; +import { getHandlers } from "./event" -var operationGroup = null; +var operationGroup = null export function pushOperation(op) { if (operationGroup) { - operationGroup.ops.push(op); + operationGroup.ops.push(op) } else { op.ownsGroup = operationGroup = { ops: [op], delayedCallbacks: [] - }; + } } } function fireCallbacksForOps(group) { // Calls delayed callbacks and cursorActivity handlers until no // new ones appear - var callbacks = group.delayedCallbacks, i = 0; + var callbacks = group.delayedCallbacks, i = 0 do { for (; i < callbacks.length; i++) - callbacks[i].call(null); + callbacks[i].call(null) for (var j = 0; j < group.ops.length; j++) { - var op = group.ops[j]; + var op = group.ops[j] if (op.cursorActivityHandlers) while (op.cursorActivityCalled < op.cursorActivityHandlers.length) - op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); + op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm) } - } while (i < callbacks.length); + } while (i < callbacks.length) } export function finishOperation(op, endCb) { - var group = op.ownsGroup; - if (!group) return; + var group = op.ownsGroup + if (!group) return - try { fireCallbacksForOps(group); } + try { fireCallbacksForOps(group) } finally { - operationGroup = null; - endCb(group); + operationGroup = null + endCb(group) } } -var orphanDelayedCallbacks = null; +var orphanDelayedCallbacks = null // Often, we want to signal events at a point where we are in the // middle of some work, but don't want the handler to start calling @@ -51,23 +51,23 @@ var orphanDelayedCallbacks = null; // operation is active, when a timeout fires. export function signalLater(emitter, type /*, values...*/) { var arr = getHandlers(emitter, type, false) - if (!arr.length) return; - var args = Array.prototype.slice.call(arguments, 2), list; + if (!arr.length) return + var args = Array.prototype.slice.call(arguments, 2), list if (operationGroup) { - list = operationGroup.delayedCallbacks; + list = operationGroup.delayedCallbacks } else if (orphanDelayedCallbacks) { - list = orphanDelayedCallbacks; + list = orphanDelayedCallbacks } else { - list = orphanDelayedCallbacks = []; - setTimeout(fireOrphanDelayed, 0); + list = orphanDelayedCallbacks = [] + setTimeout(fireOrphanDelayed, 0) } - function bnd(f) {return function(){f.apply(null, args);};} + function bnd(f) {return function(){f.apply(null, args)}} for (var i = 0; i < arr.length; ++i) - list.push(bnd(arr[i])); + list.push(bnd(arr[i])) } function fireOrphanDelayed() { - var delayed = orphanDelayedCallbacks; - orphanDelayedCallbacks = null; - for (var i = 0; i < delayed.length; ++i) delayed[i](); + var delayed = orphanDelayedCallbacks + orphanDelayedCallbacks = null + for (var i = 0; i < delayed.length; ++i) delayed[i]() } From 2182dfd79e92d9370802d39933cfbb446dd60081 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Mon, 26 Sep 2016 20:25:10 +0200 Subject: [PATCH 0029/1880] Disallow semicolons in src/ --- test/lint.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/lint.js b/test/lint.js index 355b3e1c04..cc03ce64c0 100644 --- a/test/lint.js +++ b/test/lint.js @@ -11,7 +11,8 @@ var blint = require("blint"); ["src"].forEach(function(dir) { blint.checkDir(dir, { browser: true, - ecmaVersion: 6 + ecmaVersion: 6, + semicolons: false }); }); From 5bb6a94ea4ed91e13ad7918fbde3b5c77df9df81 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 26 Sep 2016 22:30:44 +0200 Subject: [PATCH 0030/1880] Add semicolons to make the linter pass --- src/line/line_data.js | 2 +- src/measurement/update_line.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/line/line_data.js b/src/line/line_data.js index 688aa1bdd2..8b247d5306 100644 --- a/src/line/line_data.js +++ b/src/line/line_data.js @@ -96,7 +96,7 @@ export function buildLineContent(cm, lineView) { lineView.measure.map = builder.map lineView.measure.cache = {} } else { - (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map) + ;(lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map) ;(lineView.measure.caches || (lineView.measure.caches = [])).push({}) } } diff --git a/src/measurement/update_line.js b/src/measurement/update_line.js index a80d8c508c..be94b00940 100644 --- a/src/measurement/update_line.js +++ b/src/measurement/update_line.js @@ -172,7 +172,7 @@ function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { function positionLineWidget(widget, node, lineView, dims) { if (widget.noHScroll) { - (lineView.alignable || (lineView.alignable = [])).push(node) + ;(lineView.alignable || (lineView.alignable = [])).push(node) var width = dims.wrapperWidth node.style.left = dims.fixedPos + "px" if (!widget.coverGutter) { From cae456c7f18711a94e528bded3203efd716597db Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 27 Sep 2016 09:40:33 +0200 Subject: [PATCH 0031/1880] Document the refresh event --- doc/manual.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/manual.html b/doc/manual.html index e97ce07e14..b1377928de 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -634,6 +634,11 @@

Events

"scroll" (instance: CodeMirror)
Fires when the editor is scrolled.
+
"resize" (instance: CodeMirror)
+
Fires when the editor is refreshed + or resized. Mostly useful to invalidate + cached values that depend on the editor or character size.
+
"scrollCursorIntoView" (instance: CodeMirror, event: Event)
Fires when the editor tries to scroll its cursor into view. Can be hooked into to take care of additional scrollable From 39ffcd8701c35363ab754b82c3c171913ecf478e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 27 Sep 2016 09:41:45 +0200 Subject: [PATCH 0032/1880] Fix event name in manual --- doc/manual.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index b1377928de..65e030c0bf 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -634,7 +634,7 @@

Events

"scroll" (instance: CodeMirror)
Fires when the editor is scrolled.
-
"resize" (instance: CodeMirror)
+
"refresh" (instance: CodeMirror)
Fires when the editor is refreshed or resized. Mostly useful to invalidate cached values that depend on the editor or character size.
From 581854eaeb3b3d5ecf4614b7ade0babc5aaa5fe6 Mon Sep 17 00:00:00 2001 From: Apollo Zhu Date: Thu, 29 Sep 2016 01:09:40 -0400 Subject: [PATCH 0033/1880] [swift] Update to Swift3 - remove non-swifty keywords - remove repeated keywords - rearrange in more logical way --- mode/swift/swift.js | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/mode/swift/swift.js b/mode/swift/swift.js index 3c28ced329..9dcd822e91 100644 --- a/mode/swift/swift.js +++ b/mode/swift/swift.js @@ -19,24 +19,21 @@ return set } - var keywords = wordSet(["var","let","class","deinit","enum","extension","func","import","init","protocol", - "static","struct","subscript","typealias","as","dynamicType","is","new","super", - "self","Self","Type","__COLUMN__","__FILE__","__FUNCTION__","__LINE__","break","case", - "continue","default","do","else","fallthrough","if","in","for","return","switch", - "where","while","associativity","didSet","get","infix","inout","left","mutating", - "none","nonmutating","operator","override","postfix","precedence","prefix","right", - "set","unowned","weak","willSet"]) - var definingKeywords = wordSet(["var","let","class","enum","extension","func","import","protocol","struct", - "typealias","dynamicType","for"]) - var atoms = wordSet(["Infinity","NaN","undefined","null","true","false","on","off","yes","no","nil","null", - "this","super"]) - var types = wordSet(["String","bool","int","string","double","Double","Int","Float","float","public", - "private","extension"]) - var operators = "+-/*%=|&<>#" + var keywords = wordSet(["_","var","let","class","enum","extension","import","protocol","struct","func","typealias","associatedtype", + "open","public","internal","fileprivate","private","deinit","init","new","override","self","subscript","super", + "convenience","dynamic","final","indirect","lazy","required","static","unowned","unowned(safe)","unowned(unsafe)","weak","as","is", + "break","case","continue","default","else","fallthrough","for","guard","if","in","repeat","switch","where","while", + "defer","return","inout","mutating","nonmutating","catch","do","rethrows","throw","throws","try","didSet","get","set","willSet", + "assignment","associativity","infix","left","none","operator","postfix","precedence","precedencegroup","prefix","right", + "Any","AnyObject","Type","dynamicType","Self","Protocol","__COLUMN__","__FILE__","__FUNCTION__","__LINE__"]) + var definingKeywords = wordSet(["var","let","class","enum","extension","import","protocol","struct","func","typealias","associatedtype"]) + var atoms = wordSet(["true","false","nil","self","super","_"]) + var types = wordSet(["Array","Bool","Dictionary","Double","Float","Int","Never","Optional","String","Void"]) + var operators = "+-/*%=|&<>" var punc = ";,.(){}[]" var number = /^-?(?:(?:[\d_]+\.[_\d]*|\.[_\d]+|0o[0-7_\.]+|0b[01_\.]+)(?:e-?[\d_]+)?|0x[\d_a-f\.]+(?:p-?[\d_]+)?)/i var identifier = /^[_A-Za-z$][_A-Za-z$0-9]*/ - var property = /^[@\.][_A-Za-z$][_A-Za-z$0-9]*/ + var property = /^[@\#\.][_A-Za-z$][_A-Za-z$0-9]*/ var regexp = /^\/(?!\s)(?:\/\/)?(?:\\.|[^\/])+\// function tokenBase(stream, state, prev) { From 27acd6358252095da9cd51e499a4c086f82eabfe Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Tue, 27 Sep 2016 09:23:50 +0200 Subject: [PATCH 0034/1880] Move to rollup.config.js --- package.json | 4 ++-- src/banner.js => rollup.config.js | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) rename src/banner.js => rollup.config.js (61%) diff --git a/package.json b/package.json index a6e61d06dc..4cbaa3096e 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "lib": "./lib" }, "scripts": { - "build": "rollup --banner \"`cat src/banner.js`\" --format umd -n CodeMirror src/codemirror.js -o lib/codemirror.js", - "watch": "rollup -w --banner \"`cat src/banner.js`\" --format umd -n CodeMirror src/codemirror.js -o lib/codemirror.js", + "build": "rollup -c", + "watch": "rollup -w -c", "prepublish": "npm run-script build", "test": "node ./test/run.js", "lint": "bin/lint" diff --git a/src/banner.js b/rollup.config.js similarity index 61% rename from src/banner.js rename to rollup.config.js index 6bd6553f29..c1c8c11ae8 100644 --- a/src/banner.js +++ b/rollup.config.js @@ -1,4 +1,5 @@ -// CodeMirror, copyright (c) by Marijn Haverbeke and others +export default { + banner: `// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE // This is CodeMirror (http://codemirror.net), a code editor @@ -6,3 +7,9 @@ // // You can find some technical background for some of the code below // at http://marijnhaverbeke.nl/blog/#cm-internals . +`, + entry: "src/codemirror.js", + format: "umd", + dest: "lib/codemirror.js", + moduleName: "CodeMirror" +}; From 519b3ad211033ae1f855ceb0bc01f0248953be8e Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Tue, 27 Sep 2016 09:24:26 +0200 Subject: [PATCH 0035/1880] Add buble to rollup --- package.json | 1 + rollup.config.js | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 4cbaa3096e..057280c569 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "node-static": "0.6.0", "phantomjs-prebuilt": "^2.1.12", "rollup": "^0.34.10", + "rollup-plugin-buble": "^0.14.0", "rollup-watch": "^2.5.0" }, "bugs": "http://github.com/codemirror/CodeMirror/issues", diff --git a/rollup.config.js b/rollup.config.js index c1c8c11ae8..584dfe1ec4 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,3 +1,5 @@ +import buble from 'rollup-plugin-buble'; + export default { banner: `// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE @@ -11,5 +13,6 @@ export default { entry: "src/codemirror.js", format: "umd", dest: "lib/codemirror.js", - moduleName: "CodeMirror" + moduleName: "CodeMirror", + plugins: [ buble() ] }; From c17d0230e0312c2189d1d0a4d805aaca70a4e2ed Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Tue, 27 Sep 2016 10:04:56 +0200 Subject: [PATCH 0036/1880] Replace var with let --- src/display/Display.js | 2 +- src/display/gutters.js | 11 +- src/display/highlight_worker.js | 20 +-- src/display/line_numbers.js | 18 +-- src/display/operations.js | 38 ++--- src/display/scroll_events.js | 30 ++-- src/display/scrollbars.js | 36 ++--- src/display/scrolling.js | 44 ++--- src/display/selection.js | 50 +++--- src/display/update_display.js | 48 +++--- src/display/update_lines.js | 26 +-- src/display/view_tracking.js | 31 ++-- src/edit/CodeMirror.js | 34 ++-- src/edit/commands.js | 66 ++++---- src/edit/deleteNearSelection.js | 10 +- src/edit/drop_events.js | 31 ++-- src/edit/fromTextArea.js | 11 +- src/edit/global_events.js | 12 +- src/edit/key_events.js | 30 ++-- src/edit/main.js | 4 +- src/edit/methods.js | 160 +++++++++--------- src/edit/mouse_events.js | 78 ++++----- src/edit/options.js | 26 +-- src/input/ContentEditableInput.js | 160 +++++++++--------- src/input/TextareaInput.js | 63 ++++---- src/input/indent.js | 18 +-- src/input/input.js | 47 +++--- src/input/keymap.js | 37 ++--- src/input/keynames.js | 8 +- src/line/highlight.js | 64 ++++---- src/line/line_data.js | 94 +++++------ src/line/pos.js | 7 +- src/line/saw_special_spans.js | 2 +- src/line/spans.js | 149 ++++++++--------- src/line/utils_line.js | 34 ++-- src/measurement/position_measurement.js | 205 ++++++++++++------------ src/measurement/update_line.js | 44 ++--- src/measurement/widgets.js | 6 +- src/model/Doc.js | 113 ++++++------- src/model/change_measurement.js | 22 +-- src/model/changes.js | 63 ++++---- src/model/chunk.js | 53 +++--- src/model/document_data.js | 21 +-- src/model/history.js | 56 ++++--- src/model/line_widget.js | 20 +-- src/model/mark_text.js | 80 +++++---- src/model/selection.js | 23 +-- src/model/selection_updates.js | 45 +++--- src/modes.js | 29 ++-- src/util/StringStream.js | 21 +-- src/util/bidi.js | 99 ++++++------ src/util/browser.js | 44 ++--- src/util/dom.js | 32 ++-- src/util/event.js | 28 ++-- src/util/feature_detection.js | 45 +++--- src/util/misc.js | 38 ++--- src/util/operation_group.js | 22 +-- 57 files changed, 1327 insertions(+), 1281 deletions(-) diff --git a/src/display/Display.js b/src/display/Display.js index fa4c52fef7..c1879e7b16 100644 --- a/src/display/Display.js +++ b/src/display/Display.js @@ -7,7 +7,7 @@ import { scrollerGap } from "../util/misc" // display-related state. export function Display(place, doc, input) { - var d = this + let d = this this.input = input // Covers bottom-right square when both scrollbars are present. diff --git a/src/display/gutters.js b/src/display/gutters.js index 3fe9a13447..7ccf119e80 100644 --- a/src/display/gutters.js +++ b/src/display/gutters.js @@ -6,11 +6,12 @@ import { updateGutterSpace } from "./update_display" // Rebuild the gutter elements, ensure the margin to the left of the // code matches their width. export function updateGutters(cm) { - var gutters = cm.display.gutters, specs = cm.options.gutters + let gutters = cm.display.gutters, specs = cm.options.gutters removeChildren(gutters) - for (var i = 0; i < specs.length; ++i) { - var gutterClass = specs[i] - var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)) + let i = 0 + for (; i < specs.length; ++i) { + let gutterClass = specs[i] + let gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)) if (gutterClass == "CodeMirror-linenumbers") { cm.display.lineGutter = gElt gElt.style.width = (cm.display.lineNumWidth || 1) + "px" @@ -23,7 +24,7 @@ export function updateGutters(cm) { // Make sure the gutters options contains the element // "CodeMirror-linenumbers" when the lineNumbers option is true. export function setGuttersForLineNumbers(options) { - var found = indexOf(options.gutters, "CodeMirror-linenumbers") + let found = indexOf(options.gutters, "CodeMirror-linenumbers") if (found == -1 && options.lineNumbers) { options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]) } else if (found > -1 && !options.lineNumbers) { diff --git a/src/display/highlight_worker.js b/src/display/highlight_worker.js index b8a48c0e91..5d535abe70 100644 --- a/src/display/highlight_worker.js +++ b/src/display/highlight_worker.js @@ -13,24 +13,24 @@ export function startWorker(cm, time) { } function highlightWorker(cm) { - var doc = cm.doc + let doc = cm.doc if (doc.frontier < doc.first) doc.frontier = doc.first if (doc.frontier >= cm.display.viewTo) return - var end = +new Date + cm.options.workTime - var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)) - var changedLines = [] + let end = +new Date + cm.options.workTime + let state = copyState(doc.mode, getStateBefore(cm, doc.frontier)) + let changedLines = [] doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { if (doc.frontier >= cm.display.viewFrom) { // Visible - var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength - var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true) + let oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength + let highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true) line.styles = highlighted.styles - var oldCls = line.styleClasses, newCls = highlighted.classes + let oldCls = line.styleClasses, newCls = highlighted.classes if (newCls) line.styleClasses = newCls else if (oldCls) line.styleClasses = null - var ischange = !oldStyles || oldStyles.length != line.styles.length || + let ischange = !oldStyles || oldStyles.length != line.styles.length || oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass) - for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i] + for (let i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i] if (ischange) changedLines.push(doc.frontier) line.stateAfter = tooLong ? state : copyState(doc.mode, state) } else { @@ -45,7 +45,7 @@ function highlightWorker(cm) { } }) if (changedLines.length) runInOp(cm, function() { - for (var i = 0; i < changedLines.length; i++) + for (let i = 0; i < changedLines.length; i++) regLineChange(cm, changedLines[i], "text") }) } diff --git a/src/display/line_numbers.js b/src/display/line_numbers.js index 22bd32ffc4..c48f2204d5 100644 --- a/src/display/line_numbers.js +++ b/src/display/line_numbers.js @@ -7,19 +7,19 @@ import { updateGutterSpace } from "./update_display" // Re-align line numbers and gutter marks to compensate for // horizontal scrolling. export function alignHorizontally(cm) { - var display = cm.display, view = display.view + let display = cm.display, view = display.view if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return - var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft - var gutterW = display.gutters.offsetWidth, left = comp + "px" - for (var i = 0; i < view.length; i++) if (!view[i].hidden) { + let comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft + let gutterW = display.gutters.offsetWidth, left = comp + "px" + for (let i = 0; i < view.length; i++) if (!view[i].hidden) { if (cm.options.fixedGutter) { if (view[i].gutter) view[i].gutter.style.left = left if (view[i].gutterBackground) view[i].gutterBackground.style.left = left } - var align = view[i].alignable - if (align) for (var j = 0; j < align.length; j++) + let align = view[i].alignable + if (align) for (let j = 0; j < align.length; j++) align[j].style.left = left } if (cm.options.fixedGutter) @@ -31,11 +31,11 @@ export function alignHorizontally(cm) { // is needed. export function maybeUpdateLineNumberWidth(cm) { if (!cm.options.lineNumbers) return false - var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display + let doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display if (last.length != display.lineNumChars) { - var test = display.measure.appendChild(elt("div", [elt("div", last)], + let test = display.measure.appendChild(elt("div", [elt("div", last)], "CodeMirror-linenumber CodeMirror-gutter-elt")) - var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW + let innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW display.lineGutter.style.width = "" display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1 display.lineNumWidth = display.lineNumInnerWidth + padding diff --git a/src/display/operations.js b/src/display/operations.js index 2873e0e91d..cc6eef7bde 100644 --- a/src/display/operations.js +++ b/src/display/operations.js @@ -20,7 +20,7 @@ import { updateHeightsInViewport } from "./update_lines" // error-prone). Instead, display updates are batched and then all // combined and executed at once. -var nextOpId = 0 +let nextOpId = 0 // Start a new operation. export function startOperation(cm) { cm.curOp = { @@ -45,9 +45,9 @@ export function startOperation(cm) { // Finish an operation, updating the display and signalling delayed events export function endOperation(cm) { - var op = cm.curOp + let op = cm.curOp finishOperation(op, function(group) { - for (var i = 0; i < group.ops.length; i++) + for (let i = 0; i < group.ops.length; i++) group.ops[i].cm.curOp = null endOperations(group) }) @@ -56,21 +56,21 @@ export function endOperation(cm) { // The DOM updates done when an operation finishes are batched so // that the minimum number of relayouts are required. function endOperations(group) { - var ops = group.ops - for (var i = 0; i < ops.length; i++) // Read DOM + let ops = group.ops + for (let i = 0; i < ops.length; i++) // Read DOM endOperation_R1(ops[i]) - for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + for (let i = 0; i < ops.length; i++) // Write DOM (maybe) endOperation_W1(ops[i]) - for (var i = 0; i < ops.length; i++) // Read DOM + for (let i = 0; i < ops.length; i++) // Read DOM endOperation_R2(ops[i]) - for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + for (let i = 0; i < ops.length; i++) // Write DOM (maybe) endOperation_W2(ops[i]) - for (var i = 0; i < ops.length; i++) // Read DOM + for (let i = 0; i < ops.length; i++) // Read DOM endOperation_finish(ops[i]) } function endOperation_R1(op) { - var cm = op.cm, display = cm.display + let cm = op.cm, display = cm.display maybeClipScrollbars(cm) if (op.updateMaxLine) findMaxLine(cm) @@ -87,7 +87,7 @@ function endOperation_W1(op) { } function endOperation_R2(op) { - var cm = op.cm, display = cm.display + let cm = op.cm, display = cm.display if (op.updatedDisplay) updateHeightsInViewport(cm) op.barMeasure = measureForScrollbars(cm) @@ -108,7 +108,7 @@ function endOperation_R2(op) { } function endOperation_W2(op) { - var cm = op.cm + let cm = op.cm if (op.adjustWidthTo != null) { cm.display.sizer.style.minWidth = op.adjustWidthTo + "px" @@ -117,7 +117,7 @@ function endOperation_W2(op) { cm.display.maxLineChanged = false } - var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus()) + let takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus()) if (op.preparedSelection) cm.display.input.showSelection(op.preparedSelection, takeFocus) if (op.updatedDisplay || op.startHeight != cm.doc.height) @@ -133,7 +133,7 @@ function endOperation_W2(op) { } function endOperation_finish(op) { - var cm = op.cm, display = cm.display, doc = cm.doc + let cm = op.cm, display = cm.display, doc = cm.doc if (op.updatedDisplay) postUpdateDisplay(cm, op.update) @@ -155,17 +155,17 @@ function endOperation_finish(op) { } // If we need to scroll a specific position into view, do so. if (op.scrollToPos) { - var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), + let coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin) if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords) } // Fire events for markers that are hidden/unidden by editing or // undoing - var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers - if (hidden) for (var i = 0; i < hidden.length; ++i) + let hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers + if (hidden) for (let i = 0; i < hidden.length; ++i) if (!hidden[i].lines.length) signal(hidden[i], "hide") - if (unhidden) for (var i = 0; i < unhidden.length; ++i) + if (unhidden) for (let i = 0; i < unhidden.length; ++i) if (unhidden[i].lines.length) signal(unhidden[i], "unhide") if (display.wrapper.offsetHeight) @@ -206,7 +206,7 @@ export function methodOp(f) { } export function docMethodOp(f) { return function() { - var cm = this.cm + let cm = this.cm if (!cm || cm.curOp) return f.apply(this, arguments) startOperation(cm) try { return f.apply(this, arguments) } diff --git a/src/display/scroll_events.js b/src/display/scroll_events.js index 99afe7ee50..3c166b4855 100644 --- a/src/display/scroll_events.js +++ b/src/display/scroll_events.js @@ -38,7 +38,7 @@ export function setScrollLeft(cm, val, isScroller) { // is that it gives us a chance to update the display before the // actual scrolling happens, reducing flickering. -var wheelSamples = 0, wheelPixelsPerUnit = null +let wheelSamples = 0, wheelPixelsPerUnit = null // Fill in a browser-detected starting value on browsers where we // know one. These don't have to be accurate -- the result of them // being wrong would just be a slight flicker on the first wheel @@ -48,27 +48,27 @@ else if (gecko) wheelPixelsPerUnit = 15 else if (chrome) wheelPixelsPerUnit = -.7 else if (safari) wheelPixelsPerUnit = -1/3 -var wheelEventDelta = function(e) { - var dx = e.wheelDeltaX, dy = e.wheelDeltaY +let wheelEventDelta = function(e) { + let dx = e.wheelDeltaX, dy = e.wheelDeltaY if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail else if (dy == null) dy = e.wheelDelta return {x: dx, y: dy} } export function wheelEventPixels(e) { - var delta = wheelEventDelta(e) + let delta = wheelEventDelta(e) delta.x *= wheelPixelsPerUnit delta.y *= wheelPixelsPerUnit return delta } export function onScrollWheel(cm, e) { - var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y + let delta = wheelEventDelta(e), dx = delta.x, dy = delta.y - var display = cm.display, scroll = display.scroller + let display = cm.display, scroll = display.scroller // Quit if there's nothing to scroll here - var canScrollX = scroll.scrollWidth > scroll.clientWidth - var canScrollY = scroll.scrollHeight > scroll.clientHeight + let canScrollX = scroll.scrollWidth > scroll.clientWidth + let canScrollY = scroll.scrollHeight > scroll.clientHeight if (!(dx && canScrollX || dy && canScrollY)) return // Webkit browsers on OS X abort momentum scrolls when the target @@ -76,8 +76,8 @@ export function onScrollWheel(cm, e) { // This hack (see related code in patchDisplay) makes sure the // element is kept around. if (dy && mac && webkit) { - outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { - for (var i = 0; i < view.length; i++) { + outer: for (let cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { + for (let i = 0; i < view.length; i++) { if (view[i].node == cur) { cm.display.currentWheelTarget = cur break outer @@ -109,8 +109,8 @@ export function onScrollWheel(cm, e) { // 'Project' the visible viewport to cover the area that is being // scrolled into view (if we know enough to estimate it). if (dy && wheelPixelsPerUnit != null) { - var pixels = dy * wheelPixelsPerUnit - var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight + let pixels = dy * wheelPixelsPerUnit + let top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight if (pixels < 0) top = Math.max(0, top + pixels - 50) else bot = Math.min(cm.doc.height, bot + pixels + 50) updateDisplaySimple(cm, {top: top, bottom: bot}) @@ -122,9 +122,9 @@ export function onScrollWheel(cm, e) { display.wheelDX = dx; display.wheelDY = dy setTimeout(function() { if (display.wheelStartX == null) return - var movedX = scroll.scrollLeft - display.wheelStartX - var movedY = scroll.scrollTop - display.wheelStartY - var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || + let movedX = scroll.scrollLeft - display.wheelStartX + let movedY = scroll.scrollTop - display.wheelStartY + let sample = (movedY && display.wheelDY && movedY / display.wheelDY) || (movedX && display.wheelDX && movedX / display.wheelDX) display.wheelStartX = display.wheelStartY = null if (!sample) return diff --git a/src/display/scrollbars.js b/src/display/scrollbars.js index 075ae41a1b..a07f2a165d 100644 --- a/src/display/scrollbars.js +++ b/src/display/scrollbars.js @@ -12,8 +12,8 @@ import { setScrollLeft, setScrollTop } from "./scroll_events" // Prepare DOM reads needed to update the scrollbars. Done in one // shot to minimize update/measure roundtrips. export function measureForScrollbars(cm) { - var d = cm.display, gutterW = d.gutters.offsetWidth - var docH = Math.round(cm.doc.height + paddingVert(cm.display)) + let d = cm.display, gutterW = d.gutters.offsetWidth + let docH = Math.round(cm.doc.height + paddingVert(cm.display)) return { clientHeight: d.scroller.clientHeight, viewHeight: d.wrapper.clientHeight, @@ -29,8 +29,8 @@ export function measureForScrollbars(cm) { function NativeScrollbars(place, scroll, cm) { this.cm = cm - var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar") - var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar") + let vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar") + let horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar") place(vert); place(horiz) on(vert, "scroll", function() { @@ -47,14 +47,14 @@ function NativeScrollbars(place, scroll, cm) { NativeScrollbars.prototype = copyObj({ update: function(measure) { - var needsH = measure.scrollWidth > measure.clientWidth + 1 - var needsV = measure.scrollHeight > measure.clientHeight + 1 - var sWidth = measure.nativeBarWidth + let needsH = measure.scrollWidth > measure.clientWidth + 1 + let needsV = measure.scrollHeight > measure.clientHeight + 1 + let sWidth = measure.nativeBarWidth if (needsV) { this.vert.style.display = "block" this.vert.style.bottom = needsH ? sWidth + "px" : "0" - var totalHeight = measure.viewHeight - (needsH ? sWidth : 0) + let totalHeight = measure.viewHeight - (needsH ? sWidth : 0) // A bug in IE8 can cause this value to be negative, so guard it. this.vert.firstChild.style.height = Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px" @@ -67,7 +67,7 @@ NativeScrollbars.prototype = copyObj({ this.horiz.style.display = "block" this.horiz.style.right = needsV ? sWidth + "px" : "0" this.horiz.style.left = measure.barLeft + "px" - var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0) + let totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0) this.horiz.firstChild.style.width = (measure.scrollWidth - measure.clientWidth + totalWidth) + "px" } else { @@ -91,7 +91,7 @@ NativeScrollbars.prototype = copyObj({ if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert) }, zeroWidthHack: function() { - var w = mac && !mac_geMountainLion ? "12px" : "18px" + let w = mac && !mac_geMountainLion ? "12px" : "18px" this.horiz.style.height = this.vert.style.width = w this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none" this.disableHoriz = new Delayed @@ -106,15 +106,15 @@ NativeScrollbars.prototype = copyObj({ // itself (when the bar is still visible) or its filler child // (when the bar is hidden). If it is still visible, we keep // it enabled, if it's hidden, we disable pointer events. - var box = bar.getBoundingClientRect() - var elt = document.elementFromPoint(box.left + 1, box.bottom - 1) + let box = bar.getBoundingClientRect() + let elt = document.elementFromPoint(box.left + 1, box.bottom - 1) if (elt != bar) bar.style.pointerEvents = "none" else delay.set(1000, maybeDisable) } delay.set(1000, maybeDisable) }, clear: function() { - var parent = this.horiz.parentNode + let parent = this.horiz.parentNode parent.removeChild(this.horiz) parent.removeChild(this.vert) } @@ -131,9 +131,9 @@ NullScrollbars.prototype = copyObj({ export function updateScrollbars(cm, measure) { if (!measure) measure = measureForScrollbars(cm) - var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight + let startWidth = cm.display.barWidth, startHeight = cm.display.barHeight updateScrollbarsInner(cm, measure) - for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { + for (let i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { if (startWidth != cm.display.barWidth && cm.options.lineWrapping) updateHeightsInViewport(cm) updateScrollbarsInner(cm, measureForScrollbars(cm)) @@ -144,8 +144,8 @@ export function updateScrollbars(cm, measure) { // Re-synchronize the fake scrollbars with the actual size of the // content. function updateScrollbarsInner(cm, measure) { - var d = cm.display - var sizes = d.scrollbars.update(measure) + let d = cm.display + let sizes = d.scrollbars.update(measure) d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px" d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px" @@ -163,7 +163,7 @@ function updateScrollbarsInner(cm, measure) { } else d.gutterFiller.style.display = "" } -export var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars} +export let scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars} export function initScrollbars(cm) { if (cm.display.scrollbars) { diff --git a/src/display/scrolling.js b/src/display/scrolling.js index ec8cec6715..d58efe0bcf 100644 --- a/src/display/scrolling.js +++ b/src/display/scrolling.js @@ -13,11 +13,11 @@ import { setScrollLeft, setScrollTop } from "./scroll_events" export function maybeScrollWindow(cm, coords) { if (signalDOMEvent(cm, "scrollCursorIntoView")) return - var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null + let display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null if (coords.top + box.top < 0) doScroll = true else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false if (doScroll != null && !phantom) { - var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + + let scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " + coords.left + "px; width: 2px;") @@ -32,14 +32,16 @@ export function maybeScrollWindow(cm, coords) { // measured, the position of something may 'drift' during drawing). export function scrollPosIntoView(cm, pos, end, margin) { if (margin == null) margin = 0 - for (var limit = 0; limit < 5; limit++) { - var changed = false, coords = cursorCoords(cm, pos) - var endCoords = !end || end == pos ? coords : cursorCoords(cm, end) - var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), + let coords + for (let limit = 0; limit < 5; limit++) { + let changed = false + coords = cursorCoords(cm, pos) + let endCoords = !end || end == pos ? coords : cursorCoords(cm, end) + let scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), Math.min(coords.top, endCoords.top) - margin, Math.max(coords.left, endCoords.left), Math.max(coords.bottom, endCoords.bottom) + margin) - var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft + let startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft if (scrollPos.scrollTop != null) { setScrollTop(cm, scrollPos.scrollTop) if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true @@ -55,7 +57,7 @@ export function scrollPosIntoView(cm, pos, end, margin) { // Scroll a given set of coordinates into view (immediately). export function scrollIntoView(cm, x1, y1, x2, y2) { - var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2) + let scrollPos = calculateScrollPos(cm, x1, y1, x2, y2) if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop) if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft) } @@ -65,23 +67,23 @@ export function scrollIntoView(cm, x1, y1, x2, y2) { // scrollLeft properties. When these are undefined, the // vertical/horizontal position does not need to be adjusted. export function calculateScrollPos(cm, x1, y1, x2, y2) { - var display = cm.display, snapMargin = textHeight(cm.display) + let display = cm.display, snapMargin = textHeight(cm.display) if (y1 < 0) y1 = 0 - var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop - var screen = displayHeight(cm), result = {} + let screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop + let screen = displayHeight(cm), result = {} if (y2 - y1 > screen) y2 = y1 + screen - var docBottom = cm.doc.height + paddingVert(display) - var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin + let docBottom = cm.doc.height + paddingVert(display) + let atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin if (y1 < screentop) { result.scrollTop = atTop ? 0 : y1 } else if (y2 > screentop + screen) { - var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen) + let newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen) if (newTop != screentop) result.scrollTop = newTop } - var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft - var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0) - var tooWide = x2 - x1 > screenw + let screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft + let screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0) + let tooWide = x2 - x1 > screenw if (tooWide) x2 = x1 + screenw if (x1 < 10) result.scrollLeft = 0 @@ -106,7 +108,7 @@ export function addToScrollPos(cm, left, top) { // shown. export function ensureCursorVisible(cm) { resolveScrollToPos(cm) - var cur = cm.getCursor(), from = cur, to = cur + let cur = cm.getCursor(), from = cur, to = cur if (!cm.options.lineWrapping) { from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur to = Pos(cur.line, cur.ch + 1) @@ -119,11 +121,11 @@ export function ensureCursorVisible(cm) { // 'simulates' scrolling that position into view in a cheap way, so // that the effect of intermediate scroll commands is not ignored. export function resolveScrollToPos(cm) { - var range = cm.curOp.scrollToPos + let range = cm.curOp.scrollToPos if (range) { cm.curOp.scrollToPos = null - var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to) - var sPos = calculateScrollPos(cm, Math.min(from.left, to.left), + let from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to) + let sPos = calculateScrollPos(cm, Math.min(from.left, to.left), Math.min(from.top, to.top) - range.margin, Math.max(from.right, to.right), Math.max(from.bottom, to.bottom) + range.margin) diff --git a/src/display/selection.js b/src/display/selection.js index 3ee79fa358..9fa8f6eefb 100644 --- a/src/display/selection.js +++ b/src/display/selection.js @@ -10,15 +10,15 @@ export function updateSelection(cm) { } export function prepareSelection(cm, primary) { - var doc = cm.doc, result = {} - var curFragment = result.cursors = document.createDocumentFragment() - var selFragment = result.selection = document.createDocumentFragment() + let doc = cm.doc, result = {} + let curFragment = result.cursors = document.createDocumentFragment() + let selFragment = result.selection = document.createDocumentFragment() - for (var i = 0; i < doc.sel.ranges.length; i++) { + for (let i = 0; i < doc.sel.ranges.length; i++) { if (primary === false && i == doc.sel.primIndex) continue - var range = doc.sel.ranges[i] + let range = doc.sel.ranges[i] if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue - var collapsed = range.empty() + let collapsed = range.empty() if (collapsed || cm.options.showCursorWhenSelecting) drawSelectionCursor(cm, range.head, curFragment) if (!collapsed) @@ -29,16 +29,16 @@ export function prepareSelection(cm, primary) { // Draws a cursor for the given range export function drawSelectionCursor(cm, head, output) { - var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine) + let pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine) - var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")) + let cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")) cursor.style.left = pos.left + "px" cursor.style.top = pos.top + "px" cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px" if (pos.other) { // Secondary cursor, shown when on a 'jump' in bi-directional text - var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")) + let otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")) otherCursor.style.display = "" otherCursor.style.left = pos.other.left + "px" otherCursor.style.top = pos.other.top + "px" @@ -48,10 +48,10 @@ export function drawSelectionCursor(cm, head, output) { // Draws the given range as a highlighted selection function drawSelectionRange(cm, range, output) { - var display = cm.display, doc = cm.doc - var fragment = document.createDocumentFragment() - var padding = paddingH(cm.display), leftSide = padding.left - var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right + let display = cm.display, doc = cm.doc + let fragment = document.createDocumentFragment() + let padding = paddingH(cm.display), leftSide = padding.left + let rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right function add(left, top, width, bottom) { if (top < 0) top = 0 @@ -63,21 +63,21 @@ function drawSelectionRange(cm, range, output) { } function drawForLine(line, fromArg, toArg) { - var lineObj = getLine(doc, line) - var lineLen = lineObj.text.length - var start, end + let lineObj = getLine(doc, line) + let lineLen = lineObj.text.length + let start, end function coords(ch, bias) { return charCoords(cm, Pos(line, ch), "div", lineObj, bias) } iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { - var leftPos = coords(from, "left"), rightPos, left, right + let leftPos = coords(from, "left"), rightPos, left, right if (from == to) { rightPos = leftPos left = right = leftPos.left } else { rightPos = coords(to - 1, "right") - if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp } + if (dir == "rtl") { let tmp = leftPos; leftPos = rightPos; rightPos = tmp } left = leftPos.left right = rightPos.right } @@ -98,14 +98,14 @@ function drawSelectionRange(cm, range, output) { return {start: start, end: end} } - var sFrom = range.from(), sTo = range.to() + let sFrom = range.from(), sTo = range.to() if (sFrom.line == sTo.line) { drawForLine(sFrom.line, sFrom.ch, sTo.ch) } else { - var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line) - var singleVLine = visualLine(fromLine) == visualLine(toLine) - var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end - var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start + let fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line) + let singleVLine = visualLine(fromLine) == visualLine(toLine) + let leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end + let rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start if (singleVLine) { if (leftEnd.top < rightStart.top - 2) { add(leftEnd.right, leftEnd.top, null, leftEnd.bottom) @@ -124,9 +124,9 @@ function drawSelectionRange(cm, range, output) { // Cursor-blinking export function restartBlink(cm) { if (!cm.state.focused) return - var display = cm.display + let display = cm.display clearInterval(display.blinker) - var on = true + let on = true display.cursorDiv.style.visibility = "" if (cm.options.cursorBlinkRate > 0) display.blinker = setInterval(function() { diff --git a/src/display/update_display.js b/src/display/update_display.js index 06551eec8a..a8d6a4de13 100644 --- a/src/display/update_display.js +++ b/src/display/update_display.js @@ -18,7 +18,7 @@ import { adjustView, countDirtyView, resetView } from "./view_tracking" // DISPLAY DRAWING export function DisplayUpdate(cm, viewport, force) { - var display = cm.display + let display = cm.display this.viewport = viewport // Store some values that we'll need later (but don't want to force a relayout for) @@ -37,12 +37,12 @@ DisplayUpdate.prototype.signal = function(emitter, type) { this.events.push(arguments) } DisplayUpdate.prototype.finish = function() { - for (var i = 0; i < this.events.length; i++) + for (let i = 0; i < this.events.length; i++) signal.apply(null, this.events[i]) } export function maybeClipScrollbars(cm) { - var display = cm.display + let display = cm.display if (!display.scrollbarsClipped && display.scroller.offsetWidth) { display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth display.heightForcer.style.height = scrollGap(cm) + "px" @@ -56,7 +56,7 @@ export function maybeClipScrollbars(cm) { // (returning false) when there is nothing to be done and forced is // false. export function updateDisplayIfNeeded(cm, update) { - var display = cm.display, doc = cm.doc + let display = cm.display, doc = cm.doc if (update.editorIsHidden) { resetView(cm) @@ -76,9 +76,9 @@ export function updateDisplayIfNeeded(cm, update) { } // Compute a suitable new viewport (from & to) - var end = doc.first + doc.size - var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first) - var to = Math.min(end, update.visible.to + cm.options.viewportMargin) + let end = doc.first + doc.size + let from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first) + let to = Math.min(end, update.visible.to + cm.options.viewportMargin) if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom) if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo) if (sawCollapsedSpans) { @@ -86,7 +86,7 @@ export function updateDisplayIfNeeded(cm, update) { to = visualLineEndNo(cm.doc, to) } - var different = from != display.viewFrom || to != display.viewTo || + let different = from != display.viewFrom || to != display.viewTo || display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth adjustView(cm, from, to) @@ -94,14 +94,14 @@ export function updateDisplayIfNeeded(cm, update) { // Position the mover div to align with the current scroll position cm.display.mover.style.top = display.viewOffset + "px" - var toUpdate = countDirtyView(cm) + let toUpdate = countDirtyView(cm) if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) return false // For big changes, we hide the enclosing element during the // update, since that speeds up the operations on most browsers. - var focused = activeElt() + let focused = activeElt() if (toUpdate > 4) display.lineDiv.style.display = "none" patchDisplay(cm, display.updateLineNumbers, update.dims) if (toUpdate > 4) display.lineDiv.style.display = "" @@ -128,9 +128,9 @@ export function updateDisplayIfNeeded(cm, update) { } export function postUpdateDisplay(cm, update) { - var viewport = update.viewport + let viewport = update.viewport - for (var first = true;; first = false) { + for (let first = true;; first = false) { if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { // Clip forced viewport to actual scrollable area. if (viewport && viewport.top != null) @@ -143,7 +143,7 @@ export function postUpdateDisplay(cm, update) { } if (!updateDisplayIfNeeded(cm, update)) break updateHeightsInViewport(cm) - var barMeasure = measureForScrollbars(cm) + let barMeasure = measureForScrollbars(cm) updateSelection(cm) updateScrollbars(cm, barMeasure) setDocumentHeight(cm, barMeasure) @@ -157,11 +157,11 @@ export function postUpdateDisplay(cm, update) { } export function updateDisplaySimple(cm, viewport) { - var update = new DisplayUpdate(cm, viewport) + let update = new DisplayUpdate(cm, viewport) if (updateDisplayIfNeeded(cm, update)) { updateHeightsInViewport(cm) postUpdateDisplay(cm, update) - var barMeasure = measureForScrollbars(cm) + let barMeasure = measureForScrollbars(cm) updateSelection(cm) updateScrollbars(cm, barMeasure) setDocumentHeight(cm, barMeasure) @@ -174,11 +174,11 @@ export function updateDisplaySimple(cm, viewport) { // that are not there yet, and updating the ones that are out of // date. function patchDisplay(cm, updateNumbersFrom, dims) { - var display = cm.display, lineNumbers = cm.options.lineNumbers - var container = display.lineDiv, cur = container.firstChild + let display = cm.display, lineNumbers = cm.options.lineNumbers + let container = display.lineDiv, cur = container.firstChild function rm(node) { - var next = node.nextSibling + let next = node.nextSibling // Works around a throw-scroll bug in OS X Webkit if (webkit && mac && cm.display.currentWheelTarget == node) node.style.display = "none" @@ -187,18 +187,18 @@ function patchDisplay(cm, updateNumbersFrom, dims) { return next } - var view = display.view, lineN = display.viewFrom + let view = display.view, lineN = display.viewFrom // Loop over the elements in the view, syncing cur (the DOM nodes // in display.lineDiv) with the view as we go. - for (var i = 0; i < view.length; i++) { - var lineView = view[i] + for (let i = 0; i < view.length; i++) { + let lineView = view[i] if (lineView.hidden) { } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet - var node = buildLineElement(cm, lineView, lineN, dims) + let node = buildLineElement(cm, lineView, lineN, dims) container.insertBefore(node, cur) } else { // Already drawn while (cur != lineView.node) cur = rm(cur) - var updateNumber = lineNumbers && updateNumbersFrom != null && + let updateNumber = lineNumbers && updateNumbersFrom != null && updateNumbersFrom <= lineN && lineView.lineNumber if (lineView.changes) { if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false @@ -216,7 +216,7 @@ function patchDisplay(cm, updateNumbersFrom, dims) { } export function updateGutterSpace(cm) { - var width = cm.display.gutters.offsetWidth + let width = cm.display.gutters.offsetWidth cm.display.sizer.style.marginLeft = width + "px" } diff --git a/src/display/update_lines.js b/src/display/update_lines.js index 8de0698c6f..095cddef3f 100644 --- a/src/display/update_lines.js +++ b/src/display/update_lines.js @@ -6,25 +6,25 @@ import { ie, ie_version } from "../util/browser" // Read the actual heights of the rendered lines, and update their // stored heights to match. export function updateHeightsInViewport(cm) { - var display = cm.display - var prevBottom = display.lineDiv.offsetTop - for (var i = 0; i < display.view.length; i++) { - var cur = display.view[i], height + let display = cm.display + let prevBottom = display.lineDiv.offsetTop + for (let i = 0; i < display.view.length; i++) { + let cur = display.view[i], height if (cur.hidden) continue if (ie && ie_version < 8) { - var bot = cur.node.offsetTop + cur.node.offsetHeight + let bot = cur.node.offsetTop + cur.node.offsetHeight height = bot - prevBottom prevBottom = bot } else { - var box = cur.node.getBoundingClientRect() + let box = cur.node.getBoundingClientRect() height = box.bottom - box.top } - var diff = cur.line.height - height + let diff = cur.line.height - height if (height < 2) height = textHeight(display) if (diff > .001 || diff < -.001) { updateLineHeight(cur.line, height) updateWidgetHeight(cur.line) - if (cur.rest) for (var j = 0; j < cur.rest.length; j++) + if (cur.rest) for (let j = 0; j < cur.rest.length; j++) updateWidgetHeight(cur.rest[j]) } } @@ -33,7 +33,7 @@ export function updateHeightsInViewport(cm) { // Read and store the height of line widgets associated with the // given line. function updateWidgetHeight(line) { - if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) + if (line.widgets) for (let i = 0; i < line.widgets.length; ++i) line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight } @@ -41,15 +41,15 @@ function updateWidgetHeight(line) { // the the current scroll position). viewport may contain top, // height, and ensure (see op.scrollToPos) properties. export function visibleLines(display, doc, viewport) { - var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop + let top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop top = Math.floor(top - paddingTop(display)) - var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight + let bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight - var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom) + let from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom) // Ensure is a {from: {line, ch}, to: {line, ch}} object, and // forces those lines into the viewport (if possible). if (viewport && viewport.ensure) { - var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line + let ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line if (ensureFrom < from) { from = ensureFrom to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight) diff --git a/src/display/view_tracking.js b/src/display/view_tracking.js index d7ca682b1e..b9abd2fc40 100644 --- a/src/display/view_tracking.js +++ b/src/display/view_tracking.js @@ -15,7 +15,7 @@ export function regChange(cm, from, to, lendiff) { if (to == null) to = cm.doc.first + cm.doc.size if (!lendiff) lendiff = 0 - var display = cm.display + let display = cm.display if (lendiff && to < display.viewTo && (display.updateLineNumbers == null || display.updateLineNumbers > from)) display.updateLineNumbers = from @@ -35,7 +35,7 @@ export function regChange(cm, from, to, lendiff) { } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap resetView(cm) } else if (from <= display.viewFrom) { // Top overlap - var cut = viewCuttingPoint(cm, to, to + lendiff, 1) + let cut = viewCuttingPoint(cm, to, to + lendiff, 1) if (cut) { display.view = display.view.slice(cut.index) display.viewFrom = cut.lineN @@ -44,7 +44,7 @@ export function regChange(cm, from, to, lendiff) { resetView(cm) } } else if (to >= display.viewTo) { // Bottom overlap - var cut = viewCuttingPoint(cm, from, from, -1) + let cut = viewCuttingPoint(cm, from, from, -1) if (cut) { display.view = display.view.slice(0, cut.index) display.viewTo = cut.lineN @@ -52,8 +52,8 @@ export function regChange(cm, from, to, lendiff) { resetView(cm) } } else { // Gap in the middle - var cutTop = viewCuttingPoint(cm, from, from, -1) - var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1) + let cutTop = viewCuttingPoint(cm, from, from, -1) + let cutBot = viewCuttingPoint(cm, to, to + lendiff, 1) if (cutTop && cutBot) { display.view = display.view.slice(0, cutTop.index) .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) @@ -64,7 +64,7 @@ export function regChange(cm, from, to, lendiff) { } } - var ext = display.externalMeasured + let ext = display.externalMeasured if (ext) { if (to < ext.lineN) ext.lineN += lendiff @@ -77,14 +77,14 @@ export function regChange(cm, from, to, lendiff) { // "gutter", "class", "widget" export function regLineChange(cm, line, type) { cm.curOp.viewChanged = true - var display = cm.display, ext = cm.display.externalMeasured + let display = cm.display, ext = cm.display.externalMeasured if (ext && line >= ext.lineN && line < ext.lineN + ext.size) display.externalMeasured = null if (line < display.viewFrom || line >= display.viewTo) return - var lineView = display.view[findViewIndex(cm, line)] + let lineView = display.view[findViewIndex(cm, line)] if (lineView.node == null) return - var arr = lineView.changes || (lineView.changes = []) + let arr = lineView.changes || (lineView.changes = []) if (indexOf(arr, type) == -1) arr.push(type) } @@ -96,10 +96,11 @@ export function resetView(cm) { } function viewCuttingPoint(cm, oldN, newN, dir) { - var index = findViewIndex(cm, oldN), diff, view = cm.display.view + let index = findViewIndex(cm, oldN), diff, view = cm.display.view if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) return {index: index, lineN: newN} - for (var i = 0, n = cm.display.viewFrom; i < index; i++) + let n = cm.display.viewFrom + for (let i = 0; i < index; i++) n += view[i].size if (n != oldN) { if (dir > 0) { @@ -122,7 +123,7 @@ function viewCuttingPoint(cm, oldN, newN, dir) { // Force the view to cover a given range, adding empty view element // or clipping off existing ones as needed. export function adjustView(cm, from, to) { - var display = cm.display, view = display.view + let display = cm.display, view = display.view if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { display.view = buildViewArray(cm, from, to) display.viewFrom = from @@ -143,9 +144,9 @@ export function adjustView(cm, from, to) { // Count the number of lines in the view whose DOM representation is // out of date (or nonexistent). export function countDirtyView(cm) { - var view = cm.display.view, dirty = 0 - for (var i = 0; i < view.length; i++) { - var lineView = view[i] + let view = cm.display.view, dirty = 0 + for (let i = 0; i < view.length; i++) { + let lineView = view[i] if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty } return dirty diff --git a/src/edit/CodeMirror.js b/src/edit/CodeMirror.js index ee549d54c8..90650ff059 100644 --- a/src/edit/CodeMirror.js +++ b/src/edit/CodeMirror.js @@ -34,12 +34,12 @@ export function CodeMirror(place, options) { copyObj(defaults, options, false) setGuttersForLineNumbers(options) - var doc = options.value + let doc = options.value if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator) this.doc = doc - var input = new CodeMirror.inputStyles[options.inputStyle](this) - var display = this.display = new Display(place, doc, input) + let input = new CodeMirror.inputStyles[options.inputStyle](this) + let display = this.display = new Display(place, doc, input) display.wrapper.CodeMirror = this updateGutters(this) themeChanged(this) @@ -64,7 +64,7 @@ export function CodeMirror(place, options) { specialChars: null } - var cm = this + let cm = this // Override magic textarea content restore that IE sometimes does // on our hidden textarea on reload @@ -82,11 +82,11 @@ export function CodeMirror(place, options) { else onBlur(this) - for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) + for (let opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) optionHandlers[opt](this, options[opt], Init) maybeUpdateLineNumberWidth(this) if (options.finishInit) options.finishInit(this) - for (var i = 0; i < initHooks.length; ++i) initHooks[i](this) + for (let i = 0; i < initHooks.length; ++i) initHooks[i](this) endOperation(this) // Suppress optimizelegibility in Webkit, since it breaks text // measuring on line wrapping boundaries. @@ -104,16 +104,16 @@ export default CodeMirror // Attach the necessary event handlers when initializing the editor function registerEventHandlers(cm) { - var d = cm.display + let d = cm.display on(d.scroller, "mousedown", operation(cm, onMouseDown)) // Older IE's will not fire a second mousedown for a double click if (ie && ie_version < 11) on(d.scroller, "dblclick", operation(cm, function(e) { if (signalDOMEvent(cm, e)) return - var pos = posFromMouse(cm, e) + let pos = posFromMouse(cm, e) if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return e_preventDefault(e) - var word = cm.findWordAt(pos) + let word = cm.findWordAt(pos) extendSelection(cm.doc, word.anchor, word.head) })) else @@ -124,7 +124,7 @@ function registerEventHandlers(cm) { if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e)}) // Used to suppress mouse event handling when a touch happens - var touchFinished, prevTouch = {end: 0} + let touchFinished, prevTouch = {end: 0} function finishTouch() { if (d.activeTouch) { touchFinished = setTimeout(function() {d.activeTouch = null}, 1000) @@ -134,18 +134,18 @@ function registerEventHandlers(cm) { } function isMouseLikeTouchEvent(e) { if (e.touches.length != 1) return false - var touch = e.touches[0] + let touch = e.touches[0] return touch.radiusX <= 1 && touch.radiusY <= 1 } function farAway(touch, other) { if (other.left == null) return true - var dx = other.left - touch.left, dy = other.top - touch.top + let dx = other.left - touch.left, dy = other.top - touch.top return dx * dx + dy * dy > 20 * 20 } on(d.scroller, "touchstart", function(e) { if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) { clearTimeout(touchFinished) - var now = +new Date + let now = +new Date d.activeTouch = {start: now, moved: false, prev: now - prevTouch.end <= 300 ? prevTouch : null} if (e.touches.length == 1) { @@ -158,10 +158,10 @@ function registerEventHandlers(cm) { if (d.activeTouch) d.activeTouch.moved = true }) on(d.scroller, "touchend", function(e) { - var touch = d.activeTouch + let touch = d.activeTouch if (touch && !eventInWidget(d, e) && touch.left != null && !touch.moved && new Date - touch.start < 300) { - var pos = cm.coordsChar(d.activeTouch, "page"), range + let pos = cm.coordsChar(d.activeTouch, "page"), range if (!touch.prev || farAway(touch, touch.prev)) // Single tap range = new Range(pos, pos) else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap @@ -201,7 +201,7 @@ function registerEventHandlers(cm) { leave: function(e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm) }} } - var inp = d.input.getField() + let inp = d.input.getField() on(inp, "keyup", function(e) { onKeyUp.call(cm, e) }) on(inp, "keydown", operation(cm, onKeyDown)) on(inp, "keypress", operation(cm, onKeyPress)) @@ -209,5 +209,5 @@ function registerEventHandlers(cm) { on(inp, "blur", function (e) { onBlur(cm, e) }) } -var initHooks = [] +let initHooks = [] CodeMirror.defineInitHook = function(f) {initHooks.push(f)} diff --git a/src/edit/commands.js b/src/edit/commands.js index 2d670ab516..97a30d6d97 100644 --- a/src/edit/commands.js +++ b/src/edit/commands.js @@ -11,7 +11,7 @@ import { getOrder, lineLeft, lineRight } from "../util/bidi" // Commands are parameter-less actions that can be performed on an // editor, mostly used for keybindings. -export var commands = { +export let commands = { selectAll: selectAll, singleSelection: function(cm) { cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll) @@ -19,7 +19,7 @@ export var commands = { killLine: function(cm) { deleteNearSelection(cm, function(range) { if (range.empty()) { - var len = getLine(cm.doc, range.head.line).text.length + let len = getLine(cm.doc, range.head.line).text.length if (range.head.ch == len && range.head.line < cm.lastLine()) return {from: range.head, to: Pos(range.head.line + 1, 0)} else @@ -42,15 +42,15 @@ export var commands = { }, delWrappedLineLeft: function(cm) { deleteNearSelection(cm, function(range) { - var top = cm.charCoords(range.head, "div").top + 5 - var leftPos = cm.coordsChar({left: 0, top: top}, "div") + let top = cm.charCoords(range.head, "div").top + 5 + let leftPos = cm.coordsChar({left: 0, top: top}, "div") return {from: leftPos, to: range.from()} }) }, delWrappedLineRight: function(cm) { deleteNearSelection(cm, function(range) { - var top = cm.charCoords(range.head, "div").top + 5 - var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") + let top = cm.charCoords(range.head, "div").top + 5 + let rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") return {from: range.from(), to: rightPos } }) }, @@ -75,20 +75,20 @@ export var commands = { }, goLineRight: function(cm) { cm.extendSelectionsBy(function(range) { - var top = cm.charCoords(range.head, "div").top + 5 + let top = cm.charCoords(range.head, "div").top + 5 return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") }, sel_move) }, goLineLeft: function(cm) { cm.extendSelectionsBy(function(range) { - var top = cm.charCoords(range.head, "div").top + 5 + let top = cm.charCoords(range.head, "div").top + 5 return cm.coordsChar({left: 0, top: top}, "div") }, sel_move) }, goLineLeftSmart: function(cm) { cm.extendSelectionsBy(function(range) { - var top = cm.charCoords(range.head, "div").top + 5 - var pos = cm.coordsChar({left: 0, top: top}, "div") + let top = cm.charCoords(range.head, "div").top + 5 + let pos = cm.coordsChar({left: 0, top: top}, "div") if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head) return pos }, sel_move) @@ -116,10 +116,10 @@ export var commands = { indentLess: function(cm) {cm.indentSelection("subtract")}, insertTab: function(cm) {cm.replaceSelection("\t")}, insertSoftTab: function(cm) { - var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize - for (var i = 0; i < ranges.length; i++) { - var pos = ranges[i].from() - var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize) + let spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize + for (let i = 0; i < ranges.length; i++) { + let pos = ranges[i].from() + let col = countColumn(cm.getLine(pos.line), pos.ch, tabSize) spaces.push(spaceStr(tabSize - col % tabSize)) } cm.replaceSelections(spaces) @@ -130,9 +130,9 @@ export var commands = { }, transposeChars: function(cm) { runInOp(cm, function() { - var ranges = cm.listSelections(), newSel = [] - for (var i = 0; i < ranges.length; i++) { - var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text + let ranges = cm.listSelections(), newSel = [] + for (let i = 0; i < ranges.length; i++) { + let cur = ranges[i].head, line = getLine(cm.doc, cur.line).text if (line) { if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1) if (cur.ch > 0) { @@ -140,7 +140,7 @@ export var commands = { cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), Pos(cur.line, cur.ch - 2), cur, "+transpose") } else if (cur.line > cm.doc.first) { - var prev = getLine(cm.doc, cur.line - 1).text + let prev = getLine(cm.doc, cur.line - 1).text if (prev) cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + prev.charAt(prev.length - 1), @@ -154,11 +154,11 @@ export var commands = { }, newlineAndIndent: function(cm) { runInOp(cm, function() { - var sels = cm.listSelections() - for (var i = sels.length - 1; i >= 0; i--) + let sels = cm.listSelections() + for (let i = sels.length - 1; i >= 0; i--) cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input") sels = cm.listSelections() - for (var i = 0; i < sels.length; i++) + for (let i = 0; i < sels.length; i++) cm.indentLine(sels[i].from().line, null, true) ensureCursorVisible(cm) }) @@ -169,30 +169,30 @@ export var commands = { function lineStart(cm, lineN) { - var line = getLine(cm.doc, lineN) - var visual = visualLine(line) + let line = getLine(cm.doc, lineN) + let visual = visualLine(line) if (visual != line) lineN = lineNo(visual) - var order = getOrder(visual) - var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual) + let order = getOrder(visual) + let ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual) return Pos(lineN, ch) } function lineEnd(cm, lineN) { - var merged, line = getLine(cm.doc, lineN) + let merged, line = getLine(cm.doc, lineN) while (merged = collapsedSpanAtEnd(line)) { line = merged.find(1, true).line lineN = null } - var order = getOrder(line) - var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line) + let order = getOrder(line) + let ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line) return Pos(lineN == null ? lineNo(line) : lineN, ch) } function lineStartSmart(cm, pos) { - var start = lineStart(cm, pos.line) - var line = getLine(cm.doc, start.line) - var order = getOrder(line) + let start = lineStart(cm, pos.line) + let line = getLine(cm.doc, start.line) + let order = getOrder(line) if (!order || order[0].level == 0) { - var firstNonWS = Math.max(0, line.text.search(/\S/)) - var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch + let firstNonWS = Math.max(0, line.text.search(/\S/)) + let inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch return Pos(start.line, inWS ? 0 : firstNonWS) } return start diff --git a/src/edit/deleteNearSelection.js b/src/edit/deleteNearSelection.js index 00b4aa08b9..38c5342ff2 100644 --- a/src/edit/deleteNearSelection.js +++ b/src/edit/deleteNearSelection.js @@ -7,13 +7,13 @@ import { lst } from "../util/misc" // Helper for deleting text near the selection(s), used to implement // backspace, delete, and similar functionality. export function deleteNearSelection(cm, compute) { - var ranges = cm.doc.sel.ranges, kill = [] + let ranges = cm.doc.sel.ranges, kill = [] // Build up a set of ranges to kill first, merging overlapping // ranges. - for (var i = 0; i < ranges.length; i++) { - var toKill = compute(ranges[i]) + for (let i = 0; i < ranges.length; i++) { + let toKill = compute(ranges[i]) while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { - var replaced = kill.pop() + let replaced = kill.pop() if (cmp(replaced.from, toKill.from) < 0) { toKill.from = replaced.from break @@ -23,7 +23,7 @@ export function deleteNearSelection(cm, compute) { } // Next, remove those actual ranges. runInOp(cm, function() { - for (var i = kill.length - 1; i >= 0; i--) + for (let i = kill.length - 1; i >= 0; i--) replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete") ensureCursorVisible(cm) }) diff --git a/src/edit/drop_events.js b/src/edit/drop_events.js index d2aeaa7cef..b8024d920d 100644 --- a/src/edit/drop_events.js +++ b/src/edit/drop_events.js @@ -14,34 +14,34 @@ import { indexOf } from "../util/misc" // Kludge to work around strange IE behavior where it'll sometimes // re-fire a series of drag-related events right after the drop (#1551) -var lastDrop = 0 +let lastDrop = 0 export function onDrop(e) { - var cm = this + let cm = this clearDragCursor(cm) if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return e_preventDefault(e) if (ie) lastDrop = +new Date - var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files + let pos = posFromMouse(cm, e, true), files = e.dataTransfer.files if (!pos || cm.isReadOnly()) return // Might be a file drop, in which case we simply extract the text // and insert it. if (files && files.length && window.FileReader && window.File) { - var n = files.length, text = Array(n), read = 0 - var loadFile = function(file, i) { + let n = files.length, text = Array(n), read = 0 + let loadFile = function(file, i) { if (cm.options.allowDropFileTypes && indexOf(cm.options.allowDropFileTypes, file.type) == -1) return - var reader = new FileReader + let reader = new FileReader reader.onload = operation(cm, function() { - var content = reader.result + let content = reader.result if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "" text[i] = content if (++read == n) { pos = clipPos(cm.doc, pos) - var change = {from: pos, to: pos, + let change = {from: pos, to: pos, text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), origin: "paste"} makeChange(cm.doc, change) @@ -50,7 +50,7 @@ export function onDrop(e) { }) reader.readAsText(file) } - for (var i = 0; i < n; ++i) loadFile(files[i], i) + for (let i = 0; i < n; ++i) loadFile(files[i], i) } else { // Normal drop // Don't do a replace if the drop happened inside of the selected text. if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { @@ -60,12 +60,13 @@ export function onDrop(e) { return } try { - var text = e.dataTransfer.getData("Text") + let text = e.dataTransfer.getData("Text") if (text) { + let selected if (cm.state.draggingText && !cm.state.draggingText.copy) - var selected = cm.listSelections() + selected = cm.listSelections() setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)) - if (selected) for (var i = 0; i < selected.length; ++i) + if (selected) for (let i = 0; i < selected.length; ++i) replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag") cm.replaceSelection(text, "around", "paste") cm.display.input.focus() @@ -85,7 +86,7 @@ export function onDragStart(cm, e) { // Use dummy image instead of default browsers image. // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. if (e.dataTransfer.setDragImage && !safari) { - var img = elt("img", null, null, "position: fixed; left: 0; top: 0;") + let img = elt("img", null, null, "position: fixed; left: 0; top: 0;") img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" if (presto) { img.width = img.height = 1 @@ -99,9 +100,9 @@ export function onDragStart(cm, e) { } export function onDragOver(cm, e) { - var pos = posFromMouse(cm, e) + let pos = posFromMouse(cm, e) if (!pos) return - var frag = document.createDocumentFragment() + let frag = document.createDocumentFragment() drawSelectionCursor(cm, pos, frag) if (!cm.display.dragCursor) { cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors") diff --git a/src/edit/fromTextArea.js b/src/edit/fromTextArea.js index dda26d4bff..7d22101469 100644 --- a/src/edit/fromTextArea.js +++ b/src/edit/fromTextArea.js @@ -13,19 +13,22 @@ export function fromTextArea(textarea, options) { // Set autofocus to true if this textarea is focused, or if it has // autofocus and no other element is focused. if (options.autofocus == null) { - var hasFocus = activeElt() + let hasFocus = activeElt() options.autofocus = hasFocus == textarea || textarea.getAttribute("autofocus") != null && hasFocus == document.body } function save() {textarea.value = cm.getValue()} + + let realSubmit if (textarea.form) { on(textarea.form, "submit", save) // Deplorable hack to make the submit method do the right thing. if (!options.leaveSubmitMethodAlone) { - var form = textarea.form, realSubmit = form.submit + let form = textarea.form + realSubmit = form.submit try { - var wrappedSubmit = form.submit = function() { + let wrappedSubmit = form.submit = function() { save() form.submit = realSubmit form.submit() @@ -52,7 +55,7 @@ export function fromTextArea(textarea, options) { } textarea.style.display = "none" - var cm = CodeMirror(function(node) { + let cm = CodeMirror(function(node) { textarea.parentNode.insertBefore(node, textarea.nextSibling) }, options) return cm diff --git a/src/edit/global_events.js b/src/edit/global_events.js index 57542f2d32..a7ec22fe89 100644 --- a/src/edit/global_events.js +++ b/src/edit/global_events.js @@ -7,14 +7,14 @@ import { on } from "../util/event" function forEachCodeMirror(f) { if (!document.body.getElementsByClassName) return - var byClass = document.body.getElementsByClassName("CodeMirror") - for (var i = 0; i < byClass.length; i++) { - var cm = byClass[i].CodeMirror + let byClass = document.body.getElementsByClassName("CodeMirror") + for (let i = 0; i < byClass.length; i++) { + let cm = byClass[i].CodeMirror if (cm) f(cm) } } -var globalsRegistered = false +let globalsRegistered = false export function ensureGlobalHandlers() { if (globalsRegistered) return registerGlobalHandlers() @@ -22,7 +22,7 @@ export function ensureGlobalHandlers() { } function registerGlobalHandlers() { // When the window resizes, we need to refresh active editors. - var resizeTimer + let resizeTimer on(window, "resize", function() { if (resizeTimer == null) resizeTimer = setTimeout(function() { resizeTimer = null @@ -36,7 +36,7 @@ function registerGlobalHandlers() { } // Called when the window resizes function onResize(cm) { - var d = cm.display + let d = cm.display if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) return // Might be a text scaling operation, clear size caches. diff --git a/src/edit/key_events.js b/src/edit/key_events.js index 9a4944414c..8530aef315 100644 --- a/src/edit/key_events.js +++ b/src/edit/key_events.js @@ -19,7 +19,7 @@ function doHandleBinding(cm, bound, dropShift) { // Ensure previous input has been read, so that the handler sees a // consistent view of the document cm.display.input.ensurePolled() - var prevShift = cm.display.shift, done = false + let prevShift = cm.display.shift, done = false try { if (cm.isReadOnly()) cm.state.suppressEdits = true if (dropShift) cm.display.shift = false @@ -32,17 +32,17 @@ function doHandleBinding(cm, bound, dropShift) { } function lookupKeyForEditor(cm, name, handle) { - for (var i = 0; i < cm.state.keyMaps.length; i++) { - var result = lookupKey(name, cm.state.keyMaps[i], handle, cm) + for (let i = 0; i < cm.state.keyMaps.length; i++) { + let result = lookupKey(name, cm.state.keyMaps[i], handle, cm) if (result) return result } return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) || lookupKey(name, cm.options.keyMap, handle, cm) } -var stopSeq = new Delayed +let stopSeq = new Delayed function dispatchKey(cm, name, e, handle) { - var seq = cm.state.keySeq + let seq = cm.state.keySeq if (seq) { if (isModifierKey(name)) return "handled" stopSeq.set(50, function() { @@ -53,7 +53,7 @@ function dispatchKey(cm, name, e, handle) { }) name = seq + " " + name } - var result = lookupKeyForEditor(cm, name, handle) + let result = lookupKeyForEditor(cm, name, handle) if (result == "multi") cm.state.keySeq = name @@ -74,7 +74,7 @@ function dispatchKey(cm, name, e, handle) { // Handle a key from the keydown event. function handleKeyBinding(cm, e) { - var name = keyName(e, true) + let name = keyName(e, true) if (!name) return false if (e.shiftKey && !cm.state.keySeq) { @@ -97,16 +97,16 @@ function handleCharBinding(cm, e, ch) { function(b) { return doHandleBinding(cm, b, true) }) } -var lastStoppedKey = null +let lastStoppedKey = null export function onKeyDown(e) { - var cm = this + let cm = this cm.curOp.focus = activeElt() if (signalDOMEvent(cm, e)) return // IE does strange things with escape. if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false - var code = e.keyCode + let code = e.keyCode cm.display.shift = code == 16 || e.shiftKey - var handled = handleKeyBinding(cm, e) + let handled = handleKeyBinding(cm, e) if (presto) { lastStoppedKey = handled ? code : null // Opera has no cut event... we try to at least catch the key combo @@ -120,7 +120,7 @@ export function onKeyDown(e) { } function showCrossHair(cm) { - var lineDiv = cm.display.lineDiv + let lineDiv = cm.display.lineDiv addClass(lineDiv, "CodeMirror-crosshair") function up(e) { @@ -140,12 +140,12 @@ export function onKeyUp(e) { } export function onKeyPress(e) { - var cm = this + let cm = this if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return - var keyCode = e.keyCode, charCode = e.charCode + let keyCode = e.keyCode, charCode = e.charCode if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return} if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return - var ch = String.fromCharCode(charCode == null ? keyCode : charCode) + let ch = String.fromCharCode(charCode == null ? keyCode : charCode) // Some browsers fire keypress events for backspace if (ch == "\x08") return if (handleCharBinding(cm, e, ch)) return diff --git a/src/edit/main.js b/src/edit/main.js index 3f76d70207..55432c0812 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -17,8 +17,8 @@ addEditorMethods(CodeMirror) import Doc from "../model/Doc" // Set up methods on CodeMirror's prototype to redirect to the editor's document. -var dontDelegate = "iter insert remove copy getEditor constructor".split(" ") -for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) +let dontDelegate = "iter insert remove copy getEditor constructor".split(" ") +for (let prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) CodeMirror.prototype[prop] = (function(method) { return function() {return method.apply(this.doc, arguments)} })(Doc.prototype[prop]) diff --git a/src/edit/methods.js b/src/edit/methods.js index 828304d3dc..04be851246 100644 --- a/src/edit/methods.js +++ b/src/edit/methods.js @@ -32,16 +32,16 @@ import { regChange, regLineChange } from "../display/view_tracking" // convenience. export default function(CodeMirror) { - var optionHandlers = CodeMirror.optionHandlers + let optionHandlers = CodeMirror.optionHandlers - var helpers = CodeMirror.helpers = {} + let helpers = CodeMirror.helpers = {} CodeMirror.prototype = { constructor: CodeMirror, focus: function(){window.focus(); this.display.input.focus()}, setOption: function(option, value) { - var options = this.options, old = options[option] + let options = this.options, old = options[option] if (options[option] == value && option != "mode") return options[option] = value if (optionHandlers.hasOwnProperty(option)) @@ -55,8 +55,8 @@ export default function(CodeMirror) { this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)) }, removeKeyMap: function(map) { - var maps = this.state.keyMaps - for (var i = 0; i < maps.length; ++i) + let maps = this.state.keyMaps + for (let i = 0; i < maps.length; ++i) if (maps[i] == map || maps[i].name == map) { maps.splice(i, 1) return true @@ -64,7 +64,7 @@ export default function(CodeMirror) { }, addOverlay: methodOp(function(spec, options) { - var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec) + let mode = spec.token ? spec : CodeMirror.getMode(this.options, spec) if (mode.startState) throw new Error("Overlays may not be stateful.") insertSorted(this.state.overlays, {mode: mode, modeSpec: spec, opaque: options && options.opaque, @@ -74,9 +74,9 @@ export default function(CodeMirror) { regChange(this) }), removeOverlay: methodOp(function(spec) { - var overlays = this.state.overlays - for (var i = 0; i < overlays.length; ++i) { - var cur = overlays[i].modeSpec + let overlays = this.state.overlays + for (let i = 0; i < overlays.length; ++i) { + let cur = overlays[i].modeSpec if (cur == spec || typeof spec == "string" && cur.name == spec) { overlays.splice(i, 1) this.state.modeGen++ @@ -94,16 +94,16 @@ export default function(CodeMirror) { if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive) }), indentSelection: methodOp(function(how) { - var ranges = this.doc.sel.ranges, end = -1 - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i] + let ranges = this.doc.sel.ranges, end = -1 + for (let i = 0; i < ranges.length; i++) { + let range = ranges[i] if (!range.empty()) { - var from = range.from(), to = range.to() - var start = Math.max(end, from.line) + let from = range.from(), to = range.to() + let start = Math.max(end, from.line) end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1 - for (var j = start; j < end; ++j) + for (let j = start; j < end; ++j) indentLine(this, j, how) - var newRanges = this.doc.sel.ranges + let newRanges = this.doc.sel.ranges if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll) } else if (range.head.line > end) { @@ -126,22 +126,22 @@ export default function(CodeMirror) { getTokenTypeAt: function(pos) { pos = clipPos(this.doc, pos) - var styles = getLineStyles(this, getLine(this.doc, pos.line)) - var before = 0, after = (styles.length - 1) / 2, ch = pos.ch - var type + let styles = getLineStyles(this, getLine(this.doc, pos.line)) + let before = 0, after = (styles.length - 1) / 2, ch = pos.ch + let type if (ch == 0) type = styles[2] else for (;;) { - var mid = (before + after) >> 1 + let mid = (before + after) >> 1 if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid else if (styles[mid * 2 + 1] < ch) before = mid + 1 else { type = styles[mid * 2 + 2]; break } } - var cut = type ? type.indexOf("cm-overlay ") : -1 + let cut = type ? type.indexOf("cm-overlay ") : -1 return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1) }, getModeAt: function(pos) { - var mode = this.doc.mode + let mode = this.doc.mode if (!mode.innerMode) return mode return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode }, @@ -151,14 +151,14 @@ export default function(CodeMirror) { }, getHelpers: function(pos, type) { - var found = [] + let found = [] if (!helpers.hasOwnProperty(type)) return found - var help = helpers[type], mode = this.getModeAt(pos) + let help = helpers[type], mode = this.getModeAt(pos) if (typeof mode[type] == "string") { if (help[mode[type]]) found.push(help[mode[type]]) } else if (mode[type]) { - for (var i = 0; i < mode[type].length; i++) { - var val = help[mode[type][i]] + for (let i = 0; i < mode[type].length; i++) { + let val = help[mode[type][i]] if (val) found.push(val) } } else if (mode.helperType && help[mode.helperType]) { @@ -166,8 +166,8 @@ export default function(CodeMirror) { } else if (help[mode.name]) { found.push(help[mode.name]) } - for (var i = 0; i < help._global.length; i++) { - var cur = help._global[i] + for (let i = 0; i < help._global.length; i++) { + let cur = help._global[i] if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) found.push(cur.val) } @@ -175,13 +175,13 @@ export default function(CodeMirror) { }, getStateAfter: function(line, precise) { - var doc = this.doc + let doc = this.doc line = clipLine(doc, line == null ? doc.first + doc.size - 1: line) return getStateBefore(this, line + 1, precise) }, cursorCoords: function(start, mode) { - var pos, range = this.doc.sel.primary() + let pos, range = this.doc.sel.primary() if (start == null) pos = range.head else if (typeof start == "object") pos = clipPos(this.doc, start) else pos = start ? range.from() : range.to() @@ -202,9 +202,9 @@ export default function(CodeMirror) { return lineAtHeight(this.doc, height + this.display.viewOffset) }, heightAtLine: function(line, mode) { - var end = false, lineObj + let end = false, lineObj if (typeof line == "number") { - var last = this.doc.first + this.doc.size - 1 + let last = this.doc.first + this.doc.size - 1 if (line < this.doc.first) line = this.doc.first else if (line > last) { line = last; end = true } lineObj = getLine(this.doc, line) @@ -220,7 +220,7 @@ export default function(CodeMirror) { setGutterMarker: methodOp(function(line, gutterID, value) { return changeLine(this.doc, line, "gutter", function(line) { - var markers = line.gutterMarkers || (line.gutterMarkers = {}) + let markers = line.gutterMarkers || (line.gutterMarkers = {}) markers[gutterID] = value if (!value && isEmpty(markers)) line.gutterMarkers = null return true @@ -228,7 +228,7 @@ export default function(CodeMirror) { }), clearGutter: methodOp(function(gutterID) { - var cm = this, doc = cm.doc, i = doc.first + let cm = this, doc = cm.doc, i = doc.first doc.iter(function(line) { if (line.gutterMarkers && line.gutterMarkers[gutterID]) { line.gutterMarkers[gutterID] = null @@ -240,13 +240,14 @@ export default function(CodeMirror) { }), lineInfo: function(line) { + let n if (typeof line == "number") { if (!isLine(this.doc, line)) return null - var n = line + n = line line = getLine(this.doc, line) if (!line) return null } else { - var n = lineNo(line) + n = lineNo(line) if (n == null) return null } return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, @@ -257,9 +258,9 @@ export default function(CodeMirror) { getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}}, addWidget: function(pos, node, scroll, vert, horiz) { - var display = this.display + let display = this.display pos = cursorCoords(this, clipPos(this.doc, pos)) - var top = pos.bottom, left = pos.left + let top = pos.bottom, left = pos.left node.style.position = "absolute" node.setAttribute("cm-ignore-events", "true") this.display.input.setUneditable(node) @@ -267,7 +268,7 @@ export default function(CodeMirror) { if (vert == "over") { top = pos.top } else if (vert == "above" || vert == "near") { - var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), + let vspace = Math.max(display.wrapper.clientHeight, this.doc.height), hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth) // Default to positioning above (if specified and possible); otherwise default to positioning below if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) @@ -303,9 +304,10 @@ export default function(CodeMirror) { triggerElectric: methodOp(function(text) { triggerElectric(this, text) }), findPosH: function(from, amount, unit, visually) { - var dir = 1 + let dir = 1 if (amount < 0) { dir = -1; amount = -amount } - for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { + let cur = clipPos(this.doc, from) + for (let i = 0; i < amount; ++i) { cur = findPosH(this.doc, cur, dir, unit, visually) if (cur.hitSide) break } @@ -313,7 +315,7 @@ export default function(CodeMirror) { }, moveH: methodOp(function(dir, unit) { - var cm = this + let cm = this cm.extendSelectionsBy(function(range) { if (cm.display.shift || cm.doc.extend || range.empty()) return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually) @@ -323,21 +325,22 @@ export default function(CodeMirror) { }), deleteH: methodOp(function(dir, unit) { - var sel = this.doc.sel, doc = this.doc + let sel = this.doc.sel, doc = this.doc if (sel.somethingSelected()) doc.replaceSelection("", null, "+delete") else deleteNearSelection(this, function(range) { - var other = findPosH(doc, range.head, dir, unit, false) + let other = findPosH(doc, range.head, dir, unit, false) return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other} }) }), findPosV: function(from, amount, unit, goalColumn) { - var dir = 1, x = goalColumn + let dir = 1, x = goalColumn if (amount < 0) { dir = -1; amount = -amount } - for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { - var coords = cursorCoords(this, cur, "div") + let cur = clipPos(this.doc, from) + for (let i = 0; i < amount; ++i) { + let coords = cursorCoords(this, cur, "div") if (x == null) x = coords.left else coords.left = x cur = findPosV(this, coords, dir, unit) @@ -347,32 +350,32 @@ export default function(CodeMirror) { }, moveV: methodOp(function(dir, unit) { - var cm = this, doc = this.doc, goals = [] - var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected() + let cm = this, doc = this.doc, goals = [] + let collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected() doc.extendSelectionsBy(function(range) { if (collapse) return dir < 0 ? range.from() : range.to() - var headPos = cursorCoords(cm, range.head, "div") + let headPos = cursorCoords(cm, range.head, "div") if (range.goalColumn != null) headPos.left = range.goalColumn goals.push(headPos.left) - var pos = findPosV(cm, headPos, dir, unit) + let pos = findPosV(cm, headPos, dir, unit) if (unit == "page" && range == doc.sel.primary()) addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top) return pos }, sel_move) - if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++) + if (goals.length) for (let i = 0; i < doc.sel.ranges.length; i++) doc.sel.ranges[i].goalColumn = goals[i] }), // Find the word at the given position (as returned by coordsChar). findWordAt: function(pos) { - var doc = this.doc, line = getLine(doc, pos.line).text - var start = pos.ch, end = pos.ch + let doc = this.doc, line = getLine(doc, pos.line).text + let start = pos.ch, end = pos.ch if (line) { - var helper = this.getHelper(pos, "wordChars") + let helper = this.getHelper(pos, "wordChars") if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end - var startChar = line.charAt(start) - var check = isWordChar(startChar, helper) + let startChar = line.charAt(start) + let check = isWordChar(startChar, helper) ? function(ch) { return isWordChar(ch, helper) } : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch)} : function(ch) {return !/\s/.test(ch) && !isWordChar(ch)} @@ -400,7 +403,7 @@ export default function(CodeMirror) { if (y != null) this.curOp.scrollTop = y }), getScrollInfo: function() { - var scroller = this.display.scroller + let scroller = this.display.scroller return {left: scroller.scrollLeft, top: scroller.scrollTop, height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, @@ -423,7 +426,7 @@ export default function(CodeMirror) { resolveScrollToPos(this) this.curOp.scrollToPos = range } else { - var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), + let sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), Math.min(range.from.top, range.to.top) - range.margin, Math.max(range.from.right, range.to.right), Math.max(range.from.bottom, range.to.bottom) + range.margin) @@ -432,16 +435,16 @@ export default function(CodeMirror) { }), setSize: methodOp(function(width, height) { - var cm = this + let cm = this function interpret(val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val } if (width != null) cm.display.wrapper.style.width = interpret(width) if (height != null) cm.display.wrapper.style.height = interpret(height) if (cm.options.lineWrapping) clearLineMeasurementCache(this) - var lineNo = cm.display.viewFrom + let lineNo = cm.display.viewFrom cm.doc.iter(lineNo, cm.display.viewTo, function(line) { - if (line.widgets) for (var i = 0; i < line.widgets.length; i++) + if (line.widgets) for (let i = 0; i < line.widgets.length; i++) if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break } ++lineNo }) @@ -452,7 +455,7 @@ export default function(CodeMirror) { operation: function(f){return runInOp(this, f)}, refresh: methodOp(function() { - var oldHeight = this.display.cachedTextHeight + let oldHeight = this.display.cachedTextHeight regChange(this) this.curOp.forceUpdate = true clearCaches(this) @@ -464,7 +467,7 @@ export default function(CodeMirror) { }), swapDoc: methodOp(function(doc) { - var old = this.doc + let old = this.doc old.cm = null attachDoc(this, doc) clearCaches(this) @@ -502,16 +505,16 @@ export default function(CodeMirror) { // position. The resulting position will have a hitSide=true // property if it reached the end of the document. function findPosH(doc, pos, dir, unit, visually) { - var line = pos.line, ch = pos.ch, origDir = dir - var lineObj = getLine(doc, line) + let line = pos.line, ch = pos.ch, origDir = dir + let lineObj = getLine(doc, line) function findNextLine() { - var l = line + dir + let l = line + dir if (l < doc.first || l >= doc.first + doc.size) return false line = l return lineObj = getLine(doc, l) } function moveOnce(boundToLine) { - var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true) + let next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true) if (next == null) { if (!boundToLine && findNextLine()) { if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj) @@ -526,12 +529,12 @@ function findPosH(doc, pos, dir, unit, visually) { } else if (unit == "column") { moveOnce(true) } else if (unit == "word" || unit == "group") { - var sawType = null, group = unit == "group" - var helper = doc.cm && doc.cm.getHelper(pos, "wordChars") - for (var first = true;; first = false) { + let sawType = null, group = unit == "group" + let helper = doc.cm && doc.cm.getHelper(pos, "wordChars") + for (let first = true;; first = false) { if (dir < 0 && !moveOnce(!first)) break - var cur = lineObj.text.charAt(ch) || "\n" - var type = isWordChar(cur, helper) ? "w" + let cur = lineObj.text.charAt(ch) || "\n" + let type = isWordChar(cur, helper) ? "w" : group && cur == "\n" ? "n" : !group || /\s/.test(cur) ? null : "p" @@ -545,7 +548,7 @@ function findPosH(doc, pos, dir, unit, visually) { if (dir > 0 && !moveOnce(!first)) break } } - var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true) + let result = skipAtomic(doc, Pos(line, ch), pos, origDir, true) if (!cmp(pos, result)) result.hitSide = true return result } @@ -554,17 +557,18 @@ function findPosH(doc, pos, dir, unit, visually) { // "page" or "line". The resulting position will have a hitSide=true // property if it reached the end of the document. function findPosV(cm, pos, dir, unit) { - var doc = cm.doc, x = pos.left, y + let doc = cm.doc, x = pos.left, y if (unit == "page") { - var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight) - var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3) + let pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight) + let moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3) y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount } else if (unit == "line") { y = dir > 0 ? pos.bottom + 3 : pos.top - 3 } + let target for (;;) { - var target = coordsChar(cm, x, y) + target = coordsChar(cm, x, y) if (!target.outside) break if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break } y += dir * 5 diff --git a/src/edit/mouse_events.js b/src/edit/mouse_events.js index 408cc497d1..5fe10ea39f 100644 --- a/src/edit/mouse_events.js +++ b/src/edit/mouse_events.js @@ -19,7 +19,7 @@ import { bind, countColumn, findColumn, sel_mouse } from "../util/misc" // middle-click-paste. Or it might be a click on something we should // not interfere with, such as a scrollbar or widget. export function onMouseDown(e) { - var cm = this, display = cm.display + let cm = this, display = cm.display if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return display.shift = e.shiftKey @@ -33,7 +33,7 @@ export function onMouseDown(e) { return } if (clickInGutter(cm, e)) return - var start = posFromMouse(cm, e) + let start = posFromMouse(cm, e) window.focus() switch (e_button(e)) { @@ -59,12 +59,12 @@ export function onMouseDown(e) { } } -var lastClick, lastDoubleClick +let lastClick, lastDoubleClick function leftButtonDown(cm, e, start) { if (ie) setTimeout(bind(ensureFocus, cm), 0) else cm.curOp.focus = activeElt() - var now = +new Date, type + let now = +new Date, type if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { type = "triple" } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { @@ -75,7 +75,7 @@ function leftButtonDown(cm, e, start) { lastClick = {time: now, pos: start} } - var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained + let sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() && type == "single" && (contained = sel.contains(start)) > -1 && (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) && @@ -88,8 +88,8 @@ function leftButtonDown(cm, e, start) { // Start a text drag. When it ends, see if any dragging actually // happen, and treat as a click if it didn't. function leftButtonStartDrag(cm, e, start, modifier) { - var display = cm.display, startTime = +new Date - var dragEnd = operation(cm, function(e2) { + let display = cm.display, startTime = +new Date + let dragEnd = operation(cm, function(e2) { if (webkit) display.scroller.draggable = false cm.state.draggingText = false off(document, "mouseup", dragEnd) @@ -117,10 +117,10 @@ function leftButtonStartDrag(cm, e, start, modifier) { // Normal selection, as opposed to text dragging. function leftButtonSelect(cm, e, start, type, addNew) { - var display = cm.display, doc = cm.doc + let display = cm.display, doc = cm.doc e_preventDefault(e) - var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges + let ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges if (addNew && !e.shiftKey) { ourIndex = doc.sel.contains(start) if (ourIndex > -1) @@ -138,13 +138,13 @@ function leftButtonSelect(cm, e, start, type, addNew) { start = posFromMouse(cm, e, true, true) ourIndex = -1 } else if (type == "double") { - var word = cm.findWordAt(start) + let word = cm.findWordAt(start) if (cm.display.shift || doc.extend) ourRange = extendRange(doc, ourRange, word.anchor, word.head) else ourRange = word } else if (type == "triple") { - var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))) + let line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))) if (cm.display.shift || doc.extend) ourRange = extendRange(doc, ourRange, line.anchor, line.head) else @@ -169,19 +169,19 @@ function leftButtonSelect(cm, e, start, type, addNew) { replaceOneSelection(doc, ourIndex, ourRange, sel_mouse) } - var lastPos = start + let lastPos = start function extendTo(pos) { if (cmp(lastPos, pos) == 0) return lastPos = pos if (type == "rect") { - var ranges = [], tabSize = cm.options.tabSize - var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize) - var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize) - var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol) - for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); + let ranges = [], tabSize = cm.options.tabSize + let startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize) + let posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize) + let left = Math.min(startCol, posCol), right = Math.max(startCol, posCol) + for (let line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); line <= end; line++) { - var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize) + let text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize) if (left == right) ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))) else if (text.length > leftPos) @@ -192,13 +192,14 @@ function leftButtonSelect(cm, e, start, type, addNew) { {origin: "*mouse", scroll: false}) cm.scrollIntoView(pos) } else { - var oldRange = ourRange - var anchor = oldRange.anchor, head = pos + let oldRange = ourRange + let anchor = oldRange.anchor, head = pos if (type != "single") { + let range if (type == "double") - var range = cm.findWordAt(pos) + range = cm.findWordAt(pos) else - var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))) + range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))) if (cmp(range.anchor, anchor) > 0) { head = range.head anchor = minPos(oldRange.from(), range.anchor) @@ -207,31 +208,31 @@ function leftButtonSelect(cm, e, start, type, addNew) { anchor = maxPos(oldRange.to(), range.head) } } - var ranges = startSel.ranges.slice(0) + let ranges = startSel.ranges.slice(0) ranges[ourIndex] = new Range(clipPos(doc, anchor), head) setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse) } } - var editorSize = display.wrapper.getBoundingClientRect() + let editorSize = display.wrapper.getBoundingClientRect() // Used to ensure timeout re-tries don't fire when another extend // happened in the meantime (clearTimeout isn't reliable -- at // least on Chrome, the timeouts still happen even when cleared, // if the clear happens after their scheduled firing time). - var counter = 0 + let counter = 0 function extend(e) { - var curCount = ++counter - var cur = posFromMouse(cm, e, true, type == "rect") + let curCount = ++counter + let cur = posFromMouse(cm, e, true, type == "rect") if (!cur) return if (cmp(cur, lastPos) != 0) { cm.curOp.focus = activeElt() extendTo(cur) - var visible = visibleLines(display, doc) + let visible = visibleLines(display, doc) if (cur.line >= visible.to || cur.line < visible.from) setTimeout(operation(cm, function(){if (counter == curCount) extend(e)}), 150) } else { - var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0 + let outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0 if (outside) setTimeout(operation(cm, function() { if (counter != curCount) return display.scroller.scrollTop += outside @@ -250,11 +251,11 @@ function leftButtonSelect(cm, e, start, type, addNew) { doc.history.lastSelOrigin = null } - var move = operation(cm, function(e) { + let move = operation(cm, function(e) { if (!e_button(e)) done(e) else extend(e) }) - var up = operation(cm, done) + let up = operation(cm, done) cm.state.selectingText = up on(document, "mousemove", move) on(document, "mouseup", up) @@ -264,22 +265,23 @@ function leftButtonSelect(cm, e, start, type, addNew) { // Determines whether an event happened in the gutter, and fires the // handlers for the corresponding event. function gutterEvent(cm, e, type, prevent) { - try { var mX = e.clientX, mY = e.clientY } + let mX, mY + try { mX = e.clientX; mY = e.clientY } catch(e) { return false } if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false if (prevent) e_preventDefault(e) - var display = cm.display - var lineBox = display.lineDiv.getBoundingClientRect() + let display = cm.display + let lineBox = display.lineDiv.getBoundingClientRect() if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e) mY -= lineBox.top - display.viewOffset - for (var i = 0; i < cm.options.gutters.length; ++i) { - var g = display.gutters.childNodes[i] + for (let i = 0; i < cm.options.gutters.length; ++i) { + let g = display.gutters.childNodes[i] if (g && g.getBoundingClientRect().right >= mX) { - var line = lineAtHeight(cm.doc, mY) - var gutter = cm.options.gutters[i] + let line = lineAtHeight(cm.doc, mY) + let gutter = cm.options.gutters[i] signal(cm, type, cm, line, gutter, e) return e_defaultPrevented(e) } diff --git a/src/edit/options.js b/src/edit/options.js index cf0d4d8185..a2ca1c6803 100644 --- a/src/edit/options.js +++ b/src/edit/options.js @@ -17,13 +17,13 @@ import { off, on } from "../util/event" import { themeChanged } from "./utils" -export var Init = {toString: function(){return "CodeMirror.Init"}} +export let Init = {toString: function(){return "CodeMirror.Init"}} -export var defaults = {} -export var optionHandlers = {} +export let defaults = {} +export let optionHandlers = {} export function defineOptions(CodeMirror) { - var optionHandlers = CodeMirror.optionHandlers + let optionHandlers = CodeMirror.optionHandlers function option(name, deflt, handle, notOnInit) { CodeMirror.defaults[name] = deflt @@ -57,17 +57,17 @@ export function defineOptions(CodeMirror) { option("lineSeparator", null, function(cm, val) { cm.doc.lineSep = val if (!val) return - var newBreaks = [], lineNo = cm.doc.first + let newBreaks = [], lineNo = cm.doc.first cm.doc.iter(function(line) { - for (var pos = 0;;) { - var found = line.text.indexOf(val, pos) + for (let pos = 0;;) { + let found = line.text.indexOf(val, pos) if (found == -1) break pos = found + val.length newBreaks.push(Pos(lineNo, found)) } lineNo++ }) - for (var i = newBreaks.length - 1; i >= 0; i--) + for (let i = newBreaks.length - 1; i >= 0; i--) replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) }) option("specialChars", /[\u0000-\u001f\u007f\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) { @@ -90,8 +90,8 @@ export function defineOptions(CodeMirror) { guttersChanged(cm) }, true) option("keyMap", "default", function(cm, val, old) { - var next = getKeyMap(val) - var prev = old != Init && getKeyMap(old) + let next = getKeyMap(val) + let prev = old != Init && getKeyMap(old) if (prev && prev.detach) prev.detach(cm, next) if (next.attach) next.attach(cm, prev || null) }) @@ -168,10 +168,10 @@ function guttersChanged(cm) { } function dragDropChanged(cm, value, old) { - var wasOn = old && old != Init + let wasOn = old && old != Init if (!value != !wasOn) { - var funcs = cm.display.dragFunctions - var toggle = value ? on : off + let funcs = cm.display.dragFunctions + let toggle = value ? on : off toggle(cm.display.scroller, "dragstart", funcs.start) toggle(cm.display.scroller, "dragenter", funcs.enter) toggle(cm.display.scroller, "dragover", funcs.over) diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index 51597d19fa..80e91f847f 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -25,8 +25,8 @@ export default function ContentEditableInput(cm) { ContentEditableInput.prototype = copyObj({ init: function(display) { - var input = this, cm = input.cm - var div = input.div = display.lineDiv + let input = this, cm = input.cm + let div = input.div = display.lineDiv disableBrowserMagic(div, cm.options.spellcheck) on(div, "paste", function(e) { @@ -38,12 +38,12 @@ ContentEditableInput.prototype = copyObj({ }) on(div, "compositionstart", function(e) { - var data = e.data + let data = e.data input.composing = {sel: cm.doc.sel, data: data, startData: data} if (!data) return - var prim = cm.doc.sel.primary() - var line = cm.getLine(prim.head.line) - var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)) + let prim = cm.doc.sel.primary() + let line = cm.getLine(prim.head.line) + let found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)) if (found > -1 && found <= prim.head.ch) input.composing.sel = simpleSelection(Pos(prim.head.line, found), Pos(prim.head.line, found + data.length)) @@ -52,7 +52,7 @@ ContentEditableInput.prototype = copyObj({ input.composing.data = e.data }) on(div, "compositionend", function(e) { - var ours = input.composing + let ours = input.composing if (!ours) return if (e.data != ours.startData && !/\u200b/.test(e.data)) ours.data = e.data @@ -85,7 +85,7 @@ ContentEditableInput.prototype = copyObj({ } else if (!cm.options.lineWiseCopyCut) { return } else { - var ranges = copyableRanges(cm) + let ranges = copyableRanges(cm) setLastCopied({lineWise: true, text: ranges.text}) if (e.type == "cut") { cm.operation(function() { @@ -96,7 +96,7 @@ ContentEditableInput.prototype = copyObj({ } if (e.clipboardData) { e.clipboardData.clearData() - var content = lastCopied.text.join("\n") + let content = lastCopied.text.join("\n") // iOS exposes the clipboard API, but seems to discard content inserted into it e.clipboardData.setData("Text", content) if (e.clipboardData.getData("Text") == content) { @@ -105,10 +105,10 @@ ContentEditableInput.prototype = copyObj({ } } // Old-fashioned briefly-focus-a-textarea hack - var kludge = hiddenTextarea(), te = kludge.firstChild + let kludge = hiddenTextarea(), te = kludge.firstChild cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild) te.value = lastCopied.text.join("\n") - var hadFocus = document.activeElement + let hadFocus = document.activeElement selectInput(te) setTimeout(function() { cm.display.lineSpace.removeChild(kludge) @@ -121,7 +121,7 @@ ContentEditableInput.prototype = copyObj({ }, prepareSelection: function() { - var result = prepareSelection(this.cm, false) + let result = prepareSelection(this.cm, false) result.focus = this.cm.state.focused return result }, @@ -133,29 +133,30 @@ ContentEditableInput.prototype = copyObj({ }, showPrimarySelection: function() { - var sel = window.getSelection(), prim = this.cm.doc.sel.primary() - var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset) - var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset) + let sel = window.getSelection(), prim = this.cm.doc.sel.primary() + let curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset) + let curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset) if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && cmp(minPos(curAnchor, curFocus), prim.from()) == 0 && cmp(maxPos(curAnchor, curFocus), prim.to()) == 0) return - var start = posToDOM(this.cm, prim.from()) - var end = posToDOM(this.cm, prim.to()) + let start = posToDOM(this.cm, prim.from()) + let end = posToDOM(this.cm, prim.to()) if (!start && !end) return - var view = this.cm.display.view - var old = sel.rangeCount && sel.getRangeAt(0) + let view = this.cm.display.view + let old = sel.rangeCount && sel.getRangeAt(0) if (!start) { start = {node: view[0].measure.map[2], offset: 0} } else if (!end) { // FIXME dangerously hacky - var measure = view[view.length - 1].measure - var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map + let measure = view[view.length - 1].measure + let map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]} } - try { var rng = range(start.node, start.offset, end.offset, end.node) } + let rng + try { rng = range(start.node, start.offset, end.offset, end.node) } catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible if (rng) { if (!gecko && this.cm.state.focused) { @@ -172,7 +173,7 @@ ContentEditableInput.prototype = copyObj({ }, startGracePeriod: function() { - var input = this + let input = this clearTimeout(this.gracePeriod) this.gracePeriod = setTimeout(function() { input.gracePeriod = false @@ -187,15 +188,15 @@ ContentEditableInput.prototype = copyObj({ }, rememberSelection: function() { - var sel = window.getSelection() + let sel = window.getSelection() this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset }, selectionInEditor: function() { - var sel = window.getSelection() + let sel = window.getSelection() if (!sel.rangeCount) return false - var node = sel.getRangeAt(0).commonAncestorContainer + let node = sel.getRangeAt(0).commonAncestorContainer return contains(this.div, node) }, @@ -208,7 +209,7 @@ ContentEditableInput.prototype = copyObj({ supportsTouch: function() { return true }, receivedFocus: function() { - var input = this + let input = this if (this.selectionInEditor()) this.pollSelection() else @@ -224,17 +225,17 @@ ContentEditableInput.prototype = copyObj({ }, selectionChanged: function() { - var sel = window.getSelection() + let sel = window.getSelection() return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset }, pollSelection: function() { if (!this.composing && !this.gracePeriod && this.selectionChanged()) { - var sel = window.getSelection(), cm = this.cm + let sel = window.getSelection(), cm = this.cm this.rememberSelection() - var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset) - var head = domToPos(cm, sel.focusNode, sel.focusOffset) + let anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset) + let head = domToPos(cm, sel.focusNode, sel.focusOffset) if (anchor && head) runInOp(cm, function() { setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll) if (anchor.bad || head.bad) cm.curOp.selectionChanged = true @@ -243,41 +244,42 @@ ContentEditableInput.prototype = copyObj({ }, pollContent: function() { - var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary() - var from = sel.from(), to = sel.to() + let cm = this.cm, display = cm.display, sel = cm.doc.sel.primary() + let from = sel.from(), to = sel.to() if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false - var fromIndex + let fromIndex, fromLine, fromNode if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { - var fromLine = lineNo(display.view[0].line) - var fromNode = display.view[0].node + fromLine = lineNo(display.view[0].line) + fromNode = display.view[0].node } else { - var fromLine = lineNo(display.view[fromIndex].line) - var fromNode = display.view[fromIndex - 1].node.nextSibling + fromLine = lineNo(display.view[fromIndex].line) + fromNode = display.view[fromIndex - 1].node.nextSibling } - var toIndex = findViewIndex(cm, to.line) + let toIndex = findViewIndex(cm, to.line) + let toLine, toNode if (toIndex == display.view.length - 1) { - var toLine = display.viewTo - 1 - var toNode = display.lineDiv.lastChild + toLine = display.viewTo - 1 + toNode = display.lineDiv.lastChild } else { - var toLine = lineNo(display.view[toIndex + 1].line) - 1 - var toNode = display.view[toIndex + 1].node.previousSibling + toLine = lineNo(display.view[toIndex + 1].line) - 1 + toNode = display.view[toIndex + 1].node.previousSibling } - var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)) - var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)) + let newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)) + let oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)) while (newText.length > 1 && oldText.length > 1) { if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine-- } else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++ } else break } - var cutFront = 0, cutEnd = 0 - var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length) + let cutFront = 0, cutEnd = 0 + let newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length) while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) ++cutFront - var newBot = lst(newText), oldBot = lst(oldText) - var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), + let newBot = lst(newText), oldBot = lst(oldText) + let maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), oldBot.length - (oldText.length == 1 ? cutFront : 0)) while (cutEnd < maxCutEnd && newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) @@ -286,8 +288,8 @@ ContentEditableInput.prototype = copyObj({ newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd) newText[0] = newText[0].slice(cutFront) - var chFrom = Pos(fromLine, cutFront) - var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0) + let chFrom = Pos(fromLine, cutFront) + let chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0) if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { replaceRange(cm.doc, newText, chFrom, chTo, "+input") return true @@ -335,17 +337,17 @@ ContentEditableInput.prototype = copyObj({ }, ContentEditableInput.prototype) function posToDOM(cm, pos) { - var view = findViewForLine(cm, pos.line) + let view = findViewForLine(cm, pos.line) if (!view || view.hidden) return null - var line = getLine(cm.doc, pos.line) - var info = mapFromLineView(view, line, pos.line) + let line = getLine(cm.doc, pos.line) + let info = mapFromLineView(view, line, pos.line) - var order = getOrder(line), side = "left" + let order = getOrder(line), side = "left" if (order) { - var partPos = getBidiPartAt(order, pos.ch) + let partPos = getBidiPartAt(order, pos.ch) side = partPos % 2 ? "right" : "left" } - var result = nodeAndOffsetInLineMap(info.map, pos.ch, side) + let result = nodeAndOffsetInLineMap(info.map, pos.ch, side) result.offset = result.collapse == "right" ? result.end : result.start return result } @@ -353,30 +355,30 @@ function posToDOM(cm, pos) { function badPos(pos, bad) { if (bad) pos.bad = true; return pos } function domTextBetween(cm, from, to, fromLine, toLine) { - var text = "", closing = false, lineSep = cm.doc.lineSeparator() + let text = "", closing = false, lineSep = cm.doc.lineSeparator() function recognizeMarker(id) { return function(marker) { return marker.id == id } } function walk(node) { if (node.nodeType == 1) { - var cmText = node.getAttribute("cm-text") + let cmText = node.getAttribute("cm-text") if (cmText != null) { if (cmText == "") cmText = node.textContent.replace(/\u200b/g, "") text += cmText return } - var markerID = node.getAttribute("cm-marker"), range + let markerID = node.getAttribute("cm-marker"), range if (markerID) { - var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)) + let found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)) if (found.length && (range = found[0].find())) text += getBetween(cm.doc, range.from, range.to).join(lineSep) return } if (node.getAttribute("contenteditable") == "false") return - for (var i = 0; i < node.childNodes.length; i++) + for (let i = 0; i < node.childNodes.length; i++) walk(node.childNodes[i]) if (/^(pre|div|p)$/i.test(node.nodeName)) closing = true } else if (node.nodeType == 3) { - var val = node.nodeValue + let val = node.nodeValue if (!val) return if (closing) { text += lineSep @@ -394,7 +396,7 @@ function domTextBetween(cm, from, to, fromLine, toLine) { } function domToPos(cm, node, offset) { - var lineNode + let lineNode if (node == cm.display.lineDiv) { lineNode = cm.display.lineDiv.childNodes[offset] if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) @@ -405,60 +407,60 @@ function domToPos(cm, node, offset) { if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break } } - for (var i = 0; i < cm.display.view.length; i++) { - var lineView = cm.display.view[i] + for (let i = 0; i < cm.display.view.length; i++) { + let lineView = cm.display.view[i] if (lineView.node == lineNode) return locateNodeInLineView(lineView, node, offset) } } function locateNodeInLineView(lineView, node, offset) { - var wrapper = lineView.text.firstChild, bad = false + let wrapper = lineView.text.firstChild, bad = false if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true) if (node == wrapper) { bad = true node = wrapper.childNodes[offset] offset = 0 if (!node) { - var line = lineView.rest ? lst(lineView.rest) : lineView.line + let line = lineView.rest ? lst(lineView.rest) : lineView.line return badPos(Pos(lineNo(line), line.text.length), bad) } } - var textNode = node.nodeType == 3 ? node : null, topNode = node + let textNode = node.nodeType == 3 ? node : null, topNode = node if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { textNode = node.firstChild if (offset) offset = textNode.nodeValue.length } while (topNode.parentNode != wrapper) topNode = topNode.parentNode - var measure = lineView.measure, maps = measure.maps + let measure = lineView.measure, maps = measure.maps function find(textNode, topNode, offset) { - for (var i = -1; i < (maps ? maps.length : 0); i++) { - var map = i < 0 ? measure.map : maps[i] - for (var j = 0; j < map.length; j += 3) { - var curNode = map[j + 2] + for (let i = -1; i < (maps ? maps.length : 0); i++) { + let map = i < 0 ? measure.map : maps[i] + for (let j = 0; j < map.length; j += 3) { + let curNode = map[j + 2] if (curNode == textNode || curNode == topNode) { - var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]) - var ch = map[j] + offset + let line = lineNo(i < 0 ? lineView.line : lineView.rest[i]) + let ch = map[j] + offset if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)] return Pos(line, ch) } } } } - var found = find(textNode, topNode, offset) + let found = find(textNode, topNode, offset) if (found) return badPos(found, bad) // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems - for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { + for (let after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { found = find(after, after.firstChild, 0) if (found) return badPos(Pos(found.line, found.ch - dist), bad) else dist += after.textContent.length } - for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) { + for (let before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) { found = find(before, before.firstChild, -1) if (found) return badPos(Pos(found.line, found.ch + dist), bad) diff --git a/src/input/TextareaInput.js b/src/input/TextareaInput.js index 4c08f37797..e244a2d168 100644 --- a/src/input/TextareaInput.js +++ b/src/input/TextareaInput.js @@ -34,13 +34,13 @@ export default function TextareaInput(cm) { TextareaInput.prototype = copyObj({ init: function(display) { - var input = this, cm = this.cm + let input = this, cm = this.cm // Wraps and hides input textarea - var div = this.wrapper = hiddenTextarea() + let div = this.wrapper = hiddenTextarea() // The semihidden textarea that is focused when the editor is // focused, and receives input. - var te = this.textarea = div.firstChild + let te = this.textarea = div.firstChild display.wrapper.insertBefore(div, display.wrapper.firstChild) // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) @@ -71,7 +71,7 @@ TextareaInput.prototype = copyObj({ } else if (!cm.options.lineWiseCopyCut) { return } else { - var ranges = copyableRanges(cm) + let ranges = copyableRanges(cm) setLastCopied({lineWise: true, text: ranges.text}) if (e.type == "cut") { cm.setSelections(ranges.ranges, null, sel_dontScroll) @@ -98,7 +98,7 @@ TextareaInput.prototype = copyObj({ }) on(te, "compositionstart", function() { - var start = cm.getCursor("from") + let start = cm.getCursor("from") if (input.composing) input.composing.range.clear() input.composing = { start: start, @@ -116,13 +116,13 @@ TextareaInput.prototype = copyObj({ prepareSelection: function() { // Redraw the selection and/or cursor - var cm = this.cm, display = cm.display, doc = cm.doc - var result = prepareSelection(cm) + let cm = this.cm, display = cm.display, doc = cm.doc + let result = prepareSelection(cm) // Move the hidden textarea near the cursor to prevent scrolling artifacts if (cm.options.moveInputWithCursor) { - var headPos = cursorCoords(cm, doc.sel.primary().head, "div") - var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect() + let headPos = cursorCoords(cm, doc.sel.primary().head, "div") + let wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect() result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, headPos.top + lineOff.top - wrapOff.top)) result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, @@ -133,7 +133,7 @@ TextareaInput.prototype = copyObj({ }, showSelection: function(drawn) { - var cm = this.cm, display = cm.display + let cm = this.cm, display = cm.display removeChildrenAndAdd(display.cursorDiv, drawn.cursors) removeChildrenAndAdd(display.selectionDiv, drawn.selection) if (drawn.teTop != null) { @@ -146,13 +146,13 @@ TextareaInput.prototype = copyObj({ // when not typing and nothing is selected) reset: function(typing) { if (this.contextMenuPending) return - var minimal, selected, cm = this.cm, doc = cm.doc + let minimal, selected, cm = this.cm, doc = cm.doc if (cm.somethingSelected()) { this.prevInput = "" - var range = doc.sel.primary() + let range = doc.sel.primary() minimal = hasCopyEvent && (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000) - var content = minimal ? "-" : selected || cm.getSelection() + let content = minimal ? "-" : selected || cm.getSelection() this.textarea.value = content if (cm.state.focused) selectInput(this.textarea) if (ie && ie_version >= 9) this.hasSelection = content @@ -185,7 +185,7 @@ TextareaInput.prototype = copyObj({ // Poll for input changes, using the normal rate of polling. This // runs as long as the editor is focused. slowPoll: function() { - var input = this + let input = this if (input.pollingFast) return input.polling.set(this.cm.options.pollInterval, function() { input.poll() @@ -197,10 +197,10 @@ TextareaInput.prototype = copyObj({ // something in the input textarea, we poll faster, to ensure that // the change appears on the screen quickly. fastPoll: function() { - var missed = false, input = this + let missed = false, input = this input.pollingFast = true function p() { - var changed = input.poll() + let changed = input.poll() if (!changed && !missed) {missed = true; input.polling.set(60, p)} else {input.pollingFast = false; input.slowPoll()} } @@ -214,7 +214,7 @@ TextareaInput.prototype = copyObj({ // seen text (can be empty), which is stored in prevInput (we must // not reset the textarea when typing, because that breaks IME). poll: function() { - var cm = this.cm, input = this.textarea, prevInput = this.prevInput + let cm = this.cm, input = this.textarea, prevInput = this.prevInput // Since this is called a *lot*, try to bail out as cheaply as // possible when it is clear that nothing happened. hasSelection // will be the case when there is a lot of text in the textarea, @@ -224,7 +224,7 @@ TextareaInput.prototype = copyObj({ cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq) return false - var text = input.value + let text = input.value // If nothing changed, bail. if (text == prevInput && !cm.somethingSelected()) return false // Work around nonsensical selection resetting in IE9/10, and @@ -237,15 +237,15 @@ TextareaInput.prototype = copyObj({ } if (cm.doc.sel == cm.display.selForContextMenu) { - var first = text.charCodeAt(0) + let first = text.charCodeAt(0) if (first == 0x200b && !prevInput) prevInput = "\u200b" if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") } } // Find the part of the input that is actually new - var same = 0, l = Math.min(prevInput.length, text.length) + let same = 0, l = Math.min(prevInput.length, text.length) while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same - var self = this + let self = this runInOp(cm, function() { applyTextInput(cm, text.slice(same), prevInput.length - same, null, self.composing ? "*compose" : null) @@ -273,24 +273,25 @@ TextareaInput.prototype = copyObj({ }, onContextMenu: function(e) { - var input = this, cm = input.cm, display = cm.display, te = input.textarea - var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop + let input = this, cm = input.cm, display = cm.display, te = input.textarea + let pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop if (!pos || presto) return // Opera is difficult. // Reset the current text selection only if the click is done outside of the selection // and 'resetSelectionOnContextMenu' option is true. - var reset = cm.options.resetSelectionOnContextMenu + let reset = cm.options.resetSelectionOnContextMenu if (reset && cm.doc.sel.contains(pos) == -1) operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll) - var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText + let oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText input.wrapper.style.cssText = "position: absolute" - var wrapperBox = input.wrapper.getBoundingClientRect() + let wrapperBox = input.wrapper.getBoundingClientRect() te.style.cssText = "position: absolute; width: 30px; height: 30px; top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px; z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);" - if (webkit) var oldScrollY = window.scrollY // Work around Chrome issue (#2712) + let oldScrollY + if (webkit) oldScrollY = window.scrollY // Work around Chrome issue (#2712) display.input.focus() if (webkit) window.scrollTo(null, oldScrollY) display.input.reset() @@ -305,8 +306,8 @@ TextareaInput.prototype = copyObj({ // it got selected. function prepareSelectAllHack() { if (te.selectionStart != null) { - var selected = cm.somethingSelected() - var extval = "\u200b" + (selected ? te.value : "") + let selected = cm.somethingSelected() + let extval = "\u200b" + (selected ? te.value : "") te.value = "\u21da" // Used to catch context-menu undo te.value = extval input.prevInput = selected ? "" : "\u200b" @@ -325,7 +326,7 @@ TextareaInput.prototype = copyObj({ // Try to detect the user choosing select-all if (te.selectionStart != null) { if (!ie || (ie && ie_version < 9)) prepareSelectAllHack() - var i = 0, poll = function() { + let i = 0, poll = function() { if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && te.selectionEnd > 0 && input.prevInput == "\u200b") operation(cm, selectAll)(cm) @@ -339,7 +340,7 @@ TextareaInput.prototype = copyObj({ if (ie && ie_version >= 9) prepareSelectAllHack() if (captureRightClick) { e_stop(e) - var mouseup = function() { + let mouseup = function() { off(window, "mouseup", mouseup) setTimeout(rehide, 20) } diff --git a/src/input/indent.js b/src/input/indent.js index f0fc78fd05..2c1755eb9f 100644 --- a/src/input/indent.js +++ b/src/input/indent.js @@ -12,7 +12,7 @@ import { countColumn, Pass, spaceStr } from "../util/misc" // lines are not indented, and places where the mode returns Pass // are left alone. export function indentLine(cm, n, how, aggressive) { - var doc = cm.doc, state + let doc = cm.doc, state if (how == null) how = "add" if (how == "smart") { // Fall back to "prev" when the mode doesn't have an indentation @@ -21,10 +21,10 @@ export function indentLine(cm, n, how, aggressive) { else state = getStateBefore(cm, n) } - var tabSize = cm.options.tabSize - var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize) + let tabSize = cm.options.tabSize + let line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize) if (line.stateAfter) line.stateAfter = null - var curSpaceString = line.text.match(/^\s*/)[0], indentation + let curSpaceString = line.text.match(/^\s*/)[0], indentation if (!aggressive && !/\S/.test(line.text)) { indentation = 0 how = "not" @@ -47,9 +47,9 @@ export function indentLine(cm, n, how, aggressive) { } indentation = Math.max(0, indentation) - var indentString = "", pos = 0 + let indentString = "", pos = 0 if (cm.options.indentWithTabs) - for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t"} + for (let i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t"} if (pos < indentation) indentString += spaceStr(indentation - pos) if (indentString != curSpaceString) { @@ -59,10 +59,10 @@ export function indentLine(cm, n, how, aggressive) { } else { // Ensure that, if the cursor was in the whitespace at the start // of the line, it is moved to the end of that space. - for (var i = 0; i < doc.sel.ranges.length; i++) { - var range = doc.sel.ranges[i] + for (let i = 0; i < doc.sel.ranges.length; i++) { + let range = doc.sel.ranges[i] if (range.head.line == n && range.head.ch < curSpaceString.length) { - var pos = Pos(n, curSpaceString.length) + let pos = Pos(n, curSpaceString.length) replaceOneSelection(doc, i, new Range(pos, pos)) break } diff --git a/src/input/input.js b/src/input/input.js index a084e08f8b..6cc3e9111f 100644 --- a/src/input/input.js +++ b/src/input/input.js @@ -13,25 +13,25 @@ import { indentLine } from "./indent" // This will be set to a {lineWise: bool, text: [string]} object, so // that, when pasting, we know what kind of selections the copied // text was made out of. -export var lastCopied = null +export let lastCopied = null export function setLastCopied(newLastCopied) { lastCopied = newLastCopied } export function applyTextInput(cm, inserted, deleted, sel, origin) { - var doc = cm.doc + let doc = cm.doc cm.display.shift = false if (!sel) sel = doc.sel - var paste = cm.state.pasteIncoming || origin == "paste" - var textLines = doc.splitLines(inserted), multiPaste = null + let paste = cm.state.pasteIncoming || origin == "paste" + let textLines = doc.splitLines(inserted), multiPaste = null // When pasing N lines into N selections, insert one line per selection if (paste && sel.ranges.length > 1) { if (lastCopied && lastCopied.text.join("\n") == inserted) { if (sel.ranges.length % lastCopied.text.length == 0) { multiPaste = [] - for (var i = 0; i < lastCopied.text.length; i++) + for (let i = 0; i < lastCopied.text.length; i++) multiPaste.push(doc.splitLines(lastCopied.text[i])) } } else if (textLines.length == sel.ranges.length) { @@ -39,10 +39,11 @@ export function applyTextInput(cm, inserted, deleted, sel, origin) { } } + let updateInput // Normal behavior is to insert the new text into every selection - for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range = sel.ranges[i] - var from = range.from(), to = range.to() + for (let i = sel.ranges.length - 1; i >= 0; i--) { + let range = sel.ranges[i] + let from = range.from(), to = range.to() if (range.empty()) { if (deleted && deleted > 0) // Handle deletion from = Pos(from.line, from.ch - deleted) @@ -51,8 +52,8 @@ export function applyTextInput(cm, inserted, deleted, sel, origin) { else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted) from = to = Pos(from.line, 0) } - var updateInput = cm.curOp.updateInput - var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, + updateInput = cm.curOp.updateInput + let changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")} makeChange(cm.doc, changeEvent) signalLater(cm, "inputRead", cm, changeEvent) @@ -67,7 +68,7 @@ export function applyTextInput(cm, inserted, deleted, sel, origin) { } export function handlePaste(e, cm) { - var pasted = e.clipboardData && e.clipboardData.getData("Text") + let pasted = e.clipboardData && e.clipboardData.getData("Text") if (pasted) { e.preventDefault() if (!cm.isReadOnly() && !cm.options.disableInput) @@ -79,15 +80,15 @@ export function handlePaste(e, cm) { export function triggerElectric(cm, inserted) { // When an 'electric' character is inserted, immediately trigger a reindent if (!cm.options.electricChars || !cm.options.smartIndent) return - var sel = cm.doc.sel + let sel = cm.doc.sel - for (var i = sel.ranges.length - 1; i >= 0; i--) { - var range = sel.ranges[i] + for (let i = sel.ranges.length - 1; i >= 0; i--) { + let range = sel.ranges[i] if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue - var mode = cm.getModeAt(range.head) - var indented = false + let mode = cm.getModeAt(range.head) + let indented = false if (mode.electricChars) { - for (var j = 0; j < mode.electricChars.length; j++) + for (let j = 0; j < mode.electricChars.length; j++) if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { indented = indentLine(cm, range.head.line, "smart") break @@ -101,10 +102,10 @@ export function triggerElectric(cm, inserted) { } export function copyableRanges(cm) { - var text = [], ranges = [] - for (var i = 0; i < cm.doc.sel.ranges.length; i++) { - var line = cm.doc.sel.ranges[i].head.line - var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)} + let text = [], ranges = [] + for (let i = 0; i < cm.doc.sel.ranges.length; i++) { + let line = cm.doc.sel.ranges[i].head.line + let lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)} ranges.push(lineRange) text.push(cm.getRange(lineRange.anchor, lineRange.head)) } @@ -118,8 +119,8 @@ export function disableBrowserMagic(field, spellcheck) { } export function hiddenTextarea() { - var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none") - var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;") + let te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none") + let div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;") // The textarea is kept positioned near the cursor to prevent the // fact that it'll be scrolled into view on input from scrolling // our fake cursor out of view. On webkit, when wrap=off, paste is diff --git a/src/input/keymap.js b/src/input/keymap.js index 0f5941e81a..1b9564ef4f 100644 --- a/src/input/keymap.js +++ b/src/input/keymap.js @@ -3,7 +3,7 @@ import { map } from "../util/misc" import { keyNames } from "./keynames" -export var keyMap = {} +export let keyMap = {} keyMap.basic = { "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", @@ -49,10 +49,11 @@ keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault // KEYMAP DISPATCH function normalizeKeyName(name) { - var parts = name.split(/-(?!$)/), name = parts[parts.length - 1] - var alt, ctrl, shift, cmd - for (var i = 0; i < parts.length - 1; i++) { - var mod = parts[i] + let parts = name.split(/-(?!$)/) + name = parts[parts.length - 1] + let alt, ctrl, shift, cmd + for (let i = 0; i < parts.length - 1; i++) { + let mod = parts[i] if (/^(cmd|meta|m)$/i.test(mod)) cmd = true else if (/^a(lt)?$/i.test(mod)) alt = true else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true @@ -72,15 +73,15 @@ function normalizeKeyName(name) { // new normalized keymap, and then updates the old object to reflect // this. export function normalizeKeyMap(keymap) { - var copy = {} - for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) { - var value = keymap[keyname] + let copy = {} + for (let keyname in keymap) if (keymap.hasOwnProperty(keyname)) { + let value = keymap[keyname] if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue if (value == "...") { delete keymap[keyname]; continue } - var keys = map(keyname.split(" "), normalizeKeyName) - for (var i = 0; i < keys.length; i++) { - var val, name + let keys = map(keyname.split(" "), normalizeKeyName) + for (let i = 0; i < keys.length; i++) { + let val, name if (i == keys.length - 1) { name = keys.join(" ") val = value @@ -88,19 +89,19 @@ export function normalizeKeyMap(keymap) { name = keys.slice(0, i + 1).join(" ") val = "..." } - var prev = copy[name] + let prev = copy[name] if (!prev) copy[name] = val else if (prev != val) throw new Error("Inconsistent bindings for " + name) } delete keymap[keyname] } - for (var prop in copy) keymap[prop] = copy[prop] + for (let prop in copy) keymap[prop] = copy[prop] return keymap } export function lookupKey(key, map, handle, context) { map = getKeyMap(map) - var found = map.call ? map.call(key, context) : map[key] + let found = map.call ? map.call(key, context) : map[key] if (found === false) return "nothing" if (found === "...") return "multi" if (found != null && handle(found)) return "handled" @@ -108,8 +109,8 @@ export function lookupKey(key, map, handle, context) { if (map.fallthrough) { if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") return lookupKey(key, map.fallthrough, handle, context) - for (var i = 0; i < map.fallthrough.length; i++) { - var result = lookupKey(key, map.fallthrough[i], handle, context) + for (let i = 0; i < map.fallthrough.length; i++) { + let result = lookupKey(key, map.fallthrough[i], handle, context) if (result) return result } } @@ -118,14 +119,14 @@ export function lookupKey(key, map, handle, context) { // Modifier key presses don't count as 'real' key presses for the // purpose of keymap fallthrough. export function isModifierKey(value) { - var name = typeof value == "string" ? value : keyNames[value.keyCode] + let name = typeof value == "string" ? value : keyNames[value.keyCode] return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod" } // Look up the name of a key as indicated by an event object. export function keyName(event, noShift) { if (presto && event.keyCode == 34 && event["char"]) return false - var base = keyNames[event.keyCode], name = base + let base = keyNames[event.keyCode], name = base if (name == null || event.altGraphKey) return false if (event.altKey && base != "Alt") name = "Alt-" + name if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name diff --git a/src/input/keynames.js b/src/input/keynames.js index 8cf11f38cd..66bc80010c 100644 --- a/src/input/keynames.js +++ b/src/input/keynames.js @@ -1,4 +1,4 @@ -export var keyNames = { +export let keyNames = { 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", @@ -10,8 +10,8 @@ export var keyNames = { } // Number keys -for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i) +for (let i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i) // Alphabetic keys -for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i) +for (let i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i) // Function keys -for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i +for (let i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i diff --git a/src/line/highlight.js b/src/line/highlight.js index 0632be6e3e..8fd6d47b99 100644 --- a/src/line/highlight.js +++ b/src/line/highlight.js @@ -12,20 +12,20 @@ import { clipPos } from "./pos" export 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], lineClasses = {} + let st = [cm.state.modeGen], lineClasses = {} // Compute the base array of styles runMode(cm, line.text, cm.doc.mode, state, function(end, style) { st.push(end, style) }, lineClasses, forceToEnd) // Run overlays, adjust style array. - for (var o = 0; o < cm.state.overlays.length; ++o) { - var overlay = cm.state.overlays[o], i = 1, at = 0 + for (let o = 0; o < cm.state.overlays.length; ++o) { + let overlay = cm.state.overlays[o], i = 1, at = 0 runMode(cm, line.text, overlay.mode, true, function(end, style) { - var start = i + let start = i // Ensure there's a token end at the current position, and that i points at it while (at < end) { - var i_end = st[i] + let i_end = st[i] if (i_end > end) st.splice(i, 1, end, st[i+1], i_end) i += 2 @@ -37,7 +37,7 @@ export function highlightLine(cm, line, state, forceToEnd) { i = start + 2 } else { for (; start < i; start += 2) { - var cur = st[start+1] + let cur = st[start+1] st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style } } @@ -49,8 +49,8 @@ export function highlightLine(cm, line, state, forceToEnd) { export function getLineStyles(cm, line, updateFrontier) { if (!line.styles || line.styles[0] != cm.state.modeGen) { - var state = getStateBefore(cm, lineNo(line)) - var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state) + let state = getStateBefore(cm, lineNo(line)) + let result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state) line.stateAfter = state line.styles = result.styles if (result.classes) line.styleClasses = result.classes @@ -61,14 +61,14 @@ export function getLineStyles(cm, line, updateFrontier) { } export function getStateBefore(cm, n, precise) { - var doc = cm.doc, display = cm.display + let doc = cm.doc, display = cm.display if (!doc.mode.startState) return true - var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter + let pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter if (!state) state = startState(doc.mode) else state = copyState(doc.mode, state) doc.iter(pos, n, function(line) { processLine(cm, line.text, state) - var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo + let save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo line.stateAfter = save ? copyState(doc.mode, state) : null ++pos }) @@ -80,8 +80,8 @@ export function getStateBefore(cm, n, precise) { // update state, but don't save a style array. Used for lines that // aren't currently visible. export function processLine(cm, text, state, startAt) { - var mode = cm.doc.mode - var stream = new StringStream(text, cm.options.tabSize) + let mode = cm.doc.mode + let stream = new StringStream(text, cm.options.tabSize) stream.start = stream.pos = startAt || 0 if (text == "") callBlankLine(mode, state) while (!stream.eol()) { @@ -93,14 +93,14 @@ export function processLine(cm, text, state, startAt) { function callBlankLine(mode, state) { if (mode.blankLine) return mode.blankLine(state) if (!mode.innerMode) return - var inner = innerMode(mode, state) + let inner = innerMode(mode, state) if (inner.mode.blankLine) return inner.mode.blankLine(inner.state) } export function readToken(mode, stream, state, inner) { - for (var i = 0; i < 10; i++) { + for (let i = 0; i < 10; i++) { if (inner) inner[0] = innerMode(mode, state).mode - var style = mode.token(stream, state) + let style = mode.token(stream, state) if (stream.pos > stream.start) return style } throw new Error("Mode " + mode.name + " failed to advance stream.") @@ -115,10 +115,10 @@ export function takeToken(cm, pos, precise, asArray) { state: copy ? copyState(doc.mode, state) : state} } - var doc = cm.doc, mode = doc.mode, style + let doc = cm.doc, mode = doc.mode, style pos = clipPos(doc, pos) - var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise) - var stream = new StringStream(line.text, cm.options.tabSize), tokens + let line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise) + let stream = new StringStream(line.text, cm.options.tabSize), tokens if (asArray) tokens = [] while ((asArray || stream.pos < pos.ch) && !stream.eol()) { stream.start = stream.pos @@ -130,10 +130,10 @@ export function takeToken(cm, pos, precise, asArray) { function extractLineClasses(type, output) { if (type) for (;;) { - var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/) + let lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/) if (!lineClass) break type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length) - var prop = lineClass[1] ? "bgClass" : "textClass" + let prop = lineClass[1] ? "bgClass" : "textClass" if (output[prop] == null) output[prop] = lineClass[2] else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) @@ -144,11 +144,11 @@ function extractLineClasses(type, output) { // Run the given mode's parser over a line, calling f for each token. function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { - var flattenSpans = mode.flattenSpans + let flattenSpans = mode.flattenSpans if (flattenSpans == null) flattenSpans = cm.options.flattenSpans - var curStart = 0, curStyle = null - var stream = new StringStream(text, cm.options.tabSize), style - var inner = cm.options.addModeClass && [null] + let curStart = 0, curStyle = null + let stream = new StringStream(text, cm.options.tabSize), style + let inner = cm.options.addModeClass && [null] if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses) while (!stream.eol()) { if (stream.pos > cm.options.maxHighlightLength) { @@ -160,7 +160,7 @@ function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses) } if (inner) { - var mName = inner[0].name + let mName = inner[0].name if (mName) style = "m-" + (style ? mName + " " + style : mName) } if (!flattenSpans || curStyle != style) { @@ -176,7 +176,7 @@ function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { // Webkit seems to refuse to render text nodes longer than 57444 // characters, and returns inaccurate measurements in nodes // starting around 5000 chars. - var pos = Math.min(stream.pos, curStart + 5000) + let pos = Math.min(stream.pos, curStart + 5000) f(pos, curStyle) curStart = pos } @@ -188,13 +188,13 @@ function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { // smallest indentation, which tends to need the least context to // parse correctly. function findStartLine(cm, n, precise) { - var minindent, minline, doc = cm.doc - var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100) - for (var search = n; search > lim; --search) { + let minindent, minline, doc = cm.doc + let lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100) + for (let search = n; search > lim; --search) { if (search <= doc.first) return doc.first - var line = getLine(doc, search - 1) + let line = getLine(doc, search - 1) if (line.stateAfter && (!precise || search <= doc.frontier)) return search - var indented = countColumn(line.text, null, cm.options.tabSize) + let indented = countColumn(line.text, null, cm.options.tabSize) if (minline == null || minindent > indented) { minline = search - 1 minindent = indented diff --git a/src/line/line_data.js b/src/line/line_data.js index 8b247d5306..7a3a412211 100644 --- a/src/line/line_data.js +++ b/src/line/line_data.js @@ -31,7 +31,7 @@ export function updateLine(line, text, markedSpans, estimateHeight) { if (line.order != null) line.order = null detachMarkedSpans(line) attachMarkedSpans(line, markedSpans) - var estHeight = estimateHeight ? estimateHeight(line) : 1 + let estHeight = estimateHeight ? estimateHeight(line) : 1 if (estHeight != line.height) updateLineHeight(line, estHeight) } @@ -44,10 +44,10 @@ export function cleanUpLine(line) { // Convert a style as returned by a mode (either null, or a string // containing one or more styles) to a CSS style. This is cached, // and also looks for line-wide styles. -var styleToClassCache = {}, styleToClassCacheWithMode = {} +let styleToClassCache = {}, styleToClassCacheWithMode = {} function interpretTokenStyle(style, options) { if (!style || /^\s*$/.test(style)) return null - var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache + let cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache return cache[style] || (cache[style] = style.replace(/\S+/g, "cm-$&")) } @@ -61,16 +61,16 @@ export function buildLineContent(cm, lineView) { // The padding-right forces the element to have a 'border', which // is needed on Webkit to be able to get line-level bounding // rectangles for it (in measureChar). - var content = elt("span", null, null, webkit ? "padding-right: .1px" : null) - var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content, + let content = elt("span", null, null, webkit ? "padding-right: .1px" : null) + let builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content, col: 0, pos: 0, cm: cm, trailingSpace: false, splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")} lineView.measure = {} // Iterate over the logical lines that make up this visual line. - for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { - var line = i ? lineView.rest[i - 1] : lineView.line, order + for (let i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { + let line = i ? lineView.rest[i - 1] : lineView.line, order builder.pos = 0 builder.addToken = buildToken // Optionally wire in some hacks into the token-rendering @@ -78,7 +78,7 @@ export function buildLineContent(cm, lineView) { if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) builder.addToken = buildTokenBadBidi(builder.addToken, order) builder.map = [] - var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line) + let allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line) insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)) if (line.styleClasses) { if (line.styleClasses.bgClass) @@ -103,7 +103,7 @@ export function buildLineContent(cm, lineView) { // See issue #2901 if (webkit) { - var last = builder.content.lastChild + let last = builder.content.lastChild if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab"))) builder.content.className = "cm-tab-wrap-hack" } @@ -116,7 +116,7 @@ export function buildLineContent(cm, lineView) { } export function defaultSpecialCharPlaceholder(ch) { - var token = elt("span", "\u2022", "cm-invalidchar") + let token = elt("span", "\u2022", "cm-invalidchar") token.title = "\\u" + ch.charCodeAt(0).toString(16) token.setAttribute("aria-label", token.title) return token @@ -126,22 +126,24 @@ export function defaultSpecialCharPlaceholder(ch) { // the line map. Takes care to render special characters separately. function buildToken(builder, text, style, startStyle, endStyle, title, css) { if (!text) return - var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text - var special = builder.cm.state.specialChars, mustWrap = false + let displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text + let special = builder.cm.state.specialChars, mustWrap = false + let content if (!special.test(text)) { builder.col += text.length - var content = document.createTextNode(displayText) + content = document.createTextNode(displayText) builder.map.push(builder.pos, builder.pos + text.length, content) if (ie && ie_version < 9) mustWrap = true builder.pos += text.length } else { - var content = document.createDocumentFragment(), pos = 0 + content = document.createDocumentFragment() + let pos = 0 while (true) { special.lastIndex = pos - var m = special.exec(text) - var skipped = m ? m.index - pos : text.length - pos + let m = special.exec(text) + let skipped = m ? m.index - pos : text.length - pos if (skipped) { - var txt = document.createTextNode(displayText.slice(pos, pos + skipped)) + let txt = document.createTextNode(displayText.slice(pos, pos + skipped)) if (ie && ie_version < 9) content.appendChild(elt("span", [txt])) else content.appendChild(txt) builder.map.push(builder.pos, builder.pos + skipped, txt) @@ -150,18 +152,19 @@ function buildToken(builder, text, style, startStyle, endStyle, title, css) { } if (!m) break pos += skipped + 1 + let txt if (m[0] == "\t") { - var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize - var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")) + let tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize + txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")) txt.setAttribute("role", "presentation") txt.setAttribute("cm-text", "\t") builder.col += tabWidth } else if (m[0] == "\r" || m[0] == "\n") { - var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")) + txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")) txt.setAttribute("cm-text", m[0]) builder.col += 1 } else { - var txt = builder.cm.options.specialCharPlaceholder(m[0]) + txt = builder.cm.options.specialCharPlaceholder(m[0]) txt.setAttribute("cm-text", m[0]) if (ie && ie_version < 9) content.appendChild(elt("span", [txt])) else content.appendChild(txt) @@ -173,10 +176,10 @@ function buildToken(builder, text, style, startStyle, endStyle, title, css) { } builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32 if (style || startStyle || endStyle || mustWrap || css) { - var fullStyle = style || "" + let fullStyle = style || "" if (startStyle) fullStyle += startStyle if (endStyle) fullStyle += endStyle - var token = elt("span", [content], fullStyle, css) + let token = elt("span", [content], fullStyle, css) if (title) token.title = title return builder.content.appendChild(token) } @@ -185,9 +188,9 @@ function buildToken(builder, text, style, startStyle, endStyle, title, css) { function splitSpaces(text, trailingBefore) { if (text.length > 1 && !/ /.test(text)) return text - var spaceBefore = trailingBefore, result = "" - for (var i = 0; i < text.length; i++) { - var ch = text.charAt(i) + let spaceBefore = trailingBefore, result = "" + for (let i = 0; i < text.length; i++) { + let ch = text.charAt(i) if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32)) ch = "\u00a0" result += ch @@ -201,11 +204,12 @@ function splitSpaces(text, trailingBefore) { function buildTokenBadBidi(inner, order) { return function(builder, text, style, startStyle, endStyle, title, css) { style = style ? style + " cm-force-border" : "cm-force-border" - var start = builder.pos, end = start + text.length + let start = builder.pos, end = start + text.length for (;;) { // Find the part that overlaps with the start of this text - for (var i = 0; i < order.length; i++) { - var part = order[i] + let part + for (let i = 0; i < order.length; i++) { + part = order[i] if (part.to > start && part.from <= start) break } if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css) @@ -218,7 +222,7 @@ function buildTokenBadBidi(inner, order) { } function buildCollapsedSpan(builder, size, marker, ignoreWidget) { - var widget = !ignoreWidget && marker.widgetNode + let widget = !ignoreWidget && marker.widgetNode if (widget) builder.map.push(builder.pos, builder.pos + size, widget) if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { if (!widget) @@ -236,22 +240,22 @@ function buildCollapsedSpan(builder, size, marker, ignoreWidget) { // Outputs a number of spans to make up a line, taking highlighting // and marked text into account. function insertLineContent(line, builder, styles) { - var spans = line.markedSpans, allText = line.text, at = 0 + let spans = line.markedSpans, allText = line.text, at = 0 if (!spans) { - for (var i = 1; i < styles.length; i+=2) + for (let i = 1; i < styles.length; i+=2) builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options)) return } - var len = allText.length, pos = 0, i = 1, text = "", style, css - var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed + let len = allText.length, pos = 0, i = 1, text = "", style, css + let nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed for (;;) { if (nextChange == pos) { // Update current marker set spanStyle = spanEndStyle = spanStartStyle = title = css = "" collapsed = null; nextChange = Infinity - var foundBookmarks = [], endStyles - for (var j = 0; j < spans.length; ++j) { - var sp = spans[j], m = sp.marker + let foundBookmarks = [], endStyles + for (let j = 0; j < spans.length; ++j) { + let sp = spans[j], m = sp.marker if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { foundBookmarks.push(m) } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { @@ -270,10 +274,10 @@ function insertLineContent(line, builder, styles) { nextChange = sp.from } } - if (endStyles) for (var j = 0; j < endStyles.length; j += 2) + if (endStyles) for (let j = 0; j < endStyles.length; j += 2) if (endStyles[j + 1] == nextChange) spanEndStyle += " " + endStyles[j] - if (!collapsed || collapsed.from == pos) for (var j = 0; j < foundBookmarks.length; ++j) + if (!collapsed || collapsed.from == pos) for (let j = 0; j < foundBookmarks.length; ++j) buildCollapsedSpan(builder, 0, foundBookmarks[j]) if (collapsed && (collapsed.from || 0) == pos) { buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, @@ -284,12 +288,12 @@ function insertLineContent(line, builder, styles) { } if (pos >= len) break - var upto = Math.min(len, nextChange) + let upto = Math.min(len, nextChange) while (true) { if (text) { - var end = pos + text.length + let end = pos + text.length if (!collapsed) { - var tokenText = end > upto ? text.slice(0, upto - pos) : text + let tokenText = end > upto ? text.slice(0, upto - pos) : text builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css) } @@ -320,9 +324,9 @@ export function LineView(doc, line, lineN) { // Create a range of LineView objects for the given lines. export function buildViewArray(cm, from, to) { - var array = [], nextPos - for (var pos = from; pos < to; pos = nextPos) { - var view = new LineView(cm.doc, getLine(cm.doc, pos), pos) + let array = [], nextPos + for (let pos = from; pos < to; pos = nextPos) { + let view = new LineView(cm.doc, getLine(cm.doc, pos), pos) nextPos = pos + view.size array.push(view) } diff --git a/src/line/pos.js b/src/line/pos.js index b5d2513abe..73b2e0b8e8 100644 --- a/src/line/pos.js +++ b/src/line/pos.js @@ -19,17 +19,18 @@ export function minPos(a, b) { return cmp(a, b) < 0 ? a : b } export function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))} export function clipPos(doc, pos) { if (pos.line < doc.first) return Pos(doc.first, 0) - var last = doc.first + doc.size - 1 + let last = doc.first + doc.size - 1 if (pos.line > last) return Pos(last, getLine(doc, last).text.length) return clipToLen(pos, getLine(doc, pos.line).text.length) } function clipToLen(pos, linelen) { - var ch = pos.ch + let ch = pos.ch if (ch == null || ch > linelen) return Pos(pos.line, linelen) else if (ch < 0) return Pos(pos.line, 0) else return pos } export function clipPosArray(doc, array) { - for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]) + let out = [] + for (let i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]) return out } diff --git a/src/line/saw_special_spans.js b/src/line/saw_special_spans.js index 0cf5ff320b..d315e7ba99 100644 --- a/src/line/saw_special_spans.js +++ b/src/line/saw_special_spans.js @@ -1,5 +1,5 @@ // Optimize some code when these features are not used. -export var sawReadOnlySpans = false, sawCollapsedSpans = false +export let sawReadOnlySpans = false, sawCollapsedSpans = false export function seeReadOnlySpans() { sawReadOnlySpans = true diff --git a/src/line/spans.js b/src/line/spans.js index fd9bd55408..63acacfc83 100644 --- a/src/line/spans.js +++ b/src/line/spans.js @@ -13,15 +13,16 @@ export function MarkedSpan(marker, from, to) { // Search an array of spans for a span matching the given marker. export function getMarkedSpanFor(spans, marker) { - if (spans) for (var i = 0; i < spans.length; ++i) { - var span = spans[i] + if (spans) for (let i = 0; i < spans.length; ++i) { + let span = spans[i] if (span.marker == marker) return span } } // Remove a span from an array, returning undefined if no spans are // left (we don't store arrays for lines without spans). export function removeMarkedSpan(spans, span) { - for (var r, i = 0; i < spans.length; ++i) + let r + for (let i = 0; i < spans.length; ++i) if (spans[i] != span) (r || (r = [])).push(spans[i]) return r } @@ -36,22 +37,24 @@ export function addMarkedSpan(line, span) { // character position, returning an array of remaining chunks (or // undefined if nothing remains). function markedSpansBefore(old, startCh, isInsert) { - 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) + let nw + if (old) for (let i = 0; i < old.length; ++i) { + let span = old[i], marker = span.marker + let startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh) if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh) + let endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh) ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)) } } return nw } function markedSpansAfter(old, endCh, isInsert) { - if (old) for (var i = 0, nw; i < old.length; ++i) { - var span = old[i], marker = span.marker - var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh) + let nw + if (old) for (let i = 0; i < old.length; ++i) { + let span = old[i], marker = span.marker + let endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh) if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { - var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh) + let startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh) ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, span.to == null ? null : span.to - endCh)) } @@ -67,23 +70,23 @@ function markedSpansAfter(old, endCh, isInsert) { // arrays with one element for each line in (after) the change. export function stretchSpansOverChange(doc, change) { if (change.full) return null - var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans - var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans + let oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans + let oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans if (!oldFirst && !oldLast) return null - var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0 + let startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0 // Get the spans that 'stick out' on both sides - var first = markedSpansBefore(oldFirst, startCh, isInsert) - var last = markedSpansAfter(oldLast, endCh, isInsert) + let first = markedSpansBefore(oldFirst, startCh, isInsert) + let last = markedSpansAfter(oldLast, endCh, isInsert) // Next, merge those two ends - var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0) + let sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0) if (first) { // Fix up .to properties of first - for (var i = 0; i < first.length; ++i) { - var span = first[i] + for (let i = 0; i < first.length; ++i) { + let span = first[i] if (span.to == null) { - var found = getMarkedSpanFor(last, span.marker) + let found = getMarkedSpanFor(last, span.marker) if (!found) span.to = startCh else if (sameLine) span.to = found.to == null ? null : found.to + offset } @@ -91,11 +94,11 @@ export function stretchSpansOverChange(doc, change) { } if (last) { // Fix up .from in last (or move them into first in case of sameLine) - for (var i = 0; i < last.length; ++i) { - var span = last[i] + for (let i = 0; i < last.length; ++i) { + let span = last[i] if (span.to != null) span.to += offset if (span.from == null) { - var found = getMarkedSpanFor(first, span.marker) + let found = getMarkedSpanFor(first, span.marker) if (!found) { span.from = offset if (sameLine) (first || (first = [])).push(span) @@ -110,15 +113,15 @@ export function stretchSpansOverChange(doc, change) { if (first) first = clearEmptySpans(first) if (last && last != first) last = clearEmptySpans(last) - var newMarkers = [first] + let newMarkers = [first] if (!sameLine) { // Fill gap with whole-line-spans - var gap = change.text.length - 2, gapMarkers + let gap = change.text.length - 2, gapMarkers if (gap > 0 && first) - for (var i = 0; i < first.length; ++i) + for (let i = 0; i < first.length; ++i) if (first[i].to == null) (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)) - for (var i = 0; i < gap; ++i) + for (let i = 0; i < gap; ++i) newMarkers.push(gapMarkers) newMarkers.push(last) } @@ -128,8 +131,8 @@ export function stretchSpansOverChange(doc, change) { // Remove spans that are empty and don't have a clearWhenEmpty // option of false. function clearEmptySpans(spans) { - for (var i = 0; i < spans.length; ++i) { - var span = spans[i] + for (let i = 0; i < spans.length; ++i) { + let span = spans[i] if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) spans.splice(i--, 1) } @@ -139,22 +142,22 @@ function clearEmptySpans(spans) { // Used to 'clip' out readOnly ranges when making a change. export function removeReadOnlyRanges(doc, from, to) { - var markers = null + let markers = null doc.iter(from.line, to.line + 1, function(line) { - if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { - var mark = line.markedSpans[i].marker + if (line.markedSpans) for (let i = 0; i < line.markedSpans.length; ++i) { + let mark = line.markedSpans[i].marker if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) (markers || (markers = [])).push(mark) } }) if (!markers) return null - var parts = [{from: from, to: to}] - for (var i = 0; i < markers.length; ++i) { - var mk = markers[i], m = mk.find(0) - for (var j = 0; j < parts.length; ++j) { - var p = parts[j] + let parts = [{from: from, to: to}] + for (let i = 0; i < markers.length; ++i) { + let mk = markers[i], m = mk.find(0) + for (let j = 0; j < parts.length; ++j) { + let p = parts[j] if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue - var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to) + let newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to) if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) newParts.push({from: p.from, to: m.from}) if (dto > 0 || !mk.inclusiveRight && !dto) @@ -168,15 +171,15 @@ export function removeReadOnlyRanges(doc, from, to) { // Connect or disconnect spans from a line. export function detachMarkedSpans(line) { - var spans = line.markedSpans + let spans = line.markedSpans if (!spans) return - for (var i = 0; i < spans.length; ++i) + for (let i = 0; i < spans.length; ++i) spans[i].marker.detachLine(line) line.markedSpans = null } export function attachMarkedSpans(line, spans) { if (!spans) return - for (var i = 0; i < spans.length; ++i) + for (let i = 0; i < spans.length; ++i) spans[i].marker.attachLine(line) line.markedSpans = spans } @@ -190,12 +193,12 @@ function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 } // spans is larger (and thus includes the other). Falls back to // comparing ids when the spans cover exactly the same range. export function compareCollapsedMarkers(a, b) { - var lenDiff = a.lines.length - b.lines.length + let lenDiff = a.lines.length - b.lines.length if (lenDiff != 0) return lenDiff - var aPos = a.find(), bPos = b.find() - var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b) + let aPos = a.find(), bPos = b.find() + let fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b) if (fromCmp) return -fromCmp - var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b) + let toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b) if (toCmp) return toCmp return b.id - a.id } @@ -203,8 +206,8 @@ export function compareCollapsedMarkers(a, b) { // Find out whether a line ends or starts in a collapsed span. If // so, return the marker for that span. function collapsedSpanAtSide(line, start) { - var sps = sawCollapsedSpans && line.markedSpans, found - if (sps) for (var sp, i = 0; i < sps.length; ++i) { + let sps = sawCollapsedSpans && line.markedSpans, found + if (sps) for (let sp, i = 0; i < sps.length; ++i) { sp = sps[i] if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && (!found || compareCollapsedMarkers(found, sp.marker) < 0)) @@ -219,14 +222,14 @@ export function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, fals // overlaps (covers the start or end, but not both) of a new span. // Such overlap is not allowed. export function conflictingCollapsedRange(doc, lineNo, from, to, marker) { - var line = getLine(doc, lineNo) - var sps = sawCollapsedSpans && line.markedSpans - if (sps) for (var i = 0; i < sps.length; ++i) { - var sp = sps[i] + let line = getLine(doc, lineNo) + let sps = sawCollapsedSpans && line.markedSpans + if (sps) for (let i = 0; i < sps.length; ++i) { + let sp = sps[i] if (!sp.marker.collapsed) continue - var found = sp.marker.find(0) - var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker) - var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker) + let found = sp.marker.find(0) + let fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker) + let toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker) if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) || fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0)) @@ -239,7 +242,7 @@ export function conflictingCollapsedRange(doc, lineNo, from, to, marker) { // visual line. This finds the start of the visual line that the // given line is part of (usually that is the line itself). export function visualLine(line) { - var merged + let merged while (merged = collapsedSpanAtStart(line)) line = merged.find(-1, true).line return line @@ -248,7 +251,7 @@ export function visualLine(line) { // Returns an array of logical lines that continue the visual line // started by the argument, or undefined if there are no such lines. export function visualLineContinued(line) { - var merged, lines + let merged, lines while (merged = collapsedSpanAtEnd(line)) { line = merged.find(1, true).line ;(lines || (lines = [])).push(line) @@ -259,7 +262,7 @@ export function visualLineContinued(line) { // Get the line number of the start of the visual line that the // given line number is part of. export function visualLineNo(doc, lineN) { - var line = getLine(doc, lineN), vis = visualLine(line) + let line = getLine(doc, lineN), vis = visualLine(line) if (line == vis) return lineN return lineNo(vis) } @@ -268,7 +271,7 @@ export function visualLineNo(doc, lineN) { // the given line. export function visualLineEndNo(doc, lineN) { if (lineN > doc.lastLine()) return lineN - var line = getLine(doc, lineN), merged + let line = getLine(doc, lineN), merged if (!lineIsHidden(doc, line)) return lineN while (merged = collapsedSpanAtEnd(line)) line = merged.find(1, true).line @@ -279,8 +282,8 @@ export function visualLineEndNo(doc, lineN) { // are part of a visual line that starts with another line, or when // they are entirely covered by collapsed, non-widget span. export function lineIsHidden(doc, line) { - var sps = sawCollapsedSpans && line.markedSpans - if (sps) for (var sp, i = 0; i < sps.length; ++i) { + let sps = sawCollapsedSpans && line.markedSpans + if (sps) for (let sp, i = 0; i < sps.length; ++i) { sp = sps[i] if (!sp.marker.collapsed) continue if (sp.from == null) return true @@ -291,12 +294,12 @@ export function lineIsHidden(doc, line) { } function lineIsHiddenInner(doc, line, span) { if (span.to == null) { - var end = span.marker.find(1, true) + let end = span.marker.find(1, true) return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)) } if (span.marker.inclusiveRight && span.to == line.text.length) return true - for (var sp, i = 0; i < line.markedSpans.length; ++i) { + for (let sp, i = 0; i < line.markedSpans.length; ++i) { sp = line.markedSpans[i] if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && (sp.to == null || sp.to != span.from) && @@ -309,15 +312,15 @@ function lineIsHiddenInner(doc, line, span) { export function heightAtLine(lineObj) { lineObj = visualLine(lineObj) - var h = 0, chunk = lineObj.parent - for (var i = 0; i < chunk.lines.length; ++i) { - var line = chunk.lines[i] + let h = 0, chunk = lineObj.parent + for (let i = 0; i < chunk.lines.length; ++i) { + let line = chunk.lines[i] if (line == lineObj) break else h += line.height } - for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { - for (var i = 0; i < p.children.length; ++i) { - var cur = p.children[i] + for (let p = chunk.parent; p; chunk = p, p = chunk.parent) { + for (let i = 0; i < p.children.length; ++i) { + let cur = p.children[i] if (cur == chunk) break else h += cur.height } @@ -330,15 +333,15 @@ export function heightAtLine(lineObj) { // other lines onto it. export function lineLength(line) { if (line.height == 0) return 0 - var len = line.text.length, merged, cur = line + let len = line.text.length, merged, cur = line while (merged = collapsedSpanAtStart(cur)) { - var found = merged.find(0, true) + let found = merged.find(0, true) cur = found.from.line len += found.from.ch - found.to.ch } cur = line while (merged = collapsedSpanAtEnd(cur)) { - var found = merged.find(0, true) + let found = merged.find(0, true) len -= cur.text.length - found.from.ch cur = found.to.line len += cur.text.length - found.to.ch @@ -348,12 +351,12 @@ export function lineLength(line) { // Find the longest line in the document. export function findMaxLine(cm) { - var d = cm.display, doc = cm.doc + let d = cm.display, doc = cm.doc d.maxLine = getLine(doc, doc.first) d.maxLineLength = lineLength(d.maxLine) d.maxLineChanged = true doc.iter(function(line) { - var len = lineLength(line) + let len = lineLength(line) if (len > d.maxLineLength) { d.maxLineLength = len d.maxLine = line diff --git a/src/line/utils_line.js b/src/line/utils_line.js index 4e10a1d8d8..647c07791e 100644 --- a/src/line/utils_line.js +++ b/src/line/utils_line.js @@ -4,9 +4,10 @@ import { indexOf } from "../util/misc" export function getLine(doc, n) { n -= doc.first if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.") - for (var chunk = doc; !chunk.lines;) { - for (var i = 0;; ++i) { - var child = chunk.children[i], sz = child.chunkSize() + let chunk = doc + while (!chunk.lines) { + for (let i = 0;; ++i) { + let child = chunk.children[i], sz = child.chunkSize() if (n < sz) { chunk = child; break } n -= sz } @@ -17,9 +18,9 @@ export function getLine(doc, n) { // Get the part of a document between two positions, as an array of // strings. export function getBetween(doc, start, end) { - var out = [], n = start.line + let out = [], n = start.line doc.iter(start.line, end.line + 1, function(line) { - var text = line.text + let text = line.text if (n == end.line) text = text.slice(0, end.ch) if (n == start.line) text = text.slice(start.ch) out.push(text) @@ -29,7 +30,7 @@ export function getBetween(doc, start, end) { } // Get the lines between from and to, as array of strings. export function getLines(doc, from, to) { - var out = [] + let out = [] doc.iter(from, to, function(line) { out.push(line.text) }) return out } @@ -37,17 +38,17 @@ export function getLines(doc, from, to) { // Update the height of a line, propagating the height change // upwards to parent nodes. export function updateLineHeight(line, height) { - var diff = height - line.height - if (diff) for (var n = line; n; n = n.parent) n.height += diff + let diff = height - line.height + if (diff) for (let n = line; n; n = n.parent) n.height += diff } // Given a line object, find its line number by walking up through // its parent links. export 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) { - for (var i = 0;; ++i) { + let cur = line.parent, no = indexOf(cur.lines, line) + for (let chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { + for (let i = 0;; ++i) { if (chunk.children[i] == cur) break no += chunk.children[i].chunkSize() } @@ -58,18 +59,19 @@ export function lineNo(line) { // Find the line at the given vertical position, using the height // information in the document tree. export function lineAtHeight(chunk, h) { - var n = chunk.first + let n = chunk.first outer: do { - for (var i = 0; i < chunk.children.length; ++i) { - var child = chunk.children[i], ch = child.height + for (let i = 0; i < chunk.children.length; ++i) { + let child = chunk.children[i], ch = child.height if (h < ch) { chunk = child; continue outer } h -= ch n += child.chunkSize() } return n } while (!chunk.lines) - for (var i = 0; i < chunk.lines.length; ++i) { - var line = chunk.lines[i], lh = line.height + let i = 0 + for (; i < chunk.lines.length; ++i) { + let line = chunk.lines[i], lh = line.height if (h < lh) break h -= lh } diff --git a/src/measurement/position_measurement.js b/src/measurement/position_measurement.js index 75011a34d3..63e3771b1f 100644 --- a/src/measurement/position_measurement.js +++ b/src/measurement/position_measurement.js @@ -18,9 +18,9 @@ export function paddingTop(display) {return display.lineSpace.offsetTop} export function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight} export function paddingH(display) { if (display.cachedPaddingH) return display.cachedPaddingH - var e = removeChildrenAndAdd(display.measure, elt("pre", "x")) - var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle - var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)} + let e = removeChildrenAndAdd(display.measure, elt("pre", "x")) + let style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle + let data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)} if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data return data } @@ -38,15 +38,15 @@ export function displayHeight(cm) { // line. When lineWrapping is on, there might be more than one // height. function ensureLineHeights(cm, lineView, rect) { - var wrapping = cm.options.lineWrapping - var curWidth = wrapping && displayWidth(cm) + let wrapping = cm.options.lineWrapping + let curWidth = wrapping && displayWidth(cm) if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { - var heights = lineView.measure.heights = [] + let heights = lineView.measure.heights = [] if (wrapping) { lineView.measure.width = curWidth - var rects = lineView.text.firstChild.getClientRects() - for (var i = 0; i < rects.length - 1; i++) { - var cur = rects[i], next = rects[i + 1] + let rects = lineView.text.firstChild.getClientRects() + for (let i = 0; i < rects.length - 1; i++) { + let cur = rects[i], next = rects[i + 1] if (Math.abs(cur.bottom - next.bottom) > 2) heights.push((cur.bottom + next.top) / 2 - rect.top) } @@ -61,10 +61,10 @@ function ensureLineHeights(cm, lineView, rect) { export function mapFromLineView(lineView, line, lineN) { if (lineView.line == line) return {map: lineView.measure.map, cache: lineView.measure.cache} - for (var i = 0; i < lineView.rest.length; i++) + for (let i = 0; i < lineView.rest.length; i++) if (lineView.rest[i] == line) return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} - for (var i = 0; i < lineView.rest.length; i++) + for (let i = 0; i < lineView.rest.length; i++) if (lineNo(lineView.rest[i]) > lineN) return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true} } @@ -73,10 +73,10 @@ export function mapFromLineView(lineView, line, lineN) { // when measurement is needed for a line that's not in the viewport. function updateExternalMeasurement(cm, line) { line = visualLine(line) - var lineN = lineNo(line) - var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN) + let lineN = lineNo(line) + let view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN) view.lineN = lineN - var built = view.built = buildLineContent(cm, view) + let built = view.built = buildLineContent(cm, view) view.text = built.pre removeChildrenAndAdd(cm.display.lineMeasure, built.pre) return view @@ -92,7 +92,7 @@ export function measureChar(cm, line, ch, bias) { export function findViewForLine(cm, lineN) { if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) return cm.display.view[findViewIndex(cm, lineN)] - var ext = cm.display.externalMeasured + let ext = cm.display.externalMeasured if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) return ext } @@ -103,8 +103,8 @@ export function findViewForLine(cm, lineN) { // measurements in a row, can thus ensure that the set-up work is // only done once. function prepareMeasureForLine(cm, line) { - var lineN = lineNo(line) - var view = findViewForLine(cm, lineN) + let lineN = lineNo(line) + let view = findViewForLine(cm, lineN) if (view && !view.text) { view = null } else if (view && view.changes) { @@ -114,7 +114,7 @@ function prepareMeasureForLine(cm, line) { if (!view) view = updateExternalMeasurement(cm, line) - var info = mapFromLineView(view, line, lineN) + let info = mapFromLineView(view, line, lineN) return { line: line, view: view, rect: null, map: info.map, cache: info.cache, before: info.before, @@ -126,7 +126,7 @@ function prepareMeasureForLine(cm, line) { // actual character (or fetches it from the cache). function measureCharPrepared(cm, prepared, ch, bias, varHeight) { if (prepared.before) ch = -1 - var key = ch + (bias || ""), found + let key = ch + (bias || ""), found if (prepared.cache.hasOwnProperty(key)) { found = prepared.cache[key] } else { @@ -144,14 +144,15 @@ function measureCharPrepared(cm, prepared, ch, bias, varHeight) { bottom: varHeight ? found.rbottom : found.bottom} } -var nullRect = {left: 0, right: 0, top: 0, bottom: 0} +let nullRect = {left: 0, right: 0, top: 0, bottom: 0} export function nodeAndOffsetInLineMap(map, ch, bias) { - var node, start, end, collapse + let node, start, end, collapse, mStart, mEnd // First, search the line map for the text node corresponding to, // or closest to, the target character. - for (var i = 0; i < map.length; i += 3) { - var mStart = map[i], mEnd = map[i + 1] + for (let i = 0; i < map.length; i += 3) { + mStart = map[i] + mEnd = map[i + 1] if (ch < mStart) { start = 0; end = 1 collapse = "left" @@ -184,22 +185,22 @@ export function nodeAndOffsetInLineMap(map, ch, bias) { } function getUsefulRect(rects, bias) { - var rect = nullRect - if (bias == "left") for (var i = 0; i < rects.length; i++) { + let rect = nullRect + if (bias == "left") for (let i = 0; i < rects.length; i++) { if ((rect = rects[i]).left != rect.right) break - } else for (var i = rects.length - 1; i >= 0; i--) { + } else for (let i = rects.length - 1; i >= 0; i--) { if ((rect = rects[i]).left != rect.right) break } return rect } function measureCharInner(cm, prepared, ch, bias) { - var place = nodeAndOffsetInLineMap(prepared.map, ch, bias) - var node = place.node, start = place.start, end = place.end, collapse = place.collapse + let place = nodeAndOffsetInLineMap(prepared.map, ch, bias) + let node = place.node, start = place.start, end = place.end, collapse = place.collapse - var rect + let rect if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. - for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned + for (let i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) @@ -214,27 +215,28 @@ function measureCharInner(cm, prepared, ch, bias) { if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect) } else { // If it is a widget, simply get the box for the whole widget. if (start > 0) collapse = bias = "right" - var rects + let rects if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) rect = rects[bias == "right" ? rects.length - 1 : 0] else rect = node.getBoundingClientRect() } if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { - var rSpan = node.parentNode.getClientRects()[0] + let rSpan = node.parentNode.getClientRects()[0] if (rSpan) rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom} else rect = nullRect } - var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top - var mid = (rtop + rbot) / 2 - var heights = prepared.view.measure.heights - for (var i = 0; i < heights.length - 1; i++) + let rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top + let mid = (rtop + rbot) / 2 + let heights = prepared.view.measure.heights + let i = 0 + for (; i < heights.length - 1; i++) if (mid < heights[i]) break - var top = i ? heights[i - 1] : 0, bot = heights[i] - var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, + let top = i ? heights[i - 1] : 0, bot = heights[i] + let result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, top: top, bottom: bot} if (!rect.left && !rect.right) result.bogus = true @@ -249,8 +251,8 @@ function maybeUpdateRectForZooming(measure, rect) { if (!window.screen || screen.logicalXDPI == null || screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) return rect - var scaleX = screen.logicalXDPI / screen.deviceXDPI - var scaleY = screen.logicalYDPI / screen.deviceYDPI + let scaleX = screen.logicalXDPI / screen.deviceXDPI + let scaleY = screen.logicalYDPI / screen.deviceYDPI return {left: rect.left * scaleX, right: rect.right * scaleX, top: rect.top * scaleY, bottom: rect.bottom * scaleY} } @@ -259,7 +261,7 @@ export function clearLineMeasurementCacheFor(lineView) { if (lineView.measure) { lineView.measure.cache = {} lineView.measure.heights = null - if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + if (lineView.rest) for (let i = 0; i < lineView.rest.length; i++) lineView.measure.caches[i] = {} } } @@ -267,7 +269,7 @@ export function clearLineMeasurementCacheFor(lineView) { export function clearLineMeasurementCache(cm) { cm.display.externalMeasure = null removeChildren(cm.display.lineMeasure) - for (var i = 0; i < cm.display.view.length; i++) + for (let i = 0; i < cm.display.view.length; i++) clearLineMeasurementCacheFor(cm.display.view[i]) } @@ -286,19 +288,19 @@ function pageScrollY() { return window.pageYOffset || (document.documentElement // "line", "div" (display.lineDiv), "local"./null (editor), "window", // or "page". export function intoCoordSystem(cm, lineObj, rect, context) { - if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { - var size = widgetHeight(lineObj.widgets[i]) + if (lineObj.widgets) for (let i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { + let size = widgetHeight(lineObj.widgets[i]) rect.top += size; rect.bottom += size } if (context == "line") return rect if (!context) context = "local" - var yOff = heightAtLine(lineObj) + let yOff = heightAtLine(lineObj) if (context == "local") yOff += paddingTop(cm.display) else yOff -= cm.display.viewOffset if (context == "page" || context == "window") { - var lOff = cm.display.lineSpace.getBoundingClientRect() + let lOff = cm.display.lineSpace.getBoundingClientRect() yOff += lOff.top + (context == "window" ? 0 : pageScrollY()) - var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()) + let xOff = lOff.left + (context == "window" ? 0 : pageScrollX()) rect.left += xOff; rect.right += xOff } rect.top += yOff; rect.bottom += yOff @@ -309,18 +311,18 @@ export function intoCoordSystem(cm, lineObj, rect, context) { // Context may be "window", "page", "div", or "local"./null. export function fromCoordSystem(cm, coords, context) { if (context == "div") return coords - var left = coords.left, top = coords.top + let left = coords.left, top = coords.top // First move into "page" coordinate system if (context == "page") { left -= pageScrollX() top -= pageScrollY() } else if (context == "local" || !context) { - var localBox = cm.display.sizer.getBoundingClientRect() + let localBox = cm.display.sizer.getBoundingClientRect() left += localBox.left top += localBox.top } - var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect() + let lineSpaceBox = cm.display.lineSpace.getBoundingClientRect() return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top} } @@ -336,12 +338,12 @@ export function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeig lineObj = lineObj || getLine(cm.doc, pos.line) if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj) function get(ch, right) { - var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight) + let m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight) if (right) m.left = m.right; else m.right = m.left return intoCoordSystem(cm, lineObj, m, context) } function getBidi(ch, partPos) { - var part = order[partPos], right = part.level % 2 + let part = order[partPos], right = part.level % 2 if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { part = order[--partPos] ch = bidiRight(part) - (part.level % 2 ? 0 : 1) @@ -354,10 +356,10 @@ export function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeig if (right && ch == part.to && ch > part.from) return get(ch - 1) return get(ch, right) } - var order = getOrder(lineObj), ch = pos.ch + let order = getOrder(lineObj), ch = pos.ch if (!order) return get(ch) - var partPos = getBidiPartAt(order, ch) - var val = getBidi(ch, partPos) + let partPos = getBidiPartAt(order, ch) + let val = getBidi(ch, partPos) if (bidiOther != null) val.other = getBidi(ch, bidiOther) return val } @@ -365,10 +367,11 @@ export function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeig // Used to cheaply estimate the coordinates for a position. Used for // intermediate scroll updates. export function estimateCoords(cm, pos) { - var left = 0, pos = clipPos(cm.doc, pos) + let left = 0 + pos = clipPos(cm.doc, pos) if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch - var lineObj = getLine(cm.doc, pos.line) - var top = heightAtLine(lineObj) + paddingTop(cm.display) + let lineObj = getLine(cm.doc, pos.line) + let top = heightAtLine(lineObj) + paddingTop(cm.display) return {left: left, right: left, top: top, bottom: top + lineObj.height} } @@ -379,7 +382,7 @@ export function estimateCoords(cm, pos) { // is true, that means the coordinates lie outside the line's // vertical range. function PosWithInfo(line, ch, outside, xRel) { - var pos = Pos(line, ch) + let pos = Pos(line, ch) pos.xRel = xRel if (outside) pos.outside = true return pos @@ -388,19 +391,19 @@ function PosWithInfo(line, ch, outside, xRel) { // Compute the character position closest to the given coordinates. // Input must be lineSpace-local ("div" coordinate system). export function coordsChar(cm, x, y) { - var doc = cm.doc + let doc = cm.doc y += cm.display.viewOffset if (y < 0) return PosWithInfo(doc.first, 0, true, -1) - var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1 + let lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1 if (lineN > last) return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1) if (x < 0) x = 0 - var lineObj = getLine(doc, lineN) + let lineObj = getLine(doc, lineN) for (;;) { - var found = coordsCharInner(cm, lineObj, lineN, x, y) - var merged = collapsedSpanAtEnd(lineObj) - var mergedPos = merged && merged.find(0, true) + let found = coordsCharInner(cm, lineObj, lineN, x, y) + let merged = collapsedSpanAtEnd(lineObj) + let mergedPos = merged && merged.find(0, true) if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) lineN = lineNo(lineObj = mergedPos.to.line) else @@ -409,12 +412,12 @@ export function coordsChar(cm, x, y) { } function coordsCharInner(cm, lineObj, lineNo, x, y) { - var innerOff = y - heightAtLine(lineObj) - var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth - var preparedMeasure = prepareMeasureForLine(cm, lineObj) + let innerOff = y - heightAtLine(lineObj) + let wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth + let preparedMeasure = prepareMeasureForLine(cm, lineObj) function getX(ch) { - var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure) + let sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure) wrongLine = true if (innerOff > sp.bottom) return sp.left - adjust else if (innerOff < sp.top) return sp.left + adjust @@ -422,24 +425,24 @@ function coordsCharInner(cm, lineObj, lineNo, x, y) { return sp.left } - var bidi = getOrder(lineObj), dist = lineObj.text.length - var from = lineLeft(lineObj), to = lineRight(lineObj) - var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine + let bidi = getOrder(lineObj), dist = lineObj.text.length + let from = lineLeft(lineObj), to = lineRight(lineObj) + let fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1) // Do a binary search between these bounds. for (;;) { if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { - var ch = x < fromX || x - fromX <= toX - x ? from : to - var outside = ch == from ? fromOutside : toOutside - var xDiff = x - (ch == from ? fromX : toX) + let ch = x < fromX || x - fromX <= toX - x ? from : to + let outside = ch == from ? fromOutside : toOutside + let xDiff = x - (ch == from ? fromX : toX) // This is a kludge to handle the case where the coordinates // are after a line-wrapped line. We should replace it with a // more general handling of cursor positions around line // breaks. (Issue #4078) if (toOutside && !bidi && !/\s/.test(lineObj.text.charAt(ch)) && xDiff > 0 && ch < lineObj.text.length && preparedMeasure.view.measure.heights.length > 1) { - var charSize = measureCharPrepared(cm, preparedMeasure, ch, "right") + let charSize = measureCharPrepared(cm, preparedMeasure, ch, "right") if (innerOff <= charSize.bottom && innerOff >= charSize.top && Math.abs(x - charSize.right) < xDiff) { outside = false ch++ @@ -447,21 +450,21 @@ function coordsCharInner(cm, lineObj, lineNo, x, y) { } } while (isExtendingChar(lineObj.text.charAt(ch))) ++ch - var pos = PosWithInfo(lineNo, ch, outside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0) + let pos = PosWithInfo(lineNo, ch, outside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0) return pos } - var step = Math.ceil(dist / 2), middle = from + step + let step = Math.ceil(dist / 2), middle = from + step if (bidi) { middle = from - for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1) + for (let i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1) } - var middleX = getX(middle) + let middleX = getX(middle) if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step} else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step} } } -var measureText +let measureText // Compute the default text height. export function textHeight(display) { if (display.cachedTextHeight != null) return display.cachedTextHeight @@ -469,14 +472,14 @@ export function textHeight(display) { measureText = elt("pre") // Measure a bunch of lines, for browsers that compute // fractional heights. - for (var i = 0; i < 49; ++i) { + for (let i = 0; i < 49; ++i) { measureText.appendChild(document.createTextNode("x")) measureText.appendChild(elt("br")) } measureText.appendChild(document.createTextNode("x")) } removeChildrenAndAdd(display.measure, measureText) - var height = measureText.offsetHeight / 50 + let height = measureText.offsetHeight / 50 if (height > 3) display.cachedTextHeight = height removeChildren(display.measure) return height || 1 @@ -485,10 +488,10 @@ export function textHeight(display) { // Compute the default character width. export function charWidth(display) { if (display.cachedCharWidth != null) return display.cachedCharWidth - var anchor = elt("span", "xxxxxxxxxx") - var pre = elt("pre", [anchor]) + let anchor = elt("span", "xxxxxxxxxx") + let pre = elt("pre", [anchor]) removeChildrenAndAdd(display.measure, pre) - var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10 + let rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10 if (width > 2) display.cachedCharWidth = width return width || 10 } @@ -496,9 +499,9 @@ export function charWidth(display) { // Do a bulk-read of the DOM positions and sizes needed to draw the // view, so that we don't interleave reading and writing to the DOM. export function getDimensions(cm) { - var d = cm.display, left = {}, width = {} - var gutterLeft = d.gutters.clientLeft - for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { + let d = cm.display, left = {}, width = {} + let gutterLeft = d.gutters.clientLeft + for (let n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft width[cm.options.gutters[i]] = n.clientWidth } @@ -520,13 +523,13 @@ export function compensateForHScroll(display) { // first approximation until the line becomes visible (and is thus // properly measurable). export function estimateHeight(cm) { - var th = textHeight(cm.display), wrapping = cm.options.lineWrapping - var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3) + let th = textHeight(cm.display), wrapping = cm.options.lineWrapping + let perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3) return function(line) { if (lineIsHidden(cm.doc, line)) return 0 - var widgetsHeight = 0 - if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { + let widgetsHeight = 0 + if (line.widgets) for (let i = 0; i < line.widgets.length; i++) { if (line.widgets[i].height) widgetsHeight += line.widgets[i].height } @@ -538,9 +541,9 @@ export function estimateHeight(cm) { } export function estimateLineHeights(cm) { - var doc = cm.doc, est = estimateHeight(cm) + let doc = cm.doc, est = estimateHeight(cm) doc.iter(function(line) { - var estHeight = est(line) + let estHeight = est(line) if (estHeight != line.height) updateLineHeight(line, estHeight) }) } @@ -551,16 +554,16 @@ export function estimateLineHeights(cm) { // selections, and tries to estimate a character position even for // coordinates beyond the right of the text. export function posFromMouse(cm, e, liberal, forRect) { - var display = cm.display + let display = cm.display if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null - var x, y, space = display.lineSpace.getBoundingClientRect() + let x, y, space = display.lineSpace.getBoundingClientRect() // Fails unpredictably on IE[67] when mouse is dragged around quickly. try { x = e.clientX - space.left; y = e.clientY - space.top } catch (e) { return null } - var coords = coordsChar(cm, x, y), line + let coords = coordsChar(cm, x, y), line if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { - var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length + let colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)) } return coords @@ -572,8 +575,8 @@ export function findViewIndex(cm, n) { if (n >= cm.display.viewTo) return null n -= cm.display.viewFrom if (n < 0) return null - var view = cm.display.view - for (var i = 0; i < view.length; i++) { + let view = cm.display.view + for (let i = 0; i < view.length; i++) { n -= view[i].size if (n < 0) return i } diff --git a/src/measurement/update_line.js b/src/measurement/update_line.js index be94b00940..4a80a7666c 100644 --- a/src/measurement/update_line.js +++ b/src/measurement/update_line.js @@ -8,8 +8,8 @@ import { signalLater } from "../util/operation_group" // lineView.changes. This updates the relevant part of the line's // DOM structure. export function updateLineForChanges(cm, lineView, lineN, dims) { - for (var j = 0; j < lineView.changes.length; j++) { - var type = lineView.changes[j] + for (let j = 0; j < lineView.changes.length; j++) { + let type = lineView.changes[j] if (type == "text") updateLineText(cm, lineView) else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims) else if (type == "class") updateLineClasses(lineView) @@ -32,13 +32,13 @@ function ensureLineWrapped(lineView) { } function updateLineBackground(lineView) { - var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass + let cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass if (cls) cls += " CodeMirror-linebackground" if (lineView.background) { if (cls) lineView.background.className = cls else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null } } else if (cls) { - var wrap = ensureLineWrapped(lineView) + let wrap = ensureLineWrapped(lineView) lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild) } } @@ -46,7 +46,7 @@ function updateLineBackground(lineView) { // Wrapper around buildLineContent which will reuse the structure // in display.externalMeasured when possible. function getLineContent(cm, lineView) { - var ext = cm.display.externalMeasured + let ext = cm.display.externalMeasured if (ext && ext.line == lineView.line) { cm.display.externalMeasured = null lineView.measure = ext.measure @@ -59,8 +59,8 @@ function getLineContent(cm, lineView) { // classes because the mode may output tokens that influence these // classes. function updateLineText(cm, lineView) { - var cls = lineView.text.className - var built = getLineContent(cm, lineView) + let cls = lineView.text.className + let built = getLineContent(cm, lineView) if (lineView.text == lineView.node) lineView.node = built.pre lineView.text.parentNode.replaceChild(built.pre, lineView.text) lineView.text = built.pre @@ -79,7 +79,7 @@ function updateLineClasses(lineView) { ensureLineWrapped(lineView).className = lineView.line.wrapClass else if (lineView.node != lineView.text) lineView.node.className = "" - var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass + let textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass lineView.text.className = textClass || "" } @@ -93,16 +93,16 @@ function updateLineGutter(cm, lineView, lineN, dims) { lineView.gutterBackground = null } if (lineView.line.gutterClass) { - var wrap = ensureLineWrapped(lineView) + let wrap = ensureLineWrapped(lineView) lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass, "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + dims.gutterTotalWidth + "px") wrap.insertBefore(lineView.gutterBackground, lineView.text) } - var markers = lineView.line.gutterMarkers + let markers = lineView.line.gutterMarkers if (cm.options.lineNumbers || markers) { - var wrap = ensureLineWrapped(lineView) - var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + + let wrap = ensureLineWrapped(lineView) + let gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px") cm.display.input.setUneditable(gutterWrap) wrap.insertBefore(gutterWrap, lineView.text) @@ -114,8 +114,8 @@ function updateLineGutter(cm, lineView, lineN, dims) { "CodeMirror-linenumber CodeMirror-gutter-elt", "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " + cm.display.lineNumInnerWidth + "px")) - if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) { - var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id] + if (markers) for (let k = 0; k < cm.options.gutters.length; ++k) { + let id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id] if (found) gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")) @@ -125,8 +125,8 @@ function updateLineGutter(cm, lineView, lineN, dims) { function updateLineWidgets(cm, lineView, dims) { if (lineView.alignable) lineView.alignable = null - for (var node = lineView.node.firstChild, next; node; node = next) { - var next = node.nextSibling + for (let node = lineView.node.firstChild, next; node; node = next) { + next = node.nextSibling if (node.className == "CodeMirror-linewidget") lineView.node.removeChild(node) } @@ -135,7 +135,7 @@ function updateLineWidgets(cm, lineView, dims) { // Build a line's DOM representation from scratch export function buildLineElement(cm, lineView, lineN, dims) { - var built = getLineContent(cm, lineView) + let built = getLineContent(cm, lineView) lineView.text = lineView.node = built.pre if (built.bgClass) lineView.bgClass = built.bgClass if (built.textClass) lineView.textClass = built.textClass @@ -150,15 +150,15 @@ export function buildLineElement(cm, lineView, lineN, dims) { // collapsed spans). The widgets for all of them need to be drawn. function insertLineWidgets(cm, lineView, dims) { insertLineWidgetsFor(cm, lineView.line, lineView, dims, true) - if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) + if (lineView.rest) for (let i = 0; i < lineView.rest.length; i++) insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false) } function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { if (!line.widgets) return - var wrap = ensureLineWrapped(lineView) - for (var i = 0, ws = line.widgets; i < ws.length; ++i) { - var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget") + let wrap = ensureLineWrapped(lineView) + for (let i = 0, ws = line.widgets; i < ws.length; ++i) { + let widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget") if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true") positionLineWidget(widget, node, lineView, dims) cm.display.input.setUneditable(node) @@ -173,7 +173,7 @@ function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { function positionLineWidget(widget, node, lineView, dims) { if (widget.noHScroll) { ;(lineView.alignable || (lineView.alignable = [])).push(node) - var width = dims.wrapperWidth + let width = dims.wrapperWidth node.style.left = dims.fixedPos + "px" if (!widget.coverGutter) { width -= dims.gutterTotalWidth diff --git a/src/measurement/widgets.js b/src/measurement/widgets.js index f20d313e6d..554cf80977 100644 --- a/src/measurement/widgets.js +++ b/src/measurement/widgets.js @@ -3,10 +3,10 @@ import { e_target } from "../util/event" export function widgetHeight(widget) { if (widget.height != null) return widget.height - var cm = widget.doc.cm + let cm = widget.doc.cm if (!cm) return 0 if (!contains(document.body, widget.node)) { - var parentStyle = "position: relative;" + let parentStyle = "position: relative;" if (widget.coverGutter) parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;" if (widget.noHScroll) @@ -18,7 +18,7 @@ export function widgetHeight(widget) { // Return true when the given mouse event happened in a widget export function eventInWidget(display, e) { - for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { + for (let n = e_target(e); n != display.wrapper; n = n.parentNode) { if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || (n.parentNode == display.sizer && n != display.mover)) return true diff --git a/src/model/Doc.js b/src/model/Doc.js index ba004631d3..c02fe062f1 100644 --- a/src/model/Doc.js +++ b/src/model/Doc.js @@ -19,8 +19,8 @@ import { copySharedMarkers, detachSharedMarkers, findSharedMarkers, markText } f import { normalizeSelection, Range, simpleSelection } from "./selection" import { extendSelection, extendSelections, setSelection, setSelectionReplaceHistory, setSimpleSelection } from "./selection_updates" -var nextDocId = 0 -var Doc = function(text, mode, firstLine, lineSep) { +let nextDocId = 0 +let Doc = function(text, mode, firstLine, lineSep) { if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep) if (firstLine == null) firstLine = 0 @@ -30,7 +30,7 @@ var Doc = function(text, mode, firstLine, lineSep) { this.cantEdit = false this.cleanGeneration = 1 this.frontier = firstLine - var start = Pos(firstLine, 0) + let start = Pos(firstLine, 0) this.sel = simpleSelection(start) this.history = new History(null) this.id = ++nextDocId @@ -56,8 +56,8 @@ Doc.prototype = createObj(BranchChunk.prototype, { // Non-public interface for adding and removing lines. insert: function(at, lines) { - var height = 0 - for (var i = 0; i < lines.length; ++i) height += lines[i].height + let height = 0 + for (let i = 0; i < lines.length; ++i) height += lines[i].height this.insertInner(at - this.first, lines, height) }, remove: function(at, n) { this.removeInner(at - this.first, n) }, @@ -66,12 +66,12 @@ Doc.prototype = createObj(BranchChunk.prototype, { // are also available from CodeMirror (editor) instances. getValue: function(lineSep) { - var lines = getLines(this, this.first, this.first + this.size) + let lines = getLines(this, this.first, this.first + this.size) if (lineSep === false) return lines return lines.join(lineSep || this.lineSeparator()) }, setValue: docMethodOp(function(code) { - var top = Pos(this.first, 0), last = this.first + this.size - 1 + let top = Pos(this.first, 0), last = this.first + this.size - 1 makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), text: this.splitLines(code), origin: "setValue", full: true}, true) setSelection(this, simpleSelection(top)) @@ -82,12 +82,12 @@ Doc.prototype = createObj(BranchChunk.prototype, { replaceRange(this, code, from, to, origin) }, getRange: function(from, to, lineSep) { - var lines = getBetween(this, clipPos(this, from), clipPos(this, to)) + let lines = getBetween(this, clipPos(this, from), clipPos(this, to)) if (lineSep === false) return lines return lines.join(lineSep || this.lineSeparator()) }, - getLine: function(line) {var l = this.getLineHandle(line); return l && l.text}, + getLine: function(line) {let l = this.getLineHandle(line); return l && l.text}, getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line)}, getLineNumber: function(line) {return lineNo(line)}, @@ -104,7 +104,7 @@ Doc.prototype = createObj(BranchChunk.prototype, { clipPos: function(pos) {return clipPos(this, pos)}, getCursor: function(start) { - var range = this.sel.primary(), pos + let range = this.sel.primary(), pos if (start == null || start == "head") pos = range.head else if (start == "anchor") pos = range.anchor else if (start == "end" || start == "to" || start === false) pos = range.to() @@ -127,55 +127,56 @@ Doc.prototype = createObj(BranchChunk.prototype, { extendSelections(this, clipPosArray(this, heads), options) }), extendSelectionsBy: docMethodOp(function(f, options) { - var heads = map(this.sel.ranges, f) + let heads = map(this.sel.ranges, f) extendSelections(this, clipPosArray(this, heads), options) }), setSelections: docMethodOp(function(ranges, primary, options) { if (!ranges.length) return - for (var i = 0, out = []; i < ranges.length; i++) + let out = [] + for (let i = 0; i < ranges.length; i++) out[i] = new Range(clipPos(this, ranges[i].anchor), clipPos(this, ranges[i].head)) if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex) setSelection(this, normalizeSelection(out, primary), options) }), addSelection: docMethodOp(function(anchor, head, options) { - var ranges = this.sel.ranges.slice(0) + let ranges = this.sel.ranges.slice(0) ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))) setSelection(this, normalizeSelection(ranges, ranges.length - 1), options) }), getSelection: function(lineSep) { - var ranges = this.sel.ranges, lines - for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this, ranges[i].from(), ranges[i].to()) + let ranges = this.sel.ranges, lines + for (let i = 0; i < ranges.length; i++) { + let sel = getBetween(this, ranges[i].from(), ranges[i].to()) lines = lines ? lines.concat(sel) : sel } if (lineSep === false) return lines else return lines.join(lineSep || this.lineSeparator()) }, getSelections: function(lineSep) { - var parts = [], ranges = this.sel.ranges - for (var i = 0; i < ranges.length; i++) { - var sel = getBetween(this, ranges[i].from(), ranges[i].to()) + let parts = [], ranges = this.sel.ranges + for (let i = 0; i < ranges.length; i++) { + let sel = getBetween(this, ranges[i].from(), ranges[i].to()) if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator()) parts[i] = sel } return parts }, replaceSelection: function(code, collapse, origin) { - var dup = [] - for (var i = 0; i < this.sel.ranges.length; i++) + let dup = [] + for (let i = 0; i < this.sel.ranges.length; i++) dup[i] = code this.replaceSelections(dup, collapse, origin || "+input") }, replaceSelections: docMethodOp(function(code, collapse, origin) { - var changes = [], sel = this.sel - for (var i = 0; i < sel.ranges.length; i++) { - var range = sel.ranges[i] + let changes = [], sel = this.sel + for (let i = 0; i < sel.ranges.length; i++) { + let range = sel.ranges[i] changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin} } - var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse) - for (var i = changes.length - 1; i >= 0; i--) + let newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse) + for (let i = changes.length - 1; i >= 0; i--) makeChange(this, changes[i]) if (newSel) setSelectionReplaceHistory(this, newSel) else if (this.cm) ensureCursorVisible(this.cm) @@ -189,9 +190,9 @@ Doc.prototype = createObj(BranchChunk.prototype, { getExtending: function() {return this.extend}, historySize: function() { - var hist = this.history, done = 0, undone = 0 - for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done - for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone + let hist = this.history, done = 0, undone = 0 + for (let i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done + for (let i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone return {undo: done, redo: undone} }, clearHistory: function() {this.history = new History(this.history.maxGeneration)}, @@ -213,14 +214,14 @@ Doc.prototype = createObj(BranchChunk.prototype, { undone: copyHistoryArray(this.history.undone)} }, setHistory: function(histData) { - var hist = this.history = new History(this.history.maxGeneration) + let hist = this.history = new History(this.history.maxGeneration) hist.done = copyHistoryArray(histData.done.slice(0), null, true) hist.undone = copyHistoryArray(histData.undone.slice(0), null, true) }, addLineClass: docMethodOp(function(handle, where, cls) { return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { - var prop = where == "text" ? "textClass" + let prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : where == "gutter" ? "gutterClass" : "wrapClass" if (!line[prop]) line[prop] = cls @@ -231,16 +232,16 @@ Doc.prototype = createObj(BranchChunk.prototype, { }), removeLineClass: docMethodOp(function(handle, where, cls) { return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { - var prop = where == "text" ? "textClass" + let prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : where == "gutter" ? "gutterClass" : "wrapClass" - var cur = line[prop] + let cur = line[prop] if (!cur) return false else if (cls == null) line[prop] = null else { - var found = cur.match(classTest(cls)) + let found = cur.match(classTest(cls)) if (!found) return false - var end = found.index + found[0].length + let end = found.index + found[0].length line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null } return true @@ -256,7 +257,7 @@ Doc.prototype = createObj(BranchChunk.prototype, { return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range") }, setBookmark: function(pos, options) { - var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), + let realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), insertLeft: options && options.insertLeft, clearWhenEmpty: false, shared: options && options.shared, handleMouseEvents: options && options.handleMouseEvents} @@ -265,9 +266,9 @@ Doc.prototype = createObj(BranchChunk.prototype, { }, findMarksAt: function(pos) { pos = clipPos(this, pos) - var markers = [], spans = getLine(this, pos.line).markedSpans - if (spans) for (var i = 0; i < spans.length; ++i) { - var span = spans[i] + let markers = [], spans = getLine(this, pos.line).markedSpans + if (spans) for (let i = 0; i < spans.length; ++i) { + let span = spans[i] if ((span.from == null || span.from <= pos.ch) && (span.to == null || span.to >= pos.ch)) markers.push(span.marker.parent || span.marker) @@ -276,11 +277,11 @@ Doc.prototype = createObj(BranchChunk.prototype, { }, findMarks: function(from, to, filter) { from = clipPos(this, from); to = clipPos(this, to) - var found = [], lineNo = from.line + let found = [], lineNo = from.line this.iter(from.line, to.line + 1, function(line) { - var spans = line.markedSpans - if (spans) for (var i = 0; i < spans.length; i++) { - var span = spans[i] + let spans = line.markedSpans + if (spans) for (let i = 0; i < spans.length; i++) { + let span = spans[i] if (!(span.to != null && lineNo == from.line && from.ch >= span.to || span.from == null && lineNo != from.line || span.from != null && lineNo == to.line && span.from >= to.ch) && @@ -292,19 +293,19 @@ Doc.prototype = createObj(BranchChunk.prototype, { return found }, getAllMarks: function() { - var markers = [] + let markers = [] this.iter(function(line) { - var sps = line.markedSpans - if (sps) for (var i = 0; i < sps.length; ++i) + let sps = line.markedSpans + if (sps) for (let i = 0; i < sps.length; ++i) if (sps[i].from != null) markers.push(sps[i].marker) }) return markers }, posFromIndex: function(off) { - var ch, lineNo = this.first, sepSize = this.lineSeparator().length + let ch, lineNo = this.first, sepSize = this.lineSeparator().length this.iter(function(line) { - var sz = line.text.length + sepSize + let sz = line.text.length + sepSize if (sz > off) { ch = off; return true } off -= sz ++lineNo @@ -313,9 +314,9 @@ Doc.prototype = createObj(BranchChunk.prototype, { }, indexFromPos: function (coords) { coords = clipPos(this, coords) - var index = coords.ch + let index = coords.ch if (coords.line < this.first || coords.ch < 0) return 0 - var sepSize = this.lineSeparator().length + let sepSize = this.lineSeparator().length this.iter(this.first, coords.line, function (line) { index += line.text.length + sepSize }) @@ -323,7 +324,7 @@ Doc.prototype = createObj(BranchChunk.prototype, { }, copy: function(copyHistory) { - var doc = new Doc(getLines(this, this.first, this.first + this.size), + let doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first, this.lineSep) doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft doc.sel = this.sel @@ -337,10 +338,10 @@ Doc.prototype = createObj(BranchChunk.prototype, { linkedDoc: function(options) { if (!options) options = {} - var from = this.first, to = this.first + this.size + let from = this.first, to = this.first + this.size if (options.from != null && options.from > from) from = options.from if (options.to != null && options.to < to) to = options.to - var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep) + let copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep) if (options.sharedHist) copy.history = this.history ;(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}) copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}] @@ -349,8 +350,8 @@ Doc.prototype = createObj(BranchChunk.prototype, { }, unlinkDoc: function(other) { if (other instanceof CodeMirror) other = other.doc - if (this.linked) for (var i = 0; i < this.linked.length; ++i) { - var link = this.linked[i] + if (this.linked) for (let i = 0; i < this.linked.length; ++i) { + let link = this.linked[i] if (link.doc != other) continue this.linked.splice(i, 1) other.unlinkDoc(this) @@ -359,7 +360,7 @@ Doc.prototype = createObj(BranchChunk.prototype, { } // If the histories were shared, split them again if (other.history == this.history) { - var splitIds = [other.id] + let splitIds = [other.id] linkedDocs(other, function(doc) {splitIds.push(doc.id)}, true) other.history = new History(null) other.history.done = copyHistoryArray(this.history.done, splitIds) diff --git a/src/model/change_measurement.js b/src/model/change_measurement.js index ac14fa5458..881f39eb46 100644 --- a/src/model/change_measurement.js +++ b/src/model/change_measurement.js @@ -17,15 +17,15 @@ function adjustForChange(pos, change) { if (cmp(pos, change.from) < 0) return pos if (cmp(pos, change.to) <= 0) return changeEnd(change) - var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch + let line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch return Pos(line, ch) } export function computeSelAfterChange(doc, change) { - var out = [] - for (var i = 0; i < doc.sel.ranges.length; i++) { - var range = doc.sel.ranges[i] + let out = [] + for (let i = 0; i < doc.sel.ranges.length; i++) { + let range = doc.sel.ranges[i] out.push(new Range(adjustForChange(range.anchor, change), adjustForChange(range.head, change))) } @@ -42,16 +42,16 @@ function offsetPos(pos, old, nw) { // Used by replaceSelections to allow moving the selection to the // start or around the replaced test. Hint may be "start" or "around". export function computeReplacedSel(doc, changes, hint) { - var out = [] - var oldPrev = Pos(doc.first, 0), newPrev = oldPrev - for (var i = 0; i < changes.length; i++) { - var change = changes[i] - var from = offsetPos(change.from, oldPrev, newPrev) - var to = offsetPos(changeEnd(change), oldPrev, newPrev) + let out = [] + let oldPrev = Pos(doc.first, 0), newPrev = oldPrev + for (let i = 0; i < changes.length; i++) { + let change = changes[i] + let from = offsetPos(change.from, oldPrev, newPrev) + let to = offsetPos(changeEnd(change), oldPrev, newPrev) oldPrev = change.to newPrev = to if (hint == "around") { - var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0 + let range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0 out[i] = new Range(inv ? to : from, inv ? from : to) } else { out[i] = new Range(from, from) diff --git a/src/model/changes.js b/src/model/changes.js index 6a8606afcb..e39bc30392 100644 --- a/src/model/changes.js +++ b/src/model/changes.js @@ -20,7 +20,7 @@ import { setSelection, setSelectionNoUndo } from "./selection_updates" // Allow "beforeChange" event handlers to influence a change function filterChange(doc, change, update) { - var obj = { + let obj = { canceled: false, from: change.from, to: change.to, @@ -56,9 +56,9 @@ export function makeChange(doc, change, ignoreReadOnly) { // Possibly split or suppress the update based on the presence // of read-only spans in its range. - var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to) + let split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to) if (split) { - for (var i = split.length - 1; i >= 0; --i) + for (let i = split.length - 1; i >= 0; --i) makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}) } else { makeChangeInner(doc, change) @@ -67,11 +67,11 @@ export function makeChange(doc, change, ignoreReadOnly) { function makeChangeInner(doc, change) { if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return - var selAfter = computeSelAfterChange(doc, change) + let selAfter = computeSelAfterChange(doc, change) addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN) makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)) - var rebased = [] + let rebased = [] linkedDocs(doc, function(doc, sharedHist) { if (!sharedHist && indexOf(rebased, doc.history) == -1) { @@ -86,12 +86,13 @@ function makeChangeInner(doc, change) { export function makeChangeFromHistory(doc, type, allowSelectionOnly) { if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) return - var hist = doc.history, event, selAfter = doc.sel - var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done + let hist = doc.history, event, selAfter = doc.sel + let source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done // Verify that there is a useable event (so that ctrl-z won't // needlessly clear selection events) - for (var i = 0; i < source.length; i++) { + let i = 0 + for (; i < source.length; i++) { event = source[i] if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) break @@ -114,15 +115,15 @@ export function makeChangeFromHistory(doc, type, allowSelectionOnly) { // Build up a reverse change object to add to the opposite history // stack (redo when undoing, and vice versa). - var antiChanges = [] + let antiChanges = [] pushSelectionToHistory(selAfter, dest) dest.push({changes: antiChanges, generation: hist.generation}) hist.generation = event.generation || ++hist.maxGeneration - var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange") + let filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange") - for (var i = event.changes.length - 1; i >= 0; --i) { - var change = event.changes[i] + for (let i = event.changes.length - 1; i >= 0; --i) { + let change = event.changes[i] change.origin = type if (filter && !filterChange(doc, change, false)) { source.length = 0 @@ -131,10 +132,10 @@ export function makeChangeFromHistory(doc, type, allowSelectionOnly) { antiChanges.push(historyChangeFromChange(doc, change)) - var after = i ? computeSelAfterChange(doc, change) : lst(source) + let after = i ? computeSelAfterChange(doc, change) : lst(source) makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)) if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}) - var rebased = [] + let rebased = [] // Propagate to the linked documents linkedDocs(doc, function(doc, sharedHist) { @@ -158,7 +159,7 @@ function shiftDoc(doc, distance) { }), doc.sel.primIndex) if (doc.cm) { regChange(doc.cm, doc.first, doc.first - distance, distance) - for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) + for (let d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) regLineChange(doc.cm, l, "gutter") } } @@ -177,12 +178,12 @@ function makeChangeSingleDoc(doc, change, selAfter, spans) { // Clip the change to the size of this doc if (change.from.line < doc.first) { - var shift = change.text.length - 1 - (doc.first - change.from.line) + let shift = change.text.length - 1 - (doc.first - change.from.line) shiftDoc(doc, shift) change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), text: [lst(change.text)], origin: change.origin} } - var last = doc.lastLine() + let last = doc.lastLine() if (change.to.line > last) { change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), text: [change.text[0]], origin: change.origin} @@ -199,9 +200,9 @@ function makeChangeSingleDoc(doc, change, selAfter, spans) { // Handle the interaction of a change to a document with the editor // that this document is part of. function makeChangeSingleDocInEditor(cm, change, spans) { - var doc = cm.doc, display = cm.display, from = change.from, to = change.to + let doc = cm.doc, display = cm.display, from = change.from, to = change.to - var recomputeMaxLength = false, checkWidthStart = from.line + let recomputeMaxLength = false, checkWidthStart = from.line if (!cm.options.lineWrapping) { checkWidthStart = lineNo(visualLine(getLine(doc, from.line))) doc.iter(checkWidthStart, to.line + 1, function(line) { @@ -219,7 +220,7 @@ function makeChangeSingleDocInEditor(cm, change, spans) { if (!cm.options.lineWrapping) { doc.iter(checkWidthStart, from.line + change.text.length, function(line) { - var len = lineLength(line) + let len = lineLength(line) if (len > display.maxLineLength) { display.maxLine = line display.maxLineLength = len @@ -234,7 +235,7 @@ function makeChangeSingleDocInEditor(cm, change, spans) { doc.frontier = Math.min(doc.frontier, from.line) startWorker(cm, 400) - var lendiff = change.text.length - (to.line - from.line) - 1 + let lendiff = change.text.length - (to.line - from.line) - 1 // Remember that these lines changed, for updating the display if (change.full) regChange(cm) @@ -243,9 +244,9 @@ function makeChangeSingleDocInEditor(cm, change, spans) { else regChange(cm, from.line, to.line + 1, lendiff) - var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change") + let changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change") if (changeHandler || changesHandler) { - var obj = { + let obj = { from: from, to: to, text: change.text, removed: change.removed, @@ -259,7 +260,7 @@ function makeChangeSingleDocInEditor(cm, change, spans) { export function replaceRange(doc, code, from, to, origin) { if (!to) to = from - if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp } + if (cmp(to, from) < 0) { let tmp = to; to = from; from = tmp } if (typeof code == "string") code = doc.splitLines(code) makeChange(doc, {from: from, to: to, text: code, origin: origin}) } @@ -283,18 +284,18 @@ function rebaseHistSelSingle(pos, from, to, diff) { // reallocate them all on every rebase, but also avoid problems with // shared position objects being unsafely updated. function rebaseHistArray(array, from, to, diff) { - for (var i = 0; i < array.length; ++i) { - var sub = array[i], ok = true + for (let i = 0; i < array.length; ++i) { + let sub = array[i], ok = true if (sub.ranges) { if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true } - for (var j = 0; j < sub.ranges.length; j++) { + for (let j = 0; j < sub.ranges.length; j++) { rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff) rebaseHistSelSingle(sub.ranges[j].head, from, to, diff) } continue } - for (var j = 0; j < sub.changes.length; ++j) { - var cur = sub.changes[j] + for (let j = 0; j < sub.changes.length; ++j) { + let cur = sub.changes[j] if (to < cur.from.line) { cur.from = Pos(cur.from.line + diff, cur.from.ch) cur.to = Pos(cur.to.line + diff, cur.to.ch) @@ -311,7 +312,7 @@ function rebaseHistArray(array, from, to, diff) { } function rebaseHist(hist, change) { - var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1 + let from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1 rebaseHistArray(hist.done, from, to, diff) rebaseHistArray(hist.undone, from, to, diff) } @@ -320,7 +321,7 @@ function rebaseHist(hist, change) { // returning the number and optionally registering the line as // changed. export function changeLine(doc, handle, changeType, op) { - var no = handle, line = handle + let no = handle, line = handle if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)) else no = lineNo(handle) if (no == null) return null diff --git a/src/model/chunk.js b/src/model/chunk.js index 0aee95fe2f..2a05d7c545 100644 --- a/src/model/chunk.js +++ b/src/model/chunk.js @@ -18,7 +18,8 @@ import { signalLater } from "../util/operation_group" export function LeafChunk(lines) { this.lines = lines this.parent = null - for (var i = 0, height = 0; i < lines.length; ++i) { + let height = 0 + for (let i = 0; i < lines.length; ++i) { lines[i].parent = this height += lines[i].height } @@ -29,8 +30,8 @@ LeafChunk.prototype = { chunkSize: function() { return this.lines.length }, // Remove the n lines at offset 'at'. removeInner: function(at, n) { - for (var i = at, e = at + n; i < e; ++i) { - var line = this.lines[i] + for (let i = at, e = at + n; i < e; ++i) { + let line = this.lines[i] this.height -= line.height cleanUpLine(line) signalLater(line, "delete") @@ -46,20 +47,20 @@ LeafChunk.prototype = { insertInner: function(at, lines, height) { this.height += height this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)) - for (var i = 0; i < lines.length; ++i) lines[i].parent = this + for (let i = 0; i < lines.length; ++i) lines[i].parent = this }, // Used to iterate over a part of the tree. iterN: function(at, n, op) { - for (var e = at + n; at < e; ++at) + for (let e = at + n; at < e; ++at) if (op(this.lines[at])) return true } } export function BranchChunk(children) { this.children = children - var size = 0, height = 0 - for (var i = 0; i < children.length; ++i) { - var ch = children[i] + let size = 0, height = 0 + for (let i = 0; i < children.length; ++i) { + let ch = children[i] size += ch.chunkSize(); height += ch.height ch.parent = this } @@ -72,10 +73,10 @@ BranchChunk.prototype = { chunkSize: function() { return this.size }, removeInner: function(at, n) { this.size -= n - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize() + for (let i = 0; i < this.children.length; ++i) { + let child = this.children[i], sz = child.chunkSize() if (at < sz) { - var rm = Math.min(n, sz - at), oldHeight = child.height + let rm = Math.min(n, sz - at), oldHeight = child.height child.removeInner(at, rm) this.height -= oldHeight - child.height if (sz == rm) { this.children.splice(i--, 1); child.parent = null } @@ -87,28 +88,28 @@ BranchChunk.prototype = { // single leaf node. if (this.size - n < 25 && (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { - var lines = [] + let lines = [] this.collapse(lines) this.children = [new LeafChunk(lines)] this.children[0].parent = this } }, collapse: function(lines) { - for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines) + for (let i = 0; i < this.children.length; ++i) this.children[i].collapse(lines) }, insertInner: function(at, lines, height) { this.size += lines.length this.height += height - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize() + for (let i = 0; i < this.children.length; ++i) { + let child = this.children[i], sz = child.chunkSize() if (at <= sz) { child.insertInner(at, lines, height) if (child.lines && child.lines.length > 50) { // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced. // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest. - var remaining = child.lines.length % 25 + 25 - for (var pos = remaining; pos < child.lines.length;) { - var leaf = new LeafChunk(child.lines.slice(pos, pos += 25)) + let remaining = child.lines.length % 25 + 25 + for (let pos = remaining; pos < child.lines.length;) { + let leaf = new LeafChunk(child.lines.slice(pos, pos += 25)) child.height -= leaf.height this.children.splice(++i, 0, leaf) leaf.parent = this @@ -124,19 +125,19 @@ BranchChunk.prototype = { // When a node has grown, check whether it should be split. maybeSpill: function() { if (this.children.length <= 10) return - var me = this + let me = this do { - var spilled = me.children.splice(me.children.length - 5, 5) - var sibling = new BranchChunk(spilled) + let spilled = me.children.splice(me.children.length - 5, 5) + let sibling = new BranchChunk(spilled) if (!me.parent) { // Become the parent node - var copy = new BranchChunk(me.children) + let copy = new BranchChunk(me.children) copy.parent = me me.children = [copy, sibling] me = copy } else { me.size -= sibling.size me.height -= sibling.height - var myIndex = indexOf(me.parent.children, me) + let myIndex = indexOf(me.parent.children, me) me.parent.children.splice(myIndex + 1, 0, sibling) } sibling.parent = me.parent @@ -144,10 +145,10 @@ BranchChunk.prototype = { me.parent.maybeSpill() }, iterN: function(at, n, op) { - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i], sz = child.chunkSize() + for (let i = 0; i < this.children.length; ++i) { + let child = this.children[i], sz = child.chunkSize() if (at < sz) { - var used = Math.min(n, sz - at) + let used = Math.min(n, sz - at) if (child.iterN(at, used, op)) return true if ((n -= used) == 0) break at = 0 diff --git a/src/model/document_data.js b/src/model/document_data.js index 8e423bafd3..6ce2ae58e7 100644 --- a/src/model/document_data.js +++ b/src/model/document_data.js @@ -25,14 +25,15 @@ export function updateDoc(doc, change, markedSpans, estimateHeight) { signalLater(line, "change", line, change) } function linesFor(start, end) { - for (var i = start, result = []; i < end; ++i) + let result = [] + for (let i = start; i < end; ++i) result.push(new Line(text[i], spansFor(i), estimateHeight)) return result } - var from = change.from, to = change.to, text = change.text - var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line) - var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line + let from = change.from, to = change.to, text = change.text + let firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line) + let lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line // Adjust the line structure if (change.full) { @@ -41,7 +42,7 @@ export function updateDoc(doc, change, markedSpans, estimateHeight) { } else if (isWholeLineUpdate(doc, change)) { // This is a whole-line replace. Treated specially to make // sure line objects move the way they are supposed to. - var added = linesFor(0, text.length - 1) + let added = linesFor(0, text.length - 1) update(lastLine, lastLine.text, lastSpans) if (nlines) doc.remove(from.line, nlines) if (added.length) doc.insert(from.line, added) @@ -49,7 +50,7 @@ export function updateDoc(doc, change, markedSpans, estimateHeight) { if (text.length == 1) { update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans) } else { - var added = linesFor(1, text.length - 1) + let added = linesFor(1, text.length - 1) added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)) update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)) doc.insert(from.line + 1, added) @@ -60,7 +61,7 @@ export function updateDoc(doc, change, markedSpans, estimateHeight) { } else { update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)) update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans) - var added = linesFor(1, text.length - 1) + let added = linesFor(1, text.length - 1) if (nlines > 1) doc.remove(from.line + 1, nlines - 1) doc.insert(from.line + 1, added) } @@ -71,10 +72,10 @@ export function updateDoc(doc, change, markedSpans, estimateHeight) { // Call f for all linked documents. export function linkedDocs(doc, f, sharedHistOnly) { function propagate(doc, skip, sharedHist) { - if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { - var rel = doc.linked[i] + if (doc.linked) for (let i = 0; i < doc.linked.length; ++i) { + let rel = doc.linked[i] if (rel.doc == skip) continue - var shared = sharedHist && rel.sharedHist + let shared = sharedHist && rel.sharedHist if (sharedHistOnly && !shared) continue f(rel.doc, shared) propagate(rel.doc, doc, shared) diff --git a/src/model/history.js b/src/model/history.js index 8cc77b1ab0..0c7cf5bba1 100644 --- a/src/model/history.js +++ b/src/model/history.js @@ -26,7 +26,7 @@ export function History(startGen) { // Create a history change event from an updateDoc-style change // object. export function historyChangeFromChange(doc, change) { - var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)} + let histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)} attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1) linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1)}, true) return histChange @@ -36,7 +36,7 @@ export function historyChangeFromChange(doc, change) { // a change event. function clearSelectionEvents(array) { while (array.length) { - var last = lst(array) + let last = lst(array) if (last.ranges) array.pop() else break } @@ -60,9 +60,10 @@ function lastChangeEvent(hist, force) { // a single operation, or are close together with an origin that // allows merging (starting with "+") into a single event. export function addChangeToHistory(doc, change, selAfter, opId) { - var hist = doc.history + let hist = doc.history hist.undone.length = 0 - var time = +new Date, cur + let time = +new Date, cur + let last if ((hist.lastOp == opId || hist.lastOrigin == change.origin && change.origin && @@ -70,7 +71,7 @@ export function addChangeToHistory(doc, change, selAfter, opId) { change.origin.charAt(0) == "*")) && (cur = lastChangeEvent(hist, hist.lastOp == opId))) { // Merge this change into the last event - var last = lst(cur.changes) + last = lst(cur.changes) if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { // Optimized case for simple insertion -- don't want to add // new changesets for every character typed @@ -81,7 +82,7 @@ export function addChangeToHistory(doc, change, selAfter, opId) { } } else { // Can not be merged, start a new event. - var before = lst(hist.done) + let before = lst(hist.done) if (!before || !before.ranges) pushSelectionToHistory(doc.sel, hist.done) cur = {changes: [historyChangeFromChange(doc, change)], @@ -102,7 +103,7 @@ export function addChangeToHistory(doc, change, selAfter, opId) { } function selectionEventCanBeMerged(doc, origin, prev, sel) { - var ch = origin.charAt(0) + let ch = origin.charAt(0) return ch == "*" || ch == "+" && prev.ranges.length == sel.ranges.length && @@ -115,7 +116,7 @@ function selectionEventCanBeMerged(doc, origin, prev, sel) { // selection into the 'done' array when it was significantly // different (in number of selected ranges, emptiness, or time). export function addSelectionToHistory(doc, sel, opId, options) { - var hist = doc.history, origin = options && options.origin + let hist = doc.history, origin = options && options.origin // A new event is started when the previous origin does not match // the current, or the origins don't allow matching. Origins @@ -137,14 +138,14 @@ export function addSelectionToHistory(doc, sel, opId, options) { } export function pushSelectionToHistory(sel, dest) { - var top = lst(dest) + let top = lst(dest) if (!(top && top.ranges && top.equals(sel))) dest.push(sel) } // Used to store marked span information in the history. function attachLocalSpans(doc, change, from, to) { - var existing = change["spans_" + doc.id], n = 0 + let existing = change["spans_" + doc.id], n = 0 doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) { if (line.markedSpans) (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans @@ -156,7 +157,8 @@ function attachLocalSpans(doc, change, from, to) { // that have been explicitly cleared should not be restored. function removeClearedSpans(spans) { if (!spans) return null - for (var i = 0, out; i < spans.length; ++i) { + let out + for (let i = 0; i < spans.length; ++i) { if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i) } else if (out) out.push(spans[i]) } @@ -165,9 +167,10 @@ function removeClearedSpans(spans) { // Retrieve and filter the old marked spans stored in a change event. function getOldSpans(doc, change) { - var found = change["spans_" + doc.id] + let found = change["spans_" + doc.id] if (!found) return null - for (var i = 0, nw = []; i < change.text.length; ++i) + let nw = [] + for (let i = 0; i < change.text.length; ++i) nw.push(removeClearedSpans(found[i])) return nw } @@ -177,17 +180,17 @@ function getOldSpans(doc, change) { // existed in the history (so that deleting around a span and then // undoing brings back the span). export function mergeOldSpans(doc, change) { - var old = getOldSpans(doc, change) - var stretched = stretchSpansOverChange(doc, change) + let old = getOldSpans(doc, change) + let stretched = stretchSpansOverChange(doc, change) if (!old) return stretched if (!stretched) return old - for (var i = 0; i < old.length; ++i) { - var oldCur = old[i], stretchCur = stretched[i] + for (let i = 0; i < old.length; ++i) { + let oldCur = old[i], stretchCur = stretched[i] if (oldCur && stretchCur) { - spans: for (var j = 0; j < stretchCur.length; ++j) { - var span = stretchCur[j] - for (var k = 0; k < oldCur.length; ++k) + spans: for (let j = 0; j < stretchCur.length; ++j) { + let span = stretchCur[j] + for (let k = 0; k < oldCur.length; ++k) if (oldCur[k].marker == span.marker) continue spans oldCur.push(span) } @@ -201,18 +204,19 @@ export function mergeOldSpans(doc, change) { // Used both to provide a JSON-safe object in .getHistory, and, when // detaching a document, to split the history in two export function copyHistoryArray(events, newGroup, instantiateSel) { - for (var i = 0, copy = []; i < events.length; ++i) { - var event = events[i] + let copy = [] + for (let i = 0; i < events.length; ++i) { + let event = events[i] if (event.ranges) { copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event) continue } - var changes = event.changes, newChanges = [] + let changes = event.changes, newChanges = [] copy.push({changes: newChanges}) - for (var j = 0; j < changes.length; ++j) { - var change = changes[j], m + for (let j = 0; j < changes.length; ++j) { + let change = changes[j], m newChanges.push({from: change.from, to: change.to, text: change.text}) - if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { + if (newGroup) for (let prop in change) if (m = prop.match(/^spans_(\d+)$/)) { if (indexOf(newGroup, Number(m[1])) > -1) { lst(newChanges)[prop] = change[prop] delete change[prop] diff --git a/src/model/line_widget.js b/src/model/line_widget.js index b3b422aafb..23b2381b95 100644 --- a/src/model/line_widget.js +++ b/src/model/line_widget.js @@ -10,7 +10,7 @@ import { eventMixin } from "../util/event" // Line widgets are block elements displayed above or below a line. export function LineWidget(doc, node, options) { - if (options) for (var opt in options) if (options.hasOwnProperty(opt)) + if (options) for (let opt in options) if (options.hasOwnProperty(opt)) this[opt] = options[opt] this.doc = doc this.node = node @@ -23,11 +23,11 @@ function adjustScrollWhenAboveVisible(cm, line, diff) { } LineWidget.prototype.clear = function() { - var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line) + let cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line) if (no == null || !ws) return - for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1) + for (let i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1) if (!ws.length) line.widgets = null - var height = widgetHeight(this) + let height = widgetHeight(this) updateLineHeight(line, Math.max(0, line.height - height)) if (cm) runInOp(cm, function() { adjustScrollWhenAboveVisible(cm, line, -height) @@ -35,9 +35,9 @@ LineWidget.prototype.clear = function() { }) } LineWidget.prototype.changed = function() { - var oldH = this.height, cm = this.doc.cm, line = this.line + let oldH = this.height, cm = this.doc.cm, line = this.line this.height = null - var diff = widgetHeight(this) - oldH + let diff = widgetHeight(this) - oldH if (!diff) return updateLineHeight(line, line.height + diff) if (cm) runInOp(cm, function() { @@ -47,16 +47,16 @@ LineWidget.prototype.changed = function() { } export function addLineWidget(doc, handle, node, options) { - var widget = new LineWidget(doc, node, options) - var cm = doc.cm + let widget = new LineWidget(doc, node, options) + let cm = doc.cm if (cm && widget.noHScroll) cm.display.alignWidgets = true changeLine(doc, handle, "widget", function(line) { - var widgets = line.widgets || (line.widgets = []) + let widgets = line.widgets || (line.widgets = []) if (widget.insertAt == null) widgets.push(widget) else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget) widget.line = line if (cm && !lineIsHidden(doc, line)) { - var aboveVisible = heightAtLine(line) < doc.scrollTop + let aboveVisible = heightAtLine(line) < doc.scrollTop updateLineHeight(line, line.height + widgetHeight(widget)) if (aboveVisible) addToScrollPos(cm, null, widget.height) cm.curOp.forceUpdate = true diff --git a/src/model/mark_text.js b/src/model/mark_text.js index c103a57481..f15cefb29a 100644 --- a/src/model/mark_text.js +++ b/src/model/mark_text.js @@ -27,7 +27,10 @@ import { reCheckSelection } from "./selection_updates" // marker continues beyond the start/end of the line. Markers have // links back to the lines they currently touch. -var nextMarkerId = 0 +// Collapsed markers have unique ids, in order to be able to order +// them, which is needed for uniquely determining an outer marker +// when they overlap (they may nest, but not partially overlap). +let nextMarkerId = 0 export function TextMarker(doc, type) { this.lines = [] @@ -40,16 +43,16 @@ eventMixin(TextMarker) // Clear the marker. TextMarker.prototype.clear = function() { if (this.explicitlyCleared) return - var cm = this.doc.cm, withOp = cm && !cm.curOp + let cm = this.doc.cm, withOp = cm && !cm.curOp if (withOp) startOperation(cm) if (hasHandler(this, "clear")) { - var found = this.find() + let found = this.find() if (found) signalLater(this, "clear", found.from, found.to) } - var min = null, max = null - for (var i = 0; i < this.lines.length; ++i) { - var line = this.lines[i] - var span = getMarkedSpanFor(line.markedSpans, this) + let min = null, max = null + for (let i = 0; i < this.lines.length; ++i) { + let line = this.lines[i] + let span = getMarkedSpanFor(line.markedSpans, this) if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text") else if (cm) { if (span.to != null) max = lineNo(line) @@ -59,8 +62,8 @@ TextMarker.prototype.clear = function() { if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) updateLineHeight(line, textHeight(cm.display)) } - if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { - var visual = visualLine(this.lines[i]), len = lineLength(visual) + if (cm && this.collapsed && !cm.options.lineWrapping) for (let i = 0; i < this.lines.length; ++i) { + let visual = visualLine(this.lines[i]), len = lineLength(visual) if (len > cm.display.maxLineLength) { cm.display.maxLine = visual cm.display.maxLineLength = len @@ -87,10 +90,10 @@ TextMarker.prototype.clear = function() { // number (used to prevent looking up the same line twice). TextMarker.prototype.find = function(side, lineObj) { if (side == null && this.type == "bookmark") side = 1 - var from, to - for (var i = 0; i < this.lines.length; ++i) { - var line = this.lines[i] - var span = getMarkedSpanFor(line.markedSpans, this) + let from, to + for (let i = 0; i < this.lines.length; ++i) { + let line = this.lines[i] + let span = getMarkedSpanFor(line.markedSpans, this) if (span.from != null) { from = Pos(lineObj ? line : lineNo(line), span.from) if (side == -1) return from @@ -106,20 +109,20 @@ TextMarker.prototype.find = function(side, lineObj) { // Signals that the marker's widget changed, and surrounding layout // should be recomputed. TextMarker.prototype.changed = function() { - var pos = this.find(-1, true), widget = this, cm = this.doc.cm + let pos = this.find(-1, true), widget = this, cm = this.doc.cm if (!pos || !cm) return runInOp(cm, function() { - var line = pos.line, lineN = lineNo(pos.line) - var view = findViewForLine(cm, lineN) + let line = pos.line, lineN = lineNo(pos.line) + let view = findViewForLine(cm, lineN) if (view) { clearLineMeasurementCacheFor(view) cm.curOp.selectionChanged = cm.curOp.forceUpdate = true } cm.curOp.updateMaxLine = true if (!lineIsHidden(widget.doc, line) && widget.height != null) { - var oldHeight = widget.height + let oldHeight = widget.height widget.height = null - var dHeight = widgetHeight(widget) - oldHeight + let dHeight = widgetHeight(widget) - oldHeight if (dHeight) updateLineHeight(line, line.height + dHeight) } @@ -128,7 +131,7 @@ TextMarker.prototype.changed = function() { TextMarker.prototype.attachLine = function(line) { if (!this.lines.length && this.doc.cm) { - var op = this.doc.cm.curOp + let op = this.doc.cm.curOp if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this) } @@ -137,16 +140,11 @@ TextMarker.prototype.attachLine = function(line) { TextMarker.prototype.detachLine = function(line) { this.lines.splice(indexOf(this.lines, line), 1) if (!this.lines.length && this.doc.cm) { - var op = this.doc.cm.curOp + let op = this.doc.cm.curOp ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this) } } -// Collapsed markers have unique ids, in order to be able to order -// them, which is needed for uniquely determining an outer marker -// when they overlap (they may nest, but not partially overlap). -var nextMarkerId = 0 - // Create a marker, wire it up to the right lines, and export function markText(doc, from, to, options, type) { // Shared markers (across linked documents) are handled separately @@ -156,7 +154,7 @@ export function markText(doc, from, to, options, type) { // Ensure we are in an operation. if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type) - var marker = new TextMarker(doc, type), diff = cmp(from, to) + let marker = new TextMarker(doc, type), diff = cmp(from, to) if (options) copyObj(options, marker, false) // Don't connect empty markers unless clearWhenEmpty is false if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) @@ -178,7 +176,7 @@ export function markText(doc, from, to, options, type) { if (marker.addToHistory) addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN) - var curLine = from.line, cm = doc.cm, updateMaxLine + let curLine = from.line, cm = doc.cm, updateMaxLine doc.iter(curLine, to.line + 1, function(line) { if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) updateMaxLine = true @@ -210,7 +208,7 @@ export function markText(doc, from, to, options, type) { if (marker.collapsed) regChange(cm, from.line, to.line + 1) else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) - for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text") + for (let i = from.line; i <= to.line; i++) regLineChange(cm, i, "text") if (marker.atomic) reCheckSelection(cm.doc) signalLater(cm, "markerAdded", cm, marker) } @@ -225,7 +223,7 @@ export function markText(doc, from, to, options, type) { export function SharedTextMarker(markers, primary) { this.markers = markers this.primary = primary - for (var i = 0; i < markers.length; ++i) + for (let i = 0; i < markers.length; ++i) markers[i].parent = this } eventMixin(SharedTextMarker) @@ -233,7 +231,7 @@ eventMixin(SharedTextMarker) SharedTextMarker.prototype.clear = function() { if (this.explicitlyCleared) return this.explicitlyCleared = true - for (var i = 0; i < this.markers.length; ++i) + for (let i = 0; i < this.markers.length; ++i) this.markers[i].clear() signalLater(this, "clear") } @@ -244,12 +242,12 @@ SharedTextMarker.prototype.find = function(side, lineObj) { function markTextShared(doc, from, to, options, type) { options = copyObj(options) options.shared = false - var markers = [markText(doc, from, to, options, type)], primary = markers[0] - var widget = options.widgetNode + let markers = [markText(doc, from, to, options, type)], primary = markers[0] + let widget = options.widgetNode linkedDocs(doc, function(doc) { if (widget) options.widgetNode = widget.cloneNode(true) markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)) - for (var i = 0; i < doc.linked.length; ++i) + for (let i = 0; i < doc.linked.length; ++i) if (doc.linked[i].isParent) return primary = lst(markers) }) @@ -262,11 +260,11 @@ export function findSharedMarkers(doc) { } export function copySharedMarkers(doc, markers) { - for (var i = 0; i < markers.length; i++) { - var marker = markers[i], pos = marker.find() - var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to) + for (let i = 0; i < markers.length; i++) { + let marker = markers[i], pos = marker.find() + let mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to) if (cmp(mFrom, mTo)) { - var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type) + let subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type) marker.markers.push(subMark) subMark.parent = marker } @@ -274,11 +272,11 @@ export function copySharedMarkers(doc, markers) { } export function detachSharedMarkers(markers) { - for (var i = 0; i < markers.length; i++) { - var marker = markers[i], linked = [marker.primary.doc] + for (let i = 0; i < markers.length; i++) { + let marker = markers[i], linked = [marker.primary.doc] linkedDocs(marker.primary.doc, function(d) { linked.push(d) }) - for (var j = 0; j < marker.markers.length; j++) { - var subMarker = marker.markers[j] + for (let j = 0; j < marker.markers.length; j++) { + let subMarker = marker.markers[j] if (indexOf(linked, subMarker.doc) == -1) { subMarker.parent = null marker.markers.splice(j--, 1) diff --git a/src/model/selection.js b/src/model/selection.js index c75fcd6186..63371954e1 100644 --- a/src/model/selection.js +++ b/src/model/selection.js @@ -16,26 +16,27 @@ Selection.prototype = { equals: function(other) { if (other == this) return true if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false - for (var i = 0; i < this.ranges.length; i++) { - var here = this.ranges[i], there = other.ranges[i] + for (let i = 0; i < this.ranges.length; i++) { + let here = this.ranges[i], there = other.ranges[i] if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false } return true }, deepCopy: function() { - for (var out = [], i = 0; i < this.ranges.length; i++) + let out = [] + for (let i = 0; i < this.ranges.length; i++) out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)) return new Selection(out, this.primIndex) }, somethingSelected: function() { - for (var i = 0; i < this.ranges.length; i++) + for (let i = 0; i < this.ranges.length; i++) if (!this.ranges[i].empty()) return true return false }, contains: function(pos, end) { if (!end) end = pos - for (var i = 0; i < this.ranges.length; i++) { - var range = this.ranges[i] + for (let i = 0; i < this.ranges.length; i++) { + let range = this.ranges[i] if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) return i } @@ -59,14 +60,14 @@ Range.prototype = { // build a selection out of it. 'Consumes' ranges array (modifying // it). export function normalizeSelection(ranges, primIndex) { - var prim = ranges[primIndex] + let prim = ranges[primIndex] ranges.sort(function(a, b) { return cmp(a.from(), b.from()) }) primIndex = indexOf(ranges, prim) - for (var i = 1; i < ranges.length; i++) { - var cur = ranges[i], prev = ranges[i - 1] + for (let i = 1; i < ranges.length; i++) { + let cur = ranges[i], prev = ranges[i - 1] if (cmp(prev.to(), cur.from()) >= 0) { - var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()) - var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head + let from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()) + let inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head if (i <= primIndex) --primIndex ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)) } diff --git a/src/model/selection_updates.js b/src/model/selection_updates.js index 640af1f249..0e310a5d2d 100644 --- a/src/model/selection_updates.js +++ b/src/model/selection_updates.js @@ -18,9 +18,9 @@ import { normalizeSelection, Range, Selection, simpleSelection } from "./selecti // Used for cursor motion and such. export function extendRange(doc, range, head, other) { if (doc.cm && doc.cm.display.shift || doc.extend) { - var anchor = range.anchor + let anchor = range.anchor if (other) { - var posBefore = cmp(head, anchor) < 0 + let posBefore = cmp(head, anchor) < 0 if (posBefore != (cmp(other, anchor) < 0)) { anchor = head head = other @@ -42,15 +42,16 @@ export function extendSelection(doc, head, other, options) { // Extend all selections (pos is an array of selections with length // equal the number of selections) export function extendSelections(doc, heads, options) { - for (var out = [], i = 0; i < doc.sel.ranges.length; i++) + let out = [] + for (let i = 0; i < doc.sel.ranges.length; i++) out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null) - var newSel = normalizeSelection(out, doc.sel.primIndex) + let newSel = normalizeSelection(out, doc.sel.primIndex) setSelection(doc, newSel, options) } // Updates a single range in the selection. export function replaceOneSelection(doc, i, range, options) { - var ranges = doc.sel.ranges.slice(0) + let ranges = doc.sel.ranges.slice(0) ranges[i] = range setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options) } @@ -63,11 +64,11 @@ export function setSimpleSelection(doc, anchor, head, options) { // Give beforeSelectionChange handlers a change to influence a // selection update. function filterSelectionChange(doc, sel, options) { - var obj = { + let obj = { ranges: sel.ranges, update: function(ranges) { this.ranges = [] - for (var i = 0; i < ranges.length; i++) + for (let i = 0; i < ranges.length; i++) this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), clipPos(doc, ranges[i].head)) }, @@ -80,7 +81,7 @@ function filterSelectionChange(doc, sel, options) { } export function setSelectionReplaceHistory(doc, sel, options) { - var done = doc.history.done, last = lst(done) + let done = doc.history.done, last = lst(done) if (last && last.ranges) { done[done.length - 1] = sel setSelectionNoUndo(doc, sel, options) @@ -99,7 +100,7 @@ export function setSelectionNoUndo(doc, sel, options) { if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) sel = filterSelectionChange(doc, sel, options) - var bias = options && options.bias || + let bias = options && options.bias || (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1) setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)) @@ -128,12 +129,12 @@ export function reCheckSelection(doc) { // Return a selection that does not partially select any atomic // ranges. function skipAtomicInSelection(doc, sel, bias, mayClear) { - var out - for (var i = 0; i < sel.ranges.length; i++) { - var range = sel.ranges[i] - var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i] - var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear) - var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear) + let out + for (let i = 0; i < sel.ranges.length; i++) { + let range = sel.ranges[i] + let old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i] + let newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear) + let newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear) if (out || newAnchor != range.anchor || newHead != range.head) { if (!out) out = sel.ranges.slice(0, i) out[i] = new Range(newAnchor, newHead) @@ -143,9 +144,9 @@ function skipAtomicInSelection(doc, sel, bias, mayClear) { } function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { - var line = getLine(doc, pos.line) - if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { - var sp = line.markedSpans[i], m = sp.marker + let line = getLine(doc, pos.line) + if (line.markedSpans) for (let i = 0; i < line.markedSpans.length; ++i) { + let sp = line.markedSpans[i], m = sp.marker if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) && (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) { if (mayClear) { @@ -158,14 +159,14 @@ function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { if (!m.atomic) continue if (oldPos) { - var near = m.find(dir < 0 ? 1 : -1), diff + let near = m.find(dir < 0 ? 1 : -1), diff if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null) if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0)) return skipAtomicInner(doc, near, pos, dir, mayClear) } - var far = m.find(dir < 0 ? -1 : 1) + let far = m.find(dir < 0 ? -1 : 1) if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) far = movePos(doc, far, dir, far.line == pos.line ? line : null) return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null @@ -176,8 +177,8 @@ function skipAtomicInner(doc, pos, oldPos, dir, mayClear) { // Ensure a given position is not inside an atomic range. export function skipAtomic(doc, pos, oldPos, bias, mayClear) { - var dir = bias || 1 - var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || + let dir = bias || 1 + let found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) || (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) || skipAtomicInner(doc, pos, oldPos, -dir, mayClear) || (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true)) diff --git a/src/modes.js b/src/modes.js index 15d16cefcb..065a463b5b 100644 --- a/src/modes.js +++ b/src/modes.js @@ -1,7 +1,7 @@ import { copyObj, createObj } from "./util/misc" // Known modes, by name and by MIME -export var modes = {}, mimeModes = {} +export let modes = {}, mimeModes = {} // Extra arguments are stored as the mode's dependencies, which is // used by (legacy) mechanisms like loadmode.js to automatically @@ -22,7 +22,7 @@ export function resolveMode(spec) { if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { spec = mimeModes[spec] } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { - var found = mimeModes[spec.name] + let found = mimeModes[spec.name] if (typeof found == "string") found = {name: found} spec = createObj(found, spec) spec.name = found.name @@ -38,13 +38,13 @@ export function resolveMode(spec) { // Given a mode spec (anything that resolveMode accepts), find and // initialize an actual mode object. export function getMode(options, spec) { - var spec = resolveMode(spec) - var mfactory = modes[spec.name] + spec = resolveMode(spec) + let mfactory = modes[spec.name] if (!mfactory) return getMode(options, "text/plain") - var modeObj = mfactory(options, spec) + let modeObj = mfactory(options, spec) if (modeExtensions.hasOwnProperty(spec.name)) { - var exts = modeExtensions[spec.name] - for (var prop in exts) { + let exts = modeExtensions[spec.name] + for (let prop in exts) { if (!exts.hasOwnProperty(prop)) continue if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop] modeObj[prop] = exts[prop] @@ -52,7 +52,7 @@ export function getMode(options, spec) { } modeObj.name = spec.name if (spec.helperType) modeObj.helperType = spec.helperType - if (spec.modeProps) for (var prop in spec.modeProps) + if (spec.modeProps) for (let prop in spec.modeProps) modeObj[prop] = spec.modeProps[prop] return modeObj @@ -60,18 +60,18 @@ export function getMode(options, spec) { // This can be used to attach properties to mode objects from // outside the actual mode definition. -export var modeExtensions = {} +export let modeExtensions = {} export function extendMode(mode, properties) { - var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}) + let exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}) copyObj(properties, exts) } export function copyState(mode, state) { if (state === true) return state if (mode.copyState) return mode.copyState(state) - var nstate = {} - for (var n in state) { - var val = state[n] + let nstate = {} + for (let n in state) { + let val = state[n] if (val instanceof Array) val = val.concat([]) nstate[n] = val } @@ -81,8 +81,9 @@ export function copyState(mode, state) { // Given a mode and a state (for that mode), find the inner mode and // state at the position that the state refers to. export function innerMode(mode, state) { + let info while (mode.innerMode) { - var info = mode.innerMode(state) + info = mode.innerMode(state) if (!info || info.mode == mode) break state = info.state mode = info.mode diff --git a/src/util/StringStream.js b/src/util/StringStream.js index d04807426c..cf7b8244a9 100644 --- a/src/util/StringStream.js +++ b/src/util/StringStream.js @@ -5,7 +5,7 @@ import { countColumn } from "./misc" // Fed to the mode parsers, provides helper functions to make // parsers more succinct. -var StringStream = function(string, tabSize) { +let StringStream = function(string, tabSize) { this.pos = this.start = 0 this.string = string this.tabSize = tabSize || 8 @@ -22,24 +22,25 @@ StringStream.prototype = { return this.string.charAt(this.pos++) }, eat: function(match) { - var ch = this.string.charAt(this.pos) - if (typeof match == "string") var ok = ch == match - else var ok = ch && (match.test ? match.test(ch) : match(ch)) + let ch = this.string.charAt(this.pos) + let ok + if (typeof match == "string") ok = ch == match + else ok = ch && (match.test ? match.test(ch) : match(ch)) if (ok) {++this.pos; return ch} }, eatWhile: function(match) { - var start = this.pos + let start = this.pos while (this.eat(match)){} return this.pos > start }, eatSpace: function() { - var start = this.pos + let start = this.pos while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos return this.pos > start }, skipToEnd: function() {this.pos = this.string.length}, skipTo: function(ch) { - var found = this.string.indexOf(ch, this.pos) + let found = this.string.indexOf(ch, this.pos) if (found > -1) {this.pos = found; return true} }, backUp: function(n) {this.pos -= n}, @@ -56,14 +57,14 @@ StringStream.prototype = { }, match: function(pattern, consume, caseInsensitive) { if (typeof pattern == "string") { - var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str} - var substr = this.string.substr(this.pos, pattern.length) + let cased = function(str) {return caseInsensitive ? str.toLowerCase() : str} + let substr = this.string.substr(this.pos, pattern.length) if (cased(substr) == cased(pattern)) { if (consume !== false) this.pos += pattern.length return true } } else { - var match = this.string.slice(this.pos).match(pattern) + let match = this.string.slice(this.pos).match(pattern) if (match && match.index > 0) return null if (match && consume !== false) this.pos += match[0].length return match diff --git a/src/util/bidi.js b/src/util/bidi.js index f12dccf50b..4c365f4c9b 100644 --- a/src/util/bidi.js +++ b/src/util/bidi.js @@ -4,9 +4,9 @@ import { isExtendingChar, lst } from "./misc" export function iterateBidiSections(order, from, to, f) { if (!order) return f(from, to, "ltr") - var found = false - for (var i = 0; i < order.length; ++i) { - var part = order[i] + let found = false + for (let i = 0; i < order.length; ++i) { + let part = order[i] if (part.from < to && part.to > from || from == to && part.to == from) { f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr") found = true @@ -18,25 +18,26 @@ export function iterateBidiSections(order, from, to, f) { export function bidiLeft(part) { return part.level % 2 ? part.to : part.from } export function bidiRight(part) { return part.level % 2 ? part.from : part.to } -export function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0 } +export function lineLeft(line) { let order = getOrder(line); return order ? bidiLeft(order[0]) : 0 } export function lineRight(line) { - var order = getOrder(line) + let order = getOrder(line) if (!order) return line.text.length return bidiRight(lst(order)) } function compareBidiLevel(order, a, b) { - var linedir = order[0].level + let linedir = order[0].level if (a == linedir) return true if (b == linedir) return false return a < b } -export var bidiOther = null +export let bidiOther = null export function getBidiPartAt(order, pos) { + let found bidiOther = null - for (var i = 0, found; i < order.length; ++i) { - var cur = order[i] + for (let i = 0; i < order.length; ++i) { + let cur = order[i] if (cur.from < pos && cur.to > pos) return i if ((cur.from == pos || cur.to == pos)) { if (found == null) { @@ -66,10 +67,10 @@ function moveInLine(line, pos, dir, byUnit) { // LTR text touch each other. This often requires the cursor offset // to move more than one unit, in order to visually move one unit. export function moveVisually(line, start, dir, byUnit) { - var bidi = getOrder(line) + let bidi = getOrder(line) if (!bidi) return moveLogically(line, start, dir, byUnit) - var pos = getBidiPartAt(bidi, start), part = bidi[pos] - var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit) + let pos = getBidiPartAt(bidi, start), part = bidi[pos] + let target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit) for (;;) { if (target > part.from && target < part.to) return target @@ -89,7 +90,7 @@ export function moveVisually(line, start, dir, byUnit) { } export function moveLogically(line, start, dir, byUnit) { - var target = start + dir + let target = start + dir if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir return target < 0 || target > line.text.length ? null : target } @@ -117,11 +118,11 @@ export function moveLogically(line, start, dir, byUnit) { // Returns null if characters are ordered as they appear // (left-to-right), or an array of sections ({from, to, level} // objects) in the order in which they occur visually. -export var bidiOrdering = (function() { +export let bidiOrdering = (function() { // Character types for codepoints 0 to 0xff - var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN" + let lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN" // Character types for codepoints 0x600 to 0x6ff - var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm" + let arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm" function charType(code) { if (code <= 0xf7) return lowTypes.charAt(code) else if (0x590 <= code && code <= 0x5f4) return "R" @@ -132,10 +133,10 @@ export var bidiOrdering = (function() { else return "L" } - var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/ - var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/ + let bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/ + let isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/ // Browsers seem to always treat the boundaries of block elements as being L. - var outerType = "L" + let outerType = "L" function BidiSpan(level, from, to) { this.level = level @@ -144,16 +145,16 @@ export var bidiOrdering = (function() { return function(str) { if (!bidiRE.test(str)) return false - var len = str.length, types = [] - for (var i = 0, type; i < len; ++i) - types.push(type = charType(str.charCodeAt(i))) + let len = str.length, types = [] + for (let i = 0; i < len; ++i) + types.push(charType(str.charCodeAt(i))) // W1. Examine each non-spacing mark (NSM) in the level run, and // change the type of the NSM to the type of the previous // character. If the NSM is at the start of the level run, it will // get the type of sor. - for (var i = 0, prev = outerType; i < len; ++i) { - var type = types[i] + for (let i = 0, prev = outerType; i < len; ++i) { + let type = types[i] if (type == "m") types[i] = prev else prev = type } @@ -163,8 +164,8 @@ export var bidiOrdering = (function() { // AL is found, change the type of the European number to Arabic // number. // W3. Change all ALs to R. - for (var i = 0, cur = outerType; i < len; ++i) { - var type = types[i] + for (let i = 0, cur = outerType; i < len; ++i) { + let type = types[i] if (type == "1" && cur == "r") types[i] = "n" else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R" } } @@ -172,8 +173,8 @@ export var bidiOrdering = (function() { // W4. A single European separator between two European numbers // changes to a European number. A single common separator between // two numbers of the same type changes to that type. - for (var i = 1, prev = types[0]; i < len - 1; ++i) { - var type = types[i] + for (let i = 1, prev = types[0]; i < len - 1; ++i) { + let type = types[i] if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1" else if (type == "," && prev == types[i+1] && (prev == "1" || prev == "n")) types[i] = prev @@ -184,13 +185,14 @@ export var bidiOrdering = (function() { // numbers changes to all European numbers. // W6. Otherwise, separators and terminators change to Other // Neutral. - for (var i = 0; i < len; ++i) { - var type = types[i] + for (let i = 0; i < len; ++i) { + let type = types[i] if (type == ",") types[i] = "N" else if (type == "%") { - for (var end = i + 1; end < len && types[end] == "%"; ++end) {} - var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N" - for (var j = i; j < end; ++j) types[j] = replace + let end + for (end = i + 1; end < len && types[end] == "%"; ++end) {} + let replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N" + for (let j = i; j < end; ++j) types[j] = replace i = end - 1 } } @@ -198,8 +200,8 @@ export var bidiOrdering = (function() { // W7. Search backwards from each instance of a European number // until the first strong type (R, L, or sor) is found. If an L is // found, then change the type of the European number to L. - for (var i = 0, cur = outerType; i < len; ++i) { - var type = types[i] + for (let i = 0, cur = outerType; i < len; ++i) { + let type = types[i] if (cur == "L" && type == "1") types[i] = "L" else if (isStrong.test(type)) cur = type } @@ -210,13 +212,14 @@ export var bidiOrdering = (function() { // terms of their influence on neutrals. Start-of-level-run (sor) // and end-of-level-run (eor) are used at level run boundaries. // N2. Any remaining neutrals take the embedding direction. - for (var i = 0; i < len; ++i) { + for (let i = 0; i < len; ++i) { if (isNeutral.test(types[i])) { - for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {} - var before = (i ? types[i-1] : outerType) == "L" - var after = (end < len ? types[end] : outerType) == "L" - var replace = before || after ? "L" : "R" - for (var j = i; j < end; ++j) types[j] = replace + let end + for (end = i + 1; end < len && isNeutral.test(types[end]); ++end) {} + let before = (i ? types[i-1] : outerType) == "L" + let after = (end < len ? types[end] : outerType) == "L" + let replace = before || after ? "L" : "R" + for (let j = i; j < end; ++j) types[j] = replace i = end - 1 } } @@ -226,19 +229,19 @@ export var bidiOrdering = (function() { // levels (0, 1, 2) in an implementation that doesn't take // explicit embedding into account, we can build up the order on // the fly, without following the level-based algorithm. - var order = [], m - for (var i = 0; i < len;) { + let order = [], m + for (let i = 0; i < len;) { if (countsAsLeft.test(types[i])) { - var start = i + let start = i for (++i; i < len && countsAsLeft.test(types[i]); ++i) {} order.push(new BidiSpan(0, start, i)) } else { - var pos = i, at = order.length + let pos = i, at = order.length for (++i; i < len && types[i] != "L"; ++i) {} - for (var j = pos; j < i;) { + for (let j = pos; j < i;) { if (countsAsNum.test(types[j])) { if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)) - var nstart = j + let nstart = j for (++j; j < i && countsAsNum.test(types[j]); ++j) {} order.splice(at, 0, new BidiSpan(2, nstart, j)) pos = j @@ -268,7 +271,7 @@ export var bidiOrdering = (function() { // false for lines that are fully left-to-right, and an array of // BidiSpan objects otherwise. export function getOrder(line) { - var order = line.order + let order = line.order if (order == null) order = line.order = bidiOrdering(line.text) return order } diff --git a/src/util/browser.js b/src/util/browser.js index ae48fb5c65..ce678a82a4 100644 --- a/src/util/browser.js +++ b/src/util/browser.js @@ -1,31 +1,31 @@ // Kludges for bugs and behavior differences that can't be feature // detected are enabled based on userAgent etc sniffing. -var userAgent = navigator.userAgent -var platform = navigator.platform +let userAgent = navigator.userAgent +let platform = navigator.platform -export var gecko = /gecko\/\d/i.test(userAgent) -var ie_upto10 = /MSIE \d/.test(userAgent) -var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent) -export var ie = ie_upto10 || ie_11up -export var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]) -export var webkit = /WebKit\//.test(userAgent) -var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent) -export var chrome = /Chrome\//.test(userAgent) -export var presto = /Opera\//.test(userAgent) -export var safari = /Apple Computer/.test(navigator.vendor) -export var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent) -export var phantom = /PhantomJS/.test(userAgent) +export let gecko = /gecko\/\d/i.test(userAgent) +let ie_upto10 = /MSIE \d/.test(userAgent) +let ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent) +export let ie = ie_upto10 || ie_11up +export let ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]) +export let webkit = /WebKit\//.test(userAgent) +let qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent) +export let chrome = /Chrome\//.test(userAgent) +export let presto = /Opera\//.test(userAgent) +export let safari = /Apple Computer/.test(navigator.vendor) +export let mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent) +export let phantom = /PhantomJS/.test(userAgent) -export var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent) +export let ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent) // This is woefully incomplete. Suggestions for alternative methods welcome. -export var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent) -export var mac = ios || /Mac/.test(platform) -export var chromeOS = /\bCrOS\b/.test(userAgent) -export var windows = /win/i.test(platform) +export let mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent) +export let mac = ios || /Mac/.test(platform) +export let chromeOS = /\bCrOS\b/.test(userAgent) +export let windows = /win/i.test(platform) -var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/) +let presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/) if (presto_version) presto_version = Number(presto_version[1]) if (presto_version && presto_version >= 15) { presto = false; webkit = true } // Some browsers use the wrong event properties to signal cmd/ctrl on OS X -export var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)) -export var captureRightClick = gecko || (ie && ie_version >= 9) +export let flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)) +export let captureRightClick = gecko || (ie && ie_version >= 9) diff --git a/src/util/dom.js b/src/util/dom.js index df2cfd0aac..465dbb5a5e 100644 --- a/src/util/dom.js +++ b/src/util/dom.js @@ -2,17 +2,17 @@ import { ie, ie_version, ios } from "./browser" export function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") } -export var rmClass = function(node, cls) { - var current = node.className - var match = classTest(cls).exec(current) +export let rmClass = function(node, cls) { + let current = node.className + let match = classTest(cls).exec(current) if (match) { - var after = current.slice(match.index + match[0].length) + let after = current.slice(match.index + match[0].length) node.className = current.slice(0, match.index) + (after ? match[1] + after : "") } } export function removeChildren(e) { - for (var count = e.childNodes.length; count > 0; --count) + for (let count = e.childNodes.length; count > 0; --count) e.removeChild(e.firstChild) return e } @@ -22,23 +22,23 @@ export function removeChildrenAndAdd(parent, e) { } export function elt(tag, content, className, style) { - var e = document.createElement(tag) + let e = document.createElement(tag) if (className) e.className = className if (style) e.style.cssText = style if (typeof content == "string") e.appendChild(document.createTextNode(content)) - else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]) + else if (content) for (let i = 0; i < content.length; ++i) e.appendChild(content[i]) return e } -export var range +export let range if (document.createRange) range = function(node, start, end, endNode) { - var r = document.createRange() + let r = document.createRange() r.setEnd(endNode || node, end) r.setStart(node, start) return r } else range = function(node, start, end) { - var r = document.body.createTextRange() + let r = document.body.createTextRange() try { r.moveToElementText(node.parentNode) } catch(e) { return r } r.collapse(true) @@ -58,8 +58,8 @@ export function contains(parent, child) { } while (child = child.parentNode) } -export var activeElt = function() { - var activeElement = document.activeElement +export let activeElt = function() { + let activeElement = document.activeElement while (activeElement && activeElement.root && activeElement.root.activeElement) activeElement = activeElement.root.activeElement return activeElement @@ -72,17 +72,17 @@ if (ie && ie_version < 11) activeElt = function() { } export function addClass(node, cls) { - var current = node.className + let current = node.className if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls } export function joinClasses(a, b) { - var as = a.split(" ") - for (var i = 0; i < as.length; i++) + let as = a.split(" ") + for (let i = 0; i < as.length; i++) if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i] return b } -export var selectInput = function(node) { node.select() } +export let selectInput = function(node) { node.select() } if (ios) // Mobile Safari apparently has a bug where select() is broken. selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length } else if (ie) // Suppress mysterious IE10 errors diff --git a/src/util/event.js b/src/util/event.js index b2137583fb..e667a9f3c0 100644 --- a/src/util/event.js +++ b/src/util/event.js @@ -6,21 +6,21 @@ import { indexOf } from "./misc" // Lightweight event framework. on/off also work on DOM nodes, // registering native DOM handlers. -export var on = function(emitter, type, f) { +export let on = function(emitter, type, f) { if (emitter.addEventListener) emitter.addEventListener(type, f, false) else if (emitter.attachEvent) emitter.attachEvent("on" + type, f) else { - var map = emitter._handlers || (emitter._handlers = {}) - var arr = map[type] || (map[type] = []) + let map = emitter._handlers || (emitter._handlers = {}) + let arr = map[type] || (map[type] = []) arr.push(f) } } -var noHandlers = [] +let noHandlers = [] export function getHandlers(emitter, type, copy) { - var arr = emitter._handlers && emitter._handlers[type] + let arr = emitter._handlers && emitter._handlers[type] if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers else return arr || noHandlers } @@ -31,17 +31,17 @@ export function off(emitter, type, f) { else if (emitter.detachEvent) emitter.detachEvent("on" + type, f) else { - var handlers = getHandlers(emitter, type, false) - for (var i = 0; i < handlers.length; ++i) + let handlers = getHandlers(emitter, type, false) + for (let i = 0; i < handlers.length; ++i) if (handlers[i] == f) { handlers.splice(i, 1); break } } } export function signal(emitter, type /*, values...*/) { - var handlers = getHandlers(emitter, type, true) + let handlers = getHandlers(emitter, type, true) if (!handlers.length) return - var args = Array.prototype.slice.call(arguments, 2) - for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args) + let args = Array.prototype.slice.call(arguments, 2) + for (let i = 0; i < handlers.length; ++i) handlers[i].apply(null, args) } // The DOM events that CodeMirror handles can be overridden by @@ -55,10 +55,10 @@ export function signalDOMEvent(cm, e, override) { } export function signalCursorActivity(cm) { - var arr = cm._handlers && cm._handlers.cursorActivity + let arr = cm._handlers && cm._handlers.cursorActivity if (!arr) return - var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []) - for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) + let set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []) + for (let i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) set.push(arr[i]) } @@ -91,7 +91,7 @@ export function e_stop(e) {e_preventDefault(e); e_stopPropagation(e)} export function e_target(e) {return e.target || e.srcElement} export function e_button(e) { - var b = e.which + let b = e.which if (b == null) { if (e.button & 1) b = 1 else if (e.button & 2) b = 3 diff --git a/src/util/feature_detection.js b/src/util/feature_detection.js index 1e9baf41e5..d98393af90 100644 --- a/src/util/feature_detection.js +++ b/src/util/feature_detection.js @@ -2,35 +2,35 @@ import { elt, range, removeChildren, removeChildrenAndAdd } from "./dom" import { ie, ie_version } from "./browser" // Detect drag-and-drop -export var dragAndDrop = function() { +export let dragAndDrop = function() { // There is *some* kind of drag-and-drop support in IE6-8, but I // couldn't get it to work yet. if (ie && ie_version < 9) return false - var div = elt('div') + let div = elt('div') return "draggable" in div || "dragDrop" in div }() -var zwspSupported +let zwspSupported export function zeroWidthElement(measure) { if (zwspSupported == null) { - var test = elt("span", "\u200b") + let test = elt("span", "\u200b") removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])) if (measure.firstChild.offsetHeight != 0) zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8) } - var node = zwspSupported ? elt("span", "\u200b") : + let node = zwspSupported ? elt("span", "\u200b") : elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px") node.setAttribute("cm-text", "") return node } // Feature-detect IE's crummy client rect reporting for bidi text -var badBidiRects +let badBidiRects export function hasBadBidiRects(measure) { if (badBidiRects != null) return badBidiRects - var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")) - var r0 = range(txt, 0, 1).getBoundingClientRect() - var r1 = range(txt, 1, 2).getBoundingClientRect() + let txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")) + let r0 = range(txt, 0, 1).getBoundingClientRect() + let r1 = range(txt, 1, 2).getBoundingClientRect() removeChildren(measure) if (!r0 || r0.left == r0.right) return false // Safari returns null in some cases (#2780) return badBidiRects = (r1.right - r0.right < 3) @@ -38,13 +38,13 @@ export function hasBadBidiRects(measure) { // See if "".split is the broken IE version, if so, provide an // alternative way to split lines. -export var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function(string) { - var pos = 0, result = [], l = string.length +export let splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function(string) { + let pos = 0, result = [], l = string.length while (pos <= l) { - var nl = string.indexOf("\n", pos) + let nl = string.indexOf("\n", pos) if (nl == -1) nl = string.length - var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl) - var rt = line.indexOf("\r") + let line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl) + let rt = line.indexOf("\r") if (rt != -1) { result.push(line.slice(0, rt)) pos += rt + 1 @@ -56,28 +56,29 @@ export var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function(string) { return result } : function(string){return string.split(/\r\n?|\n/)} -export var hasSelection = window.getSelection ? function(te) { +export let hasSelection = window.getSelection ? function(te) { try { return te.selectionStart != te.selectionEnd } catch(e) { return false } } : function(te) { - try {var range = te.ownerDocument.selection.createRange()} + let range + try {range = te.ownerDocument.selection.createRange()} catch(e) {} if (!range || range.parentElement() != te) return false return range.compareEndPoints("StartToEnd", range) != 0 } -export var hasCopyEvent = (function() { - var e = elt("div") +export let hasCopyEvent = (function() { + let e = elt("div") if ("oncopy" in e) return true e.setAttribute("oncopy", "return;") return typeof e.oncopy == "function" })() -var badZoomedRects = null +let badZoomedRects = null export function hasBadZoomedRects(measure) { if (badZoomedRects != null) return badZoomedRects - var node = removeChildrenAndAdd(measure, elt("span", "x")) - var normal = node.getBoundingClientRect() - var fromRange = range(node, 0, 1).getBoundingClientRect() + let node = removeChildrenAndAdd(measure, elt("span", "x")) + let normal = node.getBoundingClientRect() + let fromRange = range(node, 0, 1).getBoundingClientRect() return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1 } diff --git a/src/util/misc.js b/src/util/misc.js index a6e3340db1..c94de8bd2c 100644 --- a/src/util/misc.js +++ b/src/util/misc.js @@ -1,11 +1,11 @@ export function bind(f) { - var args = Array.prototype.slice.call(arguments, 1) + let args = Array.prototype.slice.call(arguments, 1) return function(){return f.apply(null, args)} } export function copyObj(obj, target, overwrite) { if (!target) target = {} - for (var prop in obj) + for (let prop in obj) if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) target[prop] = obj[prop] return target @@ -18,8 +18,8 @@ export function countColumn(string, end, tabSize, startIndex, startValue) { end = string.search(/[^\s\u00a0]/) if (end == -1) end = string.length } - for (var i = startIndex || 0, n = startValue || 0;;) { - var nextTab = string.indexOf("\t", i) + for (let i = startIndex || 0, n = startValue || 0;;) { + let nextTab = string.indexOf("\t", i) if (nextTab < 0 || nextTab >= end) return n + (end - i) n += nextTab - i @@ -35,28 +35,28 @@ Delayed.prototype.set = function(ms, f) { } export function indexOf(array, elt) { - for (var i = 0; i < array.length; ++i) + for (let i = 0; i < array.length; ++i) if (array[i] == elt) return i return -1 } // Number of pixels added to scroller and sizer to hide scrollbar -export var scrollerGap = 30 +export let scrollerGap = 30 // Returned or thrown by various protocols to signal 'I'm not // handling this'. -export var Pass = {toString: function(){return "CodeMirror.Pass"}} +export let Pass = {toString: function(){return "CodeMirror.Pass"}} // Reused option objects for setSelection & friends -export var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"} +export let sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"} // The inverse of countColumn -- find the offset that corresponds to // a particular column. export function findColumn(string, goal, tabSize) { - for (var pos = 0, col = 0;;) { - var nextTab = string.indexOf("\t", pos) + for (let pos = 0, col = 0;;) { + let nextTab = string.indexOf("\t", pos) if (nextTab == -1) nextTab = string.length - var skipped = nextTab - pos + let skipped = nextTab - pos if (nextTab == string.length || col + skipped >= goal) return pos + Math.min(skipped, goal - col) col += nextTab - pos @@ -66,7 +66,7 @@ export function findColumn(string, goal, tabSize) { } } -var spaceStrs = [""] +let spaceStrs = [""] export function spaceStr(n) { while (spaceStrs.length <= n) spaceStrs.push(lst(spaceStrs) + " ") @@ -76,13 +76,13 @@ export function spaceStr(n) { export function lst(arr) { return arr[arr.length-1] } export function map(array, f) { - var out = [] - for (var i = 0; i < array.length; i++) out[i] = f(array[i], i) + let out = [] + for (let i = 0; i < array.length; i++) out[i] = f(array[i], i) return out } export function insertSorted(array, value, score) { - var pos = 0, priority = score(value) + let pos = 0, priority = score(value) while (pos < array.length && score(array[pos]) <= priority) pos++ array.splice(pos, 0, value) } @@ -90,7 +90,7 @@ export function insertSorted(array, value, score) { export function nothing() {} export function createObj(base, props) { - var inst + let inst if (Object.create) { inst = Object.create(base) } else { @@ -101,7 +101,7 @@ export function createObj(base, props) { return inst } -var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/ +let nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/ export function isWordCharBasic(ch) { return /\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)) @@ -113,7 +113,7 @@ export function isWordChar(ch, helper) { } export function isEmpty(obj) { - for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false + for (let n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false return true } @@ -122,5 +122,5 @@ export function isEmpty(obj) { // as editing and measuring is concerned. This is not fully correct, // since some scripts/fonts/browsers also treat other configurations // of code points as a group. -var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/ +let extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/ export function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) } diff --git a/src/util/operation_group.js b/src/util/operation_group.js index d48f6eb32a..d743f994e5 100644 --- a/src/util/operation_group.js +++ b/src/util/operation_group.js @@ -1,6 +1,6 @@ import { getHandlers } from "./event" -var operationGroup = null +let operationGroup = null export function pushOperation(op) { if (operationGroup) { @@ -16,12 +16,12 @@ export function pushOperation(op) { function fireCallbacksForOps(group) { // Calls delayed callbacks and cursorActivity handlers until no // new ones appear - var callbacks = group.delayedCallbacks, i = 0 + let callbacks = group.delayedCallbacks, i = 0 do { for (; i < callbacks.length; i++) callbacks[i].call(null) - for (var j = 0; j < group.ops.length; j++) { - var op = group.ops[j] + for (let j = 0; j < group.ops.length; j++) { + let op = group.ops[j] if (op.cursorActivityHandlers) while (op.cursorActivityCalled < op.cursorActivityHandlers.length) op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm) @@ -30,7 +30,7 @@ function fireCallbacksForOps(group) { } export function finishOperation(op, endCb) { - var group = op.ownsGroup + let group = op.ownsGroup if (!group) return try { fireCallbacksForOps(group) } @@ -40,7 +40,7 @@ export function finishOperation(op, endCb) { } } -var orphanDelayedCallbacks = null +let orphanDelayedCallbacks = null // Often, we want to signal events at a point where we are in the // middle of some work, but don't want the handler to start calling @@ -50,9 +50,9 @@ var orphanDelayedCallbacks = null // them to be executed when the last operation ends, or, if no // operation is active, when a timeout fires. export function signalLater(emitter, type /*, values...*/) { - var arr = getHandlers(emitter, type, false) + let arr = getHandlers(emitter, type, false) if (!arr.length) return - var args = Array.prototype.slice.call(arguments, 2), list + let args = Array.prototype.slice.call(arguments, 2), list if (operationGroup) { list = operationGroup.delayedCallbacks } else if (orphanDelayedCallbacks) { @@ -62,12 +62,12 @@ export function signalLater(emitter, type /*, values...*/) { setTimeout(fireOrphanDelayed, 0) } function bnd(f) {return function(){f.apply(null, args)}} - for (var i = 0; i < arr.length; ++i) + for (let i = 0; i < arr.length; ++i) list.push(bnd(arr[i])) } function fireOrphanDelayed() { - var delayed = orphanDelayedCallbacks + let delayed = orphanDelayedCallbacks orphanDelayedCallbacks = null - for (var i = 0; i < delayed.length; ++i) delayed[i]() + for (let i = 0; i < delayed.length; ++i) delayed[i]() } From 6992c534ad33ce60e7500fe04a99a481ef8f548e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 29 Sep 2016 11:16:44 +0200 Subject: [PATCH 0037/1880] =?UTF-8?q?Change=20one=20let=20back=20to=20var?= =?UTF-8?q?=20to=20work=20around=20a=20Bubl=C3=A9=20issue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue #4261 --- src/model/history.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/history.js b/src/model/history.js index 0c7cf5bba1..2a7502cb8e 100644 --- a/src/model/history.js +++ b/src/model/history.js @@ -216,7 +216,7 @@ export function copyHistoryArray(events, newGroup, instantiateSel) { for (let j = 0; j < changes.length; ++j) { let change = changes[j], m newChanges.push({from: change.from, to: change.to, text: change.text}) - if (newGroup) for (let prop in change) if (m = prop.match(/^spans_(\d+)$/)) { + if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { if (indexOf(newGroup, Number(m[1])) > -1) { lst(newChanges)[prop] = change[prop] delete change[prop] From 9ad40ee76ffba6ab90f990b5b5bf1490b32410ef Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Thu, 29 Sep 2016 11:00:09 +0200 Subject: [PATCH 0038/1880] Convert anonymous to arrow functions --- src/display/focus.js | 14 +- src/display/highlight_worker.js | 4 +- src/display/mode_state.js | 2 +- src/display/operations.js | 2 +- src/display/scroll_events.js | 4 +- src/display/scrollbars.js | 12 +- src/display/selection.js | 7 +- src/edit/CodeMirror.js | 40 ++-- src/edit/commands.js | 252 +++++++++++------------- src/edit/deleteNearSelection.js | 2 +- src/edit/drop_events.js | 6 +- src/edit/fromTextArea.js | 13 +- src/edit/global_events.js | 8 +- src/edit/key_events.js | 11 +- src/edit/main.js | 8 +- src/edit/methods.js | 24 ++- src/edit/mouse_events.js | 14 +- src/edit/options.js | 58 +++--- src/input/ContentEditableInput.js | 36 ++-- src/input/TextareaInput.js | 20 +- src/input/input.js | 4 +- src/line/highlight.js | 21 +- src/line/line_data.js | 2 +- src/line/spans.js | 4 +- src/line/utils_line.js | 4 +- src/measurement/position_measurement.js | 4 +- src/model/Doc.js | 14 +- src/model/changes.js | 28 +-- src/model/history.js | 4 +- src/model/line_widget.js | 6 +- src/model/mark_text.js | 15 +- src/model/selection.js | 2 +- src/util/StringStream.js | 2 +- src/util/feature_detection.js | 10 +- src/util/operation_group.js | 3 +- 35 files changed, 305 insertions(+), 355 deletions(-) diff --git a/src/display/focus.js b/src/display/focus.js index e6a9f5218d..ee52daffac 100644 --- a/src/display/focus.js +++ b/src/display/focus.js @@ -9,12 +9,10 @@ export function ensureFocus(cm) { export function delayBlurEvent(cm) { cm.state.delayingBlurEvent = true - setTimeout(function() { - if (cm.state.delayingBlurEvent) { - cm.state.delayingBlurEvent = false - onBlur(cm) - } - }, 100) + setTimeout(() => { if (cm.state.delayingBlurEvent) { + cm.state.delayingBlurEvent = false + onBlur(cm) + } }, 100) } export function onFocus(cm, e) { @@ -30,7 +28,7 @@ export function onFocus(cm, e) { // select-all detection hack) if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { cm.display.input.reset() - if (webkit) setTimeout(function() { cm.display.input.reset(true) }, 20) // Issue #1730 + if (webkit) setTimeout(() => cm.display.input.reset(true), 20) // Issue #1730 } cm.display.input.receivedFocus() } @@ -45,5 +43,5 @@ export function onBlur(cm, e) { rmClass(cm.display.wrapper, "CodeMirror-focused") } clearInterval(cm.display.blinker) - setTimeout(function() {if (!cm.state.focused) cm.display.shift = false}, 150) + setTimeout(() => { if (!cm.state.focused) cm.display.shift = false }, 150) } diff --git a/src/display/highlight_worker.js b/src/display/highlight_worker.js index 5d535abe70..d34db2b42e 100644 --- a/src/display/highlight_worker.js +++ b/src/display/highlight_worker.js @@ -20,7 +20,7 @@ function highlightWorker(cm) { let state = copyState(doc.mode, getStateBefore(cm, doc.frontier)) let changedLines = [] - doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { + doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), line => { if (doc.frontier >= cm.display.viewFrom) { // Visible let oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength let highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true) @@ -44,7 +44,7 @@ function highlightWorker(cm) { return true } }) - if (changedLines.length) runInOp(cm, function() { + if (changedLines.length) runInOp(cm, () => { for (let i = 0; i < changedLines.length; i++) regLineChange(cm, changedLines[i], "text") }) diff --git a/src/display/mode_state.js b/src/display/mode_state.js index 7742c722a4..8c4c60b058 100644 --- a/src/display/mode_state.js +++ b/src/display/mode_state.js @@ -11,7 +11,7 @@ export function loadMode(cm) { } export function resetModeState(cm) { - cm.doc.iter(function(line) { + cm.doc.iter(line => { if (line.stateAfter) line.stateAfter = null if (line.styles) line.styles = null }) diff --git a/src/display/operations.js b/src/display/operations.js index cc6eef7bde..30a63a613a 100644 --- a/src/display/operations.js +++ b/src/display/operations.js @@ -46,7 +46,7 @@ export function startOperation(cm) { // Finish an operation, updating the display and signalling delayed events export function endOperation(cm) { let op = cm.curOp - finishOperation(op, function(group) { + finishOperation(op, group => { for (let i = 0; i < group.ops.length; i++) group.ops[i].cm.curOp = null endOperations(group) diff --git a/src/display/scroll_events.js b/src/display/scroll_events.js index 3c166b4855..e85d2a02fd 100644 --- a/src/display/scroll_events.js +++ b/src/display/scroll_events.js @@ -48,7 +48,7 @@ else if (gecko) wheelPixelsPerUnit = 15 else if (chrome) wheelPixelsPerUnit = -.7 else if (safari) wheelPixelsPerUnit = -1/3 -let wheelEventDelta = function(e) { +function wheelEventDelta(e) { let dx = e.wheelDeltaX, dy = e.wheelDeltaY if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail @@ -120,7 +120,7 @@ export function onScrollWheel(cm, e) { if (display.wheelStartX == null) { display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop display.wheelDX = dx; display.wheelDY = dy - setTimeout(function() { + setTimeout(() => { if (display.wheelStartX == null) return let movedX = scroll.scrollLeft - display.wheelStartX let movedY = scroll.scrollTop - display.wheelStartY diff --git a/src/display/scrollbars.js b/src/display/scrollbars.js index a07f2a165d..a85fffe9a5 100644 --- a/src/display/scrollbars.js +++ b/src/display/scrollbars.js @@ -33,10 +33,10 @@ function NativeScrollbars(place, scroll, cm) { let horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar") place(vert); place(horiz) - on(vert, "scroll", function() { + on(vert, "scroll", () => { if (vert.clientHeight) scroll(vert.scrollTop, "vertical") }) - on(horiz, "scroll", function() { + on(horiz, "scroll", () => { if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal") }) @@ -172,14 +172,14 @@ export function initScrollbars(cm) { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass) } - cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function(node) { + cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](node => { cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller) // Prevent clicks in the scrollbars from killing focus - on(node, "mousedown", function() { - if (cm.state.focused) setTimeout(function() { cm.display.input.focus() }, 0) + on(node, "mousedown", () => { + if (cm.state.focused) setTimeout(() => cm.display.input.focus(), 0) }) node.setAttribute("cm-not-content", "true") - }, function(pos, axis) { + }, (pos, axis) => { if (axis == "horizontal") setScrollLeft(cm, pos) else setScrollTop(cm, pos) }, cm) diff --git a/src/display/selection.js b/src/display/selection.js index 9fa8f6eefb..8380de82e5 100644 --- a/src/display/selection.js +++ b/src/display/selection.js @@ -70,7 +70,7 @@ function drawSelectionRange(cm, range, output) { return charCoords(cm, Pos(line, ch), "div", lineObj, bias) } - iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { + iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, (from, to, dir) => { let leftPos = coords(from, "left"), rightPos, left, right if (from == to) { rightPos = leftPos @@ -129,9 +129,8 @@ export function restartBlink(cm) { let on = true display.cursorDiv.style.visibility = "" if (cm.options.cursorBlinkRate > 0) - display.blinker = setInterval(function() { - display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden" - }, cm.options.cursorBlinkRate) + display.blinker = setInterval(() => display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden", + cm.options.cursorBlinkRate) else if (cm.options.cursorBlinkRate < 0) display.cursorDiv.style.visibility = "hidden" } diff --git a/src/edit/CodeMirror.js b/src/edit/CodeMirror.js index 90650ff059..909ffcb185 100644 --- a/src/edit/CodeMirror.js +++ b/src/edit/CodeMirror.js @@ -68,7 +68,7 @@ export function CodeMirror(place, options) { // Override magic textarea content restore that IE sometimes does // on our hidden textarea on reload - if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true) }, 20) + if (ie && ie_version < 11) setTimeout(() => cm.display.input.reset(true), 20) registerEventHandlers(this) ensureGlobalHandlers() @@ -108,7 +108,7 @@ function registerEventHandlers(cm) { on(d.scroller, "mousedown", operation(cm, onMouseDown)) // Older IE's will not fire a second mousedown for a double click if (ie && ie_version < 11) - on(d.scroller, "dblclick", operation(cm, function(e) { + on(d.scroller, "dblclick", operation(cm, e => { if (signalDOMEvent(cm, e)) return let pos = posFromMouse(cm, e) if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return @@ -117,17 +117,17 @@ function registerEventHandlers(cm) { extendSelection(cm.doc, word.anchor, word.head) })) else - on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e) }) + on(d.scroller, "dblclick", e => signalDOMEvent(cm, e) || e_preventDefault(e)) // Some browsers fire contextmenu *after* opening the menu, at // which point we can't mess with it anymore. Context menu is // handled in onMouseDown for these browsers. - if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e)}) + if (!captureRightClick) on(d.scroller, "contextmenu", e => onContextMenu(cm, e)) // Used to suppress mouse event handling when a touch happens let touchFinished, prevTouch = {end: 0} function finishTouch() { if (d.activeTouch) { - touchFinished = setTimeout(function() {d.activeTouch = null}, 1000) + touchFinished = setTimeout(() => d.activeTouch = null, 1000) prevTouch = d.activeTouch prevTouch.end = +new Date } @@ -142,7 +142,7 @@ function registerEventHandlers(cm) { let dx = other.left - touch.left, dy = other.top - touch.top return dx * dx + dy * dy > 20 * 20 } - on(d.scroller, "touchstart", function(e) { + on(d.scroller, "touchstart", e => { if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) { clearTimeout(touchFinished) let now = +new Date @@ -154,10 +154,10 @@ function registerEventHandlers(cm) { } } }) - on(d.scroller, "touchmove", function() { + on(d.scroller, "touchmove", () => { if (d.activeTouch) d.activeTouch.moved = true }) - on(d.scroller, "touchend", function(e) { + on(d.scroller, "touchend", e => { let touch = d.activeTouch if (touch && !eventInWidget(d, e) && touch.left != null && !touch.moved && new Date - touch.start < 300) { @@ -178,7 +178,7 @@ function registerEventHandlers(cm) { // Sync scrolling between fake scrollbars and real scrollable // area, ensure viewport is updated when scrolling. - on(d.scroller, "scroll", function() { + on(d.scroller, "scroll", () => { if (d.scroller.clientHeight) { setScrollTop(cm, d.scroller.scrollTop) setScrollLeft(cm, d.scroller.scrollLeft, true) @@ -187,27 +187,27 @@ function registerEventHandlers(cm) { }) // Listen to wheel events in order to try and update the viewport on time. - on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e)}) - on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e)}) + on(d.scroller, "mousewheel", e => onScrollWheel(cm, e)) + on(d.scroller, "DOMMouseScroll", e => onScrollWheel(cm, e)) // Prevent wrapper from ever scrolling - on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0 }) + on(d.wrapper, "scroll", () => d.wrapper.scrollTop = d.wrapper.scrollLeft = 0) d.dragFunctions = { - enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e)}, - over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e) }}, - start: function(e){onDragStart(cm, e)}, + enter: e => {if (!signalDOMEvent(cm, e)) e_stop(e)}, + over: e => {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e) }}, + start: e => onDragStart(cm, e), drop: operation(cm, onDrop), - leave: function(e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm) }} + leave: e => {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm) }} } let inp = d.input.getField() - on(inp, "keyup", function(e) { onKeyUp.call(cm, e) }) + on(inp, "keyup", e => onKeyUp.call(cm, e)) on(inp, "keydown", operation(cm, onKeyDown)) on(inp, "keypress", operation(cm, onKeyPress)) - on(inp, "focus", function(e) { onFocus(cm, e) }) - on(inp, "blur", function (e) { onBlur(cm, e) }) + on(inp, "focus", e => onFocus(cm, e)) + on(inp, "blur", e => onBlur(cm, e)) } let initHooks = [] -CodeMirror.defineInitHook = function(f) {initHooks.push(f)} +CodeMirror.defineInitHook = f => initHooks.push(f) diff --git a/src/edit/commands.js b/src/edit/commands.js index 97a30d6d97..fe39ed727f 100644 --- a/src/edit/commands.js +++ b/src/edit/commands.js @@ -13,109 +13,87 @@ import { getOrder, lineLeft, lineRight } from "../util/bidi" // editor, mostly used for keybindings. export let commands = { selectAll: selectAll, - singleSelection: function(cm) { - cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll) - }, - killLine: function(cm) { - deleteNearSelection(cm, function(range) { - if (range.empty()) { - let len = getLine(cm.doc, range.head.line).text.length - if (range.head.ch == len && range.head.line < cm.lastLine()) - return {from: range.head, to: Pos(range.head.line + 1, 0)} - else - return {from: range.head, to: Pos(range.head.line, len)} - } else { - return {from: range.from(), to: range.to()} - } - }) - }, - deleteLine: function(cm) { - deleteNearSelection(cm, function(range) { - return {from: Pos(range.from().line, 0), - to: clipPos(cm.doc, Pos(range.to().line + 1, 0))} - }) - }, - delLineLeft: function(cm) { - deleteNearSelection(cm, function(range) { - return {from: Pos(range.from().line, 0), to: range.from()} - }) - }, - delWrappedLineLeft: function(cm) { - deleteNearSelection(cm, function(range) { - let top = cm.charCoords(range.head, "div").top + 5 - let leftPos = cm.coordsChar({left: 0, top: top}, "div") - return {from: leftPos, to: range.from()} - }) - }, - delWrappedLineRight: function(cm) { - deleteNearSelection(cm, function(range) { - let top = cm.charCoords(range.head, "div").top + 5 - let rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") - return {from: range.from(), to: rightPos } - }) - }, - undo: function(cm) {cm.undo()}, - redo: function(cm) {cm.redo()}, - undoSelection: function(cm) {cm.undoSelection()}, - redoSelection: function(cm) {cm.redoSelection()}, - goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0))}, - goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()))}, - goLineStart: function(cm) { - cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line) }, - {origin: "+move", bias: 1}) - }, - goLineStartSmart: function(cm) { - cm.extendSelectionsBy(function(range) { - return lineStartSmart(cm, range.head) - }, {origin: "+move", bias: 1}) - }, - goLineEnd: function(cm) { - cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line) }, - {origin: "+move", bias: -1}) - }, - goLineRight: function(cm) { - cm.extendSelectionsBy(function(range) { - let top = cm.charCoords(range.head, "div").top + 5 - return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") - }, sel_move) - }, - goLineLeft: function(cm) { - cm.extendSelectionsBy(function(range) { - let top = cm.charCoords(range.head, "div").top + 5 - return cm.coordsChar({left: 0, top: top}, "div") - }, sel_move) - }, - goLineLeftSmart: function(cm) { - cm.extendSelectionsBy(function(range) { - let top = cm.charCoords(range.head, "div").top + 5 - let pos = cm.coordsChar({left: 0, top: top}, "div") - if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head) - return pos - }, sel_move) - }, - goLineUp: function(cm) {cm.moveV(-1, "line")}, - goLineDown: function(cm) {cm.moveV(1, "line")}, - goPageUp: function(cm) {cm.moveV(-1, "page")}, - goPageDown: function(cm) {cm.moveV(1, "page")}, - goCharLeft: function(cm) {cm.moveH(-1, "char")}, - goCharRight: function(cm) {cm.moveH(1, "char")}, - goColumnLeft: function(cm) {cm.moveH(-1, "column")}, - goColumnRight: function(cm) {cm.moveH(1, "column")}, - goWordLeft: function(cm) {cm.moveH(-1, "word")}, - goGroupRight: function(cm) {cm.moveH(1, "group")}, - goGroupLeft: function(cm) {cm.moveH(-1, "group")}, - goWordRight: function(cm) {cm.moveH(1, "word")}, - delCharBefore: function(cm) {cm.deleteH(-1, "char")}, - delCharAfter: function(cm) {cm.deleteH(1, "char")}, - delWordBefore: function(cm) {cm.deleteH(-1, "word")}, - delWordAfter: function(cm) {cm.deleteH(1, "word")}, - delGroupBefore: function(cm) {cm.deleteH(-1, "group")}, - delGroupAfter: function(cm) {cm.deleteH(1, "group")}, - indentAuto: function(cm) {cm.indentSelection("smart")}, - indentMore: function(cm) {cm.indentSelection("add")}, - indentLess: function(cm) {cm.indentSelection("subtract")}, - insertTab: function(cm) {cm.replaceSelection("\t")}, - insertSoftTab: function(cm) { + singleSelection: cm => cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll), + killLine: cm => deleteNearSelection(cm, range => { + if (range.empty()) { + let len = getLine(cm.doc, range.head.line).text.length + if (range.head.ch == len && range.head.line < cm.lastLine()) + return {from: range.head, to: Pos(range.head.line + 1, 0)} + else + return {from: range.head, to: Pos(range.head.line, len)} + } else { + return {from: range.from(), to: range.to()} + } + }), + deleteLine: cm => deleteNearSelection(cm, range => ({ + from: Pos(range.from().line, 0), + to: clipPos(cm.doc, Pos(range.to().line + 1, 0)) + })), + delLineLeft: cm => deleteNearSelection(cm, range => ({ + from: Pos(range.from().line, 0), to: range.from() + })), + delWrappedLineLeft: cm => deleteNearSelection(cm, range => { + let top = cm.charCoords(range.head, "div").top + 5 + let leftPos = cm.coordsChar({left: 0, top: top}, "div") + return {from: leftPos, to: range.from()} + }), + delWrappedLineRight: cm => deleteNearSelection(cm, range => { + let top = cm.charCoords(range.head, "div").top + 5 + let rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") + return {from: range.from(), to: rightPos } + }), + undo: cm => cm.undo(), + redo: cm => cm.redo(), + undoSelection: cm => cm.undoSelection(), + redoSelection: cm => cm.redoSelection(), + goDocStart: cm => cm.extendSelection(Pos(cm.firstLine(), 0)), + goDocEnd: cm => cm.extendSelection(Pos(cm.lastLine())), + goLineStart: cm => cm.extendSelectionsBy(range => lineStart(cm, range.head.line), + {origin: "+move", bias: 1} + ), + goLineStartSmart: cm => cm.extendSelectionsBy(range => lineStartSmart(cm, range.head), + {origin: "+move", bias: 1} + ), + goLineEnd: cm => cm.extendSelectionsBy(range => lineEnd(cm, range.head.line), + {origin: "+move", bias: -1} + ), + goLineRight: cm => cm.extendSelectionsBy(range => { + let top = cm.charCoords(range.head, "div").top + 5 + return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div") + }, sel_move), + goLineLeft: cm => cm.extendSelectionsBy(range => { + let top = cm.charCoords(range.head, "div").top + 5 + return cm.coordsChar({left: 0, top: top}, "div") + }, sel_move), + goLineLeftSmart: cm => cm.extendSelectionsBy(range => { + let top = cm.charCoords(range.head, "div").top + 5 + let pos = cm.coordsChar({left: 0, top: top}, "div") + if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head) + return pos + }, sel_move), + goLineUp: cm => cm.moveV(-1, "line"), + goLineDown: cm => cm.moveV(1, "line"), + goPageUp: cm => cm.moveV(-1, "page"), + goPageDown: cm => cm.moveV(1, "page"), + goCharLeft: cm => cm.moveH(-1, "char"), + goCharRight: cm => cm.moveH(1, "char"), + goColumnLeft: cm => cm.moveH(-1, "column"), + goColumnRight: cm => cm.moveH(1, "column"), + goWordLeft: cm => cm.moveH(-1, "word"), + goGroupRight: cm => cm.moveH(1, "group"), + goGroupLeft: cm => cm.moveH(-1, "group"), + goWordRight: cm => cm.moveH(1, "word"), + delCharBefore: cm => cm.deleteH(-1, "char"), + delCharAfter: cm => cm.deleteH(1, "char"), + delWordBefore: cm => cm.deleteH(-1, "word"), + delWordAfter: cm => cm.deleteH(1, "word"), + delGroupBefore: cm => cm.deleteH(-1, "group"), + delGroupAfter: cm => cm.deleteH(1, "group"), + indentAuto: cm => cm.indentSelection("smart"), + indentMore: cm => cm.indentSelection("add"), + indentLess: cm => cm.indentSelection("subtract"), + insertTab: cm => cm.replaceSelection("\t"), + insertSoftTab: cm => { let spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize for (let i = 0; i < ranges.length; i++) { let pos = ranges[i].from() @@ -124,47 +102,43 @@ export let commands = { } cm.replaceSelections(spaces) }, - defaultTab: function(cm) { + defaultTab: cm => { if (cm.somethingSelected()) cm.indentSelection("add") else cm.execCommand("insertTab") }, - transposeChars: function(cm) { - runInOp(cm, function() { - let ranges = cm.listSelections(), newSel = [] - for (let i = 0; i < ranges.length; i++) { - let cur = ranges[i].head, line = getLine(cm.doc, cur.line).text - if (line) { - if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1) - if (cur.ch > 0) { - cur = new Pos(cur.line, cur.ch + 1) - cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), - Pos(cur.line, cur.ch - 2), cur, "+transpose") - } else if (cur.line > cm.doc.first) { - let prev = getLine(cm.doc, cur.line - 1).text - if (prev) - cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + - prev.charAt(prev.length - 1), - Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose") - } + transposeChars: cm => runInOp(cm, () => { + let ranges = cm.listSelections(), newSel = [] + for (let i = 0; i < ranges.length; i++) { + let cur = ranges[i].head, line = getLine(cm.doc, cur.line).text + if (line) { + if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1) + if (cur.ch > 0) { + cur = new Pos(cur.line, cur.ch + 1) + cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), + Pos(cur.line, cur.ch - 2), cur, "+transpose") + } else if (cur.line > cm.doc.first) { + let prev = getLine(cm.doc, cur.line - 1).text + if (prev) + cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + + prev.charAt(prev.length - 1), + Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose") } - newSel.push(new Range(cur, cur)) } - cm.setSelections(newSel) - }) - }, - newlineAndIndent: function(cm) { - runInOp(cm, function() { - let sels = cm.listSelections() - for (let i = sels.length - 1; i >= 0; i--) - cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input") - sels = cm.listSelections() - for (let i = 0; i < sels.length; i++) - cm.indentLine(sels[i].from().line, null, true) - ensureCursorVisible(cm) - }) - }, - openLine: function(cm) {cm.replaceSelection("\n", "start")}, - toggleOverwrite: function(cm) {cm.toggleOverwrite()} + newSel.push(new Range(cur, cur)) + } + cm.setSelections(newSel) + }), + newlineAndIndent: cm => runInOp(cm, () => { + let sels = cm.listSelections() + for (let i = sels.length - 1; i >= 0; i--) + cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input") + sels = cm.listSelections() + for (let i = 0; i < sels.length; i++) + cm.indentLine(sels[i].from().line, null, true) + ensureCursorVisible(cm) + }), + openLine: cm => cm.replaceSelection("\n", "start"), + toggleOverwrite: cm => cm.toggleOverwrite() } diff --git a/src/edit/deleteNearSelection.js b/src/edit/deleteNearSelection.js index 38c5342ff2..5a9bd2cfd5 100644 --- a/src/edit/deleteNearSelection.js +++ b/src/edit/deleteNearSelection.js @@ -22,7 +22,7 @@ export function deleteNearSelection(cm, compute) { kill.push(toKill) } // Next, remove those actual ranges. - runInOp(cm, function() { + runInOp(cm, () => { for (let i = kill.length - 1; i >= 0; i--) replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete") ensureCursorVisible(cm) diff --git a/src/edit/drop_events.js b/src/edit/drop_events.js index b8024d920d..43e996fb68 100644 --- a/src/edit/drop_events.js +++ b/src/edit/drop_events.js @@ -29,13 +29,13 @@ export function onDrop(e) { // and insert it. if (files && files.length && window.FileReader && window.File) { let n = files.length, text = Array(n), read = 0 - let loadFile = function(file, i) { + let loadFile = (file, i) => { if (cm.options.allowDropFileTypes && indexOf(cm.options.allowDropFileTypes, file.type) == -1) return let reader = new FileReader - reader.onload = operation(cm, function() { + reader.onload = operation(cm, () => { let content = reader.result if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "" text[i] = content @@ -56,7 +56,7 @@ export function onDrop(e) { if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { cm.state.draggingText(e) // Ensure the editor is re-focused - setTimeout(function() {cm.display.input.focus()}, 20) + setTimeout(() => cm.display.input.focus(), 20) return } try { diff --git a/src/edit/fromTextArea.js b/src/edit/fromTextArea.js index 7d22101469..5d920830b3 100644 --- a/src/edit/fromTextArea.js +++ b/src/edit/fromTextArea.js @@ -28,7 +28,7 @@ export function fromTextArea(textarea, options) { let form = textarea.form realSubmit = form.submit try { - let wrappedSubmit = form.submit = function() { + let wrappedSubmit = form.submit = () => { save() form.submit = realSubmit form.submit() @@ -38,10 +38,10 @@ export function fromTextArea(textarea, options) { } } - options.finishInit = function(cm) { + options.finishInit = cm => { cm.save = save - cm.getTextArea = function() { return textarea } - cm.toTextArea = function() { + cm.getTextArea = () => textarea + cm.toTextArea = () => { cm.toTextArea = isNaN // Prevent this from being ran twice save() textarea.parentNode.removeChild(cm.getWrapperElement()) @@ -55,8 +55,7 @@ export function fromTextArea(textarea, options) { } textarea.style.display = "none" - let cm = CodeMirror(function(node) { - textarea.parentNode.insertBefore(node, textarea.nextSibling) - }, options) + let cm = CodeMirror(node => textarea.parentNode.insertBefore(node, textarea.nextSibling), + options) return cm } diff --git a/src/edit/global_events.js b/src/edit/global_events.js index a7ec22fe89..dd7d185308 100644 --- a/src/edit/global_events.js +++ b/src/edit/global_events.js @@ -23,16 +23,14 @@ export function ensureGlobalHandlers() { function registerGlobalHandlers() { // When the window resizes, we need to refresh active editors. let resizeTimer - on(window, "resize", function() { - if (resizeTimer == null) resizeTimer = setTimeout(function() { + on(window, "resize", () => { + if (resizeTimer == null) resizeTimer = setTimeout(() => { resizeTimer = null forEachCodeMirror(onResize) }, 100) }) // When the window loses focus, we want to show the editor as blurred - on(window, "blur", function() { - forEachCodeMirror(onBlur) - }) + on(window, "blur", () => forEachCodeMirror(onBlur)) } // Called when the window resizes function onResize(cm) { diff --git a/src/edit/key_events.js b/src/edit/key_events.js index 8530aef315..8e695473ba 100644 --- a/src/edit/key_events.js +++ b/src/edit/key_events.js @@ -45,7 +45,7 @@ function dispatchKey(cm, name, e, handle) { let seq = cm.state.keySeq if (seq) { if (isModifierKey(name)) return "handled" - stopSeq.set(50, function() { + stopSeq.set(50, () => { if (cm.state.keySeq == seq) { cm.state.keySeq = null cm.display.input.reset() @@ -81,20 +81,19 @@ function handleKeyBinding(cm, e) { // First try to resolve full name (including 'Shift-'). Failing // that, see if there is a cursor-motion command (starting with // 'go') bound to the keyname without 'Shift-'. - return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true)}) - || dispatchKey(cm, name, e, function(b) { + return dispatchKey(cm, "Shift-" + name, e, b => doHandleBinding(cm, b, true)) + || dispatchKey(cm, name, e, b => { if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) return doHandleBinding(cm, b) }) } else { - return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b) }) + return dispatchKey(cm, name, e, b => doHandleBinding(cm, b)) } } // Handle a key from the keypress event function handleCharBinding(cm, e, ch) { - return dispatchKey(cm, "'" + ch + "'", e, - function(b) { return doHandleBinding(cm, b, true) }) + return dispatchKey(cm, "'" + ch + "'", e, b => doHandleBinding(cm, b, true)) } let lastStoppedKey = null diff --git a/src/edit/main.js b/src/edit/main.js index 55432c0812..2831d2a03d 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -46,17 +46,15 @@ CodeMirror.defineMode = function(name/*, mode, …*/) { CodeMirror.defineMIME = defineMIME // Minimal default mode. -CodeMirror.defineMode("null", function() { - return {token: function(stream) {stream.skipToEnd()}} -}) +CodeMirror.defineMode("null", () => ({token: stream => stream.skipToEnd()})) CodeMirror.defineMIME("text/plain", "null") // EXTENSIONS -CodeMirror.defineExtension = function(name, func) { +CodeMirror.defineExtension = (name, func) => { CodeMirror.prototype[name] = func } -CodeMirror.defineDocExtension = function(name, func) { +CodeMirror.defineDocExtension = (name, func) => { Doc.prototype[name] = func } diff --git a/src/edit/methods.js b/src/edit/methods.js index 04be851246..260ffa5df2 100644 --- a/src/edit/methods.js +++ b/src/edit/methods.js @@ -69,7 +69,7 @@ export default function(CodeMirror) { insertSorted(this.state.overlays, {mode: mode, modeSpec: spec, opaque: options && options.opaque, priority: (options && options.priority) || 0}, - function(overlay) { return overlay.priority }) + overlay => overlay.priority) this.state.modeGen++ regChange(this) }), @@ -219,7 +219,7 @@ export default function(CodeMirror) { defaultCharWidth: function() { return charWidth(this.display) }, setGutterMarker: methodOp(function(line, gutterID, value) { - return changeLine(this.doc, line, "gutter", function(line) { + return changeLine(this.doc, line, "gutter", line => { let markers = line.gutterMarkers || (line.gutterMarkers = {}) markers[gutterID] = value if (!value && isEmpty(markers)) line.gutterMarkers = null @@ -229,7 +229,7 @@ export default function(CodeMirror) { clearGutter: methodOp(function(gutterID) { let cm = this, doc = cm.doc, i = doc.first - doc.iter(function(line) { + doc.iter(line => { if (line.gutterMarkers && line.gutterMarkers[gutterID]) { line.gutterMarkers[gutterID] = null regLineChange(cm, i, "gutter") @@ -316,7 +316,7 @@ export default function(CodeMirror) { moveH: methodOp(function(dir, unit) { let cm = this - cm.extendSelectionsBy(function(range) { + cm.extendSelectionsBy(range => { if (cm.display.shift || cm.doc.extend || range.empty()) return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually) else @@ -329,7 +329,7 @@ export default function(CodeMirror) { if (sel.somethingSelected()) doc.replaceSelection("", null, "+delete") else - deleteNearSelection(this, function(range) { + deleteNearSelection(this, range => { let other = findPosH(doc, range.head, dir, unit, false) return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other} }) @@ -352,7 +352,7 @@ export default function(CodeMirror) { moveV: methodOp(function(dir, unit) { let cm = this, doc = this.doc, goals = [] let collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected() - doc.extendSelectionsBy(function(range) { + doc.extendSelectionsBy(range => { if (collapse) return dir < 0 ? range.from() : range.to() let headPos = cursorCoords(cm, range.head, "div") @@ -376,9 +376,9 @@ export default function(CodeMirror) { if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end let startChar = line.charAt(start) let check = isWordChar(startChar, helper) - ? function(ch) { return isWordChar(ch, helper) } - : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch)} - : function(ch) {return !/\s/.test(ch) && !isWordChar(ch)} + ? ch => isWordChar(ch, helper) + : /\s/.test(startChar) ? ch => /\s/.test(ch) + : ch => (!/\s/.test(ch) && !isWordChar(ch)) while (start > 0 && check(line.charAt(start - 1))) --start while (end < line.length && check(line.charAt(end))) ++end } @@ -436,14 +436,12 @@ export default function(CodeMirror) { setSize: methodOp(function(width, height) { let cm = this - function interpret(val) { - return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val - } + let interpret = val => typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val if (width != null) cm.display.wrapper.style.width = interpret(width) if (height != null) cm.display.wrapper.style.height = interpret(height) if (cm.options.lineWrapping) clearLineMeasurementCache(this) let lineNo = cm.display.viewFrom - cm.doc.iter(lineNo, cm.display.viewTo, function(line) { + cm.doc.iter(lineNo, cm.display.viewTo, line => { if (line.widgets) for (let i = 0; i < line.widgets.length; i++) if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break } ++lineNo diff --git a/src/edit/mouse_events.js b/src/edit/mouse_events.js index 5fe10ea39f..784f195b3e 100644 --- a/src/edit/mouse_events.js +++ b/src/edit/mouse_events.js @@ -28,7 +28,7 @@ export function onMouseDown(e) { // Briefly turn off draggability, to allow widgets to do // normal dragging things. display.scroller.draggable = false - setTimeout(function(){display.scroller.draggable = true}, 100) + setTimeout(() => display.scroller.draggable = true, 100) } return } @@ -49,7 +49,7 @@ export function onMouseDown(e) { case 2: if (webkit) cm.state.lastMiddleDown = +new Date if (start) extendSelection(cm.doc, start) - setTimeout(function() {display.input.focus()}, 20) + setTimeout(() => display.input.focus(), 20) e_preventDefault(e) break case 3: @@ -89,7 +89,7 @@ function leftButtonDown(cm, e, start) { // happen, and treat as a click if it didn't. function leftButtonStartDrag(cm, e, start, modifier) { let display = cm.display, startTime = +new Date - let dragEnd = operation(cm, function(e2) { + let dragEnd = operation(cm, e2 => { if (webkit) display.scroller.draggable = false cm.state.draggingText = false off(document, "mouseup", dragEnd) @@ -100,7 +100,7 @@ function leftButtonStartDrag(cm, e, start, modifier) { extendSelection(cm.doc, start) // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) if (webkit || ie && ie_version == 9) - setTimeout(function() {document.body.focus(); display.input.focus()}, 20) + setTimeout(() => {document.body.focus(); display.input.focus()}, 20) else display.input.focus() } @@ -230,10 +230,10 @@ function leftButtonSelect(cm, e, start, type, addNew) { extendTo(cur) let visible = visibleLines(display, doc) if (cur.line >= visible.to || cur.line < visible.from) - setTimeout(operation(cm, function(){if (counter == curCount) extend(e)}), 150) + setTimeout(operation(cm, () => {if (counter == curCount) extend(e)}), 150) } else { let outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0 - if (outside) setTimeout(operation(cm, function() { + if (outside) setTimeout(operation(cm, () => { if (counter != curCount) return display.scroller.scrollTop += outside extend(e) @@ -251,7 +251,7 @@ function leftButtonSelect(cm, e, start, type, addNew) { doc.history.lastSelOrigin = null } - let move = operation(cm, function(e) { + let move = operation(cm, e => { if (!e_button(e)) done(e) else extend(e) }) diff --git a/src/edit/options.js b/src/edit/options.js index a2ca1c6803..ea19d5ba2a 100644 --- a/src/edit/options.js +++ b/src/edit/options.js @@ -28,7 +28,7 @@ export function defineOptions(CodeMirror) { function option(name, deflt, handle, notOnInit) { CodeMirror.defaults[name] = deflt if (handle) optionHandlers[name] = - notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old)} : handle + notOnInit ? (cm, val, old) => {if (old != Init) handle(cm, val, old)} : handle } CodeMirror.defineOption = option @@ -38,10 +38,8 @@ export function defineOptions(CodeMirror) { // These two are, on init, called from the constructor because they // have to be initialized before the editor can start at all. - option("value", "", function(cm, val) { - cm.setValue(val) - }, true) - option("mode", null, function(cm, val) { + option("value", "", (cm, val) => cm.setValue(val), true) + option("mode", null, (cm, val) => { cm.doc.modeOption = val loadMode(cm) }, true) @@ -49,16 +47,16 @@ export function defineOptions(CodeMirror) { option("indentUnit", 2, loadMode, true) option("indentWithTabs", false) option("smartIndent", true) - option("tabSize", 4, function(cm) { + option("tabSize", 4, cm => { resetModeState(cm) clearCaches(cm) regChange(cm) }, true) - option("lineSeparator", null, function(cm, val) { + option("lineSeparator", null, (cm, val) => { cm.doc.lineSep = val if (!val) return let newBreaks = [], lineNo = cm.doc.first - cm.doc.iter(function(line) { + cm.doc.iter(line => { for (let pos = 0;;) { let found = line.text.indexOf(val, pos) if (found == -1) break @@ -70,26 +68,24 @@ export function defineOptions(CodeMirror) { for (let i = newBreaks.length - 1; i >= 0; i--) replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) }) - option("specialChars", /[\u0000-\u001f\u007f\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) { + option("specialChars", /[\u0000-\u001f\u007f\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, (cm, val, old) => { cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g") if (old != Init) cm.refresh() }) - option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh()}, true) + option("specialCharPlaceholder", defaultSpecialCharPlaceholder, cm => cm.refresh(), true) option("electricChars", true) - option("inputStyle", mobile ? "contenteditable" : "textarea", function() { + option("inputStyle", mobile ? "contenteditable" : "textarea", () => { throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME }, true) - option("spellcheck", false, function(cm, val) { - cm.getInputField().spellcheck = val - }, true) + option("spellcheck", false, (cm, val) => cm.getInputField().spellcheck = val, true) option("rtlMoveVisually", !windows) option("wholeLineUpdateBefore", true) - option("theme", "default", function(cm) { + option("theme", "default", cm => { themeChanged(cm) guttersChanged(cm) }, true) - option("keyMap", "default", function(cm, val, old) { + option("keyMap", "default", (cm, val, old) => { let next = getKeyMap(val) let prev = old != Init && getKeyMap(old) if (prev && prev.detach) prev.detach(cm, next) @@ -98,33 +94,33 @@ export function defineOptions(CodeMirror) { option("extraKeys", null) option("lineWrapping", false, wrappingChanged, true) - option("gutters", [], function(cm) { + option("gutters", [], cm => { setGuttersForLineNumbers(cm.options) guttersChanged(cm) }, true) - option("fixedGutter", true, function(cm, val) { + option("fixedGutter", true, (cm, val) => { cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0" cm.refresh() }, true) - option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm)}, true) - option("scrollbarStyle", "native", function(cm) { + option("coverGutterNextToScrollbar", false, cm => updateScrollbars(cm), true) + option("scrollbarStyle", "native", cm => { initScrollbars(cm) updateScrollbars(cm) cm.display.scrollbars.setScrollTop(cm.doc.scrollTop) cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft) }, true) - option("lineNumbers", false, function(cm) { + option("lineNumbers", false, cm => { setGuttersForLineNumbers(cm.options) guttersChanged(cm) }, true) option("firstLineNumber", 1, guttersChanged, true) - option("lineNumberFormatter", function(integer) {return integer}, guttersChanged, true) + option("lineNumberFormatter", integer => integer, guttersChanged, true) option("showCursorWhenSelecting", false, updateSelection, true) option("resetSelectionOnContextMenu", true) option("lineWiseCopyCut", true) - option("readOnly", false, function(cm, val) { + option("readOnly", false, (cm, val) => { if (val == "nocursor") { onBlur(cm) cm.display.input.blur() @@ -134,7 +130,7 @@ export function defineOptions(CodeMirror) { } cm.display.input.readOnlyChanged(val) }) - option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset()}, true) + option("disableInput", false, (cm, val) => {if (!val) cm.display.input.reset()}, true) option("dragDrop", true, dragDropChanged) option("allowDropFileTypes", null) @@ -147,24 +143,22 @@ export function defineOptions(CodeMirror) { option("flattenSpans", true, resetModeState, true) option("addModeClass", false, resetModeState, true) option("pollInterval", 100) - option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val}) + option("undoDepth", 200, (cm, val) => cm.doc.history.undoDepth = val) option("historyEventDelay", 1250) - option("viewportMargin", 10, function(cm){cm.refresh()}, true) + option("viewportMargin", 10, cm => cm.refresh(), true) option("maxHighlightLength", 10000, resetModeState, true) - option("moveInputWithCursor", true, function(cm, val) { + option("moveInputWithCursor", true, (cm, val) => { if (!val) cm.display.input.resetPosition() }) - option("tabindex", null, function(cm, val) { - cm.display.input.getField().tabIndex = val || "" - }) + option("tabindex", null, (cm, val) => cm.display.input.getField().tabIndex = val || "") option("autofocus", null) } function guttersChanged(cm) { updateGutters(cm) regChange(cm) - setTimeout(function(){alignHorizontally(cm)}, 20) + setTimeout(() => alignHorizontally(cm), 20) } function dragDropChanged(cm, value, old) { @@ -192,5 +186,5 @@ function wrappingChanged(cm) { estimateLineHeights(cm) regChange(cm) clearCaches(cm) - setTimeout(function(){updateScrollbars(cm)}, 100) + setTimeout(() => updateScrollbars(cm), 100) } diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index 80e91f847f..59ef55fa9d 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -29,15 +29,15 @@ ContentEditableInput.prototype = copyObj({ let div = input.div = display.lineDiv disableBrowserMagic(div, cm.options.spellcheck) - on(div, "paste", function(e) { + on(div, "paste", e => { if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return // IE doesn't fire input events, so we schedule a read for the pasted content in this way - if (ie_version <= 11) setTimeout(operation(cm, function() { + if (ie_version <= 11) setTimeout(operation(cm, () => { if (!input.pollContent()) regChange(cm) }), 20) }) - on(div, "compositionstart", function(e) { + on(div, "compositionstart", e => { let data = e.data input.composing = {sel: cm.doc.sel, data: data, startData: data} if (!data) return @@ -48,10 +48,8 @@ ContentEditableInput.prototype = copyObj({ input.composing.sel = simpleSelection(Pos(prim.head.line, found), Pos(prim.head.line, found + data.length)) }) - on(div, "compositionupdate", function(e) { - input.composing.data = e.data - }) - on(div, "compositionend", function(e) { + on(div, "compositionupdate", e => input.composing.data = e.data) + on(div, "compositionend", e => { let ours = input.composing if (!ours) return if (e.data != ours.startData && !/\u200b/.test(e.data)) @@ -59,7 +57,7 @@ ContentEditableInput.prototype = copyObj({ // Need a small delay to prevent other code (input event, // selection polling) from doing damage when fired right after // compositionend. - setTimeout(function() { + setTimeout(() => { if (!ours.handled) input.applyComposition(ours) if (input.composing == ours) @@ -67,14 +65,12 @@ ContentEditableInput.prototype = copyObj({ }, 50) }) - on(div, "touchstart", function() { - input.forceCompositionEnd() - }) + on(div, "touchstart", () => input.forceCompositionEnd()) - on(div, "input", function() { + on(div, "input", () => { if (input.composing) return if (cm.isReadOnly() || !input.pollContent()) - runInOp(input.cm, function() {regChange(cm)}) + runInOp(input.cm, () => regChange(cm)) }) function onCopyCut(e) { @@ -88,7 +84,7 @@ ContentEditableInput.prototype = copyObj({ let ranges = copyableRanges(cm) setLastCopied({lineWise: true, text: ranges.text}) if (e.type == "cut") { - cm.operation(function() { + cm.operation(() => { cm.setSelections(ranges.ranges, 0, sel_dontScroll) cm.replaceSelection("", null, "cut") }) @@ -110,7 +106,7 @@ ContentEditableInput.prototype = copyObj({ te.value = lastCopied.text.join("\n") let hadFocus = document.activeElement selectInput(te) - setTimeout(function() { + setTimeout(() => { cm.display.lineSpace.removeChild(kludge) hadFocus.focus() if (hadFocus == div) input.showPrimarySelection() @@ -175,10 +171,10 @@ ContentEditableInput.prototype = copyObj({ startGracePeriod: function() { let input = this clearTimeout(this.gracePeriod) - this.gracePeriod = setTimeout(function() { + this.gracePeriod = setTimeout(() => { input.gracePeriod = false if (input.selectionChanged()) - input.cm.operation(function() { input.cm.curOp.selectionChanged = true }) + input.cm.operation(() => input.cm.curOp.selectionChanged = true) }, 20) }, @@ -213,7 +209,7 @@ ContentEditableInput.prototype = copyObj({ if (this.selectionInEditor()) this.pollSelection() else - runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true }) + runInOp(this.cm, () => input.cm.curOp.selectionChanged = true) function poll() { if (input.cm.state.focused) { @@ -236,7 +232,7 @@ ContentEditableInput.prototype = copyObj({ this.rememberSelection() let anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset) let head = domToPos(cm, sel.focusNode, sel.focusOffset) - if (anchor && head) runInOp(cm, function() { + if (anchor && head) runInOp(cm, () => { setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll) if (anchor.bad || head.bad) cm.curOp.selectionChanged = true }) @@ -356,7 +352,7 @@ function badPos(pos, bad) { if (bad) pos.bad = true; return pos } function domTextBetween(cm, from, to, fromLine, toLine) { let text = "", closing = false, lineSep = cm.doc.lineSeparator() - function recognizeMarker(id) { return function(marker) { return marker.id == id } } + function recognizeMarker(id) { return marker => marker.id == id } function walk(node) { if (node.nodeType == 1) { let cmText = node.getAttribute("cm-text") diff --git a/src/input/TextareaInput.js b/src/input/TextareaInput.js index e244a2d168..17f6f599cd 100644 --- a/src/input/TextareaInput.js +++ b/src/input/TextareaInput.js @@ -46,12 +46,12 @@ TextareaInput.prototype = copyObj({ // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) if (ios) te.style.width = "0px" - on(te, "input", function() { + on(te, "input", () => { if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null input.poll() }) - on(te, "paste", function(e) { + on(te, "paste", e => { if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return cm.state.pasteIncoming = true @@ -86,18 +86,18 @@ TextareaInput.prototype = copyObj({ on(te, "cut", prepareCopyCut) on(te, "copy", prepareCopyCut) - on(display.scroller, "paste", function(e) { + on(display.scroller, "paste", e => { if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return cm.state.pasteIncoming = true input.focus() }) // Prevent normal selection in the editor (we handle our own) - on(display.lineSpace, "selectstart", function(e) { + on(display.lineSpace, "selectstart", e => { if (!eventInWidget(display, e)) e_preventDefault(e) }) - on(te, "compositionstart", function() { + on(te, "compositionstart", () => { let start = cm.getCursor("from") if (input.composing) input.composing.range.clear() input.composing = { @@ -105,7 +105,7 @@ TextareaInput.prototype = copyObj({ range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"}) } }) - on(te, "compositionend", function() { + on(te, "compositionend", () => { if (input.composing) { input.poll() input.composing.range.clear() @@ -187,7 +187,7 @@ TextareaInput.prototype = copyObj({ slowPoll: function() { let input = this if (input.pollingFast) return - input.polling.set(this.cm.options.pollInterval, function() { + input.polling.set(this.cm.options.pollInterval, () => { input.poll() if (input.cm.state.focused) input.slowPoll() }) @@ -246,7 +246,7 @@ TextareaInput.prototype = copyObj({ while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same let self = this - runInOp(cm, function() { + runInOp(cm, () => { applyTextInput(cm, text.slice(same), prevInput.length - same, null, self.composing ? "*compose" : null) @@ -326,7 +326,7 @@ TextareaInput.prototype = copyObj({ // Try to detect the user choosing select-all if (te.selectionStart != null) { if (!ie || (ie && ie_version < 9)) prepareSelectAllHack() - let i = 0, poll = function() { + let i = 0, poll = () => { if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && te.selectionEnd > 0 && input.prevInput == "\u200b") operation(cm, selectAll)(cm) @@ -340,7 +340,7 @@ TextareaInput.prototype = copyObj({ if (ie && ie_version >= 9) prepareSelectAllHack() if (captureRightClick) { e_stop(e) - let mouseup = function() { + let mouseup = () => { off(window, "mouseup", mouseup) setTimeout(rehide, 20) } diff --git a/src/input/input.js b/src/input/input.js index 6cc3e9111f..e51a90a119 100644 --- a/src/input/input.js +++ b/src/input/input.js @@ -35,7 +35,7 @@ export function applyTextInput(cm, inserted, deleted, sel, origin) { multiPaste.push(doc.splitLines(lastCopied.text[i])) } } else if (textLines.length == sel.ranges.length) { - multiPaste = map(textLines, function(l) { return [l] }) + multiPaste = map(textLines, l => [l]) } } @@ -72,7 +72,7 @@ export function handlePaste(e, cm) { if (pasted) { e.preventDefault() if (!cm.isReadOnly() && !cm.options.disableInput) - runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste") }) + runInOp(cm, () => applyTextInput(cm, pasted, 0, null, "paste")) return true } } diff --git a/src/line/highlight.js b/src/line/highlight.js index 8fd6d47b99..f54e7eaa56 100644 --- a/src/line/highlight.js +++ b/src/line/highlight.js @@ -14,14 +14,13 @@ export function highlightLine(cm, line, state, forceToEnd) { // mode/overlays that it is based on (for easy invalidation). let st = [cm.state.modeGen], lineClasses = {} // Compute the base array of styles - runMode(cm, line.text, cm.doc.mode, state, function(end, style) { - st.push(end, style) - }, lineClasses, forceToEnd) + runMode(cm, line.text, cm.doc.mode, state, (end, style) => st.push(end, style), + lineClasses, forceToEnd) // Run overlays, adjust style array. for (let o = 0; o < cm.state.overlays.length; ++o) { let overlay = cm.state.overlays[o], i = 1, at = 0 - runMode(cm, line.text, overlay.mode, true, function(end, style) { + runMode(cm, line.text, overlay.mode, true, (end, style) => { let start = i // Ensure there's a token end at the current position, and that i points at it while (at < end) { @@ -66,7 +65,7 @@ export function getStateBefore(cm, n, precise) { let pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter if (!state) state = startState(doc.mode) else state = copyState(doc.mode, state) - doc.iter(pos, n, function(line) { + doc.iter(pos, n, line => { processLine(cm, line.text, state) let save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo line.stateAfter = save ? copyState(doc.mode, state) : null @@ -108,12 +107,12 @@ export function readToken(mode, stream, state, inner) { // Utility for getTokenAt and getLineTokens export function takeToken(cm, pos, precise, asArray) { - function getObj(copy) { - return {start: stream.start, end: stream.pos, - string: stream.current(), - type: style || null, - state: copy ? copyState(doc.mode, state) : state} - } + let getObj = copy => ({ + start: stream.start, end: stream.pos, + string: stream.current(), + type: style || null, + state: copy ? copyState(doc.mode, state) : state + }) let doc = cm.doc, mode = doc.mode, style pos = clipPos(doc, pos) diff --git a/src/line/line_data.js b/src/line/line_data.js index 7a3a412211..93b57577da 100644 --- a/src/line/line_data.js +++ b/src/line/line_data.js @@ -202,7 +202,7 @@ function splitSpaces(text, trailingBefore) { // Work around nonsense dimensions being reported for stretches of // right-to-left text. function buildTokenBadBidi(inner, order) { - return function(builder, text, style, startStyle, endStyle, title, css) { + return (builder, text, style, startStyle, endStyle, title, css) => { style = style ? style + " cm-force-border" : "cm-force-border" let start = builder.pos, end = start + text.length for (;;) { diff --git a/src/line/spans.js b/src/line/spans.js index 63acacfc83..267ee7182c 100644 --- a/src/line/spans.js +++ b/src/line/spans.js @@ -143,7 +143,7 @@ function clearEmptySpans(spans) { // Used to 'clip' out readOnly ranges when making a change. export function removeReadOnlyRanges(doc, from, to) { let markers = null - doc.iter(from.line, to.line + 1, function(line) { + doc.iter(from.line, to.line + 1, line => { if (line.markedSpans) for (let i = 0; i < line.markedSpans.length; ++i) { let mark = line.markedSpans[i].marker if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) @@ -355,7 +355,7 @@ export function findMaxLine(cm) { d.maxLine = getLine(doc, doc.first) d.maxLineLength = lineLength(d.maxLine) d.maxLineChanged = true - doc.iter(function(line) { + doc.iter(line => { let len = lineLength(line) if (len > d.maxLineLength) { d.maxLineLength = len diff --git a/src/line/utils_line.js b/src/line/utils_line.js index 647c07791e..e4e6943f55 100644 --- a/src/line/utils_line.js +++ b/src/line/utils_line.js @@ -19,7 +19,7 @@ export function getLine(doc, n) { // strings. export function getBetween(doc, start, end) { let out = [], n = start.line - doc.iter(start.line, end.line + 1, function(line) { + doc.iter(start.line, end.line + 1, line => { let text = line.text if (n == end.line) text = text.slice(0, end.ch) if (n == start.line) text = text.slice(start.ch) @@ -31,7 +31,7 @@ export function getBetween(doc, start, end) { // Get the lines between from and to, as array of strings. export function getLines(doc, from, to) { let out = [] - doc.iter(from, to, function(line) { out.push(line.text) }) + doc.iter(from, to, line => { out.push(line.text) }) // iter aborts when callback returns truthy value return out } diff --git a/src/measurement/position_measurement.js b/src/measurement/position_measurement.js index 63e3771b1f..5688836ee0 100644 --- a/src/measurement/position_measurement.js +++ b/src/measurement/position_measurement.js @@ -525,7 +525,7 @@ export function compensateForHScroll(display) { export function estimateHeight(cm) { let th = textHeight(cm.display), wrapping = cm.options.lineWrapping let perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3) - return function(line) { + return line => { if (lineIsHidden(cm.doc, line)) return 0 let widgetsHeight = 0 @@ -542,7 +542,7 @@ export function estimateHeight(cm) { export function estimateLineHeights(cm) { let doc = cm.doc, est = estimateHeight(cm) - doc.iter(function(line) { + doc.iter(line => { let estHeight = est(line) if (estHeight != line.height) updateLineHeight(line, estHeight) }) diff --git a/src/model/Doc.js b/src/model/Doc.js index c02fe062f1..fcb2c1e109 100644 --- a/src/model/Doc.js +++ b/src/model/Doc.js @@ -220,7 +220,7 @@ Doc.prototype = createObj(BranchChunk.prototype, { }, addLineClass: docMethodOp(function(handle, where, cls) { - return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", line => { let prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : where == "gutter" ? "gutterClass" : "wrapClass" @@ -231,7 +231,7 @@ Doc.prototype = createObj(BranchChunk.prototype, { }) }), removeLineClass: docMethodOp(function(handle, where, cls) { - return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { + return changeLine(this, handle, where == "gutter" ? "gutter" : "class", line => { let prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : where == "gutter" ? "gutterClass" : "wrapClass" @@ -278,7 +278,7 @@ Doc.prototype = createObj(BranchChunk.prototype, { findMarks: function(from, to, filter) { from = clipPos(this, from); to = clipPos(this, to) let found = [], lineNo = from.line - this.iter(from.line, to.line + 1, function(line) { + this.iter(from.line, to.line + 1, line => { let spans = line.markedSpans if (spans) for (let i = 0; i < spans.length; i++) { let span = spans[i] @@ -294,7 +294,7 @@ Doc.prototype = createObj(BranchChunk.prototype, { }, getAllMarks: function() { let markers = [] - this.iter(function(line) { + this.iter(line => { let sps = line.markedSpans if (sps) for (let i = 0; i < sps.length; ++i) if (sps[i].from != null) markers.push(sps[i].marker) @@ -304,7 +304,7 @@ Doc.prototype = createObj(BranchChunk.prototype, { posFromIndex: function(off) { let ch, lineNo = this.first, sepSize = this.lineSeparator().length - this.iter(function(line) { + this.iter(line => { let sz = line.text.length + sepSize if (sz > off) { ch = off; return true } off -= sz @@ -317,7 +317,7 @@ Doc.prototype = createObj(BranchChunk.prototype, { let index = coords.ch if (coords.line < this.first || coords.ch < 0) return 0 let sepSize = this.lineSeparator().length - this.iter(this.first, coords.line, function (line) { + this.iter(this.first, coords.line, line => { // iter aborts when callback returns a truthy value index += line.text.length + sepSize }) return index @@ -361,7 +361,7 @@ Doc.prototype = createObj(BranchChunk.prototype, { // If the histories were shared, split them again if (other.history == this.history) { let splitIds = [other.id] - linkedDocs(other, function(doc) {splitIds.push(doc.id)}, true) + linkedDocs(other, doc => splitIds.push(doc.id), true) other.history = new History(null) other.history.done = copyHistoryArray(this.history.done, splitIds) other.history.undone = copyHistoryArray(this.history.undone, splitIds) diff --git a/src/model/changes.js b/src/model/changes.js index e39bc30392..c6692d4c5a 100644 --- a/src/model/changes.js +++ b/src/model/changes.js @@ -26,13 +26,13 @@ function filterChange(doc, change, update) { to: change.to, text: change.text, origin: change.origin, - cancel: function() { this.canceled = true } + cancel: () => obj.canceled = true } - if (update) obj.update = function(from, to, text, origin) { - if (from) this.from = clipPos(doc, from) - if (to) this.to = clipPos(doc, to) - if (text) this.text = text - if (origin !== undefined) this.origin = origin + if (update) obj.update = (from, to, text, origin) => { + if (from) obj.from = clipPos(doc, from) + if (to) obj.to = clipPos(doc, to) + if (text) obj.text = text + if (origin !== undefined) obj.origin = origin } signal(doc, "beforeChange", doc, obj) if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj) @@ -73,7 +73,7 @@ function makeChangeInner(doc, change) { makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)) let rebased = [] - linkedDocs(doc, function(doc, sharedHist) { + linkedDocs(doc, (doc, sharedHist) => { if (!sharedHist && indexOf(rebased, doc.history) == -1) { rebaseHist(doc.history, change) rebased.push(doc.history) @@ -138,7 +138,7 @@ export function makeChangeFromHistory(doc, type, allowSelectionOnly) { let rebased = [] // Propagate to the linked documents - linkedDocs(doc, function(doc, sharedHist) { + linkedDocs(doc, (doc, sharedHist) => { if (!sharedHist && indexOf(rebased, doc.history) == -1) { rebaseHist(doc.history, change) rebased.push(doc.history) @@ -153,10 +153,10 @@ export function makeChangeFromHistory(doc, type, allowSelectionOnly) { function shiftDoc(doc, distance) { if (distance == 0) return doc.first += distance - doc.sel = new Selection(map(doc.sel.ranges, function(range) { - return new Range(Pos(range.anchor.line + distance, range.anchor.ch), - Pos(range.head.line + distance, range.head.ch)) - }), doc.sel.primIndex) + doc.sel = new Selection(map(doc.sel.ranges, range => new Range( + Pos(range.anchor.line + distance, range.anchor.ch), + Pos(range.head.line + distance, range.head.ch) + )), doc.sel.primIndex) if (doc.cm) { regChange(doc.cm, doc.first, doc.first - distance, distance) for (let d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) @@ -205,7 +205,7 @@ function makeChangeSingleDocInEditor(cm, change, spans) { let recomputeMaxLength = false, checkWidthStart = from.line if (!cm.options.lineWrapping) { checkWidthStart = lineNo(visualLine(getLine(doc, from.line))) - doc.iter(checkWidthStart, to.line + 1, function(line) { + doc.iter(checkWidthStart, to.line + 1, line => { if (line == display.maxLine) { recomputeMaxLength = true return true @@ -219,7 +219,7 @@ function makeChangeSingleDocInEditor(cm, change, spans) { updateDoc(doc, change, spans, estimateHeight(cm)) if (!cm.options.lineWrapping) { - doc.iter(checkWidthStart, from.line + change.text.length, function(line) { + doc.iter(checkWidthStart, from.line + change.text.length, line => { let len = lineLength(line) if (len > display.maxLineLength) { display.maxLine = line diff --git a/src/model/history.js b/src/model/history.js index 2a7502cb8e..83938cf4c1 100644 --- a/src/model/history.js +++ b/src/model/history.js @@ -28,7 +28,7 @@ export function History(startGen) { export function historyChangeFromChange(doc, change) { let histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)} attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1) - linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1)}, true) + linkedDocs(doc, doc => attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1), true) return histChange } @@ -146,7 +146,7 @@ export function pushSelectionToHistory(sel, dest) { // Used to store marked span information in the history. function attachLocalSpans(doc, change, from, to) { let existing = change["spans_" + doc.id], n = 0 - doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) { + doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), line => { if (line.markedSpans) (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans ++n diff --git a/src/model/line_widget.js b/src/model/line_widget.js index 23b2381b95..e832e8c483 100644 --- a/src/model/line_widget.js +++ b/src/model/line_widget.js @@ -29,7 +29,7 @@ LineWidget.prototype.clear = function() { if (!ws.length) line.widgets = null let height = widgetHeight(this) updateLineHeight(line, Math.max(0, line.height - height)) - if (cm) runInOp(cm, function() { + if (cm) runInOp(cm, () => { adjustScrollWhenAboveVisible(cm, line, -height) regLineChange(cm, no, "widget") }) @@ -40,7 +40,7 @@ LineWidget.prototype.changed = function() { let diff = widgetHeight(this) - oldH if (!diff) return updateLineHeight(line, line.height + diff) - if (cm) runInOp(cm, function() { + if (cm) runInOp(cm, () => { cm.curOp.forceUpdate = true adjustScrollWhenAboveVisible(cm, line, diff) }) @@ -50,7 +50,7 @@ export function addLineWidget(doc, handle, node, options) { let widget = new LineWidget(doc, node, options) let cm = doc.cm if (cm && widget.noHScroll) cm.display.alignWidgets = true - changeLine(doc, handle, "widget", function(line) { + changeLine(doc, handle, "widget", line => { let widgets = line.widgets || (line.widgets = []) if (widget.insertAt == null) widgets.push(widget) else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget) diff --git a/src/model/mark_text.js b/src/model/mark_text.js index f15cefb29a..4250288ef3 100644 --- a/src/model/mark_text.js +++ b/src/model/mark_text.js @@ -111,7 +111,7 @@ TextMarker.prototype.find = function(side, lineObj) { TextMarker.prototype.changed = function() { let pos = this.find(-1, true), widget = this, cm = this.doc.cm if (!pos || !cm) return - runInOp(cm, function() { + runInOp(cm, () => { let line = pos.line, lineN = lineNo(pos.line) let view = findViewForLine(cm, lineN) if (view) { @@ -177,7 +177,7 @@ export function markText(doc, from, to, options, type) { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN) let curLine = from.line, cm = doc.cm, updateMaxLine - doc.iter(curLine, to.line + 1, function(line) { + doc.iter(curLine, to.line + 1, line => { if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) updateMaxLine = true if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0) @@ -187,11 +187,11 @@ export function markText(doc, from, to, options, type) { ++curLine }) // lineIsHidden depends on the presence of the spans, so needs a second pass - if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) { + if (marker.collapsed) doc.iter(from.line, to.line + 1, line => { if (lineIsHidden(doc, line)) updateLineHeight(line, 0) }) - if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear() }) + if (marker.clearOnEnter) on(marker, "beforeCursorEnter", () => marker.clear()) if (marker.readOnly) { seeReadOnlySpans() @@ -244,7 +244,7 @@ function markTextShared(doc, from, to, options, type) { options.shared = false let markers = [markText(doc, from, to, options, type)], primary = markers[0] let widget = options.widgetNode - linkedDocs(doc, function(doc) { + linkedDocs(doc, doc => { if (widget) options.widgetNode = widget.cloneNode(true) markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)) for (let i = 0; i < doc.linked.length; ++i) @@ -255,8 +255,7 @@ function markTextShared(doc, from, to, options, type) { } export function findSharedMarkers(doc) { - return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), - function(m) { return m.parent }) + return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), m => m.parent) } export function copySharedMarkers(doc, markers) { @@ -274,7 +273,7 @@ export function copySharedMarkers(doc, markers) { export function detachSharedMarkers(markers) { for (let i = 0; i < markers.length; i++) { let marker = markers[i], linked = [marker.primary.doc] - linkedDocs(marker.primary.doc, function(d) { linked.push(d) }) + linkedDocs(marker.primary.doc, d => linked.push(d)) for (let j = 0; j < marker.markers.length; j++) { let subMarker = marker.markers[j] if (indexOf(linked, subMarker.doc) == -1) { diff --git a/src/model/selection.js b/src/model/selection.js index 63371954e1..120af2a45c 100644 --- a/src/model/selection.js +++ b/src/model/selection.js @@ -61,7 +61,7 @@ Range.prototype = { // it). export function normalizeSelection(ranges, primIndex) { let prim = ranges[primIndex] - ranges.sort(function(a, b) { return cmp(a.from(), b.from()) }) + ranges.sort((a, b) => cmp(a.from(), b.from())) primIndex = indexOf(ranges, prim) for (let i = 1; i < ranges.length; i++) { let cur = ranges[i], prev = ranges[i - 1] diff --git a/src/util/StringStream.js b/src/util/StringStream.js index cf7b8244a9..92dbc69062 100644 --- a/src/util/StringStream.js +++ b/src/util/StringStream.js @@ -57,7 +57,7 @@ StringStream.prototype = { }, match: function(pattern, consume, caseInsensitive) { if (typeof pattern == "string") { - let cased = function(str) {return caseInsensitive ? str.toLowerCase() : str} + let cased = str => caseInsensitive ? str.toLowerCase() : str let substr = this.string.substr(this.pos, pattern.length) if (cased(substr) == cased(pattern)) { if (consume !== false) this.pos += pattern.length diff --git a/src/util/feature_detection.js b/src/util/feature_detection.js index d98393af90..e65881d4ca 100644 --- a/src/util/feature_detection.js +++ b/src/util/feature_detection.js @@ -38,7 +38,7 @@ export function hasBadBidiRects(measure) { // See if "".split is the broken IE version, if so, provide an // alternative way to split lines. -export let splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function(string) { +export let splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? string => { let pos = 0, result = [], l = string.length while (pos <= l) { let nl = string.indexOf("\n", pos) @@ -54,12 +54,12 @@ export let splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function(string) { } } return result -} : function(string){return string.split(/\r\n?|\n/)} +} : string => string.split(/\r\n?|\n/) -export let hasSelection = window.getSelection ? function(te) { +export let hasSelection = window.getSelection ? te => { try { return te.selectionStart != te.selectionEnd } catch(e) { return false } -} : function(te) { +} : te => { let range try {range = te.ownerDocument.selection.createRange()} catch(e) {} @@ -67,7 +67,7 @@ export let hasSelection = window.getSelection ? function(te) { return range.compareEndPoints("StartToEnd", range) != 0 } -export let hasCopyEvent = (function() { +export let hasCopyEvent = (() => { let e = elt("div") if ("oncopy" in e) return true e.setAttribute("oncopy", "return;") diff --git a/src/util/operation_group.js b/src/util/operation_group.js index d743f994e5..f50da343a9 100644 --- a/src/util/operation_group.js +++ b/src/util/operation_group.js @@ -61,9 +61,8 @@ export function signalLater(emitter, type /*, values...*/) { list = orphanDelayedCallbacks = [] setTimeout(fireOrphanDelayed, 0) } - function bnd(f) {return function(){f.apply(null, args)}} for (let i = 0; i < arr.length; ++i) - list.push(bnd(arr[i])) + list.push(() => arr[i].apply(null, args)) } function fireOrphanDelayed() { From cef4089021830fc17e8374619a008ead8fb57d90 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 30 Sep 2016 10:27:29 +0200 Subject: [PATCH 0039/1880] Remove a few vars that worked around this-binding issue --- src/edit/CodeMirror.js | 6 ++--- src/edit/methods.js | 38 +++++++++++++++---------------- src/input/ContentEditableInput.js | 7 +++--- src/input/TextareaInput.js | 24 +++++++++---------- 4 files changed, 34 insertions(+), 41 deletions(-) diff --git a/src/edit/CodeMirror.js b/src/edit/CodeMirror.js index 909ffcb185..7e17002d15 100644 --- a/src/edit/CodeMirror.js +++ b/src/edit/CodeMirror.js @@ -64,11 +64,9 @@ export function CodeMirror(place, options) { specialChars: null } - let cm = this - // Override magic textarea content restore that IE sometimes does // on our hidden textarea on reload - if (ie && ie_version < 11) setTimeout(() => cm.display.input.reset(true), 20) + if (ie && ie_version < 11) setTimeout(() => this.display.input.reset(true), 20) registerEventHandlers(this) ensureGlobalHandlers() @@ -77,7 +75,7 @@ export function CodeMirror(place, options) { this.curOp.forceUpdate = true attachDoc(this, doc) - if ((options.autofocus && !mobile) || cm.hasFocus()) + if ((options.autofocus && !mobile) || this.hasFocus()) setTimeout(bind(onFocus, this), 20) else onBlur(this) diff --git a/src/edit/methods.js b/src/edit/methods.js index 260ffa5df2..f609d912e0 100644 --- a/src/edit/methods.js +++ b/src/edit/methods.js @@ -228,11 +228,11 @@ export default function(CodeMirror) { }), clearGutter: methodOp(function(gutterID) { - let cm = this, doc = cm.doc, i = doc.first + let doc = this.doc, i = doc.first doc.iter(line => { if (line.gutterMarkers && line.gutterMarkers[gutterID]) { line.gutterMarkers[gutterID] = null - regLineChange(cm, i, "gutter") + regLineChange(this, i, "gutter") if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null } ++i @@ -315,10 +315,9 @@ export default function(CodeMirror) { }, moveH: methodOp(function(dir, unit) { - let cm = this - cm.extendSelectionsBy(range => { - if (cm.display.shift || cm.doc.extend || range.empty()) - return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually) + this.extendSelectionsBy(range => { + if (this.display.shift || this.doc.extend || range.empty()) + return findPosH(this.doc, range.head, dir, unit, this.options.rtlMoveVisually) else return dir < 0 ? range.from() : range.to() }, sel_move) @@ -350,17 +349,17 @@ export default function(CodeMirror) { }, moveV: methodOp(function(dir, unit) { - let cm = this, doc = this.doc, goals = [] - let collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected() + let doc = this.doc, goals = [] + let collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected() doc.extendSelectionsBy(range => { if (collapse) return dir < 0 ? range.from() : range.to() - let headPos = cursorCoords(cm, range.head, "div") + let headPos = cursorCoords(this, range.head, "div") if (range.goalColumn != null) headPos.left = range.goalColumn goals.push(headPos.left) - let pos = findPosV(cm, headPos, dir, unit) + let pos = findPosV(this, headPos, dir, unit) if (unit == "page" && range == doc.sel.primary()) - addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top) + addToScrollPos(this, null, charCoords(this, pos, "div").top - headPos.top) return pos }, sel_move) if (goals.length) for (let i = 0; i < doc.sel.ranges.length; i++) @@ -435,19 +434,18 @@ export default function(CodeMirror) { }), setSize: methodOp(function(width, height) { - let cm = this let interpret = val => typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val - if (width != null) cm.display.wrapper.style.width = interpret(width) - if (height != null) cm.display.wrapper.style.height = interpret(height) - if (cm.options.lineWrapping) clearLineMeasurementCache(this) - let lineNo = cm.display.viewFrom - cm.doc.iter(lineNo, cm.display.viewTo, line => { + if (width != null) this.display.wrapper.style.width = interpret(width) + if (height != null) this.display.wrapper.style.height = interpret(height) + if (this.options.lineWrapping) clearLineMeasurementCache(this) + let lineNo = this.display.viewFrom + this.doc.iter(lineNo, this.display.viewTo, line => { if (line.widgets) for (let i = 0; i < line.widgets.length; i++) - if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break } + if (line.widgets[i].noHScroll) { regLineChange(this, lineNo, "widget"); break } ++lineNo }) - cm.curOp.forceUpdate = true - signal(cm, "refresh", this) + this.curOp.forceUpdate = true + signal(this, "refresh", this) }), operation: function(f){return runInOp(this, f)}, diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index 59ef55fa9d..fbb327f034 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -169,12 +169,11 @@ ContentEditableInput.prototype = copyObj({ }, startGracePeriod: function() { - let input = this clearTimeout(this.gracePeriod) this.gracePeriod = setTimeout(() => { - input.gracePeriod = false - if (input.selectionChanged()) - input.cm.operation(() => input.cm.curOp.selectionChanged = true) + this.gracePeriod = false + if (this.selectionChanged()) + this.cm.operation(() => this.cm.curOp.selectionChanged = true) }, 20) }, diff --git a/src/input/TextareaInput.js b/src/input/TextareaInput.js index 17f6f599cd..3193aa6890 100644 --- a/src/input/TextareaInput.js +++ b/src/input/TextareaInput.js @@ -47,7 +47,7 @@ TextareaInput.prototype = copyObj({ if (ios) te.style.width = "0px" on(te, "input", () => { - if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null + if (ie && ie_version >= 9 && this.hasSelection) this.hasSelection = null input.poll() }) @@ -185,11 +185,10 @@ TextareaInput.prototype = copyObj({ // Poll for input changes, using the normal rate of polling. This // runs as long as the editor is focused. slowPoll: function() { - let input = this - if (input.pollingFast) return - input.polling.set(this.cm.options.pollInterval, () => { - input.poll() - if (input.cm.state.focused) input.slowPoll() + if (this.pollingFast) return + this.polling.set(this.cm.options.pollInterval, () => { + this.poll() + if (this.cm.state.focused) this.slowPoll() }) }, @@ -245,18 +244,17 @@ TextareaInput.prototype = copyObj({ let same = 0, l = Math.min(prevInput.length, text.length) while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same - let self = this runInOp(cm, () => { applyTextInput(cm, text.slice(same), prevInput.length - same, - null, self.composing ? "*compose" : null) + null, this.composing ? "*compose" : null) // Don't leave long text in the textarea, since it makes further polling slow - if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = "" - else self.prevInput = text + if (text.length > 1000 || text.indexOf("\n") > -1) input.value = this.prevInput = "" + else this.prevInput = text - if (self.composing) { - self.composing.range.clear() - self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"), + if (this.composing) { + this.composing.range.clear() + this.composing.range = cm.markText(this.composing.start, cm.getCursor("to"), {className: "CodeMirror-composing"}) } }) From 96cd8885ad759350273c71235493f6b225590442 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Thu, 29 Sep 2016 22:45:48 +0200 Subject: [PATCH 0040/1880] Convert a few long CSS strings to template strings --- src/display/scrolling.js | 8 ++++---- src/display/selection.js | 6 +++--- src/input/TextareaInput.js | 8 ++++---- src/measurement/update_line.js | 16 ++++++++-------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/display/scrolling.js b/src/display/scrolling.js index d58efe0bcf..db9463cd04 100644 --- a/src/display/scrolling.js +++ b/src/display/scrolling.js @@ -17,10 +17,10 @@ export function maybeScrollWindow(cm, coords) { if (coords.top + box.top < 0) doScroll = true else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false if (doScroll != null && !phantom) { - let scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + - (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + - (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " + - coords.left + "px; width: 2px;") + let scrollNode = elt("div", "\u200b", null, `position: absolute; + top: ${coords.top - display.viewOffset - paddingTop(cm.display)}px; + height: ${coords.bottom - coords.top + scrollGap(cm) + display.barHeight}px; + left: ${coords.left}px; width: 2px;`) cm.display.lineSpace.appendChild(scrollNode) scrollNode.scrollIntoView(doScroll) cm.display.lineSpace.removeChild(scrollNode) diff --git a/src/display/selection.js b/src/display/selection.js index 8380de82e5..e3f912403a 100644 --- a/src/display/selection.js +++ b/src/display/selection.js @@ -57,9 +57,9 @@ function drawSelectionRange(cm, range, output) { if (top < 0) top = 0 top = Math.round(top) bottom = Math.round(bottom) - fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + - "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) + - "px; height: " + (bottom - top) + "px")) + fragment.appendChild(elt("div", null, "CodeMirror-selected", `position: absolute; left: ${left}px; + top: ${top}px; width: ${width == null ? rightSide - left : width}px; + height: ${bottom - top}px`)) } function drawForLine(line, fromArg, toArg) { diff --git a/src/input/TextareaInput.js b/src/input/TextareaInput.js index 3193aa6890..a150f05d16 100644 --- a/src/input/TextareaInput.js +++ b/src/input/TextareaInput.js @@ -284,10 +284,10 @@ TextareaInput.prototype = copyObj({ let oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText input.wrapper.style.cssText = "position: absolute" let wrapperBox = input.wrapper.getBoundingClientRect() - te.style.cssText = "position: absolute; width: 30px; height: 30px; top: " + (e.clientY - wrapperBox.top - 5) + - "px; left: " + (e.clientX - wrapperBox.left - 5) + "px; z-index: 1000; background: " + - (ie ? "rgba(255, 255, 255, .05)" : "transparent") + - "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);" + te.style.cssText = `position: absolute; width: 30px; height: 30px; + top: ${e.clientY - wrapperBox.top - 5}px; left: ${e.clientX - wrapperBox.left - 5}px; + z-index: 1000; background: ${ie ? "rgba(255, 255, 255, .05)" : "transparent"}; + outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);` let oldScrollY if (webkit) oldScrollY = window.scrollY // Work around Chrome issue (#2712) display.input.focus() diff --git a/src/measurement/update_line.js b/src/measurement/update_line.js index 4a80a7666c..cbfa657b38 100644 --- a/src/measurement/update_line.js +++ b/src/measurement/update_line.js @@ -95,15 +95,15 @@ function updateLineGutter(cm, lineView, lineN, dims) { if (lineView.line.gutterClass) { let wrap = ensureLineWrapped(lineView) lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass, - "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + - "px; width: " + dims.gutterTotalWidth + "px") + `left: ${cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth}px + width: ${dims.gutterTotalWidth}px`) wrap.insertBefore(lineView.gutterBackground, lineView.text) } let markers = lineView.line.gutterMarkers if (cm.options.lineNumbers || markers) { let wrap = ensureLineWrapped(lineView) - let gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + - (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px") + let gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", `left: + ${cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth}px`) cm.display.input.setUneditable(gutterWrap) wrap.insertBefore(gutterWrap, lineView.text) if (lineView.line.gutterClass) @@ -112,13 +112,13 @@ function updateLineGutter(cm, lineView, lineN, dims) { lineView.lineNumber = gutterWrap.appendChild( elt("div", lineNumberFor(cm.options, lineN), "CodeMirror-linenumber CodeMirror-gutter-elt", - "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " - + cm.display.lineNumInnerWidth + "px")) + `left: ${dims.gutterLeft["CodeMirror-linenumbers"]}px; + width: ${cm.display.lineNumInnerWidth}px`)) if (markers) for (let k = 0; k < cm.options.gutters.length; ++k) { let id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id] if (found) - gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + - dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")) + gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", + `left: ${dims.gutterLeft[id]}px; width: ${dims.gutterWidth[id]}px`)) } } } From 850671fa39bc5a6ab3c35340f22b87e1d98160eb Mon Sep 17 00:00:00 2001 From: Hasan Karahan Date: Fri, 30 Sep 2016 14:41:17 +0400 Subject: [PATCH 0041/1880] Fix duplicate cm- prefix in overlay styling Ensure that when an overlay is added that the class `cm-overlay` is used to denote a `span` instead of `cm-cm-overlay` (with the `cm-` prefix repeated twice). * E.g. before fix: ``` zpelling ``` * And after fix: ``` zpelling ``` --- src/line/highlight.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/line/highlight.js b/src/line/highlight.js index f54e7eaa56..dcf020adf7 100644 --- a/src/line/highlight.js +++ b/src/line/highlight.js @@ -32,12 +32,12 @@ export function highlightLine(cm, line, state, forceToEnd) { } if (!style) return if (overlay.opaque) { - st.splice(start, i - start, end, "cm-overlay " + style) + st.splice(start, i - start, end, "overlay " + style) i = start + 2 } else { for (; start < i; start += 2) { let cur = st[start+1] - st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style + st[start+1] = (cur ? cur + " " : "") + "overlay " + style } } }, lineClasses) From 920ecc1c6b82aa565a43702f3e7f1e766ab26849 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 30 Sep 2016 14:11:45 +0200 Subject: [PATCH 0042/1880] Fix ignoring of overlay styles in getTokenTypeAt --- src/edit/methods.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edit/methods.js b/src/edit/methods.js index f609d912e0..b63f9bd26b 100644 --- a/src/edit/methods.js +++ b/src/edit/methods.js @@ -136,7 +136,7 @@ export default function(CodeMirror) { else if (styles[mid * 2 + 1] < ch) before = mid + 1 else { type = styles[mid * 2 + 2]; break } } - let cut = type ? type.indexOf("cm-overlay ") : -1 + let cut = type ? type.indexOf("overlay ") : -1 return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1) }, From 27018275ec6912f4cbdeadb11d89e96d54f48ce9 Mon Sep 17 00:00:00 2001 From: Kyle Kelley Date: Sat, 1 Oct 2016 09:20:37 -0700 Subject: [PATCH 0043/1880] [real-world uses] Add nteract --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 1b272862b8..8db34cd9fa 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -123,6 +123,7 @@

CodeMirror real-world uses

  • Navigate CMS
  • nodeMirror (IDE project)
  • NoTex (rST authoring)
  • +
  • nteract (interactive literate coding notebook)
  • Oak (online outliner)
  • OpenCampus
  • ORG (z80 assembly IDE)
  • From 1233299f9f4e697102ad2d30f9cff5015d2623a8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 2 Oct 2016 11:42:32 +0200 Subject: [PATCH 0044/1880] [python mode] Don't highlight comments with odd indentation as error Closes #4276 --- mode/python/python.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/python/python.js b/mode/python/python.js index efeed7f154..30f1428e3a 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -85,7 +85,7 @@ var lineOffset = stream.indentation(); if (lineOffset > scopeOffset) pushPyScope(state); - else if (lineOffset < scopeOffset && dedent(stream, state)) + else if (lineOffset < scopeOffset && dedent(stream, state) && stream.peek() != "#") state.errorToken = true; return null; } else { From 5f93b65403f06505f729b8336a0da8e7b46fe67c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 2 Oct 2016 12:11:40 +0200 Subject: [PATCH 0045/1880] [haskell mode] Make sure unfinished strings have token type string To make closebrackets work with this mode Closes #4277 --- mode/haskell/haskell.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mode/haskell/haskell.js b/mode/haskell/haskell.js index fe0bab67ed..4197666a44 100644 --- a/mode/haskell/haskell.js +++ b/mode/haskell/haskell.js @@ -56,7 +56,7 @@ CodeMirror.defineMode("haskell", function(_config, modeConfig) { if (source.eat('\'')) { return "string"; } - return "error"; + return "string error"; } if (ch == '"') { @@ -166,7 +166,7 @@ CodeMirror.defineMode("haskell", function(_config, modeConfig) { } } setState(normal); - return "error"; + return "string error"; } function stringGap(source, setState) { @@ -194,7 +194,7 @@ CodeMirror.defineMode("haskell", function(_config, modeConfig) { "module", "newtype", "of", "then", "type", "where", "_"); setType("keyword")( - "\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>"); + "\.\.", ":", "::", "=", "\\", "<-", "->", "@", "~", "=>"); setType("builtin")( "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<", From 4cedb7e56ad865ac5825a18de2ddae65def32cce Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 2 Oct 2016 12:12:05 +0200 Subject: [PATCH 0046/1880] Add lib/codemirror.js to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f91c241f20..01019cf150 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *.swp .idea *.iml +/lib/codemirror.js From 7dbaf144c085ccdccc9ee3b8e8fced2a349d7eda Mon Sep 17 00:00:00 2001 From: Leon Sorokin Date: Sun, 2 Oct 2016 17:45:27 -0500 Subject: [PATCH 0047/1880] [dracula theme] consistent selection styling regardless of focus This prevents a selection from inheriting the default gray background when editor is defocused. --- theme/dracula.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/dracula.css b/theme/dracula.css index 57f979ae69..b2ef62913c 100644 --- a/theme/dracula.css +++ b/theme/dracula.css @@ -16,7 +16,7 @@ .cm-s-dracula .CodeMirror-gutters { color: #282a36; } .cm-s-dracula .CodeMirror-cursor { border-left: solid thin #f8f8f0; } .cm-s-dracula .CodeMirror-linenumber { color: #6D8A88; } -.cm-s-dracula.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); } +.cm-s-dracula .CodeMirror-selected { background: rgba(255, 255, 255, 0.10); } .cm-s-dracula .CodeMirror-line::selection, .cm-s-dracula .CodeMirror-line > span::selection, .cm-s-dracula .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); } .cm-s-dracula .CodeMirror-line::-moz-selection, .cm-s-dracula .CodeMirror-line > span::-moz-selection, .cm-s-dracula .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); } .cm-s-dracula span.cm-comment { color: #6272a4; } From ba82593e49c3622f1d3053d4e239e1a22b3e10f3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 4 Oct 2016 09:09:39 +0200 Subject: [PATCH 0048/1880] Remove IE7-related CSS kludges --- lib/codemirror.css | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index 18b0bf70db..d7821d17df 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -206,9 +206,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} display: inline-block; vertical-align: top; margin-bottom: -30px; - /* Hack to make IE7 behave */ - *zoom:1; - *display:inline; } .CodeMirror-gutter-wrapper { position: absolute; @@ -327,9 +324,6 @@ div.CodeMirror-dragcursors { background: rgba(255, 255, 0, .4); } -/* IE7 hack to prevent it from returning funny offsetTops on the spans */ -.CodeMirror span { *vertical-align: text-bottom; } - /* Used to force a border model for a node */ .cm-force-border { padding-right: .1px; } From fb78601b475393d0e534662cf19910e5582b4101 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 4 Oct 2016 09:12:15 +0200 Subject: [PATCH 0049/1880] Fix normalizing of s- prefix to key names --- src/input/keymap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/keymap.js b/src/input/keymap.js index 1b9564ef4f..3a107bb466 100644 --- a/src/input/keymap.js +++ b/src/input/keymap.js @@ -57,7 +57,7 @@ function normalizeKeyName(name) { if (/^(cmd|meta|m)$/i.test(mod)) cmd = true else if (/^a(lt)?$/i.test(mod)) alt = true else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true - else if (/^s(hift)$/i.test(mod)) shift = true + else if (/^s(hift)?$/i.test(mod)) shift = true else throw new Error("Unrecognized modifier name: " + mod) } if (alt) name = "Alt-" + name From a194325bb17111d5fc6bfd5a384a9df6a30e9b4d Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Sun, 2 Oct 2016 16:37:31 +0200 Subject: [PATCH 0050/1880] Add regression test for #4078 --- test/test.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/test.js b/test/test.js index a7658311e7..de2c66e830 100644 --- a/test/test.js +++ b/test/test.js @@ -1107,6 +1107,23 @@ testCM("measureEndOfLine", function(cm) { eqPos(cm.coordsChar({left: endPos.left, top: endPos.top + 5}), Pos(0, 18)); }, {mode: "text/html", value: "", lineWrapping: true}, ie_lt8 || opera_lt10); +testCM("measureWrappedEndOfLine", function(cm) { + if (phantom) return; + cm.setSize(null, "auto"); + var inner = byClassName(cm.getWrapperElement(), "CodeMirror-lines")[0].firstChild; + var lh = inner.offsetHeight; + for (var step = 10, w = cm.charCoords(Pos(0, 7), "div").right;; w += step) { + cm.setSize(w); + if (inner.offsetHeight < 2.5 * lh) { + if (step == 10) { w -= 10; step = 1; } + else break; + } + } + var endPos = cm.charCoords(Pos(0, 12)); // Next-to-last since last would wrap (#1862) + endPos.left += w; // Add width of editor just to be sure that we are behind last character + eqPos(cm.coordsChar(endPos), Pos(0, 13)); +}, {mode: "text/html", value: "0123456789abcde0123456789", lineWrapping: true}, ie_lt8 || opera_lt10); + testCM("scrollVerticallyAndHorizontally", function(cm) { if (cm.getOption("inputStyle") != "textarea") return; cm.setSize(100, 100); From 6b3b6a600101eb29a53a45f6117ba3db14ba17c2 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Sun, 2 Oct 2016 13:44:45 +0200 Subject: [PATCH 0051/1880] Document transposeChars, fix some inconsistencies With non-empty selections, transposeChar would only work on the chars next to head and ignore the selected chars. Also, a cursor at line start was not moved on successful swapping. --- src/edit/commands.js | 14 ++++++++++++-- test/emacs_test.js | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/edit/commands.js b/src/edit/commands.js index fe39ed727f..0b0125d1e9 100644 --- a/src/edit/commands.js +++ b/src/edit/commands.js @@ -106,9 +106,17 @@ export let commands = { if (cm.somethingSelected()) cm.indentSelection("add") else cm.execCommand("insertTab") }, + // Swap the two chars left and right of each selection's head. + // Move cursor behind the two swapped characters afterwards. + // + // Doesn't consider line feeds a character. + // Doesn't scan more than one line above to find a character. + // Doesn't do anything on an empty line. + // Doesn't do anything with non-empty selections. transposeChars: cm => runInOp(cm, () => { let ranges = cm.listSelections(), newSel = [] for (let i = 0; i < ranges.length; i++) { + if (!ranges[i].empty()) continue let cur = ranges[i].head, line = getLine(cm.doc, cur.line).text if (line) { if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1) @@ -118,10 +126,12 @@ export let commands = { Pos(cur.line, cur.ch - 2), cur, "+transpose") } else if (cur.line > cm.doc.first) { let prev = getLine(cm.doc, cur.line - 1).text - if (prev) + if (prev) { + cur = new Pos(cur.line, 1) cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() + prev.charAt(prev.length - 1), - Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose") + Pos(cur.line - 1, prev.length - 1), cur, "+transpose") + } } } newSel.push(new Range(cur, cur)) diff --git a/test/emacs_test.js b/test/emacs_test.js index 124575c724..628651c786 100644 --- a/test/emacs_test.js +++ b/test/emacs_test.js @@ -111,7 +111,7 @@ sim("transposeChar", "abcd\ne", "Ctrl-F", "Ctrl-T", "Ctrl-T", txt("bcad\ne"), at(0, 3), "Ctrl-F", "Ctrl-T", "Ctrl-T", "Ctrl-T", txt("bcda\ne"), at(0, 4), - "Ctrl-F", "Ctrl-T", txt("bcde\na"), at(1, 0)); + "Ctrl-F", "Ctrl-T", txt("bcde\na"), at(1, 1)); sim("manipWordCase", "foo BAR bAZ", "Alt-C", "Alt-L", "Alt-U", txt("Foo bar BAZ"), From f5751d0feb78bcb6c0307d4be527fba25341a691 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 6 Oct 2016 21:41:07 +0200 Subject: [PATCH 0052/1880] [javascript mode] Support TypeScript return type annotations on arrow functions Closes #4256 --- mode/javascript/javascript.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 65f85f3a98..8ff38b81bf 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -209,6 +209,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var arrow = stream.string.indexOf("=>", stream.start); if (arrow < 0) return; + if (isTS) { // Try to skip TypeScript return type declarations after the arguments + var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow)) + if (m) arrow = m.index + } + var depth = 0, sawSomething = false; for (var pos = arrow - 1; pos >= 0; --pos) { var ch = stream.string.charAt(pos); From 437f3842a2b339297f9934e5d6cb9ce861c05e0a Mon Sep 17 00:00:00 2001 From: mtaran-google Date: Tue, 11 Oct 2016 13:39:30 -0700 Subject: [PATCH 0053/1880] [sublime] Fix unfoldAll "ctrl+K ctrl+J" shortcut --- keymap/sublime.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keymap/sublime.js b/keymap/sublime.js index db9f54de16..fada04c038 100644 --- a/keymap/sublime.js +++ b/keymap/sublime.js @@ -570,7 +570,7 @@ map["Shift-" + ctrl + "["] = "fold"; map["Shift-" + ctrl + "]"] = "unfold"; - map[cK + ctrl + "0"] = map[cK + ctrl + "j"] = "unfoldAll"; + map[cK + ctrl + "0"] = map[cK + ctrl + "J"] = "unfoldAll"; map[ctrl + "I"] = "findIncremental"; map["Shift-" + ctrl + "I"] = "findIncrementalReverse"; From 9903967353f5ca1a1f9a14e3d3f98809ef0aee5e Mon Sep 17 00:00:00 2001 From: mtaran-google Date: Mon, 10 Oct 2016 18:28:59 -0700 Subject: [PATCH 0054/1880] [markdown] auto-close backticks --- mode/markdown/markdown.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 9dd44574fc..3dcce8d3b1 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -809,6 +809,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { getType: getType, + closeBrackets: "()[]{}''\"\"``", fold: "markdown" }; return mode; From 358086a5694d67424ccaa46c1bc0c9a16d4b3e09 Mon Sep 17 00:00:00 2001 From: mtaran-google Date: Mon, 10 Oct 2016 18:11:48 -0700 Subject: [PATCH 0055/1880] [go] auto-close backticks --- mode/go/go.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/go/go.js b/mode/go/go.js index 3c9ef6b989..803a5ba27b 100644 --- a/mode/go/go.js +++ b/mode/go/go.js @@ -173,6 +173,7 @@ CodeMirror.defineMode("go", function(config) { }, electricChars: "{}):", + closeBrackets: "()[]{}''\"\"``", fold: "brace", blockCommentStart: "/*", blockCommentEnd: "*/", From 147389d43293bc63fcab10e1c7d34f0c0a921016 Mon Sep 17 00:00:00 2001 From: mtaran-google Date: Mon, 10 Oct 2016 18:10:36 -0700 Subject: [PATCH 0056/1880] [shell] auto-close backticks --- mode/shell/shell.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/shell/shell.js b/mode/shell/shell.js index a684e8c233..570b4e2419 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -129,6 +129,7 @@ CodeMirror.defineMode('shell', function() { token: function(stream, state) { return tokenize(stream, state); }, + closeBrackets: "()[]{}''\"\"``", lineComment: '#', fold: "brace" }; From 0e4c156a9ab63dcbc5fa9f60ada54e3c5d5ad03b Mon Sep 17 00:00:00 2001 From: Philipp A Date: Tue, 11 Oct 2016 14:03:48 +0200 Subject: [PATCH 0057/1880] [r mode] Various improvements Closes #4297 --- mode/r/index.html | 65 +++++++++++++++++++++++++---------------------- mode/r/r.js | 15 ++++++++--- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/mode/r/index.html b/mode/r/index.html index 6dd9634659..01b6e664b7 100644 --- a/mode/r/index.html +++ b/mode/r/index.html @@ -31,47 +31,50 @@

    R mode

    + @@ -109,6 +110,7 @@

    Test Suite

    + From 55fb95f0e859c23b5eba667ac91e2fff7b07f375 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 17 Oct 2016 21:21:39 +0200 Subject: [PATCH 0070/1880] Move measurement/update_line to display/ Because it has nothing to do with measurement. --- src/display/update_display.js | 2 +- src/{measurement => display}/update_line.js | 0 src/measurement/position_measurement.js | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{measurement => display}/update_line.js (100%) diff --git a/src/display/update_display.js b/src/display/update_display.js index a8d6a4de13..4e016a2515 100644 --- a/src/display/update_display.js +++ b/src/display/update_display.js @@ -2,12 +2,12 @@ import { sawCollapsedSpans } from "../line/saw_special_spans" import { heightAtLine, visualLineEndNo, visualLineNo } from "../line/spans" import { getLine, lineNumberFor } from "../line/utils_line" import { displayHeight, displayWidth, getDimensions, paddingVert, scrollGap } from "../measurement/position_measurement" -import { buildLineElement, updateLineForChanges } from "../measurement/update_line" import { mac, webkit } from "../util/browser" import { activeElt, removeChildren } from "../util/dom" import { hasHandler, signal } from "../util/event" import { indexOf } from "../util/misc" +import { buildLineElement, updateLineForChanges } from "./update_line" import { startWorker } from "./highlight_worker" import { maybeUpdateLineNumberWidth } from "./line_numbers" import { measureForScrollbars, updateScrollbars } from "./scrollbars" diff --git a/src/measurement/update_line.js b/src/display/update_line.js similarity index 100% rename from src/measurement/update_line.js rename to src/display/update_line.js diff --git a/src/measurement/position_measurement.js b/src/measurement/position_measurement.js index 5688836ee0..4ece080e49 100644 --- a/src/measurement/position_measurement.js +++ b/src/measurement/position_measurement.js @@ -8,8 +8,8 @@ import { elt, removeChildren, range, removeChildrenAndAdd } from "../util/dom" import { e_target } from "../util/event" import { hasBadZoomedRects } from "../util/feature_detection" import { countColumn, isExtendingChar, scrollerGap } from "../util/misc" +import { updateLineForChanges } from "../display/update_line" -import { updateLineForChanges } from "./update_line" import { widgetHeight } from "./widgets" // POSITION MEASUREMENT From 05115c54a6d168535d78d303a21ce027fa4647d0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 18 Oct 2016 22:06:08 +0200 Subject: [PATCH 0071/1880] [css mode] Make translateX/Y/Z highlight properly Closes #4325 --- mode/css/css.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/css/css.js b/mode/css/css.js index ea7bd01d84..b6be4cd508 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -672,7 +672,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", "trad-chinese-formal", "trad-chinese-informal", - "translate", "translate3d", "translateX", "translateY", "translateZ", + "translate", "translate3d", "translatex", "translatey", "translatez", "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", From 344c8d560f7f4ea5c2a68209600e3689fbd61193 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 18 Oct 2016 22:28:49 +0200 Subject: [PATCH 0072/1880] [css mode] Better fix for mixed-case keywords Closes #4325 --- mode/css/css.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index b6be4cd508..e56e3dd8c6 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -414,7 +414,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { function keySet(array) { var keys = {}; for (var i = 0; i < array.length; ++i) { - keys[array[i]] = true; + keys[array[i].toLowerCase()] = true; } return keys; } @@ -672,7 +672,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", "trad-chinese-formal", "trad-chinese-informal", - "translate", "translate3d", "translatex", "translatey", "translatez", + "translate", "translate3d", "translateX", "translateY", "translateZ", "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", From edd8e6180a5209d20c175ce6aae43b3621dee4cb Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Oct 2016 09:50:25 +0200 Subject: [PATCH 0073/1880] [closebrackets addon] Don't skip over quotes at the start of a string Closes #4287 --- addon/edit/closebrackets.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index af7fce2a82..7c47bcd096 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -116,7 +116,9 @@ if (opening && !range.empty()) { curType = "surround"; } else if ((identical || !opening) && next == ch) { - if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch) + if (identical && stringStartsAfter(cm, cur)) + curType = "both"; + else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch) curType = "skipThree"; else curType = "skip"; @@ -192,4 +194,9 @@ stream.start = stream.pos; } } + + function stringStartsAfter(cm, pos) { + var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1)) + return /\bstring/.test(token.type) && token.start == pos.ch + } }); From b25f85746f7b036642ebd74cd9496a36b636cbbd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Oct 2016 09:58:35 +0200 Subject: [PATCH 0074/1880] Normalize line endings in inserted/pasted content Issue #4289 --- src/input/input.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/input/input.js b/src/input/input.js index e51a90a119..57e4ea533b 100644 --- a/src/input/input.js +++ b/src/input/input.js @@ -7,6 +7,7 @@ import { ios, webkit } from "../util/browser" import { elt } from "../util/dom" import { lst, map } from "../util/misc" import { signalLater } from "../util/operation_group" +import { splitLinesAuto } from "../util/feature_detection" import { indentLine } from "./indent" @@ -25,7 +26,7 @@ export function applyTextInput(cm, inserted, deleted, sel, origin) { if (!sel) sel = doc.sel let paste = cm.state.pasteIncoming || origin == "paste" - let textLines = doc.splitLines(inserted), multiPaste = null + let textLines = splitLinesAuto(inserted), multiPaste = null // When pasing N lines into N selections, insert one line per selection if (paste && sel.ranges.length > 1) { if (lastCopied && lastCopied.text.join("\n") == inserted) { From 1502f805a868a2e3ee87d0574ff18e592fd9785f Mon Sep 17 00:00:00 2001 From: Todd Berman Date: Thu, 6 Oct 2016 14:37:54 -0700 Subject: [PATCH 0075/1880] Add `mergeMarkerLocation` to options to allow customization --- addon/merge/merge.js | 33 +++++++++++++++++++++++++-------- doc/manual.html | 6 +++++- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index cc94cafb8c..2cfeabe426 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -40,6 +40,7 @@ (this.edit.state.diffViews || (this.edit.state.diffViews = [])).push(this); this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options))); this.orig.state.diffViews = [this]; + this.classes.location = options.mergeMarkerLocation || "background"; this.diff = getDiff(asString(orig), asString(options.value)); this.chunks = getChunks(this.diff); @@ -192,14 +193,20 @@ // Updating the marks for editor content function clearMarks(editor, arr, classes) { + function removeLineClass(l, klass) { + var classList = Array.isArray(classes.location) ? classes.location : [classes.location] + for (var c = 0; c < classList.length; ++c) { + editor.removeLineClass(l, classList[c], klass) + } + } for (var i = 0; i < arr.length; ++i) { var mark = arr[i]; if (mark instanceof CodeMirror.TextMarker) { mark.clear(); } else if (mark.parent) { - editor.removeLineClass(mark, "background", classes.chunk); - editor.removeLineClass(mark, "background", classes.start); - editor.removeLineClass(mark, "background", classes.end); + removeLineClass(mark, classes.chunk); + removeLineClass(mark, classes.start); + removeLineClass(mark, classes.end); } } arr.length = 0; @@ -231,19 +238,29 @@ var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1)); var cls = type == DIFF_DELETE ? classes.del : classes.insert; function markChunk(start, end) { + function addLineClass(l, klass) { + var classList = Array.isArray(classes.location) ? classes.location : [classes.location] + var ret = null + for (var c = 0; c < classList.length; ++c) { + ret = editor.addLineClass(l, classList[c], klass) + } + + return ret + } + var bfrom = Math.max(from, start), bto = Math.min(to, end); for (var i = bfrom; i < bto; ++i) { - var line = editor.addLineClass(i, "background", classes.chunk); - if (i == start) editor.addLineClass(line, "background", classes.start); - if (i == end - 1) editor.addLineClass(line, "background", classes.end); + var line = addLineClass(i, classes.chunk); + if (i == start) addLineClass(line, classes.start); + if (i == end - 1) addLineClass(line, classes.end); marks.push(line); } // When the chunk is empty, make sure a horizontal line shows up if (start == end && bfrom == end && bto == end) { if (bfrom) - marks.push(editor.addLineClass(bfrom - 1, "background", classes.end)); + marks.push(addLineClass(bfrom - 1, classes.end)); else - marks.push(editor.addLineClass(bfrom, "background", classes.start)); + marks.push(addLineClass(bfrom, classes.start)); } } diff --git a/doc/manual.html b/doc/manual.html index 65e030c0bf..baa8356fa0 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2583,7 +2583,7 @@

    Addons

    Optional to position that will be used by pick() instead of the global one passed with the full list of completions.
    - +
    The plugin understands the following options (the options object will also be passed along to the hinting function, which may understand additional options): @@ -2986,6 +2986,10 @@

    Addons

    showDifferences: boolean
    When true (the default), changed pieces of text are highlighted.
    +
    mergeMarkerLocations: string|Array
    +
    By default the merge highlights are added using addLineClass with "background". + Override this to customize it to be any valid `where` parameter or an Array of valid `where` + parameters.
    The addon also defines commands "goNextDiff" and "goPrevDiff" to quickly jump to the next From 9a316b33d72439cf52ab189ab1e60a16e8b15fe5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Oct 2016 10:27:34 +0200 Subject: [PATCH 0076/1880] Update previous patch to change option name and clean up code Issue #4288 --- addon/merge/merge.js | 60 +++++++++++++++++++++----------------------- doc/manual.html | 8 +++--- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index 2cfeabe426..2f53406edc 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -40,7 +40,9 @@ (this.edit.state.diffViews || (this.edit.state.diffViews = [])).push(this); this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options))); this.orig.state.diffViews = [this]; - this.classes.location = options.mergeMarkerLocation || "background"; + var classLocation = options.chunkClassLocation || "background"; + if (Object.prototype.toString.call(classLocation) != "[object Array]") classLocation = [classLocation] + this.classes.classLocation = classLocation this.diff = getDiff(asString(orig), asString(options.value)); this.chunks = getChunks(this.diff); @@ -192,22 +194,22 @@ // Updating the marks for editor content - function clearMarks(editor, arr, classes) { - function removeLineClass(l, klass) { - var classList = Array.isArray(classes.location) ? classes.location : [classes.location] - for (var c = 0; c < classList.length; ++c) { - editor.removeLineClass(l, classList[c], klass) - } + function removeClass(editor, line, classes) { + var locs = classes.classLocation + for (var i = 0; i < locs.length; i++) { + editor.removeLineClass(line, locs[i], classes.chunk); + editor.removeLineClass(line, locs[i], classes.start); + editor.removeLineClass(line, locs[i], classes.chunk); } + } + + function clearMarks(editor, arr, classes) { for (var i = 0; i < arr.length; ++i) { var mark = arr[i]; - if (mark instanceof CodeMirror.TextMarker) { + if (mark instanceof CodeMirror.TextMarker) mark.clear(); - } else if (mark.parent) { - removeLineClass(mark, classes.chunk); - removeLineClass(mark, classes.start); - removeLineClass(mark, classes.end); - } + else if (mark.parent) + removeClass(editor, mark, classes); } arr.length = 0; } @@ -233,34 +235,30 @@ }); } + function addClass(editor, lineNr, classes, main, start, end) { + var locs = classes.classLocation, line = editor.getLineHandle(lineNr); + for (var i = 0; i < locs.length; i++) { + if (main) editor.addLineClass(line, locs[i], classes.chunk); + if (start) editor.addLineClass(line, locs[i], classes.start); + if (end) editor.addLineClass(line, locs[i], classes.end); + } + return line; + } + function markChanges(editor, diff, type, marks, from, to, classes) { var pos = Pos(0, 0); var top = Pos(from, 0), bot = editor.clipPos(Pos(to - 1)); var cls = type == DIFF_DELETE ? classes.del : classes.insert; function markChunk(start, end) { - function addLineClass(l, klass) { - var classList = Array.isArray(classes.location) ? classes.location : [classes.location] - var ret = null - for (var c = 0; c < classList.length; ++c) { - ret = editor.addLineClass(l, classList[c], klass) - } - - return ret - } - var bfrom = Math.max(from, start), bto = Math.min(to, end); - for (var i = bfrom; i < bto; ++i) { - var line = addLineClass(i, classes.chunk); - if (i == start) addLineClass(line, classes.start); - if (i == end - 1) addLineClass(line, classes.end); - marks.push(line); - } + for (var i = bfrom; i < bto; ++i) + marks.push(addClass(editor, i, classes, true, i == start, i == end - 1)); // When the chunk is empty, make sure a horizontal line shows up if (start == end && bfrom == end && bto == end) { if (bfrom) - marks.push(addLineClass(bfrom - 1, classes.end)); + marks.push(addClass(editor, bfrom - 1, classes, false, false, true)); else - marks.push(addLineClass(bfrom, classes.start)); + marks.push(addClass(editor, bfrom, classes, false, true, false)); } } diff --git a/doc/manual.html b/doc/manual.html index baa8356fa0..f9e9946533 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2986,9 +2986,11 @@

    Addons

    showDifferences: boolean
    When true (the default), changed pieces of text are highlighted.
    -
    mergeMarkerLocations: string|Array
    -
    By default the merge highlights are added using addLineClass with "background". - Override this to customize it to be any valid `where` parameter or an Array of valid `where` +
    chunkClassLocation: string|Array
    +
    By default the chunk highlights are added + using addLineClass + with "background". Override this to customize it to be any + valid `where` parameter or an Array of valid `where` parameters.
    The addon also defines commands "goNextDiff" From 7484049deddcff8ccc9a7ff1989adb4bb00a9e80 Mon Sep 17 00:00:00 2001 From: themrmax Date: Mon, 10 Oct 2016 10:34:54 +1100 Subject: [PATCH 0077/1880] add quickstart to project readme --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index ff2622a2b8..84466293b4 100644 --- a/README.md +++ b/README.md @@ -26,3 +26,9 @@ The CodeMirror community aims to be welcoming to everybody. We use the [Contributor Covenant (1.1)](http://contributor-covenant.org/version/1/1/0/) as our code of conduct. + +### Quickstart + +To build the project, make sure you have Node.js installed (at least version 6) +and then `npm install && npm build`. To run, just open `index.html` in your +browser (you don't need to run a webserver). Run the tests with `npm test`. From e1c3b9e9e7ab876abf4fb3458006b205709367c4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Oct 2016 11:00:48 +0200 Subject: [PATCH 0078/1880] [lint addon] Provide a way to show tooltips only on the gutter Closes #4308 --- addon/lint/lint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/lint/lint.js b/addon/lint/lint.js index e3a452766d..c1f1702f92 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -226,7 +226,7 @@ var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); if (state.options.lintOnChange !== false) cm.on("change", onChange); - if (state.options.tooltips != false) + if (state.options.tooltips != false && state.options.tooltips != "gutter") CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); startLinting(cm); From 1523a8b79afab2618e7bedaaf34adf5f232fd15b Mon Sep 17 00:00:00 2001 From: Mu-An Chiou Date: Wed, 12 Oct 2016 17:02:30 +0800 Subject: [PATCH 0079/1880] Fix addRange behavior in contenteditable mode When selecting at the beginning of a line ranges need to be removed for new range to be added properly. (in Safari) --- src/input/ContentEditableInput.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index fbb327f034..cdaa825488 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -157,7 +157,10 @@ ContentEditableInput.prototype = copyObj({ if (rng) { if (!gecko && this.cm.state.focused) { sel.collapse(start.node, start.offset) - if (!rng.collapsed) sel.addRange(rng) + if (!rng.collapsed) { + sel.removeAllRanges() + sel.addRange(rng) + } } else { sel.removeAllRanges() sel.addRange(rng) From 763575c2bd91747c7b44a70ebc24f79b85d71e6e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Oct 2016 11:29:52 +0200 Subject: [PATCH 0080/1880] Mark release 5.20.0 --- AUTHORS | 12 ++++++++++++ CHANGELOG.md | 24 ++++++++++++++++++++++++ doc/manual.html | 2 +- doc/releases.html | 14 ++++++++++++++ index.html | 2 +- package.json | 2 +- 6 files changed, 53 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index ada8c3f9cf..e2cb74a557 100644 --- a/AUTHORS +++ b/AUTHORS @@ -9,6 +9,7 @@ Adam King adanlobato Adán Lobato Adrian Aichner +Adrian Heine aeroson Ahmad Amireh Ahmad M. Zawawi @@ -61,10 +62,12 @@ anthonygego Anthony Gégo Anthony Grimes Anton Kovalyov +Apollo Zhu AQNOUCH Mohammed areos Arnab Bose as3boyan +atelierbram AtomicPages LLC Atul Bhouraskar Aurelian Oancea @@ -151,6 +154,7 @@ deebugger Deep Thought Devin Abbott Devon Carew +Dick Choi dignifiedquire Dimage Sapelkin Dmitry Kiselyov @@ -284,6 +288,7 @@ John Van Der Loo Jon Ander Peñalba Jonas Döbertin Jonathan Malmaud +Jon Gacnik jongalloway Jon Malmaud Jon Sangster @@ -321,6 +326,7 @@ Kris Ciccarello ks-ifware kubelsmieci KwanEsq +Kyle Kelley Lanfei Lanny Laszlo Vidacs @@ -336,6 +342,7 @@ lochel Lorenzo Stoakes Luciano Longo Lu Fangjian +Luke Browning Luke Granger-Brown Luke Stagner lynschinzer @@ -358,6 +365,7 @@ Mario Pietsch Mark Anderson Mark Lentczner Marko Bonaci +Mark Peace Markus Bordihn Martin Balek Martín Gaitán @@ -415,6 +423,7 @@ Moritz Schwörer mps ms mtaran-google +Mu-An Chiou Narciso Jaramillo Nathan Williams ndr @@ -439,6 +448,7 @@ nlwillia noragrossman Norman Rzepka Oreoluwa Onatemowo +Oskar Segersvärd pablo pabloferz Page @@ -547,6 +557,7 @@ tfjgeorge Thaddee Tyl thanasis TheHowl +themrmax think Thomas Dvornik Thomas Kluyver @@ -557,6 +568,7 @@ Timothy Farrell Timothy Gu Timothy Hatcher TobiasBg +Todd Berman Tomas-A Tomas Varaneckas Tom Erik Støwer diff --git a/CHANGELOG.md b/CHANGELOG.md index f368485cfe..b243546569 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,27 @@ +## 5.20.0 (2016-10-20) + +### Bug fixes + +Make `newlineAndIndent` command work with multiple cursors on the same line. + +Make sure keypress events for backspace are ignored. + +Tokens styled with overlays no longer get a nonsense `cm-cm-overlay` class. + +Line endings for pasted content are now normalized to the editor's [preferred ending](http://codemirror.net/doc/manual.html#option_lineSeparator). + +[javascript mode](http://codemirror.net/mode/javascript): Improve support for class expressions. Support TypeScript optional class properties, the `abstract` keyword, and return type declarations for arrow functions. + +[css mode](http://codemirror.net/mode/css): Fix highlighting of mixed-case keywords. + +[closebrackets addon](http://codemirror.net/doc/manual.html#addon_closebrackets): Improve behavior when typing a quote before a string. + +### New features + +The core is now maintained as a number of small files, using ES6 syntax and modules, under the `src/` directory. A git checkout no longer contains a working `codemirror.js` until you `npm build` (but when installing from NPM, it is included). + +The [`refresh`](http://codemirror.net/doc/manual.html#event_refresh) event is now documented and stable. + ## 5.19.0 (2016-09-20) ### Bugfixes diff --git a/doc/manual.html b/doc/manual.html index f9e9946533..36354b71f3 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.19.1 + version 5.20.0

    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 5a0c6b715c..cfc366f3e2 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,20 @@

    Release notes and version history

    Version 5.x

    +

    20-10-2016: Version 5.20.0:

    + +
      +
    • Make newlineAndIndent command work with multiple cursors on the same line.
    • +
    • Make sure keypress events for backspace are ignored.
    • +
    • Tokens styled with overlays no longer get a nonsense cm-cm-overlay class.
    • +
    • Line endings for pasted content are now normalized to the editor's preferred ending.
    • +
    • javascript mode: Improve support for class expressions. Support TypeScript optional class properties, the abstract keyword, and return type declarations for arrow functions.
    • +
    • css mode: Fix highlighting of mixed-case keywords.
    • +
    • closebrackets addon: Improve behavior when typing a quote before a string.
    • +
    • The core is now maintained as a number of small files, using ES6 syntax and modules, under the src/ directory. A git checkout no longer contains a working codemirror.js until you npm build (but when installing from NPM, it is included).
    • +
    • The refresh event is now documented and stable.
    • +
    +

    20-09-2016: Version 5.19.0:

      diff --git a/index.html b/index.html index 3423eab209..f4e56a70c8 100644 --- a/index.html +++ b/index.html @@ -96,7 +96,7 @@

      This is CodeMirror

    - Get the current version: 5.19.0.
    + Get the current version: 5.20.0.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index 057280c569..74040d5658 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.19.1", + "version": "5.20.0", "main": "lib/codemirror.js", "description": "Full-featured in-browser code editor", "license": "MIT", From 81d7f09b6de4044e2945bed39edb48e61d1f5495 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Oct 2016 11:33:05 +0200 Subject: [PATCH 0081/1880] Bump version number post-5.20 --- doc/manual.html | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 36354b71f3..0cff1be813 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.20.0 + version 5.20.1

    CodeMirror is a code-editor component that can be embedded in diff --git a/package.json b/package.json index 74040d5658..7dbf4751e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.20.0", + "version": "5.20.1", "main": "lib/codemirror.js", "description": "Full-featured in-browser code editor", "license": "MIT", From cea0e041e3fcefdb0869891cb02880bdc07ab966 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Oct 2016 15:39:49 +0200 Subject: [PATCH 0082/1880] Drop bower.json To further underline our lack of commitment to having the github repository serve as a package distribution mechanism. --- bower.json | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 bower.json diff --git a/bower.json b/bower.json deleted file mode 100644 index 903d9f55f8..0000000000 --- a/bower.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "codemirror", - "main": ["lib/codemirror.js", "lib/codemirror.css"], - "ignore": [ - "**/.*", - "node_modules", - "components", - "bin", - "demo", - "doc", - "test", - "index.html", - "package.json", - "mode/*/*test.js", - "mode/*/*.html" - ] -} From 33f2044c8105b37b5f4b4e60893d457f696ba634 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Oct 2016 21:56:21 +0200 Subject: [PATCH 0083/1880] Fix installation instruction Closes #4333 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 84466293b4..1b3309881c 100644 --- a/README.md +++ b/README.md @@ -30,5 +30,5 @@ conduct. ### Quickstart To build the project, make sure you have Node.js installed (at least version 6) -and then `npm install && npm build`. To run, just open `index.html` in your +and then `npm install && npm run build`. To run, just open `index.html` in your browser (you don't need to run a webserver). Run the tests with `npm test`. From f73ff23d5aa3247e0fc46d3ffde73cf9c900f48d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 21 Oct 2016 08:13:42 +0200 Subject: [PATCH 0084/1880] Fix release script to bump version in correct file --- bin/release | 2 +- src/edit/main.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/release b/bin/release index df1fb269c3..b31d511857 100755 --- a/bin/release +++ b/bin/release @@ -16,7 +16,7 @@ function rewrite(file, f) { fs.writeFileSync(file, f(fs.readFileSync(file, "utf8")), "utf8"); } -rewrite("lib/codemirror.js", function(lib) { +rewrite("src/edit/main.js", function(lib) { return lib.replace(/CodeMirror\.version = "\d+\.\d+\.\d+"/, "CodeMirror.version = \"" + number + "\""); }); diff --git a/src/edit/main.js b/src/edit/main.js index 2831d2a03d..16dc032155 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.19.1" +CodeMirror.version = "5.20.1" From d221bf5d15680e06528e1558c014d178c4bc740d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 21 Oct 2016 08:17:46 +0200 Subject: [PATCH 0085/1880] Mark release 5.20.2 --- CHANGELOG.md | 6 ++++++ doc/manual.html | 2 +- index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b243546569..a7e995ab4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 5.20.2 (2016-10-21) + +### Bug fixes + +Fix `CodeMirror.version` returning the wrong version number. + ## 5.20.0 (2016-10-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 0cff1be813..2944f0d5e5 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.20.1 + version 5.20.2

    CodeMirror is a code-editor component that can be embedded in diff --git a/index.html b/index.html index f4e56a70c8..1d1bb3c8a2 100644 --- a/index.html +++ b/index.html @@ -96,7 +96,7 @@

    This is CodeMirror

    - Get the current version: 5.20.0.
    + Get the current version: 5.20.2.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index 7dbf4751e1..8a58fbded2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.20.1", + "version": "5.20.2", "main": "lib/codemirror.js", "description": "Full-featured in-browser code editor", "license": "MIT", diff --git a/src/edit/main.js b/src/edit/main.js index 16dc032155..4335965626 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.20.1" +CodeMirror.version = "5.20.2" From 06431f4d7eb24b0945bc7bb0b775a4f644766c64 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 21 Oct 2016 08:19:57 +0200 Subject: [PATCH 0086/1880] Bump version number post-5.20.2 --- doc/manual.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 2944f0d5e5..6ef27689ce 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.20.2 + version 5.20.3

    CodeMirror is a code-editor component that can be embedded in diff --git a/package.json b/package.json index 8a58fbded2..1d07d681b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.20.2", + "version": "5.20.3", "main": "lib/codemirror.js", "description": "Full-featured in-browser code editor", "license": "MIT", diff --git a/src/edit/main.js b/src/edit/main.js index 4335965626..57fcffa04e 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.20.2" +CodeMirror.version = "5.20.3" From 63bf6594d80b09359025ebc9282e49ed37574cd2 Mon Sep 17 00:00:00 2001 From: Todd Berman Date: Thu, 20 Oct 2016 20:37:42 -0700 Subject: [PATCH 0087/1880] Add classes to each pane for isolated style changes, handle document swapping --- addon/merge/merge.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index 2f53406edc..b0f78c87fd 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -116,8 +116,14 @@ // Update faster when a line was added/removed setDealign(change.text.length - 1 != change.to.line - change.from.line); } + function swapDoc() { + dv.diffOutOfDate = true; + update("full"); + } dv.edit.on("change", change); dv.orig.on("change", change); + dv.edit.on("swapDoc", swapDoc); + dv.orig.on("swapDoc", swapDoc); dv.edit.on("markerAdded", setDealign); dv.edit.on("markerCleared", setDealign); dv.orig.on("markerAdded", setDealign); @@ -464,18 +470,18 @@ if (hasLeft) { left = this.left = new DiffView(this, "left"); - var leftPane = elt("div", null, "CodeMirror-merge-pane"); + var leftPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-left"); wrap.push(leftPane); wrap.push(buildGap(left)); } - var editPane = elt("div", null, "CodeMirror-merge-pane"); + var editPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-editor"); wrap.push(editPane); if (hasRight) { right = this.right = new DiffView(this, "right"); wrap.push(buildGap(right)); - var rightPane = elt("div", null, "CodeMirror-merge-pane"); + var rightPane = elt("div", null, "CodeMirror-merge-pane CodeMirror-merge-right"); wrap.push(rightPane); } From e83ee37e5c54d0b088087bfdb897c7e3d5aacbad Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 22 Oct 2016 09:03:43 +0200 Subject: [PATCH 0088/1880] [css mode] Drop marker-offset property Closes #4340 --- mode/css/css.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/css/css.js b/mode/css/css.js index e56e3dd8c6..b75732034e 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -494,7 +494,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "line-stacking-shift", "line-stacking-strategy", "list-style", "list-style-image", "list-style-position", "list-style-type", "margin", "margin-bottom", "margin-left", "margin-right", "margin-top", - "marker-offset", "marks", "marquee-direction", "marquee-loop", + "marks", "marquee-direction", "marquee-loop", "marquee-play-count", "marquee-speed", "marquee-style", "max-height", "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index", "nav-left", "nav-right", "nav-up", "object-fit", "object-position", From db12d64243ee9d2994e12ffb2935ebac0cbf3c1c Mon Sep 17 00:00:00 2001 From: Todd Berman Date: Sat, 22 Oct 2016 17:59:55 -0700 Subject: [PATCH 0089/1880] [merge addon] Remove the end class when removing chunk styling --- addon/merge/merge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index b0f78c87fd..e9700821b1 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -205,7 +205,7 @@ for (var i = 0; i < locs.length; i++) { editor.removeLineClass(line, locs[i], classes.chunk); editor.removeLineClass(line, locs[i], classes.start); - editor.removeLineClass(line, locs[i], classes.chunk); + editor.removeLineClass(line, locs[i], classes.end); } } From 0164f02bf1ce823e300520ef198d620f30d47220 Mon Sep 17 00:00:00 2001 From: BigBlueHat Date: Wed, 26 Oct 2016 17:01:08 -0400 Subject: [PATCH 0090/1880] [yaml mode] Add text/yaml MIME type --- mode/meta.js | 2 +- mode/yaml/yaml.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mode/meta.js b/mode/meta.js index 47e9a31ce8..cb0684b984 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -157,7 +157,7 @@ {name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd"], alias: ["rss", "wsdl", "xsd"]}, {name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]}, {name: "Yacas", mime: "text/x-yacas", mode: "yacas", ext: ["ys"]}, - {name: "YAML", mime: "text/x-yaml", mode: "yaml", ext: ["yaml", "yml"], alias: ["yml"]}, + {name: "YAML", mimes: ["text/x-yaml", "text/yaml"], mode: "yaml", ext: ["yaml", "yml"], alias: ["yml"]}, {name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]}, {name: "mscgen", mime: "text/x-mscgen", mode: "mscgen", ext: ["mscgen", "mscin", "msc"]}, {name: "xu", mime: "text/x-xu", mode: "mscgen", ext: ["xu"]}, diff --git a/mode/yaml/yaml.js b/mode/yaml/yaml.js index b7015e599c..59c0ecdbec 100644 --- a/mode/yaml/yaml.js +++ b/mode/yaml/yaml.js @@ -113,5 +113,6 @@ CodeMirror.defineMode("yaml", function() { }); CodeMirror.defineMIME("text/x-yaml", "yaml"); +CodeMirror.defineMIME("text/yaml", "yaml"); }); From 2eb94e54b6e9e1df5004fe8089311be8e3b73146 Mon Sep 17 00:00:00 2001 From: BigBlueHat Date: Thu, 27 Oct 2016 10:41:00 -0400 Subject: [PATCH 0091/1880] [vue mode] Fix media type Demo had the correct `text/x-vue` defineMIME was using `script/x-vue` There is, however, no `script/*` top-level media type: http://www.iana.org/assignments/media-types/media-types.xhtml Left, old `script/x-vue` for backwards compatibility. --- mode/meta.js | 1 + mode/vue/vue.js | 1 + 2 files changed, 2 insertions(+) diff --git a/mode/meta.js b/mode/meta.js index cb0684b984..8faf7677df 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -154,6 +154,7 @@ {name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]}, {name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]}, {name: "VHDL", mime: "text/x-vhdl", mode: "vhdl", ext: ["vhd", "vhdl"]}, + {name: "Vue.js Component", mimes: ["script/x-vue", "text/x-vue"], mode: "vue", ext: ["vue"]}, {name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd"], alias: ["rss", "wsdl", "xsd"]}, {name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]}, {name: "Yacas", mime: "text/x-yacas", mode: "yacas", ext: ["ys"]}, diff --git a/mode/vue/vue.js b/mode/vue/vue.js index f8089af501..c0eab6b82f 100644 --- a/mode/vue/vue.js +++ b/mode/vue/vue.js @@ -66,4 +66,5 @@ }, "htmlmixed", "xml", "javascript", "coffeescript", "css", "sass", "stylus", "pug", "handlebars"); CodeMirror.defineMIME("script/x-vue", "vue"); + CodeMirror.defineMIME("text/x-vue", "vue"); }); From e2c146e6463f31839b49bfef303e962116970a88 Mon Sep 17 00:00:00 2001 From: Adrien Bertrand Date: Sat, 29 Oct 2016 19:14:54 +0200 Subject: [PATCH 0092/1880] Fix constructor typo for MergeView. --- addon/merge/merge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index e9700821b1..72526d0179 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -545,7 +545,7 @@ } MergeView.prototype = { - constuctor: MergeView, + constructor: MergeView, editor: function() { return this.edit; }, rightOriginal: function() { return this.right && this.right.orig; }, leftOriginal: function() { return this.left && this.left.orig; }, From 7b00c30cdb959cf1980ca5f5cbac3cf331b83b08 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 31 Oct 2016 09:47:35 +0100 Subject: [PATCH 0093/1880] [ruby mode] Make else and elsif electric Closes #4345 --- mode/ruby/ruby.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/ruby/ruby.js b/mode/ruby/ruby.js index 10cad8d9f1..085f909f5f 100644 --- a/mode/ruby/ruby.js +++ b/mode/ruby/ruby.js @@ -275,7 +275,7 @@ CodeMirror.defineMode("ruby", function(config) { (state.continuedLine ? config.indentUnit : 0); }, - electricInput: /^\s*(?:end|rescue|\})$/, + electricInput: /^\s*(?:end|rescue|elsif|else|\})$/, lineComment: "#" }; }); From c4d9363e18925842b7741e11611d870baf4bb14e Mon Sep 17 00:00:00 2001 From: sverweij Date: Fri, 28 Oct 2016 23:03:34 +0200 Subject: [PATCH 0094/1880] [mscgen mode] adds support for language constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit and adds the xù specific keyword 'xu' --- mode/mscgen/index.html | 2 +- mode/mscgen/mscgen.js | 8 +++++++- mode/mscgen/mscgen_test.js | 10 +++++++++- mode/mscgen/msgenny_test.js | 7 ++++++- mode/mscgen/xu_test.js | 19 +++++++++++++++---- 5 files changed, 38 insertions(+), 8 deletions(-) diff --git a/mode/mscgen/index.html b/mode/mscgen/index.html index 8c28ee6200..b1d7e7c2e6 100644 --- a/mode/mscgen/index.html +++ b/mode/mscgen/index.html @@ -59,7 +59,7 @@

    Xù mode

    # Xù - expansions to MscGen to support inline expressions # https://github.com/sverweij/mscgen_js/blob/master/wikum/xu.md # More samples: https://sverweij.github.io/mscgen_js -msc { +xu { hscale="0.8", width="700"; diff --git a/mode/mscgen/mscgen.js b/mode/mscgen/mscgen.js index d61b470652..2cd6f42703 100644 --- a/mode/mscgen/mscgen.js +++ b/mode/mscgen/mscgen.js @@ -23,6 +23,7 @@ mscgen: { "keywords" : ["msc"], "options" : ["hscale", "width", "arcgradient", "wordwraparcs"], + "constants" : ["true", "false", "on", "off"], "attributes" : ["label", "idurl", "id", "url", "linecolor", "linecolour", "textcolor", "textcolour", "textbgcolor", "textbgcolour", "arclinecolor", "arclinecolour", "arctextcolor", "arctextcolour", "arctextbgcolor", "arctextbgcolour", "arcskip"], "brackets" : ["\\{", "\\}"], // [ and ] are brackets too, but these get handled in with lists "arcsWords" : ["note", "abox", "rbox", "box"], @@ -31,8 +32,9 @@ "operators" : ["="] }, xu: { - "keywords" : ["msc"], + "keywords" : ["msc", "xu"], "options" : ["hscale", "width", "arcgradient", "wordwraparcs", "watermark"], + "constants" : ["true", "false", "on", "off", "auto"], "attributes" : ["label", "idurl", "id", "url", "linecolor", "linecolour", "textcolor", "textcolour", "textbgcolor", "textbgcolour", "arclinecolor", "arclinecolour", "arctextcolor", "arctextcolour", "arctextbgcolor", "arctextbgcolour", "arcskip"], "brackets" : ["\\{", "\\}"], // [ and ] are brackets too, but these get handled in with lists "arcsWords" : ["note", "abox", "rbox", "box", "alt", "else", "opt", "break", "par", "seq", "strict", "neg", "critical", "ignore", "consider", "assert", "loop", "ref", "exc"], @@ -43,6 +45,7 @@ msgenny: { "keywords" : null, "options" : ["hscale", "width", "arcgradient", "wordwraparcs", "watermark"], + "constants" : ["true", "false", "on", "off", "auto"], "attributes" : null, "brackets" : ["\\{", "\\}"], "arcsWords" : ["note", "abox", "rbox", "box", "alt", "else", "opt", "break", "par", "seq", "strict", "neg", "critical", "ignore", "consider", "assert", "loop", "ref", "exc"], @@ -146,6 +149,9 @@ if (!!pConfig.operators && pStream.match(wordRegexp(pConfig.operators), true, true)) return "operator"; + if (!!pConfig.constants && pStream.match(wordRegexp(pConfig.constants), true, true)) + return "variable"; + /* attribute lists */ if (!pConfig.inAttributeList && !!pConfig.attributes && pStream.match(/\[/, true, true)) { pConfig.inAttributeList = true; diff --git a/mode/mscgen/mscgen_test.js b/mode/mscgen/mscgen_test.js index e319a3997e..956c5758e1 100644 --- a/mode/mscgen/mscgen_test.js +++ b/mode/mscgen/mscgen_test.js @@ -29,6 +29,14 @@ "[base alt loop opt ref else break par seq assert]" ); + MT("xù/ msgenny constants classify as 'base'", + "[base auto]" + ); + + MT("mscgen constants classify as 'variable'", + "[variable true]", "[variable false]", "[variable on]", "[variable off]" + ); + MT("mscgen options classify as keyword", "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]" ); @@ -63,7 +71,7 @@ MT("a typical program", "[comment # typical mscgen program]", "[keyword msc][base ][bracket {]", - "[keyword wordwraparcs][operator =][string \"true\"][base , ][keyword hscale][operator =][string \"0.8\"][keyword arcgradient][operator =][base 30;]", + "[keyword wordwraparcs][operator =][variable true][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30;]", "[base a][bracket [[][attribute label][operator =][string \"Entity A\"][bracket ]]][base ,]", "[base b][bracket [[][attribute label][operator =][string \"Entity B\"][bracket ]]][base ,]", "[base c][bracket [[][attribute label][operator =][string \"Entity C\"][bracket ]]][base ;]", diff --git a/mode/mscgen/msgenny_test.js b/mode/mscgen/msgenny_test.js index 80173de082..edf9da09af 100644 --- a/mode/mscgen/msgenny_test.js +++ b/mode/mscgen/msgenny_test.js @@ -23,6 +23,11 @@ "[keyword alt]","[keyword loop]","[keyword opt]","[keyword ref]","[keyword else]","[keyword break]","[keyword par]","[keyword seq]","[keyword assert]" ); + MT("xù/ msgenny constants classify as 'variable'", + "[variable auto]", + "[variable true]", "[variable false]", "[variable on]", "[variable off]" + ); + MT("mscgen options classify as keyword", "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]" ); @@ -56,7 +61,7 @@ MT("a typical program", "[comment # typical msgenny program]", - "[keyword wordwraparcs][operator =][string \"true\"][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30;]", + "[keyword wordwraparcs][operator =][variable true][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30;]", "[base a : ][string \"Entity A\"][base ,]", "[base b : Entity B,]", "[base c : Entity C;]", diff --git a/mode/mscgen/xu_test.js b/mode/mscgen/xu_test.js index f9a50f0af2..950aeca1f9 100644 --- a/mode/mscgen/xu_test.js +++ b/mode/mscgen/xu_test.js @@ -9,7 +9,13 @@ "[keyword msc][bracket {]", "[base ]", "[bracket }]" - ); + ); + + MT("empty chart", + "[keyword xu][bracket {]", + "[base ]", + "[bracket }]" + ); MT("comments", "[comment // a single line comment]", @@ -29,6 +35,11 @@ "[keyword alt]","[keyword loop]","[keyword opt]","[keyword ref]","[keyword else]","[keyword break]","[keyword par]","[keyword seq]","[keyword assert]" ); + MT("xù/ msgenny constants classify as 'variable'", + "[variable auto]", + "[variable true]", "[variable false]", "[variable on]", "[variable off]" + ); + MT("mscgen options classify as keyword", "[keyword hscale]", "[keyword width]", "[keyword arcgradient]", "[keyword wordwraparcs]" ); @@ -61,9 +72,9 @@ ); MT("a typical program", - "[comment # typical mscgen program]", - "[keyword msc][base ][bracket {]", - "[keyword wordwraparcs][operator =][string \"true\"][keyword hscale][operator =][string \"0.8\"][keyword arcgradient][operator =][base 30;]", + "[comment # typical xu program]", + "[keyword xu][base ][bracket {]", + "[keyword wordwraparcs][operator =][string \"true\"][base , ][keyword hscale][operator =][string \"0.8\"][base , ][keyword arcgradient][operator =][base 30, ][keyword width][operator =][variable auto][base ;]", "[base a][bracket [[][attribute label][operator =][string \"Entity A\"][bracket ]]][base ,]", "[base b][bracket [[][attribute label][operator =][string \"Entity B\"][bracket ]]][base ,]", "[base c][bracket [[][attribute label][operator =][string \"Entity C\"][bracket ]]][base ;]", From d34e94781fac24518a31a33b8d0980639ad8547e Mon Sep 17 00:00:00 2001 From: Steve Hoover Date: Mon, 24 Oct 2016 14:57:06 -0400 Subject: [PATCH 0095/1880] [verilog mode] Cleanup/rewrite. --- mode/verilog/verilog.js | 400 ++++++++++++++++++++++++++-------------- 1 file changed, 264 insertions(+), 136 deletions(-) diff --git a/mode/verilog/verilog.js b/mode/verilog/verilog.js index 7513dcede2..1f6ecb9f99 100644 --- a/mode/verilog/verilog.js +++ b/mode/verilog/verilog.js @@ -302,7 +302,13 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { state.indented = stream.indentation(); state.startOfLine = true; } - if (hooks.token) hooks.token(stream, state); + if (hooks.token) { + // Call hook, with an optional return value of a style to override verilog styling. + var style = hooks.token(stream, state); + if (style !== undefined) { + return style; + } + } if (stream.eatSpace()) return null; curPunc = null; curKeyword = null; @@ -375,163 +381,285 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { name: "verilog" }); - // TLVVerilog mode - var tlvchScopePrefixes = { - ">": "property", "->": "property", "-": "hr", "|": "link", "?$": "qualifier", "?*": "qualifier", - "@-": "variable-3", "@": "variable-3", "?": "qualifier" + + // TL-Verilog mode. + // See tl-x.org for language spec. + // See the mode in action at makerchip.com. + // Contact: steve.hoover@redwoodeda.com + + // TLV Identifier prefixes. + // Note that sign is not treated separately, so "+/-" versions of numeric identifiers + // are included. + var tlvIdentifierStyle = { + "|": "link", + ">": "property", // Should condition this off for > TLV 1c. + "$": "variable", + "$$": "variable", + "?$": "qualifier", + "?*": "qualifier", + "-": "hr", + "/": "property", + "/-": "property", + "@": "variable-3", + "@-": "variable-3", + "@++": "variable-3", + "@+=": "variable-3", + "@+=-": "variable-3", + "@--": "variable-3", + "@-=": "variable-3", + "%+": "tag", + "%-": "tag", + "%": "tag", + ">>": "tag", + "<<": "tag", + "<>": "tag", + "#": "tag", // Need to choose a style for this. + "^": "attribute", + "^^": "attribute", + "^!": "attribute", + "*": "variable-2", + "**": "variable-2", + "\\": "keyword", + "\"": "comment" }; - function tlvGenIndent(stream, state) { - var tlvindentUnit = 2; - var rtnIndent = -1, indentUnitRq = 0, curIndent = stream.indentation(); - switch (state.tlvCurCtlFlowChar) { - case "\\": - curIndent = 0; - break; - case "|": - if (state.tlvPrevPrevCtlFlowChar == "@") { - indentUnitRq = -2; //-2 new pipe rq after cur pipe - break; - } - if (tlvchScopePrefixes[state.tlvPrevCtlFlowChar]) - indentUnitRq = 1; // +1 new scope - break; - case "M": // m4 - if (state.tlvPrevPrevCtlFlowChar == "@") { - indentUnitRq = -2; //-2 new inst rq after pipe - break; - } - if (tlvchScopePrefixes[state.tlvPrevCtlFlowChar]) - indentUnitRq = 1; // +1 new scope - break; - case "@": - if (state.tlvPrevCtlFlowChar == "S") - indentUnitRq = -1; // new pipe stage after stmts - if (state.tlvPrevCtlFlowChar == "|") - indentUnitRq = 1; // 1st pipe stage - break; - case "S": - if (state.tlvPrevCtlFlowChar == "@") - indentUnitRq = 1; // flow in pipe stage - if (tlvchScopePrefixes[state.tlvPrevCtlFlowChar]) - indentUnitRq = 1; // +1 new scope - break; - } - var statementIndentUnit = tlvindentUnit; - rtnIndent = curIndent + (indentUnitRq*statementIndentUnit); - return rtnIndent >= 0 ? rtnIndent : curIndent; + // Lines starting with these characters define scope (result in indentation). + var tlvScopePrefixChars = { + "/": "beh-hier", + ">": "beh-hier", + "-": "phys-hier", + "|": "pipe", + "?": "when", + "@": "stage", + "\\": "keyword" + }; + var tlvIndentUnit = 3; + var tlvTrackStatements = false; + var tlvIdentMatch = /^([~!@#\$%\^&\*-\+=\?\/\\\|'"<>]+)([\d\w_]*)/; // Matches an identifiere. + // Note that ':' is excluded, because of it's use in [:]. + var tlvFirstLevelIndentMatch = /^[! ] /; + var tlvLineIndentationMatch = /^[! ] */; + var tlvCommentMatch = /^\/[\/\*]/; + + + // Returns a style specific to the scope at the given indentation column. + // Type is one of: "indent", "scope-ident", "before-scope-ident". + function tlvScopeStyle(state, indentation, type) { + // Begin scope. + var depth = indentation / tlvIndentUnit; // TODO: Pass this in instead. + return "tlv-" + state.tlvIndentationStyle[depth] + "-" + type; + } + + // Return true if the next thing in the stream is an identifier with a mnemonic. + function tlvIdentNext(stream) { + var match; + return (match = stream.match(tlvIdentMatch, false)) && match[2].length > 0; } CodeMirror.defineMIME("text/x-tlv", { name: "verilog", + hooks: { - "\\": function(stream, state) { - var vxIndent = 0, style = false; - var curPunc = stream.string; - if ((stream.sol()) && ((/\\SV/.test(stream.string)) || (/\\TLV/.test(stream.string)))) { - curPunc = (/\\TLV_version/.test(stream.string)) - ? "\\TLV_version" : stream.string; - stream.skipToEnd(); - if (curPunc == "\\SV" && state.vxCodeActive) {state.vxCodeActive = false;}; - if ((/\\TLV/.test(curPunc) && !state.vxCodeActive) - || (curPunc=="\\TLV_version" && state.vxCodeActive)) {state.vxCodeActive = true;}; - style = "keyword"; - state.tlvCurCtlFlowChar = state.tlvPrevPrevCtlFlowChar - = state.tlvPrevCtlFlowChar = ""; - if (state.vxCodeActive == true) { - state.tlvCurCtlFlowChar = "\\"; - vxIndent = tlvGenIndent(stream, state); + + electricInput: false, + + + // Return undefined for verilog tokenizing, or style for TLV token (null not used). + // Standard CM styles are used for most formatting, but some TL-Verilog-specific highlighting + // can be enabled with the definition of cm-tlv-* styles, including highlighting for: + // - M4 tokens + // - TLV scope indentation + // - Statement delimitation (enabled by tlvTrackStatements) + token: function(stream, state) { + var style = undefined; + var match; // Return value of pattern matches. + + // Set highlighting mode based on code region (TLV or SV). + if (stream.sol() && ! state.tlvInBlockComment) { + // Process region. + if (stream.peek() == '\\') { + style = "def"; + stream.skipToEnd(); + if (stream.string.match(/\\SV/)) { + state.tlvCodeActive = false; + } else if (stream.string.match(/\\TLV/)){ + state.tlvCodeActive = true; + } + } + // Correct indentation in the face of a line prefix char. + if (state.tlvCodeActive && stream.pos == 0 && + (state.indented == 0) && (match = stream.match(tlvLineIndentationMatch, false))) { + state.indented = match[0].length; + } + + // Compute indentation state: + // o Required indentation on next line + // o Indentation scope styles + var indented = state.indented; + var depth = indented / tlvIndentUnit; + if (depth <= state.tlvIndentationStyle.length) { + // not deeper than current scope + + var blankline = stream.string.length == indented; + var chPos = depth * tlvIndentUnit; + if (chPos < stream.string.length) { + var bodyString = stream.string.slice(chPos); + var ch = bodyString[0]; + if (tlvScopePrefixChars[ch] && ((match = bodyString.match(tlvIdentMatch)) && + tlvIdentifierStyle[match[1]])) { + // this line begins scope (except non-region keyword identifiers, which are statements themselves) + if (!(ch == "\\" && chPos > 0)) { + indented += tlvIndentUnit; + state.tlvIndentationStyle[depth] = tlvScopePrefixChars[ch]; + if (tlvTrackStatements) {state.statementComment = false;} + depth++; + } + } + } + // Clear out deeper indentation levels unless line is blank. + if (!blankline) { + while (state.tlvIndentationStyle.length > depth) { + state.tlvIndentationStyle.pop(); + } + } } - state.vxIndentRq = vxIndent; } - return style; - }, - tokenBase: function(stream, state) { - var vxIndent = 0, style = false; - var tlvisOperatorChar = /[\[\]=:]/; - var tlvkpScopePrefixs = { - "**":"variable-2", "*":"variable-2", "$$":"variable", "$":"variable", - "^^":"attribute", "^":"attribute"}; - var ch = stream.peek(); - var vxCurCtlFlowCharValueAtStart = state.tlvCurCtlFlowChar; - if (state.vxCodeActive == true) { - if (/[\[\]{}\(\);\:]/.test(ch)) { - // bypass nesting and 1 char punc - style = "meta"; - stream.next(); - } else if (ch == "/") { - stream.next(); - if (stream.eat("/")) { + + if (state.tlvCodeActive) { + // Highlight as TLV. + + var beginStatement = false; + if (tlvTrackStatements) { + // This starts a statement if the position is at the scope level + // and we're not within a statement leading comment. + beginStatement = + (stream.peek() != " ") && // not a space + (style === undefined) && // not a region identifier + !state.tlvInBlockComment && // not in block comment + //!stream.match(tlvCommentMatch, false) && // not comment start + (stream.column() == state.tlvIndentationStyle.length * tlvIndentUnit); // at scope level + if (beginStatement) { + if (state.statementComment) { + // statement already started by comment + beginStatement = false; + } + state.statementComment = + stream.match(tlvCommentMatch, false); // comment start + } + } + + var match; + if (style !== undefined) { + // Region line. + style += " " + tlvScopeStyle(state, 0, "scope-ident") + } else if (((stream.pos / tlvIndentUnit) < state.tlvIndentationStyle.length) && + (match = stream.match(stream.sol() ? tlvFirstLevelIndentMatch : /^ /))) { + // Indentation + style = // make this style distinct from the previous one to prevent + // codemirror from combining spans + "tlv-indent-" + (((stream.pos % 2) == 0) ? "even" : "odd") + + // and style it + " " + tlvScopeStyle(state, stream.pos - tlvIndentUnit, "indent"); + // Style the line prefix character. + if (match[0].charAt(0) == "!") { + style += " tlv-alert-line-prefix"; + } + // Place a class before a scope identifier. + if (tlvIdentNext(stream)) { + style += " " + tlvScopeStyle(state, stream.pos, "before-scope-ident"); + } + } else if (state.tlvInBlockComment) { + // In a block comment. + if (stream.match(/^.*?\*\//)) { + // Exit block comment. + state.tlvInBlockComment = false; + if (tlvTrackStatements && !stream.eol()) { + // Anything after comment is assumed to be real statement content. + state.statementComment = false; + } + } else { + stream.skipToEnd(); + } + style = "comment"; + } else if ((match = stream.match(tlvCommentMatch)) && !state.tlvInBlockComment) { + // Start comment. + if (match[0] == "//") { + // Line comment. stream.skipToEnd(); - style = "comment"; - state.tlvCurCtlFlowChar = "S"; } else { - stream.backUp(1); + // Block comment. + state.tlvInBlockComment = true; } - } else if (ch == "@") { - // pipeline stage - style = tlvchScopePrefixes[ch]; - state.tlvCurCtlFlowChar = "@"; - stream.next(); - stream.eatWhile(/[\w\$_]/); - } else if (stream.match(/\b[mM]4+/, true)) { // match: function(pattern, consume, caseInsensitive) - // m4 pre proc - stream.skipTo("("); - style = "def"; - state.tlvCurCtlFlowChar = "M"; - } else if (ch == "!" && stream.sol()) { - // v stmt in tlv region - // state.tlvCurCtlFlowChar = "S"; style = "comment"; + } else if (match = stream.match(tlvIdentMatch)) { + // looks like an identifier (or identifier prefix) + var prefix = match[1]; + var mnemonic = match[2]; + if (// is identifier prefix + (prefix in tlvIdentifierStyle) && + // has mnemonic or we're at the end of the line (maybe it hasn't been typed yet) + (mnemonic.length > 0 || stream.eol())) { + style = tlvIdentifierStyle[prefix]; + if (stream.column() == state.indented) { + // Begin scope. + style += " " + tlvScopeStyle(state, stream.column(), "scope-ident") + } + } else { + // Just swallow one character and try again. + // This enables subsequent identifier match with preceding symbol character, which + // is legal within a statement. (Eg, !$reset). It also enables detection of + // comment start with preceding symbols. + stream.backUp(stream.current().length - 1); + style = "tlv-default"; + } + } else if (stream.match(/^\t+/)) { + // Highlight tabs, which are illegal. + style = "tlv-tab"; + } else if (stream.match(/^[\[\]{}\(\);\:]+/)) { + // [:], (), {}, ;. + style = "meta"; + } else if (match = stream.match(/^[mM]4([\+_])?[\w\d_]*/)) { + // m4 pre proc + style = (match[1] == "+") ? "tlv-m4-plus" : "tlv-m4"; + } else if (stream.match(/^ +/)){ + // Skip over spaces. + if (stream.eol()) { + // Trailing spaces. + style = "error"; + } else { + // Non-trailing spaces. + style = "tlv-default"; + } + } else if (stream.match(/^[\w\d_]+/)) { + // alpha-numeric token. + style = "number"; + } else { + // Eat the next char w/ no formatting. stream.next(); - } else if (tlvisOperatorChar.test(ch)) { - // operators - stream.eatWhile(tlvisOperatorChar); - style = "operator"; - } else if (ch == "#") { - // phy hier - state.tlvCurCtlFlowChar = (state.tlvCurCtlFlowChar == "") - ? ch : state.tlvCurCtlFlowChar; - stream.next(); - stream.eatWhile(/[+-]\d/); - style = "tag"; - } else if (tlvkpScopePrefixs.propertyIsEnumerable(ch)) { - // special TLV operators - style = tlvkpScopePrefixs[ch]; - state.tlvCurCtlFlowChar = state.tlvCurCtlFlowChar == "" ? "S" : state.tlvCurCtlFlowChar; // stmt - stream.next(); - stream.match(/[a-zA-Z_0-9]+/); - } else if (style = tlvchScopePrefixes[ch] || false) { - // special TLV operators - state.tlvCurCtlFlowChar = state.tlvCurCtlFlowChar == "" ? ch : state.tlvCurCtlFlowChar; - stream.next(); - stream.match(/[a-zA-Z_0-9]+/); + style = "tlv-default"; + } + if (beginStatement) { + style += " tlv-statement"; } - if (state.tlvCurCtlFlowChar != vxCurCtlFlowCharValueAtStart) { // flow change - vxIndent = tlvGenIndent(stream, state); - state.vxIndentRq = vxIndent; + } else { + if (stream.match(/^[mM]4([\w\d_]*)/)) { + // m4 pre proc + style = "tlv-m4"; } } return style; }, - token: function(stream, state) { - if (state.vxCodeActive == true && stream.sol() && state.tlvCurCtlFlowChar != "") { - state.tlvPrevPrevCtlFlowChar = state.tlvPrevCtlFlowChar; - state.tlvPrevCtlFlowChar = state.tlvCurCtlFlowChar; - state.tlvCurCtlFlowChar = ""; - } - }, - indent: function(state) { - return (state.vxCodeActive == true) ? state.vxIndentRq : -1; - }, + startState: function(state) { - state.tlvCurCtlFlowChar = ""; - state.tlvPrevCtlFlowChar = ""; - state.tlvPrevPrevCtlFlowChar = ""; - state.vxCodeActive = true; - state.vxIndentRq = 0; + state.tlvIndentationStyle = []; // Styles to use for each level of indentation. + state.tlvCodeActive = true; // True when we're in a TLV region (and at beginning of file). + state.tlvInBlockComment = false; // True inside /**/ comment. + if (tlvTrackStatements) { + state.statementComment = false; // True inside a statement's header comment. + } } + } }); }); From 5105da7fcd5a98dbaf276b769ce8581daac84121 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 1 Nov 2016 11:04:58 +0100 Subject: [PATCH 0096/1880] [merge addon] Fix bug in chunk-aligning algorithm Closes #4353 --- addon/merge/merge.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index 72526d0179..e7772ace66 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -343,11 +343,12 @@ j = -1; break; } else if (align[1] > chunk.editTo) { + j-- break; } } if (j > -1) - linesToAlign.splice(j - 1, 0, [getMatchingOrigLine(chunk.editTo, dv.chunks), chunk.editTo, chunk.origTo]); + linesToAlign.splice(j, 0, [getMatchingOrigLine(chunk.editTo, dv.chunks), chunk.editTo, chunk.origTo]); } } return linesToAlign; From 6d3a7457d1d9b6c4165a5b066be6e1da99776e2b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 1 Nov 2016 11:07:10 +0100 Subject: [PATCH 0097/1880] [merge addon] Fix corner case in alignable-chunk sorting Issue #4353 --- addon/merge/merge.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index e7772ace66..1d7a5cccb0 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -340,14 +340,14 @@ for (var j = 0; j < linesToAlign.length; j++) { var align = linesToAlign[j]; if (align[1] == chunk.editTo) { - j = -1; + j = -2; break; } else if (align[1] > chunk.editTo) { j-- break; } } - if (j > -1) + if (j > -2) linesToAlign.splice(j, 0, [getMatchingOrigLine(chunk.editTo, dv.chunks), chunk.editTo, chunk.origTo]); } } From ea796dad693cc1f7c7d7f4628a1ee4953ae6b3db Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 2 Nov 2016 10:07:05 +0100 Subject: [PATCH 0098/1880] [merge addon] Fix sorted insertion in aligned line set (again) Issue #4353 --- addon/merge/merge.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index 1d7a5cccb0..9bd086580b 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -335,20 +335,14 @@ linesToAlign.push([chunk.origTo, chunk.editTo, other ? getMatchingOrigLine(chunk.editTo, other.chunks) : null]); } if (other) { - for (var i = 0; i < other.chunks.length; i++) { + chunkLoop: for (var i = 0; i < other.chunks.length; i++) { var chunk = other.chunks[i]; for (var j = 0; j < linesToAlign.length; j++) { - var align = linesToAlign[j]; - if (align[1] == chunk.editTo) { - j = -2; - break; - } else if (align[1] > chunk.editTo) { - j-- - break; - } + var diff = linesToAlign[j][1] - chunk.editTo; + if (diff == 0) continue chunkLoop + if (diff > 0) break; } - if (j > -2) - linesToAlign.splice(j, 0, [getMatchingOrigLine(chunk.editTo, dv.chunks), chunk.editTo, chunk.origTo]); + linesToAlign.splice(j, 0, [getMatchingOrigLine(chunk.editTo, dv.chunks), chunk.editTo, chunk.origTo]); } } return linesToAlign; From 2466392a929761bd61e85cbea86cd533ac84eef4 Mon Sep 17 00:00:00 2001 From: Erik Welander Date: Tue, 1 Nov 2016 22:30:50 -0700 Subject: [PATCH 0099/1880] [rulers addon] Draw rulers all the way when scrollPastEnd is on. --- addon/display/rulers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/display/rulers.js b/addon/display/rulers.js index 730054473a..151cc8205f 100644 --- a/addon/display/rulers.js +++ b/addon/display/rulers.js @@ -13,12 +13,12 @@ CodeMirror.defineOption("rulers", false, function(cm, val) { if (cm.state.rulerDiv) { - cm.display.lineSpace.removeChild(cm.state.rulerDiv) + cm.state.rulerDiv.parentElement.removeChild(cm.state.rulerDiv) cm.state.rulerDiv = null cm.off("refresh", drawRulers) } if (val && val.length) { - cm.state.rulerDiv = cm.display.lineSpace.insertBefore(document.createElement("div"), cm.display.cursorDiv) + cm.state.rulerDiv = cm.display.lineSpace.parentElement.insertBefore(document.createElement("div"), cm.display.lineSpace) cm.state.rulerDiv.className = "CodeMirror-rulers" drawRulers(cm) cm.on("refresh", drawRulers) From f5e211fa49315e0c0da212dffc275d769609d1ab Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 2 Nov 2016 11:08:17 +0100 Subject: [PATCH 0100/1880] Add an includeWidgets argument to heightAtLine And use it in the merge addon to get the proper offsets for merge buttons Issue #4364 --- addon/merge/merge.js | 8 ++++---- doc/manual.html | 7 +++++-- src/edit/methods.js | 4 ++-- src/measurement/position_measurement.js | 4 ++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index 9bd086580b..0c54a66464 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -408,13 +408,13 @@ function drawConnectorsForChunk(dv, chunk, sTopOrig, sTopEdit, w) { var flip = dv.type == "left"; - var top = dv.orig.heightAtLine(chunk.origFrom, "local") - sTopOrig; + var top = dv.orig.heightAtLine(chunk.origFrom, "local", true) - sTopOrig; if (dv.svg) { var topLpx = top; - var topRpx = dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit; + var topRpx = dv.edit.heightAtLine(chunk.editFrom, "local", true) - sTopEdit; if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; } - var botLpx = dv.orig.heightAtLine(chunk.origTo, "local") - sTopOrig; - var botRpx = dv.edit.heightAtLine(chunk.editTo, "local") - sTopEdit; + var botLpx = dv.orig.heightAtLine(chunk.origTo, "local", true) - sTopOrig; + var botRpx = dv.edit.heightAtLine(chunk.editTo, "local", true) - sTopEdit; if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; } var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx; var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx; diff --git a/doc/manual.html b/doc/manual.html index 6ef27689ce..e74ec36200 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1863,13 +1863,16 @@

    Sizing, scrolling and positioning methods

    height. mode can be one of the same strings that coordsChar accepts. -
    cm.heightAtLine(line: integer|LineHandle, ?mode: string) → number
    +
    cm.heightAtLine(line: integer|LineHandle, ?mode: string, ?includeWidgets: bool) → number
    Computes the height of the top of a line, in the coordinate system specified by mode (see coordsChar), which defaults to "page". When a line below the bottom of the document is specified, the returned value is the bottom of - the last line in the document.
    + the last line in the document. By default, the position of the + actual text is returned. If `includeWidgets` is true and the + line has line widgets, the position above the first line widget + is returned.
    cm.defaultTextHeight() → number
    Returns the line height of the default font for the editor.
    cm.defaultCharWidth() → number
    diff --git a/src/edit/methods.js b/src/edit/methods.js index b63f9bd26b..8aa2a437b0 100644 --- a/src/edit/methods.js +++ b/src/edit/methods.js @@ -201,7 +201,7 @@ export default function(CodeMirror) { height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top return lineAtHeight(this.doc, height + this.display.viewOffset) }, - heightAtLine: function(line, mode) { + heightAtLine: function(line, mode, includeWidgets) { let end = false, lineObj if (typeof line == "number") { let last = this.doc.first + this.doc.size - 1 @@ -211,7 +211,7 @@ export default function(CodeMirror) { } else { lineObj = line } - return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top + + return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets).top + (end ? this.doc.height - heightAtLine(lineObj) : 0) }, diff --git a/src/measurement/position_measurement.js b/src/measurement/position_measurement.js index 4ece080e49..f62672c494 100644 --- a/src/measurement/position_measurement.js +++ b/src/measurement/position_measurement.js @@ -287,8 +287,8 @@ function pageScrollY() { return window.pageYOffset || (document.documentElement // coordinates into another coordinate system. Context may be one of // "line", "div" (display.lineDiv), "local"./null (editor), "window", // or "page". -export function intoCoordSystem(cm, lineObj, rect, context) { - if (lineObj.widgets) for (let i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { +export function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) { + if (!includeWidgets && lineObj.widgets) for (let i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { let size = widgetHeight(lineObj.widgets[i]) rect.top += size; rect.bottom += size } From e6ec325be0535893137b26545ec14b1c411fb16d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 2 Nov 2016 11:15:32 +0100 Subject: [PATCH 0101/1880] Make sure initial connectors are drawn after aligning/collapsing So that their vertical offsets actually match the position of the corresponding lines. Issue #4364 --- addon/merge/merge.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index 0c54a66464..f0d746449d 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -49,6 +49,8 @@ this.diffOutOfDate = this.dealigned = false; this.showDifferences = options.showDifferences !== false; + }, + registerEvents: function() { this.forceUpdate = registerUpdate(this); setScrollLock(this, true, false); registerScroll(this); @@ -91,10 +93,11 @@ updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes); updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes); } - makeConnections(dv); if (dv.mv.options.connect == "align") alignChunks(dv); + makeConnections(dv); + updating = false; } function setDealign(fast) { @@ -489,7 +492,6 @@ if (left) left.init(leftPane, origLeft, options); if (right) right.init(rightPane, origRight, options); - if (options.collapseIdentical) this.editor().operation(function() { collapseIdenticalStretches(self, options.collapseIdentical); @@ -498,6 +500,9 @@ this.aligners = []; alignChunks(this.left || this.right, true); } + if (left) left.registerEvents() + if (right) right.registerEvents() + var onResize = function() { if (left) makeConnections(left); From 73c5bf098ffff029a892a91d91bb8249d40c635f Mon Sep 17 00:00:00 2001 From: Steve Hoover Date: Thu, 3 Nov 2016 10:37:00 -0400 Subject: [PATCH 0102/1880] [verilog mode] Fixed inadvertent removal of TL-Verilog indent(..) function. --- mode/verilog/verilog.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/mode/verilog/verilog.js b/mode/verilog/verilog.js index 1f6ecb9f99..460cdb3b1c 100644 --- a/mode/verilog/verilog.js +++ b/mode/verilog/verilog.js @@ -494,7 +494,7 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { } // Compute indentation state: - // o Required indentation on next line + // o Auto indentation on next line // o Indentation scope styles var indented = state.indented; var depth = indented / tlvIndentUnit; @@ -508,9 +508,12 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { var ch = bodyString[0]; if (tlvScopePrefixChars[ch] && ((match = bodyString.match(tlvIdentMatch)) && tlvIdentifierStyle[match[1]])) { - // this line begins scope (except non-region keyword identifiers, which are statements themselves) + // This line begins scope. + // Next line gets indented one level. + indented += tlvIndentUnit; + // Style the next level of indentation (except non-region keyword identifiers, + // which are statements themselves) if (!(ch == "\\" && chPos > 0)) { - indented += tlvIndentUnit; state.tlvIndentationStyle[depth] = tlvScopePrefixChars[ch]; if (tlvTrackStatements) {state.statementComment = false;} depth++; @@ -524,6 +527,8 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { } } } + // Set next level of indentation. + state.tlvNextIndent = indented; } if (state.tlvCodeActive) { @@ -651,9 +656,14 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { return style; }, + indent: function(state) { + return (state.tlvCodeActive == true) ? state.tlvNextIndent : -1; + }, + startState: function(state) { state.tlvIndentationStyle = []; // Styles to use for each level of indentation. state.tlvCodeActive = true; // True when we're in a TLV region (and at beginning of file). + state.tlvNextIndent = -1; // The number of spaces to autoindent the next line if tlvCodeActive. state.tlvInBlockComment = false; // True inside /**/ comment. if (tlvTrackStatements) { state.statementComment = false; // True inside a statement's header comment. From dd10e2eef8a73349b3a8535508b3c878967a3215 Mon Sep 17 00:00:00 2001 From: pabloferz Date: Fri, 5 Feb 2016 12:09:26 +0100 Subject: [PATCH 0103/1880] [julia mode] Fixes for julia 0.5 --- mode/julia/julia.js | 217 ++++++++++++++++++++++++-------------------- 1 file changed, 119 insertions(+), 98 deletions(-) diff --git a/mode/julia/julia.js b/mode/julia/julia.js index 004de4431c..6c40bf20ee 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -11,51 +11,62 @@ })(function(CodeMirror) { "use strict"; -CodeMirror.defineMode("julia", function(_conf, parserConf) { - var ERRORCLASS = 'error'; - +CodeMirror.defineMode("julia", function(config, parserConf) { function wordRegexp(words, end) { - if (typeof end === 'undefined') { end = "\\b"; } + if (typeof end === "undefined") { end = "\\b"; } return new RegExp("^((" + words.join(")|(") + "))" + end); } var octChar = "\\\\[0-7]{1,3}"; var hexChar = "\\\\x[A-Fa-f0-9]{1,2}"; - var specialChar = "\\\\[abfnrtv0%?'\"\\\\]"; - var singleChar = "([^\\u0027\\u005C\\uD800-\\uDFFF]|[\\uD800-\\uDFFF][\\uDC00-\\uDFFF])"; - var operators = parserConf.operators || /^\.?[|&^\\%*+\-<>!=\/]=?|\?|~|:|\$|\.[<>]|<<=?|>>>?=?|\.[<>=]=|->?|\/\/|\bin\b(?!\()|[\u2208\u2209](?!\()/; + var sChar = "\\\\[abefnrtv0%?'\"\\\\]"; + var uChar = "([^\\u0027\\u005C\\uD800-\\uDFFF]|[\\uD800-\\uDFFF][\\uDC00-\\uDFFF])"; + + var operators = parserConf.operators || wordRegexp([ + "\\.?[\\\\%*+\\-<>!=\\/^]=?", "\\.?[|&\\u00F7\\u2260\\u2264\\u2265]", + "\\u00D7", "\\u2208", "\\u2209", "\\u220B", "\\u220C", "\\u2229", + "\\u222A", "\\u2286", "\\u2288", "\\u228A", "\\u22c5", "\\?", "~", ":", + "\\$", "\\.[<>]", "<<=?", ">>>?=?", "\\.[<>=]=", "->?", "\\/\\/", "=>", + "<:", "\\bin\\b(?!\\()"], ""); var delimiters = parserConf.delimiters || /^[;,()[\]{}]/; var identifiers = parserConf.identifiers || /^[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/; - var charsList = [octChar, hexChar, specialChar, singleChar]; - var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif", "try", "finally", "catch", "do"]; - 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']; - var builtinList = ['true', 'false', 'nothing', 'NaN', 'Inf']; - - //var stringPrefixes = new RegExp("^[br]?('|\")") - var stringPrefixes = /^(`|"{3}|([brv]?"))/; - var chars = wordRegexp(charsList, "'"); - var keywords = wordRegexp(keywordList); - var builtins = wordRegexp(builtinList); - var openers = wordRegexp(blockOpeners); - var closers = wordRegexp(blockClosers); + + var chars = wordRegexp([octChar, hexChar, sChar, uChar], "'"); + var openers = wordRegexp(["begin", "function", "type", "immutable", "let", + "macro", "for", "while", "quote", "if", "else", "elseif", "try", + "finally", "catch", "do"]); + var closers = wordRegexp(["end", "else", "elseif", "catch", "finally"]); + var keywords = wordRegexp(["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"]); + var builtins = wordRegexp(["true", "false", "nothing", "NaN", "Inf"]); + var macro = /^@[_A-Za-z][\w]*/; var symbol = /^:[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/; - var typeAnnotation = /^::[^,;"{()=$\s]+({[^}]*}+)*/; + var stringPrefixes = /^(`|"{3}|([_A-Za-z\u00A1-\uFFFF]*"))/; function inArray(state) { - var ch = currentScope(state); - if (ch == '[') { + return inGenerator(state, '[') + } + + function inGenerator(state, bracket) { + var curr = currentScope(state), + prev = currentScope(state, 1); + if (typeof(bracket) === "undefined") { bracket = '('; } + if (curr === bracket || (prev === bracket && curr === "for")) { return true; } return false; } - function currentScope(state) { - if (state.scopes.length == 0) { + function currentScope(state, n) { + if (typeof(n) === "undefined") { n = 0; } + if (state.scopes.length <= n) { return null; } - return state.scopes[state.scopes.length - 1]; + return state.scopes[state.scopes.length - (n + 1)]; } // tokenizers @@ -72,14 +83,15 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { leavingExpr = false; } state.leavingExpr = false; + if (leavingExpr) { if (stream.match(/^'+/)) { - return 'operator'; + return "operator"; } } if (stream.match(/^\.{2,3}/)) { - return 'operator'; + return "operator"; } if (stream.eatSpace()) { @@ -91,7 +103,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { // Handle single line comments if (ch === '#') { stream.skipToEnd(); - return 'comment'; + return "comment"; } if (ch === '[') { @@ -104,36 +116,55 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { var scope = currentScope(state); - if (scope == '[' && ch === ']') { + if (inArray(state) && ch === ']') { + if (scope === "for") { state.scopes.pop(); } state.scopes.pop(); state.leavingExpr = true; } - if (scope == '(' && ch === ')') { + if (inGenerator(state) && ch === ')') { + if (scope === "for") { state.scopes.pop(); } state.scopes.pop(); state.leavingExpr = true; } var match; - if (!inArray(state) && (match=stream.match(openers, false))) { - state.scopes.push(match); + if (match = stream.match(openers, false)) { + state.scopes.push(match[0]); } - if (!inArray(state) && stream.match(closers, false)) { + if (stream.match(closers, false)) { state.scopes.pop(); } if (inArray(state)) { - if (state.lastToken == 'end' && stream.match(/^:/)) { - return 'operator'; + if (state.lastToken == "end" && stream.match(/^:/)) { + return "operator"; } if (stream.match(/^end/)) { - return 'number'; + return "number"; } } - if (stream.match(/^=>/)) { - return 'operator'; + // Handle type annotations + if (stream.match(/^::(?![:\$])/)) { + state.tokenize = tokenAnnotation; + return state.tokenize(stream, state); + } + + // Handle symbols + if (!leavingExpr && stream.match(symbol) || stream.match(/:\./)) { + return "builtin"; + } + + // Handle parametric types + if (stream.match(/^{[^}]*}(?=\()/)) { + return "builtin"; + } + + // Handle operators and Delimiters + if (stream.match(operators)) { + return "operator"; } // Handle Number Literals @@ -156,33 +187,10 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { // Integer literals may be "long" stream.match(imMatcher); state.leavingExpr = true; - return 'number'; + return "number"; } } - if (stream.match(/^<:/)) { - return 'operator'; - } - - if (stream.match(typeAnnotation)) { - return 'builtin'; - } - - // Handle symbols - if (!leavingExpr && stream.match(symbol) || stream.match(/:\./)) { - return 'builtin'; - } - - // Handle parametric types - if (stream.match(/^{[^}]*}(?=\()/)) { - return 'builtin'; - } - - // Handle operators and Delimiters - if (stream.match(operators)) { - return 'operator'; - } - // Handle Chars if (stream.match(/^'/)) { state.tokenize = tokenChar; @@ -196,7 +204,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { } if (stream.match(macro)) { - return 'meta'; + return "meta"; } if (stream.match(delimiters)) { @@ -204,38 +212,36 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { } if (stream.match(keywords)) { - return 'keyword'; + return "keyword"; } if (stream.match(builtins)) { - return 'builtin'; + return "builtin"; } - var isDefinition = state.isDefinition || - state.lastToken == 'function' || - state.lastToken == 'macro' || - state.lastToken == 'type' || - state.lastToken == 'immutable'; + var isDefinition = state.isDefinition || state.lastToken == "function" || + state.lastToken == "macro" || state.lastToken == "type" || + state.lastToken == "immutable"; if (stream.match(identifiers)) { if (isDefinition) { if (stream.peek() === '.') { state.isDefinition = true; - return 'variable'; + return "variable"; } state.isDefinition = false; - return 'def'; + return "def"; } if (stream.match(/^({[^}]*})*\(/, false)) { return callOrDef(stream, state); } state.leavingExpr = true; - return 'variable'; + return "variable"; } // Handle non-detected items stream.next(); - return ERRORCLASS; + return "error"; } function callOrDef(stream, state) { @@ -255,8 +261,8 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { state.firstParenPos = -1; state.charsAdvanced = 0; if (isDefinition) - return 'def'; - return 'builtin'; + return "def"; + return "builtin"; } } // Unfortunately javascript does not support multiline strings, so we have @@ -268,25 +274,40 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { state.scopes.pop(); state.firstParenPos = -1; state.charsAdvanced = 0; - return 'builtin'; + return "builtin"; } state.charsAdvanced += stream.match(/^([^()]*)/)[1].length; return callOrDef(stream, state); } + function tokenAnnotation(stream, state) { + stream.match(/.*?(?=,|;|{|}|\(|\)|=|$|\s)/); + if (stream.match(/^{/)) { + state.nestedLevels++; + } else if (stream.match(/^}/)) { + state.nestedLevels--; + } + if (state.nestedLevels > 0) { + stream.match(/.*?(?={|})/); + } else if (state.nestedLevels == 0) { + state.tokenize = tokenBase; + } + return "builtin"; + } + function tokenComment(stream, state) { if (stream.match(/^#=/)) { - state.weakScopes++; + state.nestedLevels++; } if (!stream.match(/.*?(?=(#=|=#))/)) { stream.skipToEnd(); } if (stream.match(/^=#/)) { - state.weakScopes--; - if (state.weakScopes == 0) + state.nestedLevels--; + if (state.nestedLevels == 0) state.tokenize = tokenBase; } - return 'comment'; + return "comment"; } function tokenChar(stream, state) { @@ -309,33 +330,29 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { if (isChar) { state.leavingExpr = true; state.tokenize = tokenBase; - return 'string'; + return "string"; } if (!stream.match(/^[^']+(?=')/)) { stream.skipToEnd(); } if (stream.match(/^'/)) { state.tokenize = tokenBase; } - return ERRORCLASS; + return "error"; } function tokenStringFactory(delimiter) { - while ('bruv'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) { - delimiter = delimiter.substr(1); - } - var OUTCLASS = 'string'; - + delimiter = (delimiter === '`' || delimiter === '"""') ? delimiter : '"' function tokenString(stream, state) { while (!stream.eol()) { - stream.eatWhile(/[^"\\]/); + stream.eatWhile(/[^\\"]/); if (stream.eat('\\')) { stream.next(); } else if (stream.match(delimiter)) { state.tokenize = tokenBase; state.leavingExpr = true; - return OUTCLASS; + return "string"; } else { - stream.eat(/["]/); + stream.eat('"'); } } - return OUTCLASS; + return "string"; } tokenString.isString = true; return tokenString; @@ -346,10 +363,10 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { return { tokenize: tokenBase, scopes: [], - weakScopes: 0, lastToken: null, leavingExpr: false, isDefinition: false, + nestedLevels: 0, charsAdvanced: 0, firstParenPos: -1 }; @@ -366,20 +383,24 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { // Handle '.' connected identifiers if (current === '.') { style = stream.match(identifiers, false) || stream.match(macro, false) || - stream.match(/\(/, false) ? 'operator' : ERRORCLASS; + stream.match(/\(/, false) ? "operator" : "error"; } return style; }, indent: function(state, textAfter) { var delta = 0; - if (textAfter == "]" || textAfter == ")" || textAfter == "end" || textAfter == "else" || textAfter == "elseif" || textAfter == "catch" || textAfter == "finally") { + if ( textAfter === ']' || textAfter === ')' || textAfter === "end" || + textAfter === "else" || textAfter === "catch" || + textAfter === "finally" ) { delta = -1; } - return (state.scopes.length + delta) * _conf.indentUnit; + return (state.scopes.length + delta) * config.indentUnit; }, - electricInput: /(end|else(if)?|catch|finally)$/, + electricInput: /\b(end|else|catch|finally)\b/, + blockCommentStart: "#=", + blockCommentEnd: "=#", lineComment: "#", fold: "indent" }; From 4a1ed91341378942e49a4ca1d978d99eff4dd33e Mon Sep 17 00:00:00 2001 From: Jim Avery Date: Thu, 3 Nov 2016 16:38:14 -0500 Subject: [PATCH 0104/1880] [swift mode] Various improvements - Added for as a defining keyword - Added new types and operators - Fixed numbers so basic integers are represented - Identifiers can now be surrounded with backticks - Properties and #/@ instructions are now distinct, with the latter represented as a builtin type - Properties are now matched before punctuation. Code can now fold. - Remove the regexp checking as that syntax does not currently exist in Swift - Added tests --- mode/swift/swift.js | 39 +++++++----- mode/swift/test.js | 149 ++++++++++++++++++++++++++++++++++++++++++++ test/index.html | 2 + 3 files changed, 176 insertions(+), 14 deletions(-) create mode 100644 mode/swift/test.js diff --git a/mode/swift/swift.js b/mode/swift/swift.js index 9dcd822e91..329470664c 100644 --- a/mode/swift/swift.js +++ b/mode/swift/swift.js @@ -26,14 +26,20 @@ "defer","return","inout","mutating","nonmutating","catch","do","rethrows","throw","throws","try","didSet","get","set","willSet", "assignment","associativity","infix","left","none","operator","postfix","precedence","precedencegroup","prefix","right", "Any","AnyObject","Type","dynamicType","Self","Protocol","__COLUMN__","__FILE__","__FUNCTION__","__LINE__"]) - var definingKeywords = wordSet(["var","let","class","enum","extension","import","protocol","struct","func","typealias","associatedtype"]) + var definingKeywords = wordSet(["var","let","class","enum","extension","import","protocol","struct","func","typealias","associatedtype","for"]) var atoms = wordSet(["true","false","nil","self","super","_"]) - var types = wordSet(["Array","Bool","Dictionary","Double","Float","Int","Never","Optional","String","Void"]) - var operators = "+-/*%=|&<>" - var punc = ";,.(){}[]" - var number = /^-?(?:(?:[\d_]+\.[_\d]*|\.[_\d]+|0o[0-7_\.]+|0b[01_\.]+)(?:e-?[\d_]+)?|0x[\d_a-f\.]+(?:p-?[\d_]+)?)/i - var identifier = /^[_A-Za-z$][_A-Za-z$0-9]*/ - var property = /^[@\#\.][_A-Za-z$][_A-Za-z$0-9]*/ + var types = wordSet(["Array","Bool","Character","Dictionary","Double","Float","Int","Int8","Int16","Int32","Int64","Never","Optional","Set","String", + "UInt8","UInt16","UInt32","UInt64","Void"]) + var operators = "+-/*%=|&<>~^?!" + var punc = ":;,.(){}[]" + var binary = /^\-?0b[01][01_]*/ + var octal = /^\-?0o[0-7][0-7_]*/ + var hexadecimal = /^\-?0x[\dA-Fa-f][\dA-Fa-f_]*(?:(?:\.[\dA-Fa-f][\dA-Fa-f_]*)?[Pp]\-?\d[\d_]*)?/ + var decimal = /^\-?\d[\d_]*(?:\.\d[\d_]*)?(?:[Ee]\-?\d[\d_]*)?/ + var identifier = /^\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1/ + var property = /^\.(?:\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1)/ + var instruction = /^\#[A-Za-z]+/ + var attribute = /^@(?:\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1)/ var regexp = /^\/(?!\s)(?:\/\/)?(?:\\.|[^\/])+\// function tokenBase(stream, state, prev) { @@ -50,8 +56,14 @@ state.tokenize.push(tokenComment) return tokenComment(stream, state) } - if (stream.match(regexp)) return "string-2" } + if (stream.match(instruction)) return "builtin" + if (stream.match(attribute)) return "attribute" + if (stream.match(binary)) return "number" + if (stream.match(octal)) return "number" + if (stream.match(hexadecimal)) return "number" + if (stream.match(decimal)) return "number" + if (stream.match(property)) return "property" if (operators.indexOf(ch) > -1) { stream.next() return "operator" @@ -68,18 +80,15 @@ return tokenize(stream, state) } - if (stream.match(number)) return "number" - if (stream.match(property)) return "property" - if (stream.match(identifier)) { var ident = stream.current() + if (types.hasOwnProperty(ident)) return "variable-2" + if (atoms.hasOwnProperty(ident)) return "atom" if (keywords.hasOwnProperty(ident)) { if (definingKeywords.hasOwnProperty(ident)) state.prev = "define" return "keyword" } - if (types.hasOwnProperty(ident)) return "variable-2" - if (atoms.hasOwnProperty(ident)) return "atom" if (prev == "define") return "def" return "variable" } @@ -191,7 +200,9 @@ lineComment: "//", blockCommentStart: "/*", - blockCommentEnd: "*/" + blockCommentEnd: "*/", + fold: "brace", + closeBrackets: "()[]{}''\"\"``" } }) diff --git a/mode/swift/test.js b/mode/swift/test.js new file mode 100644 index 0000000000..8c8ee2f65a --- /dev/null +++ b/mode/swift/test.js @@ -0,0 +1,149 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "swift"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + // Ensure all number types are properly represented. + MT("numbers", + "[keyword var] [def a] [operator =] [number 17]", + "[keyword var] [def b] [operator =] [number -0.5]", + "[keyword var] [def c] [operator =] [number 0.3456e-4]", + "[keyword var] [def d] [operator =] [number 345e2]", + "[keyword var] [def e] [operator =] [number 0o7324]", + "[keyword var] [def f] [operator =] [number 0b10010]", + "[keyword var] [def g] [operator =] [number -0x35ade]", + "[keyword var] [def h] [operator =] [number 0xaea.ep-13]". + "[keyword var] [def i] [operator =] [number 0x13ep6"); + + // Variable/class/etc definition. + MT("definition", + "[keyword var] [def a] [operator =] [number 5]", + "[keyword let] [def b][punctuation :] [variable-2 Int] [operator =] [number 10]", + "[keyword class] [def C] [punctuation {] [punctuation }]", + "[keyword struct] [def D] [punctuation {] [punctuation }]", + "[keyword enum] [def E] [punctuation {] [punctuation }]", + "[keyword extension] [def F] [punctuation {] [punctuation }]", + "[keyword protocol] [def G] [punctuation {] [punctuation }]", + "[keyword func] [def h][punctuation ()] [punctuation {] [punctuation }]", + "[keyword import] [def Foundation]", + "[keyword typealias] [def NewString] [operator =] [variable-2 String]", + "[keyword associatedtype] [def I]", + "[keyword for] [def j] [keyword in] [number 0][punctuation ..][operator <][number 3] [punctuation {] [punctuation }]"); + + // Strings and string interpolation. + MT("strings", + "[keyword var] [def a][punctuation :] [variable-2 String] [operator =] [string \"test\"]", + "[keyword var] [def b][punctuation :] [variable-2 String] [operator =] [string \"\\(][variable a][string )\"]"); + + // Comments. + MT("comments", + "[comment // This is a comment]", + "[comment /* This is another comment */]", + "[keyword var] [def a] [operator =] [number 5] [comment // Third comment]"); + + // Atoms. + MT("atoms", + "[keyword class] [def FooClass] [punctuation {]", + " [keyword let] [def fooBool][punctuation :] [variable-2 Bool][operator ?]", + " [keyword let] [def fooInt][punctuation :] [variable-2 Int][operator ?]", + " [keyword func] [keyword init][punctuation (][variable fooBool][punctuation :] [variable-2 Bool][punctuation ,] [variable barBool][punctuation :] [variable-2 Bool][punctuation )] [punctuation {]", + " [atom super][property .init][punctuation ()]", + " [atom self][property .fooBool] [operator =] [variable fooBool]", + " [variable fooInt] [operator =] [atom nil]", + " [keyword if] [variable barBool] [operator ==] [atom true] [punctuation {]", + " [variable print][punctuation (][string \"True!\"][punctuation )]", + " [punctuation }] [keyword else] [keyword if] [variable barBool] [operator ==] [atom false] [punctuation {]", + " [keyword for] [atom _] [keyword in] [number 0][punctuation ...][number 5] [punctuation {]", + " [variable print][punctuation (][string \"False!\"][punctuation )]", + " [punctuation }]", + " [punctuation }]", + " [punctuation }]", + "[punctuation }]"); + + // Types. + MT("types", + "[keyword var] [def a] [operator =] [variable-2 Array][operator <][variable-2 Int][operator >]", + "[keyword var] [def b] [operator =] [variable-2 Set][operator <][variable-2 Bool][operator >]", + "[keyword var] [def c] [operator =] [variable-2 Dictionary][operator <][variable-2 String][punctuation ,][variable-2 Character][operator >]", + "[keyword var] [def d][punctuation :] [variable-2 Int64][operator ?] [operator =] [variable-2 Optional][punctuation (][number 8][punctuation )]", + "[keyword func] [def e][punctuation ()] [operator ->] [variable-2 Void] [punctuation {]", + " [keyword var] [def e1][punctuation :] [variable-2 Float] [operator =] [number 1.2]", + "[punctuation }]", + "[keyword func] [def f][punctuation ()] [operator ->] [variable-2 Never] [punctuation {]", + " [keyword var] [def f1][punctuation :] [variable-2 Double] [operator =] [number 2.4]", + "[punctuation }]"); + + // Operators. + MT("operators", + "[keyword var] [def a] [operator =] [number 1] [operator +] [number 2]", + "[keyword var] [def b] [operator =] [number 1] [operator -] [number 2]", + "[keyword var] [def c] [operator =] [number 1] [operator *] [number 2]", + "[keyword var] [def d] [operator =] [number 1] [operator /] [number 2]", + "[keyword var] [def e] [operator =] [number 1] [operator %] [number 2]", + "[keyword var] [def f] [operator =] [number 1] [operator |] [number 2]", + "[keyword var] [def g] [operator =] [number 1] [operator &] [number 2]", + "[keyword var] [def h] [operator =] [number 1] [operator <<] [number 2]", + "[keyword var] [def i] [operator =] [number 1] [operator >>] [number 2]", + "[keyword var] [def j] [operator =] [number 1] [operator ^] [number 2]", + "[keyword var] [def k] [operator =] [operator ~][number 1]", + "[keyword var] [def l] [operator =] [variable foo] [operator ?] [number 1] [punctuation :] [number 2]", + "[keyword var] [def m][punctuation :] [variable-2 Int] [operator =] [variable-2 Optional][punctuation (][number 8][punctuation )][operator !]"); + + // Punctuation. + MT("punctuation", + "[keyword let] [def a] [operator =] [number 1][punctuation ;] [keyword let] [def b] [operator =] [number 2]", + "[keyword let] [def testArr][punctuation :] [punctuation [[][variable-2 Int][punctuation ]]] [operator =] [punctuation [[][variable a][punctuation ,] [variable b][punctuation ]]]", + "[keyword for] [def i] [keyword in] [number 0][punctuation ..][operator <][variable testArr][property .count] [punctuation {]", + " [variable print][punctuation (][variable testArr][punctuation [[][variable i][punctuation ]])]", + "[punctuation }]"); + + // Identifiers. + MT("identifiers", + "[keyword let] [def abc] [operator =] [number 1]", + "[keyword let] [def ABC] [operator =] [number 2]", + "[keyword let] [def _123] [operator =] [number 3]", + "[keyword let] [def _$1$2$3] [operator =] [number 4]", + "[keyword let] [def A1$_c32_$_] [operator =] [number 5]", + "[keyword let] [def `var`] [operator =] [punctuation [[][number 1][punctuation ,] [number 2][punctuation ,] [number 3][punctuation ]]]", + "[keyword let] [def square$] [operator =] [variable `var`][property .map] [punctuation {][variable $0] [operator *] [variable $0][punctuation }]", + "$$ [number 1][variable a] $[atom _] [variable _$] [variable __] `[variable a] [variable b]`"); + + // Properties. + MT("properties", + "[variable print][punctuation (][variable foo][property .abc][punctuation )]", + "[variable print][punctuation (][variable foo][property .ABC][punctuation )]", + "[variable print][punctuation (][variable foo][property ._123][punctuation )]", + "[variable print][punctuation (][variable foo][property ._$1$2$3][punctuation )]", + "[variable print][punctuation (][variable foo][property .A1$_c32_$_][punctuation )]", + "[variable print][punctuation (][variable foo][property .`var`][punctuation )]", + "[variable print][punctuation (][variable foo][property .__][punctuation )]"); + + // Instructions or other things that start with #. + MT("instructions", + "[keyword if] [instruction #available][punctuation (][variable iOS] [number 9][punctuation ,] [operator *][punctuation )] [punctuation {}", + "[variable print][punctuation (][instruction #file][punctuation ,] [instruction #function][punctuation )]", + "[variable print][punctuation (][instruction #line][punctuation ,] [instruction #column][punctuation )]", + "[instruction #if] [atom true]", + " [keyword import] [variable A]", + "[instruction #elseif] [atom false]", + " [keyword import] [variable B]", + "[instruction #endif]", + "[instruction #sourceLocation][punctuation (][variable file][punctuation :] [string \"file.swift\"][punctuation ,] [variable line][punctuation :] [number 2][punctuation )]"); + + // Attributes; things that start with @. + MT("attributes", + "[instruction @objc][punctuation (][variable objcFoo][punctuation :)]", + "[instruction @available][punctuation (][variable iOS][punctuation )]"); + + // Property/number edge case. + MT("property_number", + "[variable print][punctuation (][variable foo][property ._123][punctuation )]", + "[variable print][punctuation (]") + + // TODO: correctly identify when multiple variables are being declared + // by use of a comma-separated list. + // TODO: correctly identify when variables are being declared in a tuple. + // TODO: identify protocols as types when used before an extension? +})(); diff --git a/test/index.html b/test/index.html index 8ac33c0913..cfa3bb71fb 100644 --- a/test/index.html +++ b/test/index.html @@ -35,6 +35,7 @@ + @@ -122,6 +123,7 @@

    Test Suite

    + From 18c1bcb556bd1e5bab56d2564fd79cefee4ddc79 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 9 Nov 2016 11:03:13 +0100 Subject: [PATCH 0105/1880] [swift mode] Make tests syntactically valid and in agreement with the mode Issue #4374 --- mode/swift/swift.js | 2 +- mode/swift/test.js | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/mode/swift/swift.js b/mode/swift/swift.js index 329470664c..43ab7c8fb4 100644 --- a/mode/swift/swift.js +++ b/mode/swift/swift.js @@ -40,7 +40,7 @@ var property = /^\.(?:\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1)/ var instruction = /^\#[A-Za-z]+/ var attribute = /^@(?:\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1)/ - var regexp = /^\/(?!\s)(?:\/\/)?(?:\\.|[^\/])+\// + //var regexp = /^\/(?!\s)(?:\/\/)?(?:\\.|[^\/])+\// function tokenBase(stream, state, prev) { if (stream.sol()) state.indented = stream.indentation() diff --git a/mode/swift/test.js b/mode/swift/test.js index 8c8ee2f65a..786b89e299 100644 --- a/mode/swift/test.js +++ b/mode/swift/test.js @@ -14,8 +14,8 @@ "[keyword var] [def e] [operator =] [number 0o7324]", "[keyword var] [def f] [operator =] [number 0b10010]", "[keyword var] [def g] [operator =] [number -0x35ade]", - "[keyword var] [def h] [operator =] [number 0xaea.ep-13]". - "[keyword var] [def i] [operator =] [number 0x13ep6"); + "[keyword var] [def h] [operator =] [number 0xaea.ep-13]", + "[keyword var] [def i] [operator =] [number 0x13ep6]"); // Variable/class/etc definition. MT("definition", @@ -122,20 +122,20 @@ // Instructions or other things that start with #. MT("instructions", - "[keyword if] [instruction #available][punctuation (][variable iOS] [number 9][punctuation ,] [operator *][punctuation )] [punctuation {}", - "[variable print][punctuation (][instruction #file][punctuation ,] [instruction #function][punctuation )]", - "[variable print][punctuation (][instruction #line][punctuation ,] [instruction #column][punctuation )]", - "[instruction #if] [atom true]", - " [keyword import] [variable A]", - "[instruction #elseif] [atom false]", - " [keyword import] [variable B]", - "[instruction #endif]", - "[instruction #sourceLocation][punctuation (][variable file][punctuation :] [string \"file.swift\"][punctuation ,] [variable line][punctuation :] [number 2][punctuation )]"); + "[keyword if] [builtin #available][punctuation (][variable iOS] [number 9][punctuation ,] [operator *][punctuation )] [punctuation {}]", + "[variable print][punctuation (][builtin #file][punctuation ,] [builtin #function][punctuation )]", + "[variable print][punctuation (][builtin #line][punctuation ,] [builtin #column][punctuation )]", + "[builtin #if] [atom true]", + "[keyword import] [def A]", + "[builtin #elseif] [atom false]", + "[keyword import] [def B]", + "[builtin #endif]", + "[builtin #sourceLocation][punctuation (][variable file][punctuation :] [string \"file.swift\"][punctuation ,] [variable line][punctuation :] [number 2][punctuation )]"); // Attributes; things that start with @. MT("attributes", - "[instruction @objc][punctuation (][variable objcFoo][punctuation :)]", - "[instruction @available][punctuation (][variable iOS][punctuation )]"); + "[attribute @objc][punctuation (][variable objcFoo][punctuation :)]", + "[attribute @available][punctuation (][variable iOS][punctuation )]"); // Property/number edge case. MT("property_number", From a34c02883bcf5ad0d9328de6fff0fafde9a7aa3f Mon Sep 17 00:00:00 2001 From: Paris Kasidiaris Date: Thu, 10 Nov 2016 10:16:01 +0200 Subject: [PATCH 0106/1880] [real-world uses] Add SourceLair --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 8db34cd9fa..e52c9f00f8 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -146,6 +146,7 @@

    CodeMirror real-world uses

  • Shadertoy (shader sharing)
  • sketchPatch Livecodelab
  • Skulpt (in-browser Python environment)
  • +
  • SourceLair (in-browser IDE for Django, Node.js, PHP and HTML5)
  • Snap Tomato (HTML editing/testing page)
  • Snippets.pro (code snippet sharing)
  • SolidShops (hosted e-commerce platform)
  • From 5d235c1b6ecb299892179ab8fe0f3f28693aabf1 Mon Sep 17 00:00:00 2001 From: Sander Verweij Date: Sun, 13 Nov 2016 15:26:24 +0100 Subject: [PATCH 0107/1880] [real world uses] adds mscgen.js.org --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index e52c9f00f8..dc2a7f6a97 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -118,6 +118,7 @@

    CodeMirror real-world uses

  • MIHTool (iOS web-app debugging tool)
  • Mongo MapReduce WebBrowser
  • Montage Studio (web app creator suite)
  • +
  • mscgen_js (online sequence chart editor)
  • MVC Playground
  • My2ndGeneration (social coding)
  • Navigate CMS
  • From e6eebeb19291889aa05f2bd34ce113702ec44090 Mon Sep 17 00:00:00 2001 From: pabloferz Date: Sat, 12 Nov 2016 23:13:25 -0600 Subject: [PATCH 0108/1880] [julia mode] Fix string tokenizer --- mode/julia/julia.js | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/mode/julia/julia.js b/mode/julia/julia.js index 6c40bf20ee..0174210b55 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -338,23 +338,20 @@ CodeMirror.defineMode("julia", function(config, parserConf) { } function tokenStringFactory(delimiter) { - delimiter = (delimiter === '`' || delimiter === '"""') ? delimiter : '"' + delimiter = (delimiter === '`' || delimiter === '"""') ? delimiter : '"'; function tokenString(stream, state) { - while (!stream.eol()) { - stream.eatWhile(/[^\\"]/); - if (stream.eat('\\')) { - stream.next(); - } else if (stream.match(delimiter)) { - state.tokenize = tokenBase; - state.leavingExpr = true; - return "string"; - } else { - stream.eat('"'); - } + if (stream.eat('\\')) { + stream.next(); + } else if (stream.match(delimiter)) { + state.tokenize = tokenBase; + state.leavingExpr = true; + return "string"; + } else { + stream.eat(/[`"]/); } + stream.eatWhile(/[^\\`"]/); return "string"; } - tokenString.isString = true; return tokenString; } From 0a90aa456c6c850956b2bdc45334dfe5ce7f0d5e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 14 Nov 2016 10:36:23 +0100 Subject: [PATCH 0109/1880] Simplify build instructions in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b3309881c..3328e3bdfb 100644 --- a/README.md +++ b/README.md @@ -30,5 +30,5 @@ conduct. ### Quickstart To build the project, make sure you have Node.js installed (at least version 6) -and then `npm install && npm run build`. To run, just open `index.html` in your +and then `npm install`. To run, just open `index.html` in your browser (you don't need to run a webserver). Run the tests with `npm test`. From 90819c54aae09c0002286cd43e57522432580d7c Mon Sep 17 00:00:00 2001 From: Mark Peace Date: Fri, 11 Nov 2016 16:48:36 +0000 Subject: [PATCH 0110/1880] [cypher mode] Highlight empty string literals correctly --- mode/cypher/cypher.js | 6 +++--- mode/cypher/test.js | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/mode/cypher/cypher.js b/mode/cypher/cypher.js index 1d9ca4334a..9b2490014c 100644 --- a/mode/cypher/cypher.js +++ b/mode/cypher/cypher.js @@ -20,12 +20,12 @@ CodeMirror.defineMode("cypher", function(config) { var tokenBase = function(stream/*, state*/) { var ch = stream.next(); - if (ch === "\"") { - stream.match(/.+?["]/); + if (ch ==='"') { + stream.match(/.*?"/); return "string"; } if (ch === "'") { - stream.match(/.+?[']/); + stream.match(/.*?'/); return "string"; } if (/[{}\(\),\.;\[\]]/.test(ch)) { diff --git a/mode/cypher/test.js b/mode/cypher/test.js index 34cf96caff..76d0d08296 100644 --- a/mode/cypher/test.js +++ b/mode/cypher/test.js @@ -16,4 +16,22 @@ MT("singleQuotedString", "[string 'a'][variable b]"); + + MT("single attribute (with content)", + "[node {][atom a:][string 'a'][node }]"); + + MT("multiple attribute, singleQuotedString (with content)", + "[node {][atom a:][string 'a'][node ,][atom b:][string 'b'][node }]"); + + MT("multiple attribute, doubleQuotedString (with content)", + "[node {][atom a:][string \"a\"][node ,][atom b:][string \"b\"][node }]"); + + MT("single attribute (without content)", + "[node {][atom a:][string 'a'][node }]"); + + MT("multiple attribute, singleQuotedString (without content)", + "[node {][atom a:][string ''][node ,][atom b:][string ''][node }]"); + + MT("multiple attribute, doubleQuotedString (without content)", + "[node {][atom a:][string \"\"][node ,][atom b:][string \"\"][node }]"); })(); From 532ae310c9248e696caa21ca34519b79367cd4eb Mon Sep 17 00:00:00 2001 From: Marcelo Camargo Date: Mon, 14 Nov 2016 17:37:54 -0200 Subject: [PATCH 0111/1880] [sql mode] Remove non-strict useless comparison for booleans --- mode/sql/sql.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mode/sql/sql.js b/mode/sql/sql.js index e3cbae54cf..32ced3e9de 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -32,13 +32,13 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { if (result !== false) return result; } - if (support.hexNumber == true && + if (support.hexNumber && ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/))) { // hex // ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html return "number"; - } else if (support.binaryNumber == true && + } else if (support.binaryNumber && (((ch == "b" || ch == "B") && stream.match(/^'[01]+'/)) || (ch == "0" && stream.match(/^b[01]+/)))) { // bitstring @@ -48,7 +48,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { // numbers // ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/); - support.decimallessFloat == true && stream.eat('.'); + support.decimallessFloat && stream.eat('.'); return "number"; } else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) { // placeholders @@ -58,8 +58,8 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html state.tokenize = tokenLiteral(ch); return state.tokenize(stream, state); - } else if ((((support.nCharCast == true && (ch == "n" || ch == "N")) - || (support.charsetCast == true && ch == "_" && stream.match(/[a-z][a-z0-9]*/i))) + } else if ((((support.nCharCast && (ch == "n" || ch == "N")) + || (support.charsetCast && ch == "_" && stream.match(/[a-z][a-z0-9]*/i))) && (stream.peek() == "'" || stream.peek() == '"'))) { // charset casting: _utf8'str', N'str', n'str' // ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html @@ -84,12 +84,12 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { return state.tokenize(stream, state); } else if (ch == ".") { // .1 for 0.1 - if (support.zerolessFloat == true && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) { + if (support.zerolessFloat && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) { return "number"; } // .table_name (ODBC) // // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html - if (support.ODBCdotTable == true && stream.match(/^[a-zA-Z_]+/)) { + if (support.ODBCdotTable && stream.match(/^[a-zA-Z_]+/)) { return "variable-2"; } } else if (operatorChars.test(ch)) { From beb838248ad29721f11c5b33ce08c701d93875da Mon Sep 17 00:00:00 2001 From: takamori Date: Mon, 14 Nov 2016 12:44:30 -0800 Subject: [PATCH 0112/1880] [css mode] Support user-select. As described in http://caniuse.com/#feat=user-select-none and https://developer.mozilla.org/en-US/docs/Web/CSS/user-select --- mode/css/css.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/css/css.js b/mode/css/css.js index b75732034e..985287f475 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -522,7 +522,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "text-wrap", "top", "transform", "transform-origin", "transform-style", "transition", "transition-delay", "transition-duration", "transition-property", "transition-timing-function", "unicode-bidi", - "vertical-align", "visibility", "voice-balance", "voice-duration", + "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", "voice-volume", "volume", "white-space", "widows", "width", "word-break", "word-spacing", "word-wrap", "z-index", From 5012e8772371632bc4e4162e1a0f674d42cd1d79 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 15 Nov 2016 13:18:46 +0100 Subject: [PATCH 0113/1880] [contenteditable input] Force editor selection in focus method So that the selection isn't reset to the start of the element by div.focus(). --- src/input/ContentEditableInput.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index cdaa825488..594f17f663 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -199,7 +199,11 @@ ContentEditableInput.prototype = copyObj({ }, focus: function() { - if (this.cm.options.readOnly != "nocursor") this.div.focus() + if (this.cm.options.readOnly != "nocursor") { + if (!this.selectionInEditor()) + this.showSelection(this.prepareSelection(), true) + this.div.focus() + } }, blur: function() { this.div.blur() }, getField: function() { return this.div }, From da8a35d05e720db980c4ae2307c7615aceaa53ac Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 15 Nov 2016 13:46:59 +0100 Subject: [PATCH 0114/1880] Handle compositionupdate events without corresponding compositionstart Because Android, especially Google Keyboard, just doesn't care --- src/input/ContentEditableInput.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index 594f17f663..524d571e5e 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -37,8 +37,7 @@ ContentEditableInput.prototype = copyObj({ }), 20) }) - on(div, "compositionstart", e => { - let data = e.data + function startComposing(data) { input.composing = {sel: cm.doc.sel, data: data, startData: data} if (!data) return let prim = cm.doc.sel.primary() @@ -47,8 +46,13 @@ ContentEditableInput.prototype = copyObj({ if (found > -1 && found <= prim.head.ch) input.composing.sel = simpleSelection(Pos(prim.head.line, found), Pos(prim.head.line, found + data.length)) + } + + on(div, "compositionstart", e => startComposing(e.data)) + on(div, "compositionupdate", e => { + if (input.composing) input.composing.data = e.data + else startComposing(e.data) }) - on(div, "compositionupdate", e => input.composing.data = e.data) on(div, "compositionend", e => { let ours = input.composing if (!ours) return From 0e545326ddb3a82df1b76eb18b2221990536e588 Mon Sep 17 00:00:00 2001 From: Todd Berman Date: Tue, 8 Nov 2016 09:17:56 -0800 Subject: [PATCH 0115/1880] Move setGutterMarker, clearGutter and lineInfo to Doc --- doc/manual.html | 6 +++--- src/edit/methods.js | 42 ++---------------------------------------- src/model/Doc.js | 41 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 44 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index e74ec36200..ecfe3071f7 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1699,7 +1699,7 @@

    Text-marking methods

    Widget, gutter, and decoration methods

    -
    cm.setGutterMarker(line: integer|LineHandle, gutterID: string, value: Element) → LineHandle
    +
    doc.setGutterMarker(line: integer|LineHandle, gutterID: string, value: Element) → LineHandle
    Sets the gutter marker for the given gutter (identified by its CSS class, see the gutters option) @@ -1708,7 +1708,7 @@

    Widget, gutter, and decoration methods

    will be shown in the specified gutter next to the specified line.
    -
    cm.clearGutter(gutterID: string)
    +
    doc.clearGutter(gutterID: string)
    Remove all gutter markers in the gutter with the given ID.
    @@ -1733,7 +1733,7 @@

    Widget, gutter, and decoration methods

    can be left off to remove all classes for the specified node, or be a string to remove only a specific class. -
    cm.lineInfo(line: integer|LineHandle) → object
    +
    doc.lineInfo(line: integer|LineHandle) → object
    Returns the line number, text content, and marker status of the given line, which can be either a number or a line handle. The returned object has the structure {line, handle, text, diff --git a/src/edit/methods.js b/src/edit/methods.js index 8aa2a437b0..7efaf20e2c 100644 --- a/src/edit/methods.js +++ b/src/edit/methods.js @@ -1,5 +1,4 @@ import { deleteNearSelection } from "./deleteNearSelection" -import { changeLine } from "../model/changes" import { commands } from "./commands" import { attachDoc } from "../model/document_data" import { activeElt, addClass, rmClass } from "../util/dom" @@ -18,9 +17,9 @@ import { addToScrollPos, calculateScrollPos, ensureCursorVisible, resolveScrollT import { heightAtLine } from "../line/spans" import { updateGutterSpace } from "../display/update_display" import { lineLeft, lineRight, moveLogically, moveVisually } from "../util/bidi" -import { indexOf, insertSorted, isEmpty, isWordChar, sel_dontScroll, sel_move } from "../util/misc" +import { indexOf, insertSorted, isWordChar, sel_dontScroll, sel_move } from "../util/misc" import { signalLater } from "../util/operation_group" -import { getLine, isLine, lineAtHeight, lineNo } from "../line/utils_line" +import { getLine, isLine, lineAtHeight } from "../line/utils_line" import { regChange, regLineChange } from "../display/view_tracking" // The publicly visible API. Note that methodOp(f) means @@ -218,43 +217,6 @@ export default function(CodeMirror) { defaultTextHeight: function() { return textHeight(this.display) }, defaultCharWidth: function() { return charWidth(this.display) }, - setGutterMarker: methodOp(function(line, gutterID, value) { - return changeLine(this.doc, line, "gutter", line => { - let markers = line.gutterMarkers || (line.gutterMarkers = {}) - markers[gutterID] = value - if (!value && isEmpty(markers)) line.gutterMarkers = null - return true - }) - }), - - clearGutter: methodOp(function(gutterID) { - let doc = this.doc, i = doc.first - doc.iter(line => { - if (line.gutterMarkers && line.gutterMarkers[gutterID]) { - line.gutterMarkers[gutterID] = null - regLineChange(this, i, "gutter") - if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null - } - ++i - }) - }), - - lineInfo: function(line) { - let n - if (typeof line == "number") { - if (!isLine(this.doc, line)) return null - n = line - line = getLine(this.doc, line) - if (!line) return null - } else { - n = lineNo(line) - if (n == null) return null - } - return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, - textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, - widgets: line.widgets} - }, - getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}}, addWidget: function(pos, node, scroll, vert, horiz) { diff --git a/src/model/Doc.js b/src/model/Doc.js index fcb2c1e109..27b62d1945 100644 --- a/src/model/Doc.js +++ b/src/model/Doc.js @@ -6,7 +6,7 @@ import { visualLine } from "../line/spans" import { getBetween, getLine, getLines, isLine, lineNo } from "../line/utils_line" import { classTest } from "../util/dom" import { splitLinesAuto } from "../util/feature_detection" -import { createObj, map, sel_dontScroll } from "../util/misc" +import { createObj, map, isEmpty, sel_dontScroll } from "../util/misc" import { ensureCursorVisible } from "../display/scrolling" import { changeLine, makeChange, makeChangeFromHistory, replaceRange } from "./changes" @@ -219,6 +219,45 @@ Doc.prototype = createObj(BranchChunk.prototype, { hist.undone = copyHistoryArray(histData.undone.slice(0), null, true) }, + setGutterMarker: docMethodOp(function(line, gutterID, value) { + return changeLine(this, line, "gutter", line => { + let markers = line.gutterMarkers || (line.gutterMarkers = {}) + markers[gutterID] = value + if (!value && isEmpty(markers)) line.gutterMarkers = null + return true + }) + }), + + clearGutter: docMethodOp(function(gutterID) { + let i = this.first + this.iter(line => { + if (line.gutterMarkers && line.gutterMarkers[gutterID]) { + changeLine(this, line, "gutter", () => { + line.gutterMarkers[gutterID] = null + if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null + return true + }) + } + ++i + }) + }), + + lineInfo: function(line) { + let n + if (typeof line == "number") { + if (!isLine(this, line)) return null + n = line + line = getLine(this, line) + if (!line) return null + } else { + n = lineNo(line) + if (n == null) return null + } + return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, + textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, + widgets: line.widgets} + }, + addLineClass: docMethodOp(function(handle, where, cls) { return changeLine(this, handle, where == "gutter" ? "gutter" : "class", line => { let prop = where == "text" ? "textClass" From 441641e6cb75ebbd2f5551befe2b2cde9ddf9ab2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 15 Nov 2016 14:54:05 +0100 Subject: [PATCH 0116/1880] [contenteditable input] Read from the DOM to get composition input And do so only after a delay, so that subsequent input events get a chance to fire. --- src/edit/CodeMirror.js | 1 + src/edit/mouse_events.js | 1 + src/input/ContentEditableInput.js | 67 +++++++++++++------------------ 3 files changed, 30 insertions(+), 39 deletions(-) diff --git a/src/edit/CodeMirror.js b/src/edit/CodeMirror.js index 7e17002d15..a3dc622cf1 100644 --- a/src/edit/CodeMirror.js +++ b/src/edit/CodeMirror.js @@ -142,6 +142,7 @@ function registerEventHandlers(cm) { } on(d.scroller, "touchstart", e => { if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) { + d.input.ensurePolled() clearTimeout(touchFinished) let now = +new Date d.activeTouch = {start: now, moved: false, diff --git a/src/edit/mouse_events.js b/src/edit/mouse_events.js index 784f195b3e..0b96f4cfda 100644 --- a/src/edit/mouse_events.js +++ b/src/edit/mouse_events.js @@ -21,6 +21,7 @@ import { bind, countColumn, findColumn, sel_mouse } from "../util/misc" export function onMouseDown(e) { let cm = this, display = cm.display if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return + display.input.ensurePolled() display.shift = e.shiftKey if (eventInWidget(display, e)) { diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index 524d571e5e..a7254b12c2 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -20,7 +20,9 @@ export default function ContentEditableInput(cm) { this.cm = cm this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null this.polling = new Delayed() + this.composing = null this.gracePeriod = false + this.readDOMTimeout = null } ContentEditableInput.prototype = copyObj({ @@ -37,44 +39,23 @@ ContentEditableInput.prototype = copyObj({ }), 20) }) - function startComposing(data) { - input.composing = {sel: cm.doc.sel, data: data, startData: data} - if (!data) return - let prim = cm.doc.sel.primary() - let line = cm.getLine(prim.head.line) - let found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)) - if (found > -1 && found <= prim.head.ch) - input.composing.sel = simpleSelection(Pos(prim.head.line, found), - Pos(prim.head.line, found + data.length)) - } - - on(div, "compositionstart", e => startComposing(e.data)) + on(div, "compositionstart", e => { + this.composing = {data: e.data} + }) on(div, "compositionupdate", e => { - if (input.composing) input.composing.data = e.data - else startComposing(e.data) + if (!this.composing) this.composing = {data: e.data} }) on(div, "compositionend", e => { - let ours = input.composing - if (!ours) return - if (e.data != ours.startData && !/\u200b/.test(e.data)) - ours.data = e.data - // Need a small delay to prevent other code (input event, - // selection polling) from doing damage when fired right after - // compositionend. - setTimeout(() => { - if (!ours.handled) - input.applyComposition(ours) - if (input.composing == ours) - input.composing = null - }, 50) + if (this.composing) { + if (e.data != this.composing.data) this.readFromDOMSoon() + this.composing = null + } }) on(div, "touchstart", () => input.forceCompositionEnd()) on(div, "input", () => { - if (input.composing) return - if (cm.isReadOnly() || !input.pollContent()) - runInOp(input.cm, () => regChange(cm)) + if (!this.composing) this.readFromDOMSoon() }) function onCopyCut(e) { @@ -237,7 +218,7 @@ ContentEditableInput.prototype = copyObj({ }, pollSelection: function() { - if (!this.composing && !this.gracePeriod && this.selectionChanged()) { + if (!this.composing && this.readDOMTimeout == null && !this.gracePeriod && this.selectionChanged()) { let sel = window.getSelection(), cm = this.cm this.rememberSelection() let anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset) @@ -250,6 +231,11 @@ ContentEditableInput.prototype = copyObj({ }, pollContent: function() { + if (this.readDOMTimeout != null) { + clearTimeout(this.readDOMTimeout) + this.readDOMTimeout = null + } + let cm = this.cm, display = cm.display, sel = cm.doc.sel.primary() let from = sel.from(), to = sel.to() if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false @@ -309,17 +295,20 @@ ContentEditableInput.prototype = copyObj({ this.forceCompositionEnd() }, forceCompositionEnd: function() { - if (!this.composing || this.composing.handled) return - this.applyComposition(this.composing) - this.composing.handled = true + if (!this.composing) return + this.composing = null + if (!this.pollContent()) regChange(this.cm) this.div.blur() this.div.focus() }, - applyComposition: function(composing) { - if (this.cm.isReadOnly()) - operation(this.cm, regChange)(this.cm) - else if (composing.data && composing.data != composing.startData) - operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel) + readFromDOMSoon: function() { + if (this.readDOMTimeout != null) return + this.readDOMTimeout = setTimeout(() => { + this.readDOMTimeout = null + if (this.composing) return + if (this.cm.isReadOnly() || !this.pollContent()) + runInOp(this.cm, () => regChange(this.cm)) + }, 80) }, setUneditable: function(node) { From d7b1370ca45d742c0961ce98d25ea2c2d3f0f484 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 15 Nov 2016 17:04:49 +0100 Subject: [PATCH 0117/1880] Copy event handler arrays on write Rather than on read --- src/util/event.js | 35 ++++++++++++++++++----------------- src/util/operation_group.js | 2 +- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/util/event.js b/src/util/event.js index e667a9f3c0..29fd4c5981 100644 --- a/src/util/event.js +++ b/src/util/event.js @@ -6,39 +6,40 @@ import { indexOf } from "./misc" // Lightweight event framework. on/off also work on DOM nodes, // registering native DOM handlers. +const noHandlers = [] + export let on = function(emitter, type, f) { - if (emitter.addEventListener) + if (emitter.addEventListener) { emitter.addEventListener(type, f, false) - else if (emitter.attachEvent) + } else if (emitter.attachEvent) { emitter.attachEvent("on" + type, f) - else { + } else { let map = emitter._handlers || (emitter._handlers = {}) - let arr = map[type] || (map[type] = []) - arr.push(f) + map[type] = (map[type] || noHandlers).concat(f) } } -let noHandlers = [] -export function getHandlers(emitter, type, copy) { - let arr = emitter._handlers && emitter._handlers[type] - if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers - else return arr || noHandlers +export function getHandlers(emitter, type) { + return emitter._handlers && emitter._handlers[type] || noHandlers } export function off(emitter, type, f) { - if (emitter.removeEventListener) + if (emitter.removeEventListener) { emitter.removeEventListener(type, f, false) - else if (emitter.detachEvent) + } else if (emitter.detachEvent) { emitter.detachEvent("on" + type, f) - else { - let handlers = getHandlers(emitter, type, false) - for (let i = 0; i < handlers.length; ++i) - if (handlers[i] == f) { handlers.splice(i, 1); break } + } else { + let map = emitter._handlers, arr = map && map[type] + if (arr) { + let index = indexOf(arr, f) + if (index > -1) + map[type] = arr.slice(0, index).concat(arr.slice(index + 1)) + } } } export function signal(emitter, type /*, values...*/) { - let handlers = getHandlers(emitter, type, true) + let handlers = getHandlers(emitter, type) if (!handlers.length) return let args = Array.prototype.slice.call(arguments, 2) for (let i = 0; i < handlers.length; ++i) handlers[i].apply(null, args) diff --git a/src/util/operation_group.js b/src/util/operation_group.js index f50da343a9..b8fa78ac48 100644 --- a/src/util/operation_group.js +++ b/src/util/operation_group.js @@ -50,7 +50,7 @@ let orphanDelayedCallbacks = null // them to be executed when the last operation ends, or, if no // operation is active, when a timeout fires. export function signalLater(emitter, type /*, values...*/) { - let arr = getHandlers(emitter, type, false) + let arr = getHandlers(emitter, type) if (!arr.length) return let args = Array.prototype.slice.call(arguments, 2), list if (operationGroup) { From 6019b1308d4c513cb327f1e7c3f7ff86f258a217 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 15 Nov 2016 17:33:10 +0100 Subject: [PATCH 0118/1880] [contenteditable input] Expand scanned range when selection at start/end of line So that the code doesn't get confused when backspacing or deleting across a line. This is still flaky. Ideally we'd capture backspace as a key event, but Android Chrome makes that impossible. Issue #4307 --- src/input/ContentEditableInput.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index a7254b12c2..c385bea12e 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -238,6 +238,10 @@ ContentEditableInput.prototype = copyObj({ let cm = this.cm, display = cm.display, sel = cm.doc.sel.primary() let from = sel.from(), to = sel.to() + if (from.ch == 0 && from.line > cm.firstLine()) + from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length) + if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine()) + to = Pos(to.line + 1, 0) if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false let fromIndex, fromLine, fromNode @@ -258,6 +262,7 @@ ContentEditableInput.prototype = copyObj({ toNode = display.view[toIndex + 1].node.previousSibling } + if (!fromNode) return false let newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)) let oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)) while (newText.length > 1 && oldText.length > 1) { From 69669e4b74c30a6fa2c25751970b17daf53cf88c Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Tue, 15 Nov 2016 17:22:20 -0800 Subject: [PATCH 0119/1880] =?UTF-8?q?Avoid=20=E2=80=9CUnspecified=20Error?= =?UTF-8?q?=E2=80=9D=20in=20IE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit when accessing `document.activeElement` from inside an iframe. --- src/util/dom.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/util/dom.js b/src/util/dom.js index 465dbb5a5e..349fae07d3 100644 --- a/src/util/dom.js +++ b/src/util/dom.js @@ -1,4 +1,4 @@ -import { ie, ie_version, ios } from "./browser" +import { ie, ios } from "./browser" export function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") } @@ -58,18 +58,20 @@ export function contains(parent, child) { } while (child = child.parentNode) } -export let activeElt = function() { - let activeElement = document.activeElement +export function activeElt() { + // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement. + // IE < 10 will throw when accessed while the page is loading or in an iframe. + // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable. + let activeElement + try { + activeElement = document.activeElement + } catch(e) { + activeElement = document.body || null + } while (activeElement && activeElement.root && activeElement.root.activeElement) activeElement = activeElement.root.activeElement return activeElement } -// Older versions of IE throws unspecified error when touching -// document.activeElement in some cases (during loading, in iframe) -if (ie && ie_version < 11) activeElt = function() { - try { return document.activeElement } - catch(e) { return document.body } -} export function addClass(node, cls) { let current = node.className From 8ecbdc5c6aedbac6b4038d94c30b97bddc950b1b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Nov 2016 10:12:06 +0100 Subject: [PATCH 0120/1880] [markdown mode] Allow lists without a blank line above As per CommonMark (conflicting with markdown.pl, but never mind markdown.pl) Closes #4395 --- mode/markdown/markdown.js | 15 ++++----------- mode/markdown/test.js | 7 +++---- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 3dcce8d3b1..6aedc360b0 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -83,9 +83,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/ - , ulRE = /^[*\-+]\s+/ - , olRE = /^[0-9]+([.)])\s+/ - , taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE + , listRE = /^(?:[*\-+]|^[0-9]+([.)]))\s+/ + , taskListRE = /^\[(x| )\](?=\s)/ // Must follow listRE , atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/ , setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/ , textRE = /^[^#!\[\]*_\\<>` "'(~]+/ @@ -189,14 +188,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } else if (stream.match(hrRE, true)) { state.hr = true; return tokenTypes.hr; - } else if ((lineIsEmpty(state.prevLine) || prevLineIsList) && (stream.match(ulRE, false) || stream.match(olRE, false))) { - var listType = null; - if (stream.match(ulRE, true)) { - listType = 'ul'; - } else { - stream.match(olRE, true); - listType = 'ol'; - } + } else if (match = stream.match(listRE)) { + var listType = match[1] ? "ol" : "ul"; state.indentation = stream.column() + stream.current().length; state.list = true; diff --git a/mode/markdown/test.js b/mode/markdown/test.js index 2f43a170ca..37ecb4bbfe 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -357,11 +357,10 @@ "[variable-2 1. foo]", "[variable-2 2. bar]"); - // Lists require a preceding blank line (per Dingus) - MT("listBogus", + MT("listFromParagraph", "foo", - "1. bar", - "2. hello"); + "[variable-2 1. bar]", + "[variable-2 2. hello]"); // List after hr MT("listAfterHr", From 333a1f2bfb09151f8119b4c4de5ed26c47dba2f1 Mon Sep 17 00:00:00 2001 From: Kazuhito Hokamura Date: Wed, 9 Nov 2016 23:21:13 +0900 Subject: [PATCH 0121/1880] [vim mode] Add keymap to indent --- keymap/vim.js | 5 +++++ test/vim_test.js | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/keymap/vim.js b/keymap/vim.js index a166f72b10..34570bb889 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -190,6 +190,8 @@ { keys: '.', type: 'action', action: 'repeatLastEdit' }, { keys: '', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: true, backtrack: false}}, { keys: '', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: false, backtrack: false}}, + { keys: '', type: 'action', action: 'indent', actionArgs: { indentRight: true }, context: 'insert' }, + { keys: '', type: 'action', action: 'indent', actionArgs: { indentRight: false }, context: 'insert' }, // Text object motions { keys: 'a', type: 'motion', motion: 'textObjectManipulation' }, { keys: 'i', type: 'motion', motion: 'textObjectManipulation', motionArgs: { textObjectInner: true }}, @@ -2616,6 +2618,9 @@ } repeatLastEdit(cm, vim, repeat, false /** repeatForInsert */); }, + indent: function(cm, actionArgs) { + cm.indentLine(cm.getCursor().line, actionArgs.indentRight); + }, exitInsertMode: exitInsertMode }; diff --git a/test/vim_test.js b/test/vim_test.js index 6eea5553db..703a07a779 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -3393,6 +3393,21 @@ testVim('[m, ]m, [M, ]M', function(cm, vim, helpers) { helpers.assertCursorAt(7,3); }, { value: squareBracketMotionSandbox}); +testVim('i_indent_right', function(cm, vim, helpers) { + cm.setCursor(0, 3); + var expectedValue = ' word1\nword2\nword3 '; + helpers.doKeys('i', ''); + eq(expectedValue, cm.getValue()); + helpers.assertCursorAt(0, 5); +}, { value: ' word1\nword2\nword3 ', indentUnit: 2 }); +testVim('i_indent_left', function(cm, vim, helpers) { + cm.setCursor(0, 3); + var expectedValue = ' word1\nword2\nword3 '; + helpers.doKeys('i', ''); + eq(expectedValue, cm.getValue()); + helpers.assertCursorAt(0, 1); +}, { value: ' word1\nword2\nword3 ', indentUnit: 2 }); + // Ex mode tests testVim('ex_go_to_line', function(cm, vim, helpers) { cm.setCursor(0, 0); From 692393d609e4cc96a1726830ff161c3f4e56670e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Nov 2016 10:49:06 +0100 Subject: [PATCH 0122/1880] Drop zero-width spaces in text read from DOM Issue #4307 --- src/input/ContentEditableInput.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index c385bea12e..d76058ffd5 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -282,8 +282,8 @@ ContentEditableInput.prototype = copyObj({ newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) ++cutEnd - newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd) - newText[0] = newText[0].slice(cutFront) + newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "") + newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "") let chFrom = Pos(fromLine, cutFront) let chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0) @@ -361,8 +361,8 @@ function domTextBetween(cm, from, to, fromLine, toLine) { if (node.nodeType == 1) { let cmText = node.getAttribute("cm-text") if (cmText != null) { - if (cmText == "") cmText = node.textContent.replace(/\u200b/g, "") - text += cmText + if (cmText == "") text += node.textContent.replace(/\u200b/g, "") + else text += cmText return } let markerID = node.getAttribute("cm-marker"), range From b63d14df7846691db1b45e47ca11409ee3540482 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Nov 2016 11:12:00 +0100 Subject: [PATCH 0123/1880] Mark release 5.21.0 --- AUTHORS | 10 ++++++++++ CHANGELOG.md | 30 ++++++++++++++++++++++++++++++ doc/manual.html | 2 +- doc/releases.html | 17 +++++++++++++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 61 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index e2cb74a557..09fb4cc852 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,6 +10,7 @@ adanlobato Adán Lobato Adrian Aichner Adrian Heine +Adrien Bertrand aeroson Ahmad Amireh Ahmad M. Zawawi @@ -85,6 +86,7 @@ Ben Mosher Bernhard Sirlinger Bert Chang Bharad +BigBlueHat Billy Moon binny B Krishna Chaitanya @@ -274,6 +276,7 @@ Jeff Pickhardt jem (graphite) Jeremy Parmenter Jim +Jim Avery JobJob jochenberger Jochen Berger @@ -281,6 +284,7 @@ Joel Einbinder joelpinheiro Johan Ask John Connor +John-David Dalton John Engler John Lees-Miller John Snelson @@ -311,6 +315,7 @@ jwallers@gmail.com kaniga karevn Kayur Patel +Kazuhito Hokamura Ken Newman ken restivo Ken Rockot @@ -355,6 +360,7 @@ Manideep Manuel Rego Casasnovas Marat Dreizin Marcel Gerber +Marcelo Camargo Marco Aurélio Marco Munizaga Marcus Bointon @@ -455,6 +461,7 @@ Page Panupong Pasupat paris Paris +Paris Kasidiaris Patil Arpith Patrick Stoica Patrick Strawderman @@ -506,6 +513,7 @@ Samuel Ainsworth Sam Wilson sandeepshetty Sander AKA Redsandro +Sander Verweij santec Sascha Peilicke satamas @@ -542,12 +550,14 @@ Steffen Beyer Steffen Bruchmann Stephen Lavelle Steve Champagne +Steve Hoover Steve O'Hara stoskov Stu Kennedy Sungho Kim sverweij Taha Jahangir +takamori Tako Schotanus Takuji Shimokawa Tarmil diff --git a/CHANGELOG.md b/CHANGELOG.md index a7e995ab4b..2404815f88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,33 @@ +## 5.21.0 (2016-11-21) + +### Bug fixes + +Tapping/clicking the editor in [contentEditable mode](http://codemirror.net/doc/manual.html#option_inputStyle) on Chrome now puts the cursor at the tapped position. + +Fix various crashes and misbehaviors when reading composition events in [contentEditable mode](http://codemirror.net/doc/manual.html#option_inputStyle). + +Catches and ignores an IE 'Unspecified Error' when creating an editor in an iframe before there is a ``. + +[merge addon](http://codemirror.net/doc/manual.html#addon_merge): Fix several issues in the chunk-aligning feature. + +[verilog mode](http://codemirror.net/mode/verilog): Rewritten to address various issues. + +[julia mode](http://codemirror.net/mode/julia): Recognize Julia 0.5 syntax. + +[swift mode](http://codemirror.net/mode/swift): Various fixes and adjustments to current syntax. + +[markdown mode](http://codemirror.net/mode/markdown): Allow lists without a blank line above them. + +### New features + +The [`setGutterMarker`](http://codemirror.net/doc/manual.html#setGutterMarker), [`clearGutter`](http://codemirror.net/doc/manual.html#clearGutter), and [`lineInfo`](http://codemirror.net/doc/manual.html#lineInfo) methods are now available on `Doc` objects. + +The [`heightAtLine`](http://codemirror.net/doc/manual.html#heightAtLine) method now takes an extra argument to allow finding the height at the top of the line's line widgets. + +[ruby mode](http://codemirror.net/mode/ruby): `else` and `elsif` are now immediately indented. + +[vim bindings](http://codemirror.net/demo/vim.html): Bind Ctrl-T and Ctrl-D to in- and dedent in insert mode. + ## 5.20.2 (2016-10-21) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index ecfe3071f7..be834f0f10 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.20.3 + version 5.21.0

    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index cfc366f3e2..5880469189 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,23 @@

    Release notes and version history

    Version 5.x

    +

    21-11-2016: Version 5.21.0:

    + +
      +
    • Tapping/clicking the editor in contentEditable mode on Chrome now puts the cursor at the tapped position.
    • +
    • Fix various crashes and misbehaviors when reading composition events in contentEditable mode.
    • +
    • Catches and ignores an IE 'Unspecified Error' when creating an editor in an iframe before there is a <body>.
    • +
    • merge addon: Fix several issues in the chunk-aligning feature.
    • +
    • verilog mode: Rewritten to address various issues.
    • +
    • julia mode: Recognize Julia 0.5 syntax.
    • +
    • swift mode: Various fixes and adjustments to current syntax.
    • +
    • markdown mode: Allow lists without a blank line above them.
    • +
    • The setGutterMarker, clearGutter, and lineInfo methods are now available on Doc objects.
    • +
    • The heightAtLine method now takes an extra argument to allow finding the height at the top of the line's line widgets.
    • +
    • ruby mode: else and elsif are now immediately indented.
    • +
    • vim bindings: Bind Ctrl-T and Ctrl-D to in- and dedent in insert mode.
    • +
    +

    20-10-2016: Version 5.20.0:

      diff --git a/index.html b/index.html index 1d1bb3c8a2..7164296018 100644 --- a/index.html +++ b/index.html @@ -96,7 +96,7 @@

      This is CodeMirror

    - Get the current version: 5.20.2.
    + Get the current version: 5.21.0.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index 1d07d681b8..3235a47d8d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.20.3", + "version": "5.21.0", "main": "lib/codemirror.js", "description": "Full-featured in-browser code editor", "license": "MIT", diff --git a/src/edit/main.js b/src/edit/main.js index 57fcffa04e..78c6da49d3 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.20.3" +CodeMirror.version = "5.21.0" From 5fc55e8227b3c0d1d8e3178a45fbb37f6f581e48 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Nov 2016 11:24:43 +0100 Subject: [PATCH 0124/1880] Bump version number post-5.21.0 --- doc/manual.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index be834f0f10..05c49718c9 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.21.0 + version 5.21.1

    CodeMirror is a code-editor component that can be embedded in diff --git a/package.json b/package.json index 3235a47d8d..d2e45f2f87 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.21.0", + "version": "5.21.1", "main": "lib/codemirror.js", "description": "Full-featured in-browser code editor", "license": "MIT", diff --git a/src/edit/main.js b/src/edit/main.js index 78c6da49d3..64b647b5d2 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.21.0" +CodeMirror.version = "5.21.1" From d0cde7f8470d6638aee972ec29108abd564598e0 Mon Sep 17 00:00:00 2001 From: Todd Berman Date: Tue, 22 Nov 2016 11:23:04 -0800 Subject: [PATCH 0125/1880] [overlay addon] Fix the `combine` option for overlay modes inside blankLines --- addon/mode/overlay.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/addon/mode/overlay.js b/addon/mode/overlay.js index e1b9ed3753..4e96010a65 100644 --- a/addon/mode/overlay.js +++ b/addon/mode/overlay.js @@ -76,8 +76,13 @@ CodeMirror.overlayMode = function(base, overlay, combine) { innerMode: function(state) { return {state: state.base, mode: base}; }, blankLine: function(state) { - if (base.blankLine) base.blankLine(state.base); - if (overlay.blankLine) overlay.blankLine(state.overlay); + var baseToken, overlayToken; + if (base.blankLine) baseToken = base.blankLine(state.base); + if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay); + + return overlayToken == null ? + baseToken : + (combine ? baseToken + " " + overlayToken : overlayToken); } }; }; From 214b6bf63ccf3d542930a303fe96f5c8f4134365 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 23 Nov 2016 09:39:07 +0100 Subject: [PATCH 0126/1880] [overlay addon] Fix another append-null-as-string issue --- addon/mode/overlay.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/mode/overlay.js b/addon/mode/overlay.js index 4e96010a65..4a9f99a072 100644 --- a/addon/mode/overlay.js +++ b/addon/mode/overlay.js @@ -82,7 +82,7 @@ CodeMirror.overlayMode = function(base, overlay, combine) { return overlayToken == null ? baseToken : - (combine ? baseToken + " " + overlayToken : overlayToken); + (combine && baseToken != null ? baseToken + " " + overlayToken : overlayToken); } }; }; From 8bfabc472acf00eaee0d4a099f3b90d8b5dd47a8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 23 Nov 2016 09:42:52 +0100 Subject: [PATCH 0127/1880] [commonlisp mode] Recognize character literal syntax Closes #4401 --- mode/commonlisp/commonlisp.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/commonlisp/commonlisp.js b/mode/commonlisp/commonlisp.js index fb1f99c631..5b407a9285 100644 --- a/mode/commonlisp/commonlisp.js +++ b/mode/commonlisp/commonlisp.js @@ -48,6 +48,7 @@ CodeMirror.defineMode("commonlisp", function (config) { else if (/\d/.test(ch) && stream.match(/^\d*#/)) return null; else if (ch == "|") return (state.tokenize = inComment)(stream, state); else if (ch == ":") { readSym(stream); return "meta"; } + else if (ch == "\\") { stream.next(); readSym(stream); return "string-2" } else return "error"; } else { var name = readSym(stream); From 959f8690d2f643ba7730cc847da0154767c29777 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Wed, 23 Nov 2016 13:48:29 +0100 Subject: [PATCH 0128/1880] Correct bidi types for some chars --- src/util/bidi.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/util/bidi.js b/src/util/bidi.js index 4c365f4c9b..6812d4fdeb 100644 --- a/src/util/bidi.js +++ b/src/util/bidi.js @@ -121,12 +121,12 @@ export function moveLogically(line, start, dir, byUnit) { export let bidiOrdering = (function() { // Character types for codepoints 0 to 0xff let lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN" - // Character types for codepoints 0x600 to 0x6ff - let arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm" + // Character types for codepoints 0x600 to 0x6f9 + let arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmrrmmNmmmmrr1111111111" function charType(code) { if (code <= 0xf7) return lowTypes.charAt(code) else if (0x590 <= code && code <= 0x5f4) return "R" - else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600) + else if (0x600 <= code && code <= 0x6f9) return arabicTypes.charAt(code - 0x600) else if (0x6ee <= code && code <= 0x8ac) return "r" else if (0x2000 <= code && code <= 0x200b) return "w" else if (code == 0x200c) return "b" From dac0b89f8cd14b4dd64d657db6e35e4c320659ac Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Thu, 24 Nov 2016 11:38:45 +0100 Subject: [PATCH 0129/1880] Correct bidi types for remaining Arabic chars --- src/util/bidi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/bidi.js b/src/util/bidi.js index 6812d4fdeb..6a84914035 100644 --- a/src/util/bidi.js +++ b/src/util/bidi.js @@ -122,7 +122,7 @@ export let bidiOrdering = (function() { // Character types for codepoints 0 to 0xff let lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN" // Character types for codepoints 0x600 to 0x6f9 - let arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmrrmmNmmmmrr1111111111" + let arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111" function charType(code) { if (code <= 0xf7) return lowTypes.charAt(code) else if (0x590 <= code && code <= 0x5f4) return "R" From 2bed274eb4287624cdc5c07762a32c4042e3b3dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Segersv=C3=A4rd?= Date: Fri, 25 Nov 2016 14:42:07 +0100 Subject: [PATCH 0130/1880] [soy mode] Extend and add tests Add template/variable definitions, checking, types, additional keywords and indentation fixes. --- mode/soy/soy.js | 123 ++++++++++++++++++++++++++++++++++++++++++----- mode/soy/test.js | 75 +++++++++++++++++++++++++++++ test/index.html | 2 + 3 files changed, 189 insertions(+), 11 deletions(-) create mode 100644 mode/soy/test.js diff --git a/mode/soy/soy.js b/mode/soy/soy.js index 580c306f15..9fd75c6d27 100644 --- a/mode/soy/soy.js +++ b/mode/soy/soy.js @@ -45,12 +45,40 @@ return result; } + function contains(list, element) { + while (list) { + if (list.element === element) return true; + list = list.next; + } + return false; + } + + function prepend(list, element) { + return { + element: element, + next: list + }; + } + + function pop(list) { + return list && list.next; + } + + // Reference a variable `name` in `list`. + // Let `loose` be truthy to ignore missing identifiers. + function ref(list, name, loose) { + return contains(list, name) ? "variable-2" : (loose ? "variable" : "variable-2 error"); + } + return { startState: function() { return { kind: [], kindTag: [], soyState: [], + templates: null, + variables: null, + scopes: null, indent: 0, localMode: modes.html, localState: CodeMirror.startState(modes.html) @@ -63,6 +91,9 @@ kind: state.kind.concat([]), // Values of kind="" attributes. kindTag: state.kindTag.concat([]), // Opened tags with kind="" attributes. soyState: state.soyState.concat([]), + templates: state.templates, + variables: state.variables, + scopes: state.scopes, indent: state.indent, // Indentation of the following line. localMode: state.localMode, localState: CodeMirror.copyState(state.localMode, state.localState) @@ -81,19 +112,71 @@ } return "comment"; - case "variable": - if (stream.match(/^}/)) { - state.indent -= 2 * config.indentUnit; + case "templ-def": + if (match = stream.match(/^\.?([\w]+(?!\.[\w]+)*)/)) { + state.templates = prepend(state.templates, match[1]); + state.scopes = prepend(state.scopes, state.variables); + state.soyState.pop(); + return "def"; + } + stream.next(); + return null; + + case "templ-ref": + if (match = stream.match(/^\.?([\w]+)/)) { + state.soyState.pop(); + // If the first character is '.', try to match against a local template name. + if (match[0][0] == '.') { + return ref(state.templates, match[1], true); + } + // Otherwise + return "variable"; + } + stream.next(); + return null; + + case "param-def": + if (match = stream.match(/^([\w]+)(?=:)/)) { + state.variables = prepend(state.variables, match[1]); state.soyState.pop(); - return "variable-2"; + state.soyState.push("param-type"); + return "def"; + } + stream.next(); + return null; + + case "param-type": + if (stream.peek() == "}") { + state.soyState.pop(); + return null; + } + if (stream.eatWhile(/^[\w]+/)) { + return "variable-3"; + } + stream.next(); + return null; + + case "var-def": + if (match = stream.match(/^\$([\w]+)/)) { + state.variables = prepend(state.variables, match[1]); + state.soyState.pop(); + return "def"; } stream.next(); return null; case "tag": if (stream.match(/^\/?}/)) { - if (state.tag == "/template" || state.tag == "/deltemplate") state.indent = 0; - else state.indent -= (stream.current() == "/}" || indentingTags.indexOf(state.tag) == -1 ? 2 : 1) * config.indentUnit; + if (state.tag == "/template" || state.tag == "/deltemplate") { + state.variables = state.scopes = pop(state.scopes); + state.indent = 0; + } else { + if (state.tag == "/for" || state.tag == "/foreach") { + state.variables = state.scopes = pop(state.scopes); + } + state.indent -= config.indentUnit * + (stream.current() == "/}" || indentingTags.indexOf(state.tag) == -1 ? 2 : 1); + } state.soyState.pop(); return "keyword"; } else if (stream.match(/^([\w?]+)(?==)/)) { @@ -109,6 +192,12 @@ state.soyState.push("string"); return "string"; } + if (match = stream.match(/^\$([\w]+)/)) { + return ref(state.variables, match[1]); + } + if (stream.match(/(?:as|and|or|not|in)/)) { + return "keyword"; + } stream.next(); return null; @@ -135,17 +224,13 @@ return "comment"; } else if (stream.match(stream.sol() ? /^\s*\/\/.*/ : /^\s+\/\/.*/)) { return "comment"; - } else if (stream.match(/^\{\$[\w?]*/)) { - state.indent += 2 * config.indentUnit; - state.soyState.push("variable"); - return "variable-2"; } else if (stream.match(/^\{literal}/)) { state.indent += config.indentUnit; state.soyState.push("literal"); return "keyword"; } else if (match = stream.match(/^\{([\/@\\]?[\w?]*)/)) { if (match[1] != "/switch") - state.indent += (/^(\/|(else|elseif|case|default)$)/.test(match[1]) && state.tag != "switch" ? 1 : 2) * config.indentUnit; + state.indent += (/^(\/|(else|elseif|ifempty|case|default)$)/.test(match[1]) && state.tag != "switch" ? 1 : 2) * config.indentUnit; state.tag = match[1]; if (state.tag == "/" + last(state.kindTag)) { // We found the tag that opened the current kind="". @@ -155,6 +240,22 @@ state.localState = CodeMirror.startState(state.localMode); } state.soyState.push("tag"); + if (state.tag == "template" || state.tag == "deltemplate") { + state.soyState.push("templ-def"); + } + if (state.tag == "call" || state.tag == "delcall") { + state.soyState.push("templ-ref"); + } + if (state.tag == "let") { + state.soyState.push("var-def"); + } + if (state.tag == "for" || state.tag == "foreach") { + state.scopes = prepend(state.scopes, state.variables); + state.soyState.push("var-def"); + } + if (state.tag.match(/^@param\??/)) { + state.soyState.push("param-def"); + } return "keyword"; } diff --git a/mode/soy/test.js b/mode/soy/test.js new file mode 100644 index 0000000000..1a962de3e7 --- /dev/null +++ b/mode/soy/test.js @@ -0,0 +1,75 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function() { + var mode = CodeMirror.getMode({indentUnit: 2}, "soy"); + function MT(name) {test.mode(name, mode, Array.prototype.slice.call(arguments, 1));} + + MT('let-test', + '[keyword {template] [def .name][keyword }]', + ' [keyword {let] [def $name]: [string "world"][keyword /}]', + ' [tag&bracket <][tag h1][tag&bracket >]', + ' Hello, [keyword {][variable-2 $name][keyword }]', + ' [tag&bracket ]', + '[keyword {/template}]', + ''); + + MT('param-type-test', + '[keyword {@param] [def a]: ' + + '[variable-3 list]<[[[variable-3 a]: [variable-3 int], ' + + '[variable-3 b]: [variable-3 map]<[variable-3 string], ' + + '[variable-3 bool]>]]>][keyword }]'); + + MT('undefined-var', + '[keyword {][variable-2&error $var]'); + + MT('param-scope-test', + '[keyword {template] [def .a][keyword }]', + ' [keyword {@param] [def x]: [variable-3 string][keyword }]', + ' [keyword {][variable-2 $x][keyword }]', + '[keyword {/template}]', + '', + '[keyword {template] [def .b][keyword }]', + ' [keyword {][variable-2&error $x][keyword }]', + '[keyword {/template}]', + ''); + + MT('if-variable-test', + '[keyword {if] [variable-2&error $showThing][keyword }]', + ' Yo!', + '[keyword {/if}]', + ''); + + MT('defined-if-variable-test', + '[keyword {template] [def .foo][keyword }]', + ' [keyword {@param?] [def showThing]: [variable-3 bool][keyword }]', + ' [keyword {if] [variable-2 $showThing][keyword }]', + ' Yo!', + ' [keyword {/if}]', + '[keyword {/template}]', + ''); + + MT('template-calls-test', + '[keyword {template] [def .foo][keyword }]', + ' Yo!', + '[keyword {/template}]', + '[keyword {call] [variable-2 .foo][keyword /}]', + '[keyword {call] [variable foo][keyword /}]', + '[keyword {call] [variable .bar][keyword /}]', + '[keyword {call] [variable bar][keyword /}]', + ''); + + MT('foreach-scope-test', + '[keyword {foreach] [def $foo] [keyword in] [variable-2&error $foos][keyword }]', + ' [keyword {][variable-2 $foo][keyword }]', + '[keyword {/foreach}]', + '[keyword {][variable-2&error $foo][keyword }]'); + + MT('foreach-ifempty-indent-test', + '[keyword {foreach] [def $foo] [keyword in] [variable-2&error $foos][keyword }]', + ' something', + '[keyword {ifempty}]', + ' nothing', + '[keyword {/foreach}]', + ''); +})(); diff --git a/test/index.html b/test/index.html index cfa3bb71fb..6ddf5b1021 100644 --- a/test/index.html +++ b/test/index.html @@ -33,6 +33,7 @@ + @@ -122,6 +123,7 @@

    Test Suite

    + From 0d296633aa4f297741a09ad8efa031589f6b2d9c Mon Sep 17 00:00:00 2001 From: coderaiser Date: Thu, 24 Nov 2016 17:38:01 +0200 Subject: [PATCH 0131/1880] [npmignore] add files that do nothing when installed with npm --- .npmignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.npmignore b/.npmignore index 5ed053f893..de3a24080b 100644 --- a/.npmignore +++ b/.npmignore @@ -8,3 +8,5 @@ /mode/*/*.html /mode/index.html .* +bin +rollup.config.js From 69159ccd6780c51526f112a9e028b46fbf6ecb42 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 3 Dec 2016 10:18:14 +0100 Subject: [PATCH 0132/1880] [sublime bindings] Make selectBetweenBrackets multi-cursor-aware Closes #4419 --- keymap/sublime.js | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/keymap/sublime.js b/keymap/sublime.js index 98fce4d302..171e692e67 100644 --- a/keymap/sublime.js +++ b/keymap/sublime.js @@ -166,17 +166,23 @@ var mirror = "(){}[]"; function selectBetweenBrackets(cm) { - var pos = cm.getCursor(), opening = cm.scanForBracket(pos, -1); - if (!opening) return; - for (;;) { - var closing = cm.scanForBracket(pos, 1); - if (!closing) return; - if (closing.ch == mirror.charAt(mirror.indexOf(opening.ch) + 1)) { - cm.setSelection(Pos(opening.pos.line, opening.pos.ch + 1), closing.pos, false); - return true; + var ranges = cm.listSelections(), newRanges = [] + for (var i = 0; i < ranges.length; i++) { + let range = ranges[i], pos = range.head, opening = cm.scanForBracket(pos, -1); + if (!opening) return false; + for (;;) { + var closing = cm.scanForBracket(pos, 1); + if (!closing) return false; + if (closing.ch == mirror.charAt(mirror.indexOf(opening.ch) + 1)) { + newRanges.push({anchor: Pos(opening.pos.line, opening.pos.ch + 1), + head: closing.pos}); + break; + } + pos = Pos(closing.pos.line, closing.pos.ch + 1); } - pos = Pos(closing.pos.line, closing.pos.ch + 1); } + cm.setSelections(newRanges); + return true; } cmds[map["Shift-" + ctrl + "Space"] = "selectScope"] = function(cm) { From af766c48523eb70cbf672fae6165c7612ad04e1a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 3 Dec 2016 10:22:14 +0100 Subject: [PATCH 0133/1880] Fix accidental use of 'let' --- keymap/sublime.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keymap/sublime.js b/keymap/sublime.js index 171e692e67..c5d2906bc0 100644 --- a/keymap/sublime.js +++ b/keymap/sublime.js @@ -168,7 +168,7 @@ function selectBetweenBrackets(cm) { var ranges = cm.listSelections(), newRanges = [] for (var i = 0; i < ranges.length; i++) { - let range = ranges[i], pos = range.head, opening = cm.scanForBracket(pos, -1); + var range = ranges[i], pos = range.head, opening = cm.scanForBracket(pos, -1); if (!opening) return false; for (;;) { var closing = cm.scanForBracket(pos, 1); From 5e342f21ed72f87f77f70e5ac69f111e32470704 Mon Sep 17 00:00:00 2001 From: Andrew Cheng Date: Wed, 7 Dec 2016 02:33:06 -0500 Subject: [PATCH 0134/1880] [emacs keymap] export kill, killRegion, repeated so other potential emacs-type modules can use --- keymap/emacs.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/keymap/emacs.js b/keymap/emacs.js index 3eec1e5762..57cf6e8525 100644 --- a/keymap/emacs.js +++ b/keymap/emacs.js @@ -271,6 +271,8 @@ clearMark(cm); } + CodeMirror.emacs = {kill: kill, killRegion: killRegion, repeated: repeated}; + // Actual keymap var keyMap = CodeMirror.keyMap.emacs = CodeMirror.normalizeKeyMap({ From 7760d1bb83f1f881834e9ee8ea780baeb01936e5 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Fri, 9 Dec 2016 10:54:48 +0100 Subject: [PATCH 0135/1880] Add U+061C Arabic Letter Mark to special chars --- src/edit/options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edit/options.js b/src/edit/options.js index ea19d5ba2a..97587f73e4 100644 --- a/src/edit/options.js +++ b/src/edit/options.js @@ -68,7 +68,7 @@ export function defineOptions(CodeMirror) { for (let i = newBreaks.length - 1; i >= 0; i--) replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) }) - option("specialChars", /[\u0000-\u001f\u007f\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, (cm, val, old) => { + option("specialChars", /[\u0000-\u001f\u007f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, (cm, val, old) => { cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g") if (old != Init) cm.refresh() }) From 41804498097a446ee55390f2f90d27804d371c9f Mon Sep 17 00:00:00 2001 From: Tom Klancer Date: Wed, 30 Nov 2016 17:47:38 -0500 Subject: [PATCH 0136/1880] [active-line addon] Highlight active line even when text is selected Adds an option to keep the active line highlighted even when text inside the line is selected. --- addon/selection/active-line.js | 16 ++++++++++++---- demo/activeline.html | 14 +++++++++++++- doc/manual.html | 26 ++++++++++++++++++++------ 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/addon/selection/active-line.js b/addon/selection/active-line.js index b0b3f61af2..68db3f4d3b 100644 --- a/addon/selection/active-line.js +++ b/addon/selection/active-line.js @@ -3,9 +3,13 @@ // Because sometimes you need to style the cursor's line. // -// Adds an option 'styleActiveLine' which, when enabled, gives the -// active line's wrapping
    the CSS class "CodeMirror-activeline", -// and gives its background
    the class "CodeMirror-activeline-background". +// 'styleActiveLine': when enabled, gives the active line's wrapping +//
    the CSS class "CodeMirror-activeline", and gives its background +//
    the class "CodeMirror-activeline-background". +// +// 'styleActiveSelected': An optional parameter of 'styleActiveLine'. +// When enabled, keeps the active line's styling active even when text is +// selected within the line. Has no effect if 'styleActiveLine' is not enabled. (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -52,7 +56,11 @@ var active = []; for (var i = 0; i < ranges.length; i++) { var range = ranges[i]; - if (!range.empty()) continue; + if (cm.getOption('styleActiveLine').styleActiveSelected == true) { + if (range.anchor.line != range.head.line) continue; + } else { + if (!range.empty()) continue; + } var line = cm.getLineHandleVisualStart(range.head.line); if (active[active.length - 1] != line) active.push(line); } diff --git a/demo/activeline.html b/demo/activeline.html index 741f6c45a4..7a273a77ee 100644 --- a/demo/activeline.html +++ b/demo/activeline.html @@ -65,14 +65,26 @@

    Active Line Demo

    Styling the current cursor line.

    + + diff --git a/doc/manual.html b/doc/manual.html index 05c49718c9..b5b451ae5c 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2760,12 +2760,26 @@

    Addons

    like in this demo.
    selection/active-line.js
    -
    Defines a styleActiveLine option that, when enabled, - gives the wrapper of the active line the class CodeMirror-activeline, - adds a background with the class CodeMirror-activeline-background, - and adds the class CodeMirror-activeline-gutter to the - line's gutter space is enabled. See the - demo.
    +
    Controls highlighting of the active line. +
    Defines an option + styleActiveLine which, when enabled, gives the wrapper of + the active line the class CodeMirror-activeline, adds a + background with the class CodeMirror-activeline-background, + and adds the class CodeMirror-activeline-gutter to the + line's gutter space. +
    +
    + In addition, defines an option styleActiveSelected, + that controls highlighting behavior when selected. + styleActiveSelected is an optional parameter of + styleActiveLine. If true, + the active line will remain highlighted when text within the line is + selected. If false or unspecified, the active line will + become unhighlighted as soon as text is selected. Has no effect if + styleActiveLine is not enabled. +
    +
    See the demo.
    +
    selection/selection-pointer.js
    Defines a selectionPointer option which you can From 33d0057f1edbd8e48726bb357ba960645161a8b1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 13 Dec 2016 10:53:22 +0100 Subject: [PATCH 0137/1880] [active-line addon] Rename and clean up nonEmpty options Issue #4413 --- addon/selection/active-line.js | 32 +++++++++++--------------------- demo/activeline.html | 14 ++++++-------- doc/manual.html | 34 ++++++++++++++-------------------- 3 files changed, 31 insertions(+), 49 deletions(-) diff --git a/addon/selection/active-line.js b/addon/selection/active-line.js index 68db3f4d3b..aa295d0d86 100644 --- a/addon/selection/active-line.js +++ b/addon/selection/active-line.js @@ -1,16 +1,6 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE -// Because sometimes you need to style the cursor's line. -// -// 'styleActiveLine': when enabled, gives the active line's wrapping -//
    the CSS class "CodeMirror-activeline", and gives its background -//
    the class "CodeMirror-activeline-background". -// -// 'styleActiveSelected': An optional parameter of 'styleActiveLine'. -// When enabled, keeps the active line's styling active even when text is -// selected within the line. Has no effect if 'styleActiveLine' is not enabled. - (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); @@ -25,16 +15,18 @@ var GUTT_CLASS = "CodeMirror-activeline-gutter"; CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { - var prev = old && old != CodeMirror.Init; - if (val && !prev) { - cm.state.activeLines = []; - updateActiveLines(cm, cm.listSelections()); - cm.on("beforeSelectionChange", selectionChange); - } else if (!val && prev) { + var prev = old == CodeMirror.Init ? false : old; + if (val == prev) return + if (prev) { cm.off("beforeSelectionChange", selectionChange); clearActiveLines(cm); delete cm.state.activeLines; } + if (val) { + cm.state.activeLines = []; + updateActiveLines(cm, cm.listSelections()); + cm.on("beforeSelectionChange", selectionChange); + } }); function clearActiveLines(cm) { @@ -56,11 +48,9 @@ var active = []; for (var i = 0; i < ranges.length; i++) { var range = ranges[i]; - if (cm.getOption('styleActiveLine').styleActiveSelected == true) { - if (range.anchor.line != range.head.line) continue; - } else { - if (!range.empty()) continue; - } + var option = cm.getOption("styleActiveLine"); + if (typeof option == "object" && option.nonEmpty ? range.anchor.line != range.head.line : !range.empty()) + continue var line = cm.getLineHandleVisualStart(range.head.line); if (active[active.length - 1] != line) active.push(line); } diff --git a/demo/activeline.html b/demo/activeline.html index 7a273a77ee..86c8c18e1d 100644 --- a/demo/activeline.html +++ b/demo/activeline.html @@ -65,26 +65,24 @@

    Active Line Demo

    Styling the current cursor line.

    - + diff --git a/doc/manual.html b/doc/manual.html index b5b451ae5c..0065790810 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2760,26 +2760,20 @@

    Addons

    like in this demo.
    selection/active-line.js
    -
    Controls highlighting of the active line. -
    Defines an option - styleActiveLine which, when enabled, gives the wrapper of - the active line the class CodeMirror-activeline, adds a - background with the class CodeMirror-activeline-background, - and adds the class CodeMirror-activeline-gutter to the - line's gutter space. -
    -
    - In addition, defines an option styleActiveSelected, - that controls highlighting behavior when selected. - styleActiveSelected is an optional parameter of - styleActiveLine. If true, - the active line will remain highlighted when text within the line is - selected. If false or unspecified, the active line will - become unhighlighted as soon as text is selected. Has no effect if - styleActiveLine is not enabled. -
    -
    See the demo.
    - +
    Defines a styleActiveLine option that, when + enabled, gives the wrapper of the line that contains the cursor + the class CodeMirror-activeline, adds a background + with the class CodeMirror-activeline-background, + and adds the class CodeMirror-activeline-gutter to + the line's gutter space is enabled. The option's value may be a + boolean or an object specifying the following options: +
    +
    nonEmpty: bool
    +
    Controls whether single-line selections, or just cursor + selections, are styled. Defaults to false (only cursor + selections).
    +
    + See the demo.
    selection/selection-pointer.js
    Defines a selectionPointer option which you can From 460452d73c3a6100662f33bf675e8eca07becaa0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 13 Dec 2016 23:05:37 +0100 Subject: [PATCH 0138/1880] =?UTF-8?q?Upgrade=20Bubl=C3=A9,=20use=20namedFu?= =?UTF-8?q?nctionExpressions=20option?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- rollup.config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d2e45f2f87..e2b97a9cd1 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "node-static": "0.6.0", "phantomjs-prebuilt": "^2.1.12", "rollup": "^0.34.10", - "rollup-plugin-buble": "^0.14.0", + "rollup-plugin-buble": "^0.15.0", "rollup-watch": "^2.5.0" }, "bugs": "http://github.com/codemirror/CodeMirror/issues", diff --git a/rollup.config.js b/rollup.config.js index 584dfe1ec4..9a17b24ff7 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -14,5 +14,5 @@ export default { format: "umd", dest: "lib/codemirror.js", moduleName: "CodeMirror", - plugins: [ buble() ] + plugins: [ buble({namedFunctionExpressions: false}) ] }; From 957c28f4d8c41afe8b0e0d6ec3a7a454590761ce Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 14 Dec 2016 08:26:07 +0100 Subject: [PATCH 0139/1880] [javascript mode] Accept strings and numbers as type expressions Closes #4432 --- mode/javascript/javascript.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index a717745897..b9f3925951 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -539,6 +539,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function typeexpr(type) { if (type == "variable") {cx.marked = "variable-3"; return cont(afterType);} + if (type == "string" || type == "number") return cont(afterType); if (type == "{") return cont(commasep(typeprop, "}")) if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType) } @@ -559,6 +560,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function afterType(type, value) { if (value == "<") return cont(commasep(typeexpr, ">"), afterType) + if (value == "|") return cont(typeexpr) if (type == "[") return cont(expect("]"), afterType) } function vardef() { From 70ea4303bc4efcdb7ef1956bb6123667440f0a19 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 14 Dec 2016 18:49:33 +0100 Subject: [PATCH 0140/1880] [source-highlight util] Fix looking up of modes --- bin/source-highlight | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/bin/source-highlight b/bin/source-highlight index 6d15f1ae3f..0d6239c2bc 100755 --- a/bin/source-highlight +++ b/bin/source-highlight @@ -17,14 +17,11 @@ if (sPos == -1 || sPos == process.argv.length - 1) { process.exit(1); } var lang = process.argv[sPos + 1].toLowerCase(), modeName = lang; -CodeMirror.modeInfo.forEach(function(info) { - if (info.mime == lang) { - modeName = info.mode; - } else if (info.name.toLowerCase() == lang) { - modeName = info.mode; - lang = info.mime; - } -}); +var found = CodeMirror.findModeByMIME(lang) || CodeMirror.findModeByName(lang) +if (found) { + modeName = found.mode + lang = found.mime +} if (!CodeMirror.modes[modeName]) require("../mode/" + modeName + "/" + modeName + ".js"); From c2a11a315ebe95478134e9eb94c040f14021df4f Mon Sep 17 00:00:00 2001 From: ficristo Date: Wed, 14 Dec 2016 20:35:27 +0100 Subject: [PATCH 0141/1880] [css mode] Add will-change property and its values --- mode/css/css.js | 12 ++++++------ mode/stylus/stylus.js | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index 985287f475..a1d5a388e5 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -524,7 +524,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "transition-property", "transition-timing-function", "unicode-bidi", "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", - "voice-volume", "volume", "white-space", "widows", "width", "word-break", + "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break", "word-spacing", "word-wrap", "z-index", // SVG-specific "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", @@ -598,7 +598,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch", "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse", - "compact", "condensed", "contain", "content", + "compact", "condensed", "contain", "content", "contents", "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal", "decimal-leading-zero", "default", "default-button", "dense", "destination-atop", @@ -641,7 +641,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize", "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", - "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", + "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote", "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter", @@ -653,7 +653,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running", "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen", - "scroll", "scrollbar", "se-resize", "searchfield", + "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield", "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", "searchfield-results-decoration", "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", @@ -671,9 +671,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", - "trad-chinese-formal", "trad-chinese-informal", + "trad-chinese-formal", "trad-chinese-informal", "transform", "translate", "translate3d", "translateX", "translateY", "translateZ", - "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", + "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up", "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", diff --git a/mode/stylus/stylus.js b/mode/stylus/stylus.js index 662cd03c04..8d83a01807 100644 --- a/mode/stylus/stylus.js +++ b/mode/stylus/stylus.js @@ -732,11 +732,11 @@ var documentTypes_ = ["domain", "regexp", "url", "url-prefix"]; var mediaTypes_ = ["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"]; var mediaFeatures_ = ["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid"]; - var propertyKeywords_ = ["align-content","align-items","align-self","alignment-adjust","alignment-baseline","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","baseline-shift","binding","bleed","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-feature-settings","font-family","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-weight","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-position","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","justify-content","left","letter-spacing","line-break","line-height","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marker-offset","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","max-height","max-width","min-height","min-width","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotation","rotation-point","ruby-align","ruby-overhang","ruby-position","ruby-span","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-outline","text-overflow","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","word-break","word-spacing","word-wrap","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode","font-smoothing","osx-font-smoothing"]; + var propertyKeywords_ = ["align-content","align-items","align-self","alignment-adjust","alignment-baseline","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","baseline-shift","binding","bleed","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-feature-settings","font-family","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-weight","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-position","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","justify-content","left","letter-spacing","line-break","line-height","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marker-offset","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","max-height","max-width","min-height","min-width","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotation","rotation-point","ruby-align","ruby-overhang","ruby-position","ruby-span","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-outline","text-overflow","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode","font-smoothing","osx-font-smoothing"]; var nonStandardPropertyKeywords_ = ["scrollbar-arrow-color","scrollbar-base-color","scrollbar-dark-shadow-color","scrollbar-face-color","scrollbar-highlight-color","scrollbar-shadow-color","scrollbar-3d-light-color","scrollbar-track-color","shape-inside","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","zoom"]; var fontProperties_ = ["font-family","src","unicode-range","font-variant","font-feature-settings","font-stretch","font-weight","font-style"]; var colorKeywords_ = ["aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgreen","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgreen","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","snow","springgreen","steelblue","tan","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen"]; - var valueKeywords_ = ["above","absolute","activeborder","additive","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alphabetic","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","attr","auto","avoid","avoid-column","avoid-page","avoid-region","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","bullets","button","button-bevel","buttonface","buttonhighlight","buttonshadow","buttontext","calc","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","column","compact","condensed","contain","content","content-box","context-menu","continuous","copy","counter","counters","cover","crop","cross","crosshair","currentcolor","cursive","cyclic","dashed","decimal","decimal-leading-zero","default","default-button","destination-atop","destination-in","destination-out","destination-over","devanagari","disc","discard","disclosure-closed","disclosure-open","document","dot-dash","dot-dot-dash","dotted","double","down","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ethiopic-numeric","ew-resize","expanded","extends","extra-condensed","extra-expanded","fantasy","fast","fill","fixed","flat","flex","footnotes","forwards","from","geometricPrecision","georgian","graytext","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-flex","inline-table","inset","inside","intrinsic","invert","italic","japanese-formal","japanese-informal","justify","kannada","katakana","katakana-iroha","keep-all","khmer","korean-hangul-formal","korean-hanja-formal","korean-hanja-informal","landscape","lao","large","larger","left","level","lighter","line-through","linear","linear-gradient","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","malayalam","match","matrix","matrix3d","media-controls-background","media-current-time-display","media-fullscreen-button","media-mute-button","media-play-button","media-return-to-realtime-button","media-rewind-button","media-seek-back-button","media-seek-forward-button","media-slider","media-sliderthumb","media-time-remaining-display","media-volume-slider","media-volume-slider-container","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menulist-text","menulist-textfield","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","numbers","numeric","nw-resize","nwse-resize","oblique","octal","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","perspective","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radial-gradient","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeating-linear-gradient","repeating-radial-gradient","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","rotate","rotate3d","rotateX","rotateY","rotateZ","round","row-resize","rtl","run-in","running","s-resize","sans-serif","scale","scale3d","scaleX","scaleY","scaleZ","scroll","scrollbar","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","semi-condensed","semi-expanded","separate","serif","show","sidama","simp-chinese-formal","simp-chinese-informal","single","skew","skewX","skewY","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","solid","somali","source-atop","source-in","source-out","source-over","space","spell-out","square","square-button","start","static","status-bar","stretch","stroke","sub","subpixel-antialiased","super","sw-resize","symbolic","symbols","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","tamil","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","trad-chinese-formal","trad-chinese-informal","translate","translate3d","translateX","translateY","translateZ","transparent","ultra-condensed","ultra-expanded","underline","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","var","vertical","vertical-text","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","words","x-large","x-small","xor","xx-large","xx-small","bicubic","optimizespeed","grayscale","row","row-reverse","wrap","wrap-reverse","column-reverse","flex-start","flex-end","space-between","space-around"]; + var valueKeywords_ = ["above","absolute","activeborder","additive","activecaption","afar","after-white-space","ahead","alias","all","all-scroll","alphabetic","alternate","always","amharic","amharic-abegede","antialiased","appworkspace","arabic-indic","armenian","asterisks","attr","auto","avoid","avoid-column","avoid-page","avoid-region","background","backwards","baseline","below","bidi-override","binary","bengali","blink","block","block-axis","bold","bolder","border","border-box","both","bottom","break","break-all","break-word","bullets","button","button-bevel","buttonface","buttonhighlight","buttonshadow","buttontext","calc","cambodian","capitalize","caps-lock-indicator","caption","captiontext","caret","cell","center","checkbox","circle","cjk-decimal","cjk-earthly-branch","cjk-heavenly-stem","cjk-ideographic","clear","clip","close-quote","col-resize","collapse","column","compact","condensed","contain","content","contents","content-box","context-menu","continuous","copy","counter","counters","cover","crop","cross","crosshair","currentcolor","cursive","cyclic","dashed","decimal","decimal-leading-zero","default","default-button","destination-atop","destination-in","destination-out","destination-over","devanagari","disc","discard","disclosure-closed","disclosure-open","document","dot-dash","dot-dot-dash","dotted","double","down","e-resize","ease","ease-in","ease-in-out","ease-out","element","ellipse","ellipsis","embed","end","ethiopic","ethiopic-abegede","ethiopic-abegede-am-et","ethiopic-abegede-gez","ethiopic-abegede-ti-er","ethiopic-abegede-ti-et","ethiopic-halehame-aa-er","ethiopic-halehame-aa-et","ethiopic-halehame-am-et","ethiopic-halehame-gez","ethiopic-halehame-om-et","ethiopic-halehame-sid-et","ethiopic-halehame-so-et","ethiopic-halehame-ti-er","ethiopic-halehame-ti-et","ethiopic-halehame-tig","ethiopic-numeric","ew-resize","expanded","extends","extra-condensed","extra-expanded","fantasy","fast","fill","fixed","flat","flex","footnotes","forwards","from","geometricPrecision","georgian","graytext","groove","gujarati","gurmukhi","hand","hangul","hangul-consonant","hebrew","help","hidden","hide","higher","highlight","highlighttext","hiragana","hiragana-iroha","horizontal","hsl","hsla","icon","ignore","inactiveborder","inactivecaption","inactivecaptiontext","infinite","infobackground","infotext","inherit","initial","inline","inline-axis","inline-block","inline-flex","inline-table","inset","inside","intrinsic","invert","italic","japanese-formal","japanese-informal","justify","kannada","katakana","katakana-iroha","keep-all","khmer","korean-hangul-formal","korean-hanja-formal","korean-hanja-informal","landscape","lao","large","larger","left","level","lighter","line-through","linear","linear-gradient","lines","list-item","listbox","listitem","local","logical","loud","lower","lower-alpha","lower-armenian","lower-greek","lower-hexadecimal","lower-latin","lower-norwegian","lower-roman","lowercase","ltr","malayalam","match","matrix","matrix3d","media-controls-background","media-current-time-display","media-fullscreen-button","media-mute-button","media-play-button","media-return-to-realtime-button","media-rewind-button","media-seek-back-button","media-seek-forward-button","media-slider","media-sliderthumb","media-time-remaining-display","media-volume-slider","media-volume-slider-container","media-volume-sliderthumb","medium","menu","menulist","menulist-button","menulist-text","menulist-textfield","menutext","message-box","middle","min-intrinsic","mix","mongolian","monospace","move","multiple","myanmar","n-resize","narrower","ne-resize","nesw-resize","no-close-quote","no-drop","no-open-quote","no-repeat","none","normal","not-allowed","nowrap","ns-resize","numbers","numeric","nw-resize","nwse-resize","oblique","octal","open-quote","optimizeLegibility","optimizeSpeed","oriya","oromo","outset","outside","outside-shape","overlay","overline","padding","padding-box","painted","page","paused","persian","perspective","plus-darker","plus-lighter","pointer","polygon","portrait","pre","pre-line","pre-wrap","preserve-3d","progress","push-button","radial-gradient","radio","read-only","read-write","read-write-plaintext-only","rectangle","region","relative","repeat","repeating-linear-gradient","repeating-radial-gradient","repeat-x","repeat-y","reset","reverse","rgb","rgba","ridge","right","rotate","rotate3d","rotateX","rotateY","rotateZ","round","row-resize","rtl","run-in","running","s-resize","sans-serif","scale","scale3d","scaleX","scaleY","scaleZ","scroll","scrollbar","scroll-position","se-resize","searchfield","searchfield-cancel-button","searchfield-decoration","searchfield-results-button","searchfield-results-decoration","semi-condensed","semi-expanded","separate","serif","show","sidama","simp-chinese-formal","simp-chinese-informal","single","skew","skewX","skewY","skip-white-space","slide","slider-horizontal","slider-vertical","sliderthumb-horizontal","sliderthumb-vertical","slow","small","small-caps","small-caption","smaller","solid","somali","source-atop","source-in","source-out","source-over","space","spell-out","square","square-button","start","static","status-bar","stretch","stroke","sub","subpixel-antialiased","super","sw-resize","symbolic","symbols","table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row","table-row-group","tamil","telugu","text","text-bottom","text-top","textarea","textfield","thai","thick","thin","threeddarkshadow","threedface","threedhighlight","threedlightshadow","threedshadow","tibetan","tigre","tigrinya-er","tigrinya-er-abegede","tigrinya-et","tigrinya-et-abegede","to","top","trad-chinese-formal","trad-chinese-informal","translate","translate3d","translateX","translateY","translateZ","transparent","ultra-condensed","ultra-expanded","underline","up","upper-alpha","upper-armenian","upper-greek","upper-hexadecimal","upper-latin","upper-norwegian","upper-roman","uppercase","urdu","url","var","vertical","vertical-text","visible","visibleFill","visiblePainted","visibleStroke","visual","w-resize","wait","wave","wider","window","windowframe","windowtext","words","x-large","x-small","xor","xx-large","xx-small","bicubic","optimizespeed","grayscale","row","row-reverse","wrap","wrap-reverse","column-reverse","flex-start","flex-end","space-between","space-around", "unset"]; var wordOperatorKeywords_ = ["in","and","or","not","is not","is a","is","isnt","defined","if unless"], blockKeywords_ = ["for","if","else","unless", "from", "to"], From 897bb77e55846cfefca7d84ede99f83cf4b2747e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 15 Dec 2016 10:44:28 +0100 Subject: [PATCH 0142/1880] [javascript mode] Recognize TS bool literal types and type names with dots Closes #4437 --- 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 b9f3925951..2ad7a1e970 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -539,7 +539,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function typeexpr(type) { if (type == "variable") {cx.marked = "variable-3"; return cont(afterType);} - if (type == "string" || type == "number") return cont(afterType); + if (type == "string" || type == "number" || type == "atom") return cont(afterType); if (type == "{") return cont(commasep(typeprop, "}")) if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType) } @@ -560,7 +560,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function afterType(type, value) { if (value == "<") return cont(commasep(typeexpr, ">"), afterType) - if (value == "|") return cont(typeexpr) + if (value == "|" || type == ".") return cont(typeexpr) if (type == "[") return cont(expect("]"), afterType) } function vardef() { From b0d8dd4f53fa88d1e6447cf2d759159a53f84229 Mon Sep 17 00:00:00 2001 From: Rishi Goomar Date: Thu, 1 Dec 2016 09:40:09 -0600 Subject: [PATCH 0143/1880] [mode/meta] Allow for syntax highlighting on ".R" files --- mode/meta.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/meta.js b/mode/meta.js index 8faf7677df..47364448f1 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -109,7 +109,7 @@ {name: "Python", mime: "text/x-python", mode: "python", ext: ["BUILD", "bzl", "py", "pyw"], file: /^(BUCK|BUILD)$/}, {name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]}, {name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]}, - {name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r"], alias: ["rscript"]}, + {name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r", "R"], alias: ["rscript"]}, {name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"], alias: ["rst"]}, {name: "RPM Changes", mime: "text/x-rpm-changes", mode: "rpm"}, {name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]}, From e157e82a86cf1464feb21d81c66218c6d14f6435 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 15 Dec 2016 11:51:20 +0100 Subject: [PATCH 0144/1880] Add optionChange event Issue #4417 --- doc/manual.html | 3 +++ src/edit/methods.js | 1 + 2 files changed, 4 insertions(+) diff --git a/doc/manual.html b/doc/manual.html index 0065790810..c6745e3ce6 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -639,6 +639,9 @@

    Events

    or resized. Mostly useful to invalidate cached values that depend on the editor or character size.
    +
    "optionChange" (instance: CodeMirror, option: string)
    +
    Dispatched every time an option is changed with setOption.
    +
    "scrollCursorIntoView" (instance: CodeMirror, event: Event)
    Fires when the editor tries to scroll its cursor into view. Can be hooked into to take care of additional scrollable diff --git a/src/edit/methods.js b/src/edit/methods.js index 7efaf20e2c..144e4773f6 100644 --- a/src/edit/methods.js +++ b/src/edit/methods.js @@ -45,6 +45,7 @@ export default function(CodeMirror) { options[option] = value if (optionHandlers.hasOwnProperty(option)) operation(this, optionHandlers[option])(this, value, old) + signal(this, "optionChange", this, option) }, getOption: function(option) {return this.options[option]}, From 35ec5ee2169aae3b0efe8ca437e063833c80f5d9 Mon Sep 17 00:00:00 2001 From: callodacity Date: Sat, 10 Dec 2016 11:11:19 +1100 Subject: [PATCH 0145/1880] [markdown mode] Improve markdown image lookahead --- mode/markdown/markdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 6aedc360b0..86c017c3f0 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -436,7 +436,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return getType(state); } - if (ch === '[' && state.imageMarker) { + if (ch === '[' && stream.match(/[^\]]*\](\(.*\)| ?\[.*?\])/, false) && state.imageMarker) { state.imageMarker = false; state.imageAltText = true if (modeCfg.highlightFormatting) state.formatting = "image"; From 1b9056f861f28d5baed07718eacae9988d0fd266 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 15 Dec 2016 12:07:22 +0100 Subject: [PATCH 0146/1880] [markdown mode] Make image lookahead a little cheaper Issue #4426 --- mode/markdown/markdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 86c017c3f0..4cc1dc6890 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -436,7 +436,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return getType(state); } - if (ch === '[' && stream.match(/[^\]]*\](\(.*\)| ?\[.*?\])/, false) && state.imageMarker) { + if (ch === '[' && state.imageMarker && stream.match(/[^\]]*\](\(.*?\)| ?\[.*?\])/, false)) { state.imageMarker = false; state.imageAltText = true if (modeCfg.highlightFormatting) state.formatting = "image"; From 12bece3ae4cb814344d1cf3c786f2dc0e7026ad5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 15 Dec 2016 12:18:44 +0100 Subject: [PATCH 0147/1880] Remove timeout kludge in guttersChanged Closes #4412 --- src/edit/options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edit/options.js b/src/edit/options.js index 97587f73e4..dffc577be6 100644 --- a/src/edit/options.js +++ b/src/edit/options.js @@ -158,7 +158,7 @@ export function defineOptions(CodeMirror) { function guttersChanged(cm) { updateGutters(cm) regChange(cm) - setTimeout(() => alignHorizontally(cm), 20) + alignHorizontally(cm) } function dragDropChanged(cm, value, old) { From 45c54ada1942566a25bc16bb32eb4ebd868ce22a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 15 Dec 2016 13:50:31 +0100 Subject: [PATCH 0148/1880] [merge addon] Don't use DMP's cleanupSemantic function It sometimes produces invalid output. Closes #4410 --- addon/merge/merge.js | 1 - 1 file changed, 1 deletion(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index f0d746449d..352e27dc6f 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -571,7 +571,6 @@ var dmp = new diff_match_patch(); function getDiff(a, b) { var diff = dmp.diff_main(a, b); - dmp.diff_cleanupSemantic(diff); // The library sometimes leaves in empty parts, which confuse the algorithm for (var i = 0; i < diff.length; ++i) { var part = diff[i]; From 900659feeb6d4ce95abb68c7d68767c1bb586111 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 15 Dec 2016 13:54:30 +0100 Subject: [PATCH 0149/1880] Don't autofocus until the editor has a .state property Since the input object might try to read from that on focusing Issue #4439 --- src/edit/CodeMirror.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/edit/CodeMirror.js b/src/edit/CodeMirror.js index a3dc622cf1..3c482c599f 100644 --- a/src/edit/CodeMirror.js +++ b/src/edit/CodeMirror.js @@ -45,7 +45,6 @@ export function CodeMirror(place, options) { themeChanged(this) if (options.lineWrapping) this.display.wrapper.className += " CodeMirror-wrap" - if (options.autofocus && !mobile) display.input.focus() initScrollbars(this) this.state = { @@ -64,6 +63,8 @@ export function CodeMirror(place, options) { specialChars: null } + if (options.autofocus && !mobile) display.input.focus() + // Override magic textarea content restore that IE sometimes does // on our hidden textarea on reload if (ie && ie_version < 11) setTimeout(() => this.display.input.reset(true), 20) From d5d12e0d0a631034c6363e113c808b0d6c466783 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Thu, 29 Sep 2016 11:11:38 +0200 Subject: [PATCH 0150/1880] Convert some classes to ES6 --- src/display/scrollbars.js | 81 +++++++++++---------- src/display/update_display.js | 44 ++++++------ src/input/ContentEditableInput.js | 114 +++++++++++++++--------------- src/input/TextareaInput.js | 108 ++++++++++++++-------------- src/util/misc.js | 2 +- 5 files changed, 177 insertions(+), 172 deletions(-) diff --git a/src/display/scrollbars.js b/src/display/scrollbars.js index a85fffe9a5..2026a3b0a1 100644 --- a/src/display/scrollbars.js +++ b/src/display/scrollbars.js @@ -3,7 +3,7 @@ import { on } from "../util/event" import { scrollGap, paddingVert } from "../measurement/position_measurement" import { ie, ie_version, mac, mac_geMountainLion } from "../util/browser" import { updateHeightsInViewport } from "./update_lines" -import { copyObj, Delayed } from "../util/misc" +import { Delayed } from "../util/misc" import { setScrollLeft, setScrollTop } from "./scroll_events" @@ -27,26 +27,26 @@ export function measureForScrollbars(cm) { } } -function NativeScrollbars(place, scroll, cm) { - this.cm = cm - let vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar") - let horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar") - place(vert); place(horiz) - - on(vert, "scroll", () => { - if (vert.clientHeight) scroll(vert.scrollTop, "vertical") - }) - on(horiz, "scroll", () => { - if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal") - }) - - this.checkedZeroWidth = false - // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). - if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px" -} +class NativeScrollbars { + constructor(place, scroll, cm) { + this.cm = cm + let vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar") + let horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar") + place(vert); place(horiz) + + on(vert, "scroll", () => { + if (vert.clientHeight) scroll(vert.scrollTop, "vertical") + }) + on(horiz, "scroll", () => { + if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal") + }) + + this.checkedZeroWidth = false + // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). + if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px" + } -NativeScrollbars.prototype = copyObj({ - update: function(measure) { + update(measure) { let needsH = measure.scrollWidth > measure.clientWidth + 1 let needsV = measure.scrollHeight > measure.clientHeight + 1 let sWidth = measure.nativeBarWidth @@ -81,23 +81,27 @@ NativeScrollbars.prototype = copyObj({ } return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0} - }, - setScrollLeft: function(pos) { + } + + setScrollLeft(pos) { if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz) - }, - setScrollTop: function(pos) { + } + + setScrollTop(pos) { if (this.vert.scrollTop != pos) this.vert.scrollTop = pos if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert) - }, - zeroWidthHack: function() { + } + + zeroWidthHack() { let w = mac && !mac_geMountainLion ? "12px" : "18px" this.horiz.style.height = this.vert.style.width = w this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none" this.disableHoriz = new Delayed this.disableVert = new Delayed - }, - enableZeroWidthBar: function(bar, delay) { + } + + enableZeroWidthBar(bar, delay) { bar.style.pointerEvents = "auto" function maybeDisable() { // To find out whether the scrollbar is still visible, we @@ -112,22 +116,21 @@ NativeScrollbars.prototype = copyObj({ else delay.set(1000, maybeDisable) } delay.set(1000, maybeDisable) - }, - clear: function() { + } + + clear() { let parent = this.horiz.parentNode parent.removeChild(this.horiz) parent.removeChild(this.vert) } -}, NativeScrollbars.prototype) - -function NullScrollbars() {} +} -NullScrollbars.prototype = copyObj({ - update: function() { return {bottom: 0, right: 0} }, - setScrollLeft: function() {}, - setScrollTop: function() {}, - clear: function() {} -}, NullScrollbars.prototype) +class NullScrollbars { + update() { return {bottom: 0, right: 0} } + setScrollLeft() {} + setScrollTop() {} + clear() {} +} export function updateScrollbars(cm, measure) { if (!measure) measure = measureForScrollbars(cm) diff --git a/src/display/update_display.js b/src/display/update_display.js index 4e016a2515..17d5a069e5 100644 --- a/src/display/update_display.js +++ b/src/display/update_display.js @@ -17,28 +17,30 @@ import { adjustView, countDirtyView, resetView } from "./view_tracking" // DISPLAY DRAWING -export function DisplayUpdate(cm, viewport, force) { - let display = cm.display - - this.viewport = viewport - // Store some values that we'll need later (but don't want to force a relayout for) - this.visible = visibleLines(display, cm.doc, viewport) - this.editorIsHidden = !display.wrapper.offsetWidth - this.wrapperHeight = display.wrapper.clientHeight - this.wrapperWidth = display.wrapper.clientWidth - this.oldDisplayWidth = displayWidth(cm) - this.force = force - this.dims = getDimensions(cm) - this.events = [] -} +export class DisplayUpdate { + constructor(cm, viewport, force) { + let display = cm.display + + this.viewport = viewport + // Store some values that we'll need later (but don't want to force a relayout for) + this.visible = visibleLines(display, cm.doc, viewport) + this.editorIsHidden = !display.wrapper.offsetWidth + this.wrapperHeight = display.wrapper.clientHeight + this.wrapperWidth = display.wrapper.clientWidth + this.oldDisplayWidth = displayWidth(cm) + this.force = force + this.dims = getDimensions(cm) + this.events = [] + } -DisplayUpdate.prototype.signal = function(emitter, type) { - if (hasHandler(emitter, type)) - this.events.push(arguments) -} -DisplayUpdate.prototype.finish = function() { - for (let i = 0; i < this.events.length; i++) - signal.apply(null, this.events[i]) + signal(emitter, type) { + if (hasHandler(emitter, type)) + this.events.push(arguments) + } + finish() { + for (let i = 0; i < this.events.length; i++) + signal.apply(null, this.events[i]) + } } export function maybeClipScrollbars(cm) { diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index d76058ffd5..57114af681 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -12,21 +12,21 @@ import { getBidiPartAt, getOrder } from "../util/bidi" import { gecko, ie_version } from "../util/browser" import { contains, range, removeChildrenAndAdd, selectInput } from "../util/dom" import { on, signalDOMEvent } from "../util/event" -import { copyObj, Delayed, lst, nothing, sel_dontScroll } from "../util/misc" +import { Delayed, lst, sel_dontScroll } from "../util/misc" // CONTENTEDITABLE INPUT STYLE -export default function ContentEditableInput(cm) { - this.cm = cm - this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null - this.polling = new Delayed() - this.composing = null - this.gracePeriod = false - this.readDOMTimeout = null -} +export default class ContentEditableInput { + constructor(cm) { + this.cm = cm + this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null + this.polling = new Delayed() + this.composing = null + this.gracePeriod = false + this.readDOMTimeout = null + } -ContentEditableInput.prototype = copyObj({ - init: function(display) { + init(display) { let input = this, cm = input.cm let div = input.div = display.lineDiv disableBrowserMagic(div, cm.options.spellcheck) @@ -99,21 +99,21 @@ ContentEditableInput.prototype = copyObj({ } on(div, "copy", onCopyCut) on(div, "cut", onCopyCut) - }, + } - prepareSelection: function() { + prepareSelection() { let result = prepareSelection(this.cm, false) result.focus = this.cm.state.focused return result - }, + } - showSelection: function(info, takeFocus) { + showSelection(info, takeFocus) { if (!info || !this.cm.display.view.length) return if (info.focus || takeFocus) this.showPrimarySelection() this.showMultipleSelections(info) - }, + } - showPrimarySelection: function() { + showPrimarySelection() { let sel = window.getSelection(), prim = this.cm.doc.sel.primary() let curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset) let curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset) @@ -154,48 +154,48 @@ ContentEditableInput.prototype = copyObj({ else if (gecko) this.startGracePeriod() } this.rememberSelection() - }, + } - startGracePeriod: function() { + startGracePeriod() { clearTimeout(this.gracePeriod) this.gracePeriod = setTimeout(() => { this.gracePeriod = false if (this.selectionChanged()) this.cm.operation(() => this.cm.curOp.selectionChanged = true) }, 20) - }, + } - showMultipleSelections: function(info) { + showMultipleSelections(info) { removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors) removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection) - }, + } - rememberSelection: function() { + rememberSelection() { let sel = window.getSelection() this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset - }, + } - selectionInEditor: function() { + selectionInEditor() { let sel = window.getSelection() if (!sel.rangeCount) return false let node = sel.getRangeAt(0).commonAncestorContainer return contains(this.div, node) - }, + } - focus: function() { + focus() { if (this.cm.options.readOnly != "nocursor") { if (!this.selectionInEditor()) this.showSelection(this.prepareSelection(), true) this.div.focus() } - }, - blur: function() { this.div.blur() }, - getField: function() { return this.div }, + } + blur() { this.div.blur() } + getField() { return this.div } - supportsTouch: function() { return true }, + supportsTouch() { return true } - receivedFocus: function() { + receivedFocus() { let input = this if (this.selectionInEditor()) this.pollSelection() @@ -209,15 +209,15 @@ ContentEditableInput.prototype = copyObj({ } } this.polling.set(this.cm.options.pollInterval, poll) - }, + } - selectionChanged: function() { + selectionChanged() { let sel = window.getSelection() return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset - }, + } - pollSelection: function() { + pollSelection() { if (!this.composing && this.readDOMTimeout == null && !this.gracePeriod && this.selectionChanged()) { let sel = window.getSelection(), cm = this.cm this.rememberSelection() @@ -228,9 +228,9 @@ ContentEditableInput.prototype = copyObj({ if (anchor.bad || head.bad) cm.curOp.selectionChanged = true }) } - }, + } - pollContent: function() { + pollContent() { if (this.readDOMTimeout != null) { clearTimeout(this.readDOMTimeout) this.readDOMTimeout = null @@ -291,22 +291,22 @@ ContentEditableInput.prototype = copyObj({ replaceRange(cm.doc, newText, chFrom, chTo, "+input") return true } - }, + } - ensurePolled: function() { + ensurePolled() { this.forceCompositionEnd() - }, - reset: function() { + } + reset() { this.forceCompositionEnd() - }, - forceCompositionEnd: function() { + } + forceCompositionEnd() { if (!this.composing) return this.composing = null if (!this.pollContent()) regChange(this.cm) this.div.blur() this.div.focus() - }, - readFromDOMSoon: function() { + } + readFromDOMSoon() { if (this.readDOMTimeout != null) return this.readDOMTimeout = setTimeout(() => { this.readDOMTimeout = null @@ -314,27 +314,27 @@ ContentEditableInput.prototype = copyObj({ if (this.cm.isReadOnly() || !this.pollContent()) runInOp(this.cm, () => regChange(this.cm)) }, 80) - }, + } - setUneditable: function(node) { + setUneditable(node) { node.contentEditable = "false" - }, + } - onKeyPress: function(e) { + onKeyPress(e) { e.preventDefault() if (!this.cm.isReadOnly()) operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0) - }, + } - readOnlyChanged: function(val) { + readOnlyChanged(val) { this.div.contentEditable = String(val != "nocursor") - }, + } - onContextMenu: nothing, - resetPosition: nothing, + onContextMenu() {} + resetPosition() {} +} - needsContentAttribute: true - }, ContentEditableInput.prototype) +ContentEditableInput.prototype.needsContentAttribute = true function posToDOM(cm, pos) { let view = findViewForLine(cm, pos.line) diff --git a/src/input/TextareaInput.js b/src/input/TextareaInput.js index a150f05d16..28b3327376 100644 --- a/src/input/TextareaInput.js +++ b/src/input/TextareaInput.js @@ -9,31 +9,31 @@ import { captureRightClick, ie, ie_version, ios, mac, mobile, presto, webkit } f import { activeElt, removeChildrenAndAdd, selectInput } from "../util/dom" import { e_preventDefault, e_stop, off, on, signalDOMEvent } from "../util/event" import { hasCopyEvent, hasSelection } from "../util/feature_detection" -import { copyObj, Delayed, nothing, sel_dontScroll } from "../util/misc" +import { Delayed, sel_dontScroll } from "../util/misc" // TEXTAREA INPUT STYLE -export default function TextareaInput(cm) { - this.cm = cm - // See input.poll and input.reset - this.prevInput = "" - - // Flag that indicates whether we expect input to appear real soon - // now (after some event like 'keypress' or 'input') and are - // polling intensively. - this.pollingFast = false - // Self-resetting timeout for the poller - this.polling = new Delayed() - // Tracks when input.reset has punted to just putting a short - // string into the textarea instead of the full selection. - this.inaccurateSelection = false - // Used to work around IE issue with selection being forgotten when focus moves away from textarea - this.hasSelection = false - this.composing = null -} - -TextareaInput.prototype = copyObj({ - init: function(display) { +export default class TextareaInput { + constructor(cm) { + this.cm = cm + // See input.poll and input.reset + this.prevInput = "" + + // Flag that indicates whether we expect input to appear real soon + // now (after some event like 'keypress' or 'input') and are + // polling intensively. + this.pollingFast = false + // Self-resetting timeout for the poller + this.polling = new Delayed() + // Tracks when input.reset has punted to just putting a short + // string into the textarea instead of the full selection. + this.inaccurateSelection = false + // Used to work around IE issue with selection being forgotten when focus moves away from textarea + this.hasSelection = false + this.composing = null + } + + init(display) { let input = this, cm = this.cm // Wraps and hides input textarea @@ -112,9 +112,9 @@ TextareaInput.prototype = copyObj({ input.composing = null } }) - }, + } - prepareSelection: function() { + prepareSelection() { // Redraw the selection and/or cursor let cm = this.cm, display = cm.display, doc = cm.doc let result = prepareSelection(cm) @@ -130,9 +130,9 @@ TextareaInput.prototype = copyObj({ } return result - }, + } - showSelection: function(drawn) { + showSelection(drawn) { let cm = this.cm, display = cm.display removeChildrenAndAdd(display.cursorDiv, drawn.cursors) removeChildrenAndAdd(display.selectionDiv, drawn.selection) @@ -140,11 +140,11 @@ TextareaInput.prototype = copyObj({ this.wrapper.style.top = drawn.teTop + "px" this.wrapper.style.left = drawn.teLeft + "px" } - }, + } // Reset the input to correspond to the selection (or to be empty, // when not typing and nothing is selected) - reset: function(typing) { + reset(typing) { if (this.contextMenuPending) return let minimal, selected, cm = this.cm, doc = cm.doc if (cm.somethingSelected()) { @@ -161,41 +161,41 @@ TextareaInput.prototype = copyObj({ if (ie && ie_version >= 9) this.hasSelection = null } this.inaccurateSelection = minimal - }, + } - getField: function() { return this.textarea }, + getField() { return this.textarea } - supportsTouch: function() { return false }, + supportsTouch() { return false } - focus: function() { + focus() { if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { try { this.textarea.focus() } catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM } - }, + } - blur: function() { this.textarea.blur() }, + blur() { this.textarea.blur() } - resetPosition: function() { + resetPosition() { this.wrapper.style.top = this.wrapper.style.left = 0 - }, + } - receivedFocus: function() { this.slowPoll() }, + receivedFocus() { this.slowPoll() } // Poll for input changes, using the normal rate of polling. This // runs as long as the editor is focused. - slowPoll: function() { + slowPoll() { if (this.pollingFast) return this.polling.set(this.cm.options.pollInterval, () => { this.poll() if (this.cm.state.focused) this.slowPoll() }) - }, + } // When an event has just come in that is likely to add or change // something in the input textarea, we poll faster, to ensure that // the change appears on the screen quickly. - fastPoll: function() { + fastPoll() { let missed = false, input = this input.pollingFast = true function p() { @@ -204,7 +204,7 @@ TextareaInput.prototype = copyObj({ else {input.pollingFast = false; input.slowPoll()} } input.polling.set(20, p) - }, + } // Read input from the textarea, and update the document to match. // When something is selected, it is present in the textarea, and @@ -212,7 +212,7 @@ TextareaInput.prototype = copyObj({ // used). When nothing is selected, the cursor sits after previously // seen text (can be empty), which is stored in prevInput (we must // not reset the textarea when typing, because that breaks IME). - poll: function() { + poll() { let cm = this.cm, input = this.textarea, prevInput = this.prevInput // Since this is called a *lot*, try to bail out as cheaply as // possible when it is clear that nothing happened. hasSelection @@ -259,18 +259,18 @@ TextareaInput.prototype = copyObj({ } }) return true - }, + } - ensurePolled: function() { + ensurePolled() { if (this.pollingFast && this.poll()) this.pollingFast = false - }, + } - onKeyPress: function() { + onKeyPress() { if (ie && ie_version >= 9) this.hasSelection = null this.fastPoll() - }, + } - onContextMenu: function(e) { + onContextMenu(e) { let input = this, cm = input.cm, display = cm.display, te = input.textarea let pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop if (!pos || presto) return // Opera is difficult. @@ -346,13 +346,13 @@ TextareaInput.prototype = copyObj({ } else { setTimeout(rehide, 50) } - }, + } - readOnlyChanged: function(val) { + readOnlyChanged(val) { if (!val) this.reset() - }, + } - setUneditable: nothing, + setUneditable() {} +} - needsContentAttribute: false -}, TextareaInput.prototype) +TextareaInput.prototype.needsContentAttribute = false diff --git a/src/util/misc.js b/src/util/misc.js index c94de8bd2c..2fb90914a8 100644 --- a/src/util/misc.js +++ b/src/util/misc.js @@ -87,7 +87,7 @@ export function insertSorted(array, value, score) { array.splice(pos, 0, value) } -export function nothing() {} +function nothing() {} export function createObj(base, props) { let inst From b557c1592942d29086889e65d4811d59977843ca Mon Sep 17 00:00:00 2001 From: Philipp A Date: Fri, 16 Dec 2016 12:46:39 +0100 Subject: [PATCH 0151/1880] CSS: Allow contextual glyph alternatives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ligatures were disabled since some editors didn’t allow placing the cursor inside of them. “Contextual alternatives” on the other hand still allow this, therefore this commit enables them to support e.g. Fira Code’s main gimmick. --- lib/codemirror.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index d7821d17df..2a6a262282 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -249,8 +249,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} position: relative; overflow: visible; -webkit-tap-highlight-color: transparent; - -webkit-font-variant-ligatures: none; - font-variant-ligatures: none; + -webkit-font-variant-ligatures: contextual; + font-variant-ligatures: contextual; } .CodeMirror-wrap pre { word-wrap: break-word; From e7080dcc8ecede7658d2381a17d8a6342c564f94 Mon Sep 17 00:00:00 2001 From: Martin Zagora Date: Mon, 19 Dec 2016 09:16:42 +1100 Subject: [PATCH 0152/1880] add passing test for #4437 --- mode/javascript/test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mode/javascript/test.js b/mode/javascript/test.js index 41765e75dd..971829d938 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -207,6 +207,18 @@ " [keyword private] [property _foo]: [variable-3 string];", "}") + TS("typescript_literal_types", + "[keyword import] [keyword *] [keyword as] [def Sequelize] [keyword from] [string 'sequelize'];", + "[keyword interface] [def MyAttributes] {", + " [property truthy]: [string 'true'] [operator |] [number 1] [operator |] [atom true];", + " [property falsy]: [string 'false'] [operator |] [number 0] [operator |] [atom false];", + "}", + "[keyword interface] [def MyInstance] [keyword extends] [variable-3 Sequelize].[variable-3 Instance] [operator <] [variable-3 MyAttributes] [operator >] {", + " [property rawAttributes]: [variable-3 MyAttributes];", + " [property truthy]: [string 'true'] [operator |] [number 1] [operator |] [atom true];", + " [property falsy]: [string 'false'] [operator |] [number 0] [operator |] [atom false];", + "}") + var jsonld_mode = CodeMirror.getMode( {indentUnit: 2}, {name: "javascript", jsonld: true} From b50e4310a4d6339db6ac55c7c7b3e3ae0117063e Mon Sep 17 00:00:00 2001 From: Martin Zagora Date: Mon, 19 Dec 2016 09:42:22 +1100 Subject: [PATCH 0153/1880] test: double >> breaks typescript parsing --- mode/javascript/test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mode/javascript/test.js b/mode/javascript/test.js index 971829d938..a38865d4ae 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -219,6 +219,18 @@ " [property falsy]: [string 'false'] [operator |] [number 0] [operator |] [atom false];", "}") + TS("typescript_extend_operators", + "[keyword export] [keyword interface] [def UserModel] [keyword extends]", + " [variable-3 Sequelize].[variable-3 Model] [operator <] [variable-3 UserInstance], [variable-3 UserAttributes] [operator >] {", + " [property findById]: (", + " [variable userId]: [variable-3 number]", + " ) [operator =>] [variable-3 Promise] [operator <] [variable-3 Array] [operator <] { [property id], [property name] } [operator >][operator >];", + " [property updateById]: (", + " [variable userId]: [variable-3 number],", + " [variable isActive]: [variable-3 boolean]", + " ) [operator =>] [variable-3 Promise] [operator <] [variable-3 AccountHolderNotificationPreferenceInstance] [operator >];", + " }") + var jsonld_mode = CodeMirror.getMode( {indentUnit: 2}, {name: "javascript", jsonld: true} From c71b86b9890c69f40d7dfdd44a9bb7d197201add Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 19 Dec 2016 09:59:25 +0100 Subject: [PATCH 0154/1880] [javascript mode] Parse '>>' as two separate ops in TS type param list Closes #4448 --- mode/javascript/javascript.js | 5 +++-- mode/javascript/test.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 2ad7a1e970..10419bf9de 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -146,7 +146,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { stream.skipToEnd(); return ret("error", "error"); } else if (isOperatorChar.test(ch)) { - stream.eatWhile(isOperatorChar); + if (ch != ">" || !state.lexical || state.lexical.type != ">") + stream.eatWhile(isOperatorChar); return ret("operator", "operator", stream.current()); } else if (wordRE.test(ch)) { stream.eatWhile(wordRE); @@ -559,7 +560,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { else if (type == ":") return cont(typeexpr) } function afterType(type, value) { - if (value == "<") return cont(commasep(typeexpr, ">"), afterType) + if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) if (value == "|" || type == ".") return cont(typeexpr) if (type == "[") return cont(expect("]"), afterType) } diff --git a/mode/javascript/test.js b/mode/javascript/test.js index a38865d4ae..2caefea439 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -224,7 +224,7 @@ " [variable-3 Sequelize].[variable-3 Model] [operator <] [variable-3 UserInstance], [variable-3 UserAttributes] [operator >] {", " [property findById]: (", " [variable userId]: [variable-3 number]", - " ) [operator =>] [variable-3 Promise] [operator <] [variable-3 Array] [operator <] { [property id], [property name] } [operator >][operator >];", + " ) [operator =>] [variable-3 Promise] [operator <] [variable-3 Array] [operator <] { [property id], [property name] } [operator >>];", " [property updateById]: (", " [variable userId]: [variable-3 number],", " [variable isActive]: [variable-3 boolean]", From b411c18740642ebe47ac135e3daeac0a1e58a704 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 19 Dec 2016 10:24:04 +0100 Subject: [PATCH 0155/1880] Link to elixir mode --- mode/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/index.html b/mode/index.html index 3a2fe5513e..c0001a53ee 100644 --- a/mode/index.html +++ b/mode/index.html @@ -56,6 +56,7 @@

    Language modes

  • EBNF
  • ECL
  • Eiffel
  • +
  • Elixir
  • Elm
  • Erlang
  • Factor
  • From d756ea1eb931d6ce7aa6f5eb3c8ea2e34a1bce20 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 19 Dec 2016 15:39:46 +0100 Subject: [PATCH 0156/1880] Make sure composition changes aren't dropped when forced after compositionend event. Issue #4441 --- src/input/ContentEditableInput.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index 57114af681..4c7b58ebde 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -40,15 +40,15 @@ export default class ContentEditableInput { }) on(div, "compositionstart", e => { - this.composing = {data: e.data} + this.composing = {data: e.data, done: false} }) on(div, "compositionupdate", e => { - if (!this.composing) this.composing = {data: e.data} + if (!this.composing) this.composing = {data: e.data, done: false} }) on(div, "compositionend", e => { if (this.composing) { if (e.data != this.composing.data) this.readFromDOMSoon() - this.composing = null + this.composing.done = true } }) @@ -301,6 +301,7 @@ export default class ContentEditableInput { } forceCompositionEnd() { if (!this.composing) return + clearTimeout(this.readDOMTimeout) this.composing = null if (!this.pollContent()) regChange(this.cm) this.div.blur() @@ -310,7 +311,10 @@ export default class ContentEditableInput { if (this.readDOMTimeout != null) return this.readDOMTimeout = setTimeout(() => { this.readDOMTimeout = null - if (this.composing) return + if (this.composing) { + if (this.composing.done) this.composing = null + else return + } if (this.cm.isReadOnly() || !this.pollContent()) runInOp(this.cm, () => regChange(this.cm)) }, 80) From 33d920b06a7b52ceffbf9b083e1aab00993caef7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Dec 2016 10:12:28 +0100 Subject: [PATCH 0157/1880] [javascript mode] Properly tokenize a regexp after the export keyword Closes #4452 --- mode/javascript/javascript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 10419bf9de..fe9b805f1f 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -12,7 +12,7 @@ "use strict"; function expressionAllowed(stream, state, backUp) { - return /^(?:operator|sof|keyword c|case|new|[\[{}\(,;:]|=>)$/.test(state.lastType) || + return /^(?:operator|sof|keyword c|case|new|export|[\[{}\(,;:]|=>)$/.test(state.lastType) || (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0)))) } From 708084a28130a8c22553fd6193b7870ae66fee40 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Dec 2016 10:21:46 +0100 Subject: [PATCH 0158/1880] [javascript mode] Improve import/export parsing Closes #4451 --- mode/javascript/javascript.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index fe9b805f1f..10fc95bd8a 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -658,14 +658,19 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == ":") return cont(typeexpr, maybeAssign) return pass(functiondef) } - function afterExport(_type, value) { + function afterExport(type, value) { if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); } if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); } + if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";")); return pass(statement); } + function exportField(type, value) { + if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); } + if (type == "variable") return pass(expressionNoComma, exportField); + } function afterImport(type) { if (type == "string") return cont(); - return pass(importSpec, maybeFrom); + return pass(importSpec, maybeMoreImports, maybeFrom); } function importSpec(type, value) { if (type == "{") return contCommasep(importSpec, "}"); @@ -673,6 +678,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (value == "*") cx.marked = "keyword"; return cont(maybeAs); } + function maybeMoreImports(type) { + if (type == ",") return cont(importSpec, maybeMoreImports) + } function maybeAs(_type, value) { if (value == "as") { cx.marked = "keyword"; return cont(importSpec); } } From ae45e2bdad8bb4a00c7f1cd7f6127a6963d9df8f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Dec 2016 14:04:43 +0100 Subject: [PATCH 0159/1880] [javascript mode] Also allow a regexp after 'default' (For 'export default' syntax) Issue #4452 --- mode/javascript/javascript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 10fc95bd8a..c185106ce4 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -12,7 +12,7 @@ "use strict"; function expressionAllowed(stream, state, backUp) { - return /^(?:operator|sof|keyword c|case|new|export|[\[{}\(,;:]|=>)$/.test(state.lastType) || + return /^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) || (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0)))) } From bfdfb212f76f479b3e651daa688f5da6909e7f48 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Dec 2016 15:40:12 +0100 Subject: [PATCH 0160/1880] Mark version 5.22.0 --- AUTHORS | 4 ++++ CHANGELOG.md | 18 ++++++++++++++++++ doc/manual.html | 2 +- doc/releases.html | 13 ++++++++++++- index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 38 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 09fb4cc852..9b9b3355ba 100644 --- a/AUTHORS +++ b/AUTHORS @@ -45,6 +45,7 @@ Andrea G Andreas Reischuck Andres Taylor Andre von Houck +Andrew Cheng Andrey Fedorov Andrey Klyuchnikov Andrey Lushnikov @@ -186,6 +187,7 @@ fbuchinger feizhang365 Felipe Lalanne Felix Raab +ficristo Filip Noetzel Filip Stollár flack @@ -500,6 +502,7 @@ Remi Nyborg Richard Denton Richard van der Meer Richard Z.H. Wang +Rishi Goomar Robert Crossfield Roberto Abdelkader Martínez Pérez robertop23 @@ -582,6 +585,7 @@ Todd Berman Tomas-A Tomas Varaneckas Tom Erik Støwer +Tom Klancer Tom MacWright Tony Jian Travis Heppe diff --git a/CHANGELOG.md b/CHANGELOG.md index 2404815f88..f3eb79ff5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## 5.22.0 (2016-12-20) + +### Bug fixes + +[sublime bindings](http://codemirror.net/demo/sublime.html): Make `selectBetweenBrackets` work with multiple cursors. + +[javascript mode](http://codemirror.net/mode/javascript/): Fix issues with parsing complex TypeScript types, imports, and exports. + +A contentEditable editor instance with autofocus enabled no longer crashes during initializing. + +### New features + +[emacs bindings](http://codemirror.net/demo/emacs.html): Export `CodeMirror.emacs` to allow other addons to hook into Emacs-style functionality. + +[active-line addon](http://codemirror.net/doc/manual.html#addon_active-line): Add `nonEmpty` option. + +New event: [`optionChange`](http://codemirror.net/doc/manual.html#event_optionChange). + ## 5.21.0 (2016-11-21) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index c6745e3ce6..704984fc71 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.21.1 + version 5.22.0

    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 5880469189..2dfd1fe482 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,7 +30,18 @@

    Release notes and version history

    Version 5.x

    -

    21-11-2016: Version 5.21.0:

    +

    20-12-2016: Version 5.22.0:

    + +
      +
    • sublime bindings: Make selectBetweenBrackets work with multiple cursors.
    • +
    • javascript mode: Fix issues with parsing complex TypeScript types, imports, and exports.
    • +
    • A contentEditable editor instance with autofocus enabled no longer crashes during initializing.
    • +
    • emacs bindings: Export CodeMirror.emacs to allow other addons to hook into Emacs-style functionality.
    • +
    • active-line addon: Add nonEmpty option.
    • +
    • New event: optionChange.
    • +
    + +

    21-11-2016: Version 5.21.0:

    • Tapping/clicking the editor in contentEditable mode on Chrome now puts the cursor at the tapped position.
    • diff --git a/index.html b/index.html index 7164296018..06fdc1567f 100644 --- a/index.html +++ b/index.html @@ -96,7 +96,7 @@

      This is CodeMirror

    - Get the current version: 5.21.0.
    + Get the current version: 5.22.0.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index e2b97a9cd1..c007b2a87c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.21.1", + "version": "5.22.0", "main": "lib/codemirror.js", "description": "Full-featured in-browser code editor", "license": "MIT", diff --git a/src/edit/main.js b/src/edit/main.js index 64b647b5d2..8da8f48e3a 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.21.1" +CodeMirror.version = "5.22.0" From adfa066411473c6fe2f3a6fa15e076d52eceeb94 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Dec 2016 15:52:23 +0100 Subject: [PATCH 0161/1880] Bump version number post-5.22.0 --- doc/manual.html | 2 +- index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 704984fc71..98c160946f 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.22.0 + version 5.22.1

    CodeMirror is a code-editor component that can be embedded in diff --git a/index.html b/index.html index 06fdc1567f..dd4b1ded05 100644 --- a/index.html +++ b/index.html @@ -96,7 +96,7 @@

    This is CodeMirror

    - Get the current version: 5.22.0.
    + Get the current version: 5.22.1.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index c007b2a87c..0c565e9b2b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.22.0", + "version": "5.22.1", "main": "lib/codemirror.js", "description": "Full-featured in-browser code editor", "license": "MIT", diff --git a/src/edit/main.js b/src/edit/main.js index 8da8f48e3a..429cfe94e7 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.22.0" +CodeMirror.version = "5.22.1" From 38932a8e332ca02f73d395f899cfdfa76922e132 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Dec 2016 15:53:55 +0100 Subject: [PATCH 0162/1880] Remove link to google group --- index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index dd4b1ded05..9812829e52 100644 --- a/index.html +++ b/index.html @@ -163,10 +163,10 @@

    Community

    Discussion around the project is done on a discussion forum. - There is also - the codemirror-announce - list, which is only used for major announcements (such as new - versions). If needed, you can + Announcements related to the project, such as new versions, are + posted in the + forum's "announce" + category. If needed, you can contact the maintainer directly. We aim to be an inclusive, welcoming community. To make that explicit, we have From 12abb7c7f0fcfff441810eb5ce5a8905385c84c2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 22 Dec 2016 16:55:10 +0100 Subject: [PATCH 0163/1880] Remove check for license blob in linter Closes #3909 --- test/lint.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/lint.js b/test/lint.js index cc03ce64c0..12146ffd28 100644 --- a/test/lint.js +++ b/test/lint.js @@ -3,8 +3,7 @@ var blint = require("blint"); ["mode", "lib", "addon", "keymap"].forEach(function(dir) { blint.checkDir(dir, { browser: true, - allowedGlobals: ["CodeMirror", "define", "test", "requirejs"], - blob: "// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: http:\/\/codemirror.net\/LICENSE\n\n" + allowedGlobals: ["CodeMirror", "define", "test", "requirejs"] }); }); From 3dc1a5db143bd99fd3a1a9bca1ee1005ef5c828d Mon Sep 17 00:00:00 2001 From: Emmanuel Schanzer Date: Thu, 22 Dec 2016 11:51:59 -0500 Subject: [PATCH 0164/1880] screenreader fixes --- src/line/line_data.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/line/line_data.js b/src/line/line_data.js index 93b57577da..7583c3424e 100644 --- a/src/line/line_data.js +++ b/src/line/line_data.js @@ -66,6 +66,9 @@ export function buildLineContent(cm, lineView) { col: 0, pos: 0, cm: cm, trailingSpace: false, splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")} + // hide from accessibility tree + content.setAttribute("role", "presentation") + builder.pre.setAttribute("role", "presentation") lineView.measure = {} // Iterate over the logical lines that make up this visual line. From 85956bed14dc8cdfd6610487c08243edf7ac0076 Mon Sep 17 00:00:00 2001 From: Emmanuel Schanzer Date: Thu, 22 Dec 2016 13:39:29 -0500 Subject: [PATCH 0165/1880] Also give widgets a role attribute of 'presentation' --- src/model/mark_text.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/model/mark_text.js b/src/model/mark_text.js index 4250288ef3..15ec28498f 100644 --- a/src/model/mark_text.js +++ b/src/model/mark_text.js @@ -163,6 +163,7 @@ export function markText(doc, from, to, options, type) { // Showing up as a widget implies collapsed (widget replaces text) marker.collapsed = true marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget") + marker.widgetNode.setAttribute("role", "presentation") // hide from accessibility tree if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true") if (options.insertLeft) marker.widgetNode.insertLeft = true } From aeb547774525ea6e3544a27ad3b2b387fb384e05 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 23 Dec 2016 14:03:58 +0100 Subject: [PATCH 0166/1880] Update htmlmixed documentation --- mode/htmlmixed/index.html | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/mode/htmlmixed/index.html b/mode/htmlmixed/index.html index f94df9e21a..caa7546c1e 100644 --- a/mode/htmlmixed/index.html +++ b/mode/htmlmixed/index.html @@ -72,15 +72,26 @@

    Mixed HTML Example

    The HTML mixed mode depends on the XML, JavaScript, and CSS modes.

    It takes an optional mode configuration - option, scriptTypes, which can be used to add custom - behavior for specific <script type="..."> tags. If - given, it should hold an array of {matches, mode} - objects, where matches is a string or regexp that - matches the script type, and mode is - either null, for script types that should stay in - HTML mode, or a mode - spec corresponding to the mode that should be used for the - script.

    + option, tags, which can be used to add custom + behavior for specific tags. When given, it should be an object + mapping tag names (for example script) to arrays or + three-element arrays. Those inner arrays indicate [attributeName, + valueRegexp, modeSpec] + specifications. For example, you could use ["type", /^foo$/, + "foo"] to map the attribute type="foo" to + the foo mode. When the first two fields are null + ([null, null, "mode"]), the given mode is used for + any such tag that doesn't match any of the previously given + attributes. For example:

    + +
    var myModeSpec = {
    +  name: "htmlmixed",
    +  tags: {
    +    style: [["type", /^text/(x-)?scss$/, "text/x-scss"],
    +            [null, null, "css"]],
    +    custom: [[null, null, "customMode"]]
    +  }
    +}

    MIME types defined: text/html (redefined, only takes effect if you load this parser after the From 9a015790f9833dd2ef395e7fb7c505376dd46568 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Mon, 26 Dec 2016 11:47:18 +0100 Subject: [PATCH 0167/1880] Remove unused variable This variable was unused after 0e545326ddb3a82df1b76eb18b2221990536e588. --- src/model/Doc.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/model/Doc.js b/src/model/Doc.js index 27b62d1945..006598f1fe 100644 --- a/src/model/Doc.js +++ b/src/model/Doc.js @@ -229,7 +229,6 @@ Doc.prototype = createObj(BranchChunk.prototype, { }), clearGutter: docMethodOp(function(gutterID) { - let i = this.first this.iter(line => { if (line.gutterMarkers && line.gutterMarkers[gutterID]) { changeLine(this, line, "gutter", () => { @@ -238,7 +237,6 @@ Doc.prototype = createObj(BranchChunk.prototype, { return true }) } - ++i }) }), From 97eb5221f05c09cfeafefa45b52da022fbcc46af Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 26 Dec 2016 21:48:09 +0100 Subject: [PATCH 0168/1880] [python mode] Recognize f-strings Closes #4462 --- mode/python/python.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/python/python.js b/mode/python/python.js index 30f1428e3a..4310f9fb6b 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -70,7 +70,7 @@ myBuiltins = myBuiltins.concat(["apply", "basestring", "buffer", "cmp", "coerce", "execfile", "file", "intern", "long", "raw_input", "reduce", "reload", "unichr", "unicode", "xrange", "False", "True", "None"]); - var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i"); + var stringPrefixes = new RegExp("^(([rubf]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i"); } var keywords = wordRegexp(myKeywords); var builtins = wordRegexp(myBuiltins); From 409c83aaf8f29a38328c4f751d4b3c460dee72a7 Mon Sep 17 00:00:00 2001 From: Manuel Rego Casasnovas Date: Tue, 27 Dec 2016 12:32:27 +0100 Subject: [PATCH 0169/1880] [css mode] Add "auto-flow" value for grid property See: https://drafts.csswg.org/css-grid/#grid-shorthand --- mode/css/css.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/css/css.js b/mode/css/css.js index a1d5a388e5..90de4ee795 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -589,7 +589,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "above", "absolute", "activeborder", "additive", "activecaption", "afar", "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", - "arabic-indic", "armenian", "asterisks", "attr", "auto", "avoid", "avoid-column", "avoid-page", + "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page", "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary", "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", From ea5ee6466a916b9f6a85e480c543f877d138e626 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 28 Dec 2016 23:49:53 +0100 Subject: [PATCH 0170/1880] [groovy mode] Don't reindent block comment conent Closes #4466 --- mode/groovy/groovy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/groovy/groovy.js b/mode/groovy/groovy.js index 721933b01c..daa798722e 100644 --- a/mode/groovy/groovy.js +++ b/mode/groovy/groovy.js @@ -210,7 +210,7 @@ CodeMirror.defineMode("groovy", function(config) { }, indent: function(state, textAfter) { - if (!state.tokenize[state.tokenize.length-1].isBase) return 0; + if (!state.tokenize[state.tokenize.length-1].isBase) return CodeMirror.Pass; var firstChar = textAfter && textAfter.charAt(0), ctx = state.context; if (ctx.type == "statement" && !expectExpression(state.lastToken, true)) ctx = ctx.prev; var closing = firstChar == ctx.type; From 117ecfca5b28f9931c1407e257667972020d667c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Segersv=C3=A4rd?= Date: Wed, 28 Dec 2016 13:43:55 +0100 Subject: [PATCH 0171/1880] [soy mode] Fix bug when popping scopes. --- mode/soy/soy.js | 15 +++++++++------ mode/soy/test.js | 4 +++- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/mode/soy/soy.js b/mode/soy/soy.js index 9fd75c6d27..3876333f94 100644 --- a/mode/soy/soy.js +++ b/mode/soy/soy.js @@ -60,16 +60,19 @@ }; } - function pop(list) { - return list && list.next; - } - // Reference a variable `name` in `list`. // Let `loose` be truthy to ignore missing identifiers. function ref(list, name, loose) { return contains(list, name) ? "variable-2" : (loose ? "variable" : "variable-2 error"); } + function popscope(state) { + if (state.scopes) { + state.variables = state.scopes.element; + state.scopes = state.scopes.next; + } + } + return { startState: function() { return { @@ -168,11 +171,11 @@ case "tag": if (stream.match(/^\/?}/)) { if (state.tag == "/template" || state.tag == "/deltemplate") { - state.variables = state.scopes = pop(state.scopes); + popscope(state); state.indent = 0; } else { if (state.tag == "/for" || state.tag == "/foreach") { - state.variables = state.scopes = pop(state.scopes); + popscope(state); } state.indent -= config.indentUnit * (stream.current() == "/}" || indentingTags.indexOf(state.tag) == -1 ? 2 : 1); diff --git a/mode/soy/test.js b/mode/soy/test.js index 1a962de3e7..1a4c6c934f 100644 --- a/mode/soy/test.js +++ b/mode/soy/test.js @@ -60,10 +60,12 @@ ''); MT('foreach-scope-test', + '[keyword {@param] [def bar]: [variable-3 string][keyword }]', '[keyword {foreach] [def $foo] [keyword in] [variable-2&error $foos][keyword }]', ' [keyword {][variable-2 $foo][keyword }]', '[keyword {/foreach}]', - '[keyword {][variable-2&error $foo][keyword }]'); + '[keyword {][variable-2&error $foo][keyword }]', + '[keyword {][variable-2 $bar][keyword }]'); MT('foreach-ifempty-indent-test', '[keyword {foreach] [def $foo] [keyword in] [variable-2&error $foos][keyword }]', From 7a094220148815d025fcc62f7e8a0b56316a2744 Mon Sep 17 00:00:00 2001 From: Jake Peyser Date: Wed, 28 Dec 2016 13:19:55 -0500 Subject: [PATCH 0172/1880] [materialy theme] Make general background selector more specific --- theme/material.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/material.css b/theme/material.css index 91ed6cef29..01d867932a 100644 --- a/theme/material.css +++ b/theme/material.css @@ -7,7 +7,7 @@ */ -.cm-s-material { +.cm-s-material.CodeMirror { background-color: #263238; color: rgba(233, 237, 237, 1); } From 6d3783d02911d51a16bf648b602febf2ad811bc7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 29 Dec 2016 08:54:03 +0100 Subject: [PATCH 0173/1880] [mllike mode] Don't treat every unrecognized char as a variable Closes #4473 --- mode/mllike/mllike.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mode/mllike/mllike.js b/mode/mllike/mllike.js index bf0b8a674f..4d0be609c4 100644 --- a/mode/mllike/mllike.js +++ b/mode/mllike/mllike.js @@ -83,9 +83,12 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) { if ( /[+\-*&%=<>!?|]/.test(ch)) { return 'operator'; } - stream.eatWhile(/\w/); - var cur = stream.current(); - return words.hasOwnProperty(cur) ? words[cur] : 'variable'; + if (/[\w\xa1-\uffff]/.test(ch)) { + stream.eatWhile(/[\w\xa1-\uffff]/); + var cur = stream.current(); + return words.hasOwnProperty(cur) ? words[cur] : 'variable'; + } + return null } function tokenString(stream, state) { From 9fe20534371a496375e409f987d2176b90c6f1e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Segersv=C3=A4rd?= Date: Thu, 29 Dec 2016 11:01:27 +0100 Subject: [PATCH 0174/1880] [soy mode] Add missing `\b`s to keyword regex Closes #4468 --- mode/soy/soy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/soy/soy.js b/mode/soy/soy.js index 3876333f94..3e9c04a49e 100644 --- a/mode/soy/soy.js +++ b/mode/soy/soy.js @@ -198,7 +198,7 @@ if (match = stream.match(/^\$([\w]+)/)) { return ref(state.variables, match[1]); } - if (stream.match(/(?:as|and|or|not|in)/)) { + if (stream.match(/\b(?:as|and|or|not|in)\b/)) { return "keyword"; } stream.next(); From 77eb24c188131a89a06990523c32bd37ccc96e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Segersv=C3=A4rd?= Date: Thu, 29 Dec 2016 11:47:11 +0100 Subject: [PATCH 0175/1880] [soy mode] Add tests for 9fe2053, find bug and fix it --- mode/soy/soy.js | 4 ++-- mode/soy/test.js | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mode/soy/soy.js b/mode/soy/soy.js index 3e9c04a49e..b9eec59a4c 100644 --- a/mode/soy/soy.js +++ b/mode/soy/soy.js @@ -198,8 +198,8 @@ if (match = stream.match(/^\$([\w]+)/)) { return ref(state.variables, match[1]); } - if (stream.match(/\b(?:as|and|or|not|in)\b/)) { - return "keyword"; + if (match = stream.match(/^\w+/)) { + return /^(?:as|and|or|not|in)$/.test(match[0]) ? "keyword" : null; } stream.next(); return null; diff --git a/mode/soy/test.js b/mode/soy/test.js index 1a4c6c934f..9e265c1b0c 100644 --- a/mode/soy/test.js +++ b/mode/soy/test.js @@ -5,6 +5,12 @@ var mode = CodeMirror.getMode({indentUnit: 2}, "soy"); function MT(name) {test.mode(name, mode, Array.prototype.slice.call(arguments, 1));} + // Test of small keywords and words containing them. + MT('keywords-test', + '[keyword {] [keyword as] worrying [keyword and] notorious [keyword as]', + ' the Fandor-alias assassin, [keyword or]', + ' Corcand cannot fit [keyword in] [keyword }]'); + MT('let-test', '[keyword {template] [def .name][keyword }]', ' [keyword {let] [def $name]: [string "world"][keyword /}]', From 4c39f5e8be2bcaa716c5c81f3db18d0db1810d76 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 2 Jan 2017 00:39:12 +0100 Subject: [PATCH 0176/1880] Make findModeByMIME +xml/+json aware Issue #4476 --- mode/meta.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mode/meta.js b/mode/meta.js index 47364448f1..bb60502416 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -155,7 +155,7 @@ {name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]}, {name: "VHDL", mime: "text/x-vhdl", mode: "vhdl", ext: ["vhd", "vhdl"]}, {name: "Vue.js Component", mimes: ["script/x-vue", "text/x-vue"], mode: "vue", ext: ["vue"]}, - {name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd"], alias: ["rss", "wsdl", "xsd"]}, + {name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd", "svg"], alias: ["rss", "wsdl", "xsd"]}, {name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]}, {name: "Yacas", mime: "text/x-yacas", mode: "yacas", ext: ["ys"]}, {name: "YAML", mimes: ["text/x-yaml", "text/yaml"], mode: "yaml", ext: ["yaml", "yml"], alias: ["yml"]}, @@ -178,6 +178,8 @@ if (info.mimes) for (var j = 0; j < info.mimes.length; j++) if (info.mimes[j] == mime) return info; } + if (/\+xml$/.test(mime)) return CodeMirror.findModeByMIME("application/xml") + if (/\+json$/.test(mime)) return CodeMirror.findModeByMIME("application/json") }; CodeMirror.findModeByExtension = function(ext) { From ec8e89ba441495c79710c5fda7fd05d61a6787b6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 2 Jan 2017 00:45:36 +0100 Subject: [PATCH 0177/1880] [closebrackets addon] Add override option Closes #4478 --- addon/edit/closebrackets.js | 2 +- doc/manual.html | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 7c47bcd096..62b99c1ba8 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -45,7 +45,7 @@ function getConfig(cm) { var deflt = cm.state.closeBrackets; - if (!deflt) return null; + if (!deflt || deflt.override) return deflt; var mode = cm.getModeAt(cm.getCursor()); return mode.closeBrackets || deflt; } diff --git a/doc/manual.html b/doc/manual.html index 98c160946f..3c252381ba 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2314,7 +2314,13 @@

    Addons

    it. explode should be a similar string that gives the pairs of characters that, when enter is pressed between them, should have the second character also moved to its own - line. Demo here. + line. By default, if the active mode has + a closeBrackets property, that overrides the + configuration given in the option. But you can add + an override property with a truthy value to + override mode-specific + configuration. Demo + here.
    edit/matchtags.js
    Defines an option matchTags that, when enabled, From 7ff3b02e724300d61d6a7b81eb8139778060a529 Mon Sep 17 00:00:00 2001 From: ficristo Date: Mon, 2 Jan 2017 09:00:08 +0100 Subject: [PATCH 0178/1880] [javascript mode] add tests for async keyword --- mode/javascript/test.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/mode/javascript/test.js b/mode/javascript/test.js index 2caefea439..56b90e3cfe 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -190,6 +190,36 @@ " }", "}"); + MT("async", + "[keyword async] [keyword function] [def foo]([def args]) { [keyword return] [atom true]; }"); + + MT("async_assignment", + "[keyword const] [def foo] [operator =] [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; };"); + + MT("async_object", + "[keyword let] [def obj] [operator =] { [property async]: [atom false] };"); + + // async be highlighet as keyword and foo as def, but it requires potentially expensive look-ahead. See #4173 + MT("async_object_function", + "[keyword let] [def obj] [operator =] { [property async] [property foo]([def args]) { [keyword return] [atom true]; } };"); + + MT("async_object_properties", + "[keyword let] [def obj] [operator =] {", + " [property prop1]: [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; },", + " [property prop2]: [keyword async] [keyword function] ([def args]) { [keyword return] [atom true]; },", + " [property prop3]: [keyword async] [keyword function] [def prop3]([def args]) { [keyword return] [atom true]; },", + "};"); + + MT("async_arrow", + "[keyword const] [def foo] [operator =] [keyword async] ([def args]) [operator =>] { [keyword return] [atom true]; };"); + + MT("async_jquery", + "[variable $].[property ajax]({", + " [property url]: [variable url],", + " [property async]: [atom true],", + " [property method]: [string 'GET']", + "});"); + var ts_mode = CodeMirror.getMode({indentUnit: 2}, "application/typescript") function TS(name) { test.mode(name, ts_mode, Array.prototype.slice.call(arguments, 1)) From 90d7915450f33f03d0d251b6bdda7228289acd41 Mon Sep 17 00:00:00 2001 From: Paul Masson Date: Tue, 3 Jan 2017 14:03:42 -0800 Subject: [PATCH 0179/1880] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 766132177a..1bca6bfed4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2016 by Marijn Haverbeke and others +Copyright (C) 2017 by Marijn Haverbeke and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From d4e2e7ac0b745b04a82cd2f2847c44951b98822a Mon Sep 17 00:00:00 2001 From: Paul Masson Date: Tue, 3 Jan 2017 14:11:38 -0800 Subject: [PATCH 0180/1880] [real-world uses] Add SageMathCell --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index dc2a7f6a97..2429ba1655 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -142,6 +142,7 @@

    CodeMirror real-world uses

  • Rascal (tiny computer)
  • RealTime.io (Internet-of-Things infrastructure)
  • Refork (animation demo gallery and sharing)
  • +
  • SageMathCell (interactive mathematical software)
  • SageMathCloud (interactive mathematical software environment)
  • ServePHP (PHP code testing in Chrome dev tools)
  • Shadertoy (shader sharing)
  • From 3a83dccdfa96e2dc90c3129d281525ff41241255 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 4 Jan 2017 09:58:53 +0100 Subject: [PATCH 0181/1880] [markdown mode] Be somewhat more restrictive about HTML open tags Closes #4484 --- mode/markdown/markdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 4cc1dc6890..1aeb34414c 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -490,7 +490,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return type + tokenTypes.linkEmail; } - if (ch === '<' && stream.match(/^(!--|\w)/, false)) { + if (ch === '<' && stream.match(/^(!--|[a-z]+(?:\s+[a-z_:.\-]+(?:\s*=\s*[^ >]+)?)*\s*>)/i, false)) { var end = stream.string.indexOf(">", stream.pos); if (end != -1) { var atts = stream.string.substring(stream.start, end); From 6928fec6695f468f17b5031e48192ad2f7d505f1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 4 Jan 2017 10:59:11 +0100 Subject: [PATCH 0182/1880] [panel addon] Implement a 'stable' option Issue #4485 --- addon/display/panel.js | 9 +++++++++ demo/panel.html | 4 ++-- doc/manual.html | 11 +++++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/addon/display/panel.js b/addon/display/panel.js index ba29484d6c..a6ac74f0ca 100644 --- a/addon/display/panel.js +++ b/addon/display/panel.js @@ -38,6 +38,9 @@ var height = (options && options.height) || node.offsetHeight; this._setSize(null, info.heightLeft -= height); info.panels++; + if (options.stable && isAtTop(this, node)) + this.scrollTo(null, this.getScrollInfo().top + height) + return new Panel(this, node, options, height); }); @@ -109,4 +112,10 @@ cm.setSize = cm._setSize; cm.setSize(); } + + function isAtTop(cm, dom) { + for (let sibling = dom.nextSibling; sibling; sibling = sibling.nextSibling) + if (sibling == cm.getWrapperElement()) return true + return false + } }); diff --git a/demo/panel.html b/demo/panel.html index b3b0b7ca6b..1ce3d87c79 100644 --- a/demo/panel.html +++ b/demo/panel.html @@ -115,7 +115,7 @@

    Panel Demo

    } function addPanel(where) { var node = makePanel(where); - panels[node.id] = editor.addPanel(node, {position: where}); + panels[node.id] = editor.addPanel(node, {position: where, stable: true}); } addPanel("top"); @@ -126,7 +126,7 @@

    Panel Demo

    var panel = panels["panel-" + id]; var node = makePanel(""); - panels[node.id] = editor.addPanel(node, {replace: panel, position: "after-top"}); + panels[node.id] = editor.addPanel(node, {replace: panel, position: "after-top", stable: true}); return false; } diff --git a/doc/manual.html b/doc/manual.html index 3c252381ba..7acc872b8b 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2910,7 +2910,7 @@

    Addons

    changed.
    The method accepts the following options:
    -
    position : string
    +
    position: string
    Controls the position of the newly added panel. The following values are recognized:
    @@ -2924,12 +2924,15 @@

    Addons

    Adds the panel at the top of the bottom panels.
    -
    before : Panel
    +
    before: Panel
    The new panel will be added before the given panel.
    -
    after : Panel
    +
    after: Panel
    The new panel will be added after the given panel.
    -
    replace : Panel
    +
    replace: Panel
    The new panel will replace the given panel.
    +
    stable: bool
    +
    Whether to scroll the editor to keep the text's vertical + position stable, when adding a panel above it. Defaults to false.
    When using the after, before or replace options, if the panel doesn't exists or has been removed, From 35f09250d7d3dbb3da28aa3a7efdf757bdfdc42f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 4 Jan 2017 11:02:56 +0100 Subject: [PATCH 0183/1880] Fix ES6-ism in addon --- addon/display/panel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/display/panel.js b/addon/display/panel.js index a6ac74f0ca..7da34a42da 100644 --- a/addon/display/panel.js +++ b/addon/display/panel.js @@ -114,7 +114,7 @@ } function isAtTop(cm, dom) { - for (let sibling = dom.nextSibling; sibling; sibling = sibling.nextSibling) + for (var sibling = dom.nextSibling; sibling; sibling = sibling.nextSibling) if (sibling == cm.getWrapperElement()) return true return false } From f78c0915e5c403c925e48c714fd1fd671a4c35f0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 4 Jan 2017 11:03:50 +0100 Subject: [PATCH 0184/1880] Lint addons and modes with ecmaVersion 5 --- test/lint.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/lint.js b/test/lint.js index 12146ffd28..502706de8e 100644 --- a/test/lint.js +++ b/test/lint.js @@ -3,7 +3,8 @@ var blint = require("blint"); ["mode", "lib", "addon", "keymap"].forEach(function(dir) { blint.checkDir(dir, { browser: true, - allowedGlobals: ["CodeMirror", "define", "test", "requirejs"] + allowedGlobals: ["CodeMirror", "define", "test", "requirejs"], + ecmaVersion: 5 }); }); From 0fb17df6694b0ba63ec0568d84709e9a07e19a9b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 5 Jan 2017 09:44:27 +0100 Subject: [PATCH 0185/1880] [panel plugin] Make stable option also take effect when a panel is removed Issue #4485 --- addon/display/panel.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addon/display/panel.js b/addon/display/panel.js index 7da34a42da..74199ff059 100644 --- a/addon/display/panel.js +++ b/addon/display/panel.js @@ -57,6 +57,8 @@ this.cleared = true; var info = this.cm.state.panels; this.cm._setSize(null, info.heightLeft += this.height); + if (this.options.stable && isAtTop(this.cm, this.node)) + this.cm.scrollTo(null, this.cm.getScrollInfo().top - this.height) info.wrapper.removeChild(this.node); if (--info.panels == 0) removePanels(this.cm); }; From dc94b0f0c6ea97c09344d1a34da70f8e2d1d708f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 12 Jan 2017 14:35:32 +0100 Subject: [PATCH 0186/1880] [merge addon] Anchor copy button to editable side for insertions Since showing it next to an empty chunk looks bad Issue #4492 --- addon/merge/merge.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index 352e27dc6f..b3a9af405c 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -431,10 +431,10 @@ var editOriginals = dv.mv.options.allowEditingOriginals; copy.title = editOriginals ? "Push to left" : "Revert chunk"; copy.chunk = chunk; - copy.style.top = top + "px"; + copy.style.top = (chunk.origTo < chunk.origFrom ? top : dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit) + "px"; if (editOriginals) { - var topReverse = dv.orig.heightAtLine(chunk.editFrom, "local") - sTopEdit; + var topReverse = dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit; var copyReverse = dv.copyButtons.appendChild(elt("div", dv.type == "right" ? "\u21dd" : "\u21dc", "CodeMirror-merge-copy-reverse")); copyReverse.title = "Push to right"; From fc93599160949802e8752ecf32b63e24c0c1b461 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 12 Jan 2017 14:37:39 +0100 Subject: [PATCH 0187/1880] Don't exclude rollup.config.js from NPM See https://discuss.codemirror.net/t/npm-install-failing-for-cm-git-dependency/1088 --- .npmignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.npmignore b/.npmignore index de3a24080b..f23ca7195d 100644 --- a/.npmignore +++ b/.npmignore @@ -9,4 +9,3 @@ /mode/index.html .* bin -rollup.config.js From 8a0c813b208b5a2c0dae7b5a9b635168017165ba Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 12 Jan 2017 14:40:43 +0100 Subject: [PATCH 0188/1880] Include 5.22.2 in release notes --- CHANGELOG.md | 6 ++++++ doc/manual.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3eb79ff5c..9074c1b0c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 5.22.2 (2017-01-12) + +### Bug fixes + +Include rollup.config.js in NPM package, so that it can be used to build from source. + ## 5.22.0 (2016-12-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 7acc872b8b..f765185eb3 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.22.1 + version 5.22.3

    CodeMirror is a code-editor component that can be embedded in diff --git a/package.json b/package.json index 0c565e9b2b..fa82dd11dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.22.1", + "version": "5.22.3", "main": "lib/codemirror.js", "description": "Full-featured in-browser code editor", "license": "MIT", diff --git a/src/edit/main.js b/src/edit/main.js index 429cfe94e7..c16f377119 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.22.1" +CodeMirror.version = "5.22.3" From 66d9403c8e5511b5469e1009534e8266296d64ed Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 13 Jan 2017 08:19:44 +0100 Subject: [PATCH 0189/1880] [merge addon] Fix incorrect compare Issue #4492 --- addon/merge/merge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index b3a9af405c..a8132b605d 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -431,7 +431,7 @@ var editOriginals = dv.mv.options.allowEditingOriginals; copy.title = editOriginals ? "Push to left" : "Revert chunk"; copy.chunk = chunk; - copy.style.top = (chunk.origTo < chunk.origFrom ? top : dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit) + "px"; + copy.style.top = (chunk.origTo > chunk.origFrom ? top : dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit) + "px"; if (editOriginals) { var topReverse = dv.edit.heightAtLine(chunk.editFrom, "local") - sTopEdit; From 379c1aeb941b8403c51be15a8e64c614ed61143f Mon Sep 17 00:00:00 2001 From: Martin Zagora Date: Mon, 16 Jan 2017 14:59:51 +1100 Subject: [PATCH 0190/1880] TypeScript: add a test for usage of interface syntax with const --- mode/javascript/test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mode/javascript/test.js b/mode/javascript/test.js index 56b90e3cfe..c02eb06c31 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -261,6 +261,12 @@ " ) [operator =>] [variable-3 Promise] [operator <] [variable-3 AccountHolderNotificationPreferenceInstance] [operator >];", " }") + TS("typescript_interface_with_const", + "[keyword const] [def hello]: {", + " [property prop1][operator ?]: [variable-3 string];", + " [property prop2][operator ?]: [variable-3 string];", + "} [operator =] {};") + var jsonld_mode = CodeMirror.getMode( {indentUnit: 2}, {name: "javascript", jsonld: true} From 7166a44efbfcc9b84dc9efb4ec36da478370663d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 16 Jan 2017 21:47:45 +0100 Subject: [PATCH 0191/1880] [javascript mode] Improve TypeScript interface type parsing Issue #4494 --- mode/javascript/javascript.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index c185106ce4..17890dcc12 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -505,9 +505,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == ":") return cont(expressionNoComma); if (type == "(") return pass(functiondef); } - function commasep(what, end) { + function commasep(what, end, sep) { function proceed(type, value) { - if (type == ",") { + if (sep ? sep.indexOf(type) > -1 : type == ",") { var lex = cx.state.lexical; if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; return cont(function(type, value) { @@ -541,16 +541,18 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function typeexpr(type) { if (type == "variable") {cx.marked = "variable-3"; return cont(afterType);} if (type == "string" || type == "number" || type == "atom") return cont(afterType); - if (type == "{") return cont(commasep(typeprop, "}")) + if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex) if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType) } function maybeReturnType(type) { if (type == "=>") return cont(typeexpr) } - function typeprop(type) { + function typeprop(type, value) { if (type == "variable" || cx.style == "keyword") { cx.marked = "property" return cont(typeprop) + } else if (value == "?") { + return cont(typeprop) } else if (type == ":") { return cont(typeexpr) } From 6709974d3b01dc6aa153de37edf4170b0431b1f6 Mon Sep 17 00:00:00 2001 From: Zeno Rocha Date: Wed, 18 Jan 2017 06:28:31 -0800 Subject: [PATCH 0192/1880] [dracula theme] Adjust colors, remove duplicate definition --- theme/dracula.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/theme/dracula.css b/theme/dracula.css index b2ef62913c..53a660b521 100644 --- a/theme/dracula.css +++ b/theme/dracula.css @@ -24,8 +24,7 @@ .cm-s-dracula span.cm-number { color: #bd93f9; } .cm-s-dracula span.cm-variable { color: #50fa7b; } .cm-s-dracula span.cm-variable-2 { color: white; } -.cm-s-dracula span.cm-def { color: #ffb86c; } -.cm-s-dracula span.cm-keyword { color: #ff79c6; } +.cm-s-dracula span.cm-def { color: #50fa7b; } .cm-s-dracula span.cm-operator { color: #ff79c6; } .cm-s-dracula span.cm-keyword { color: #ff79c6; } .cm-s-dracula span.cm-atom { color: #bd93f9; } @@ -35,7 +34,7 @@ .cm-s-dracula span.cm-qualifier { color: #50fa7b; } .cm-s-dracula span.cm-property { color: #66d9ef; } .cm-s-dracula span.cm-builtin { color: #50fa7b; } -.cm-s-dracula span.cm-variable-3 { color: #50fa7b; } +.cm-s-dracula span.cm-variable-3 { color: #ffb86c; } .cm-s-dracula .CodeMirror-activeline-background { background: rgba(255,255,255,0.1); } .cm-s-dracula .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; } From 73c4e24a8e6c0bb078f5fb497edb484bd5523f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Vr=C3=A1na?= Date: Tue, 20 Dec 2016 16:45:20 +0100 Subject: [PATCH 0193/1880] [sublime bindings] Don't sort last line with no selected chars Selecting two full lines including line ends makes a selection from line 1 to line 3 (ch: 0). This command used to sort three lines (1 to 3) which is not what I expect. This change makes it sort only two lines if there are no selected characters on the last line. It also fixes a fatal error if there are more than one selection on the same line (the code used 'range' instead of 'ranges'). It also selects the trailing newline after sorting the lines so that the whole lines are selected. --- keymap/sublime.js | 5 +++-- test/sublime_test.js | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/keymap/sublime.js b/keymap/sublime.js index c5d2906bc0..3d112ab961 100644 --- a/keymap/sublime.js +++ b/keymap/sublime.js @@ -310,7 +310,8 @@ if (range.empty()) continue; var from = range.from().line, to = range.to().line; while (i < ranges.length - 1 && ranges[i + 1].from().line == to) - to = range[++i].to().line; + to = ranges[++i].to().line; + if (!ranges[i].to().ch) to--; toSort.push(from, to); } if (toSort.length) selected = true; @@ -331,7 +332,7 @@ return a < b ? -1 : a == b ? 0 : 1; }); cm.replaceRange(lines, start, end); - if (selected) ranges.push({anchor: start, head: end}); + if (selected) ranges.push({anchor: start, head: Pos(to + 1, 0)}); } if (selected) cm.setSelections(ranges, 0); }); diff --git a/test/sublime_test.js b/test/sublime_test.js index c5c19c0a23..57f16485e1 100644 --- a/test/sublime_test.js +++ b/test/sublime_test.js @@ -249,11 +249,11 @@ "undo", setSel(0, 0, 2, 0, 3, 0, 5, 0), - "sortLines", val("a\nb\nc\nA\nB\nC"), - hasSel(0, 0, 2, 1, - 3, 0, 5, 1), + "sortLines", val("b\nc\na\nB\nC\nA"), + hasSel(0, 0, 2, 0, + 3, 0, 5, 0), "undo", - setSel(1, 0, 4, 0), "sortLinesInsensitive", val("c\na\nB\nb\nC\nA")); + setSel(1, 0, 5, 0), "sortLinesInsensitive", val("c\na\nB\nb\nC\nA")); stTest("bookmarks", "abc\ndef\nghi\njkl", Pos(0, 1), "toggleBookmark", From 73638df40c9631155b1985f0ee63b6ffe2398b6a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 19 Jan 2017 23:35:01 +0100 Subject: [PATCH 0194/1880] Mark version 5.23.0 --- AUTHORS | 3 +++ CHANGELOG.md | 16 ++++++++++++++++ doc/manual.html | 2 +- doc/releases.html | 34 ++++++++++++++++++++++------------ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 45 insertions(+), 16 deletions(-) diff --git a/AUTHORS b/AUTHORS index 9b9b3355ba..866c78f842 100644 --- a/AUTHORS +++ b/AUTHORS @@ -175,6 +175,7 @@ eborden edsharp ekhaled Elisée +Emmanuel Schanzer Enam Mijbah Noor Eric Allam Erik Welander @@ -247,6 +248,7 @@ Irakli Gozalishvili Ivan Kurnosov Ivoah Jacob Lee +Jake Peyser Jakob Miland Jakub Vrana Jakub Vrána @@ -617,6 +619,7 @@ Yunchi Luo Yuvi Panda Zac Anger Zachary Dremann +Zeno Rocha Zhang Hao zziuni 魏鹏刚 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9074c1b0c5..07ed0295e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## 5.23.0 (2017-01-19) + +### Bug fixes + +Presentation-related elements DOM elements are now marked as such to help screen readers. + +[markdown mode](http://codemirror.net/mode/markdown/): Be more picky about what HTML tags look like to avoid false positives. + +### New features + +`findModeByMIME` now understands `+json` and `+xml` MIME suffixes. + +[closebrackets addon](http://codemirror.net/doc/manual.html#addon_closebrackets): Add support for an `override` option to ignore language-specific defaults. + +[panel addon](http://codemirror.net/doc/manual.html#addon_panel): Add a `stable` option that auto-scrolls the content to keep it in the same place when inserting/removing a panel. + ## 5.22.2 (2017-01-12) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index f765185eb3..a5eb223355 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.22.3 + version 5.23.0

    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 2dfd1fe482..69c0e66b10 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,18 +30,28 @@

    Release notes and version history

    Version 5.x

    -

    20-12-2016: Version 5.22.0:

    - -
      -
    • sublime bindings: Make selectBetweenBrackets work with multiple cursors.
    • -
    • javascript mode: Fix issues with parsing complex TypeScript types, imports, and exports.
    • -
    • A contentEditable editor instance with autofocus enabled no longer crashes during initializing.
    • -
    • emacs bindings: Export CodeMirror.emacs to allow other addons to hook into Emacs-style functionality.
    • -
    • active-line addon: Add nonEmpty option.
    • -
    • New event: optionChange.
    • -
    - -

    21-11-2016: Version 5.21.0:

    +

    19-01-2017: Version 5.23.0:

    + +
      +
    • Presentation-related elements DOM elements are now marked as such to help screen readers.
    • +
    • markdown mode: Be more picky about what HTML tags look like to avoid false positives.
    • +
    • findModeByMIME now understands +json and +xml MIME suffixes.
    • +
    • closebrackets addon: Add support for an override option to ignore language-specific defaults.
    • +
    • panel addon: Add a stable option that auto-scrolls the content to keep it in the same place when inserting/removing a panel.
    • +
    + +

    20-12-2016: Version 5.22.0:

    + +
      +
    • sublime bindings: Make selectBetweenBrackets work with multiple cursors.
    • +
    • javascript mode: Fix issues with parsing complex TypeScript types, imports, and exports.
    • +
    • A contentEditable editor instance with autofocus enabled no longer crashes during initializing.
    • +
    • emacs bindings: Export CodeMirror.emacs to allow other addons to hook into Emacs-style functionality.
    • +
    • active-line addon: Add nonEmpty option.
    • +
    • New event: optionChange.
    • +
    + +

    21-11-2016: Version 5.21.0:

    • Tapping/clicking the editor in contentEditable mode on Chrome now puts the cursor at the tapped position.
    • diff --git a/index.html b/index.html index 9812829e52..df98ffd096 100644 --- a/index.html +++ b/index.html @@ -96,7 +96,7 @@

      This is CodeMirror

    - Get the current version: 5.22.1.
    + Get the current version: 5.23.0.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index fa82dd11dc..f7b617cd22 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.22.3", + "version": "5.23.0", "main": "lib/codemirror.js", "description": "Full-featured in-browser code editor", "license": "MIT", diff --git a/src/edit/main.js b/src/edit/main.js index c16f377119..b6d3d488ad 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.22.3" +CodeMirror.version = "5.23.0" From 82162728938e8536d39a3f9937d7eb905e00eb9b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 20 Jan 2017 08:25:33 +0100 Subject: [PATCH 0195/1880] [shell mode] Improve tokenizing of $'' strings Closes #4505 --- mode/shell/shell.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/shell/shell.js b/mode/shell/shell.js index 570b4e2419..a636387395 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -108,8 +108,8 @@ CodeMirror.defineMode('shell', function() { if (state.tokens.length > 1) stream.eat('$'); var ch = stream.next(), hungry = /\w/; if (ch === '{') hungry = /[^}]/; - if (ch === '(') { - state.tokens[0] = tokenString(')'); + if (/['"(]/.test(ch)) { + state.tokens[0] = tokenString(ch == "(" ? ")" : ch); return tokenize(stream, state); } if (!/\d/.test(ch)) { From 39ad3b619ba9ea481f2847fb85aed647b67d17d1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 20 Jan 2017 22:12:11 +0100 Subject: [PATCH 0196/1880] [python mode] Accept underscores in number literals Closes #4506 --- mode/python/python.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mode/python/python.js b/mode/python/python.js index 4310f9fb6b..b539d84aa6 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -113,8 +113,8 @@ if (stream.match(/^[0-9\.]/, false)) { var floatLiteral = false; // Floats - if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; } - if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; } + if (stream.match(/^[\d_]*\.\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" @@ -124,13 +124,13 @@ // Integers var intLiteral = false; // Hex - if (stream.match(/^0x[0-9a-f]+/i)) intLiteral = true; + if (stream.match(/^0x[0-9a-f_]+/i)) intLiteral = true; // Binary - if (stream.match(/^0b[01]+/i)) intLiteral = true; + if (stream.match(/^0b[01_]+/i)) intLiteral = true; // Octal - if (stream.match(/^0o[0-7]+/i)) intLiteral = true; + if (stream.match(/^0o[0-7_]+/i)) intLiteral = true; // Decimal - if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) { + if (stream.match(/^[1-9][\d_]*(e[\+\-]?[\d_]+)?/)) { // Decimal literals may be "imaginary" stream.eat(/J/i); // TODO - Can you have imaginary longs? From 71af74da531f7ac7b08e6fcad37892dbf5375664 Mon Sep 17 00:00:00 2001 From: ficristo Date: Thu, 22 Dec 2016 16:33:50 +0100 Subject: [PATCH 0197/1880] [sass mode] Use same token types as CSS/SCSS mode. Add tests --- mode/sass/index.html | 4 +- mode/sass/sass.js | 71 +++++++++++++++++++++-------- mode/sass/test.js | 103 +++++++++++++++++++++++++++++++++++++++++++ test/index.html | 2 + 4 files changed, 161 insertions(+), 19 deletions(-) create mode 100644 mode/sass/test.js diff --git a/mode/sass/index.html b/mode/sass/index.html index 9f4a790221..6305649e5c 100644 --- a/mode/sass/index.html +++ b/mode/sass/index.html @@ -7,6 +7,7 @@ +
    - Get the current version: 5.27.4.
    + Get the current version: 5.28.0.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index ef824b0b0a..e413d2c57b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.27.5", + "version": "5.28.0", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "description": "Full-featured in-browser code editor", diff --git a/src/edit/main.js b/src/edit/main.js index 54a7a6e3cc..5a20c6473e 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.27.5" +CodeMirror.version = "5.28.0" From e246c6b165697c28ae584584d1cb56a31c87c707 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 21 Jul 2017 12:21:43 +0200 Subject: [PATCH 0552/1880] Bump version number post-5.28.0 --- doc/manual.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index b4500c375b..da4423f960 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.28.0 + version 5.28.1

    CodeMirror is a code-editor component that can be embedded in diff --git a/package.json b/package.json index e413d2c57b..ff6971cd8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.28.0", + "version": "5.28.1", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "description": "Full-featured in-browser code editor", diff --git a/src/edit/main.js b/src/edit/main.js index 5a20c6473e..e7a2122d6e 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.28.0" +CodeMirror.version = "5.28.1" From 0a1fb070028e2bc9ac6fb1e0c5940102bf7d0fa7 Mon Sep 17 00:00:00 2001 From: dwelle Date: Fri, 21 Jul 2017 17:56:58 +0200 Subject: [PATCH 0553/1880] [gfm mode] update doc --- mode/gfm/index.html | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/mode/gfm/index.html b/mode/gfm/index.html index 642c8ce71d..bec130ca51 100644 --- a/mode/gfm/index.html +++ b/mode/gfm/index.html @@ -70,21 +70,32 @@

    GFM mode

    ## A bit of GitHub spice +See http://github.github.com/github-flavored-markdown/. + +(Set `gitHubSpice: false` in mode options to disable): + * SHA: be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 * User@SHA ref: mojombo@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 * User/Project@SHA: mojombo/god@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 * \#Num: #1 * User/#Num: mojombo#1 * User/Project#Num: mojombo/god#1 -* emoji: :smile: (note: you must add the CSS rule yourself. Set `emoji: false` in mode options to disable) -See http://github.github.com/github-flavored-markdown/. +(Set `emoji: false` in mode options to disable): + +* emoji: :smile: + + @@ -115,6 +116,7 @@

    Test Suite

    + From 3ec7088b8aef7910db0f554ccd4c94d1a77bd71c Mon Sep 17 00:00:00 2001 From: Michael Walker Date: Mon, 24 Jul 2017 09:45:42 +0100 Subject: [PATCH 0558/1880] Use background-color for cm-searching --- lib/codemirror.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index b008351a62..f4d3c5f40b 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -319,8 +319,8 @@ div.CodeMirror-dragcursors { .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } .cm-searching { - background: #ffa; - background: rgba(255, 255, 0, .4); + background-color: #ffa; + background-color: rgba(255, 255, 0, .4); } /* Used to force a border model for a node */ From c53dc1678a0a1fce9e75f57e902ff73fad2ce64b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 25 Jul 2017 19:09:51 +0200 Subject: [PATCH 0559/1880] [python mode] Simplify tokenizing of operators, fix recognition of several ops Issue #4876 --- mode/python/python.js | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/mode/python/python.js b/mode/python/python.js index 2d2b08c810..c318793207 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -41,10 +41,11 @@ CodeMirror.defineMode("python", function(conf, parserConf) { var ERRORCLASS = "error"; - var singleDelimiters = parserConf.singleDelimiters || /^[\(\)\[\]\{\}@,:`=;\.]/; - var doubleOperators = parserConf.doubleOperators || /^([!<>]==|<>|<<|>>|\/\/|\*\*)/; - var doubleDelimiters = parserConf.doubleDelimiters || /^(\+=|\-=|\*=|%=|\/=|&=|\|=|\^=)/; - var tripleDelimiters = parserConf.tripleDelimiters || /^(\/\/=|>>=|<<=|\*\*=)/; + var delimiters = parserConf.delimiters || parserConf.singleDelimiters || /^[\(\)\[\]\{\}@,:`=;\.]/; + // (Backwards-compatiblity with old, cumbersome config system) + var operators = [parserConf.singleOperators, parserConf.doubleOperators, parserConf.doubleDelimiters, parserConf.tripleDelimiters, + parserConf.operators || /^([-+*/%\/&|^]=?|[<>=]+|\/\/=?|\*\*=?|!=|[~!@])/] + for (var i = 0; i < operators.length; i++) if (!operators[i]) operators.splice(i--, 1) var hangingIndent = parserConf.hangingIndent || conf.indentUnit; @@ -58,13 +59,11 @@ var py3 = !(parserConf.version && Number(parserConf.version) < 3) if (py3) { // since http://legacy.python.org/dev/peps/pep-0465/ @ is also an operator - var singleOperators = parserConf.singleOperators || /^[\+\-\*\/%&|\^~<>!@]/; var identifiers = parserConf.identifiers|| /^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*/; myKeywords = myKeywords.concat(["nonlocal", "False", "True", "None", "async", "await"]); myBuiltins = myBuiltins.concat(["ascii", "bytes", "exec", "print"]); var stringPrefixes = new RegExp("^(([rbuf]|(br))?('{3}|\"{3}|['\"]))", "i"); } else { - var singleOperators = parserConf.singleOperators || /^[\+\-\*\/%&|\^~<>!]/; var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*/; myKeywords = myKeywords.concat(["exec", "print"]); myBuiltins = myBuiltins.concat(["apply", "basestring", "buffer", "cmp", "coerce", "execfile", @@ -151,15 +150,10 @@ return state.tokenize(stream, state); } - // Handle operators and Delimiters - if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) - return "punctuation"; + for (var i = 0; i < operators.length; i++) + if (stream.match(operators[i])) return "operator" - if (stream.match(doubleOperators) || stream.match(singleOperators)) - return "operator"; - - if (stream.match(singleDelimiters)) - return "punctuation"; + if (stream.match(delimiters)) return "punctuation"; if (state.lastToken == "." && stream.match(identifiers)) return "property"; From e4c6f2b34f32681682c59f09d68f90a80d22d18a Mon Sep 17 00:00:00 2001 From: dwelle Date: Thu, 27 Jul 2017 12:51:39 +0200 Subject: [PATCH 0560/1880] [markdown mode] disallow lists and fencedCode inside blockquote --- mode/markdown/markdown.js | 6 +++--- mode/markdown/test.js | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index db8359e9b9..d646d884b4 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -196,7 +196,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } else if (stream.match(hrRE, true)) { state.hr = true; return tokenTypes.hr; - } else if (match = stream.match(listRE)) { + } else if (!state.quote && (match = stream.match(listRE))) { var listType = match[1] ? "ol" : "ul"; state.indentation = lineIndentation + stream.current().length; @@ -211,7 +211,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.f = state.inline; if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType]; return getType(state); - } else if (modeCfg.fencedCodeBlocks && (match = stream.match(fencedCodeRE, true))) { + } else if (modeCfg.fencedCodeBlocks && !state.quote && (match = stream.match(fencedCodeRE, true))) { state.fencedChars = match[1] // try switching mode state.localMode = getMode(match[2]); @@ -400,7 +400,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { if (modeCfg.highlightFormatting) state.formatting = "code"; stream.eatWhile('`'); var count = stream.current().length - if (state.code == 0) { + if (state.code == 0 && (!state.quote || count == 1)) { state.code = count return getType(state) } else if (count == state.code) { // Must be exact diff --git a/mode/markdown/test.js b/mode/markdown/test.js index 8dac53aade..c2ac548305 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -323,6 +323,20 @@ "", "hello"); + // disallow lists inside blockquote for now because it causes problems outside blockquote + // TODO: fix to be CommonMark-compliant + MT("listNestedInBlockquote", + "[quote"e-1 > - foo]"); + + // disallow fenced blocks inside blockquote because it causes problems outside blockquote + // TODO: fix to be CommonMark-compliant + MT("fencedBlockNestedInBlockquote", + "[quote"e-1 > ```]", + "[quote"e-1 > code]", + "[quote"e-1 > ```]", + // ensure we still allow inline code + "[quote"e-1 > ][quote"e-1&comment `code`]"); + // Header with leading space after continued blockquote (#3287, negative indentation) MT("headerAfterContinuedBlockquote", "[quote"e-1 > foo]", From 0927b971c866c92602d7200f061d59ff78026e09 Mon Sep 17 00:00:00 2001 From: "Jan T. Sott" Date: Tue, 25 Jul 2017 22:32:28 +0200 Subject: [PATCH 0561/1880] [nsis mode] Add support for NSIS 3.02 --- mode/nsis/nsis.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mode/nsis/nsis.js b/mode/nsis/nsis.js index dc8c74cdf4..d6c61facf3 100644 --- a/mode/nsis/nsis.js +++ b/mode/nsis/nsis.js @@ -24,20 +24,20 @@ CodeMirror.defineSimpleMode("nsis",{ { regex: /`(?:[^\\`]|\\.)*`?/, token: "string" }, // Compile Time Commands - {regex: /^\s*(?:\!(include|addincludedir|addplugindir|appendfile|cd|delfile|echo|error|execute|packhdr|finalize|getdllversion|system|tempfile|warning|verbose|define|undef|insertmacro|makensis|searchparse|searchreplace))\b/, token: "keyword"}, + {regex: /^\s*(?:\!(include|addincludedir|addplugindir|appendfile|cd|delfile|echo|error|execute|packhdr|pragma|finalize|getdllversion|system|tempfile|warning|verbose|define|undef|insertmacro|makensis|searchparse|searchreplace))\b/, token: "keyword"}, // Conditional Compilation {regex: /^\s*(?:\!(if(?:n?def)?|ifmacron?def|macro))\b/, token: "keyword", indent: true}, {regex: /^\s*(?:\!(else|endif|macroend))\b/, token: "keyword", dedent: true}, // Runtime Commands - {regex: /^\s*(?:Abort|AddBrandingImage|AddSize|AllowRootDirInstall|AllowSkipFiles|AutoCloseWindow|BGFont|BGGradient|BrandingText|BringToFront|Call|CallInstDLL|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|CreateDirectory|CreateFont|CreateShortCut|Delete|DeleteINISec|DeleteINIStr|DeleteRegKey|DeleteRegValue|DetailPrint|DetailsButtonText|DirText|DirVar|DirVerify|EnableWindow|EnumRegKey|EnumRegValue|Exch|Exec|ExecShell|ExecWait|ExpandEnvStrings|File|FileBufSize|FileClose|FileErrorText|FileOpen|FileRead|FileReadByte|FileReadUTF16LE|FileReadWord|FileWriteUTF16LE|FileSeek|FileWrite|FileWriteByte|FileWriteWord|FindClose|FindFirst|FindNext|FindWindow|FlushINI|GetCurInstType|GetCurrentAddress|GetDlgItem|GetDLLVersion|GetDLLVersionLocal|GetErrorLevel|GetFileTime|GetFileTimeLocal|GetFullPathName|GetFunctionAddress|GetInstDirError|GetLabelAddress|GetTempFileName|Goto|HideWindow|Icon|IfAbort|IfErrors|IfFileExists|IfRebootFlag|IfSilent|InitPluginsDir|InstallButtonText|InstallColors|InstallDir|InstallDirRegKey|InstProgressFlags|InstType|InstTypeGetText|InstTypeSetText|IntCmp|IntCmpU|IntFmt|IntOp|IsWindow|LangString|LicenseBkColor|LicenseData|LicenseForceSelection|LicenseLangString|LicenseText|LoadLanguageFile|LockWindow|LogSet|LogText|ManifestDPIAware|ManifestSupportedOS|MessageBox|MiscButtonText|Name|Nop|OutFile|Page|PageCallbacks|Pop|Push|Quit|ReadEnvStr|ReadINIStr|ReadRegDWORD|ReadRegStr|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|SectionGetFlags|SectionGetInstTypes|SectionGetSize|SectionGetText|SectionIn|SectionSetFlags|SectionSetInstTypes|SectionSetSize|SectionSetText|SendMessage|SetAutoClose|SetBrandingImage|SetCompress|SetCompressor|SetCompressorDictSize|SetCtlColors|SetCurInstType|SetDatablockOptimize|SetDateSave|SetDetailsPrint|SetDetailsView|SetErrorLevel|SetErrors|SetFileAttributes|SetFont|SetOutPath|SetOverwrite|SetRebootFlag|SetRegView|SetShellVarContext|SetSilent|ShowInstDetails|ShowUninstDetails|ShowWindow|SilentInstall|SilentUnInstall|Sleep|SpaceTexts|StrCmp|StrCmpS|StrCpy|StrLen|SubCaption|Unicode|UninstallButtonText|UninstallCaption|UninstallIcon|UninstallSubCaption|UninstallText|UninstPage|UnRegDLL|Var|VIAddVersionKey|VIFileVersion|VIProductVersion|WindowIcon|WriteINIStr|WriteRegBin|WriteRegDWORD|WriteRegExpandStr|WriteRegStr|WriteUninstaller|XPStyle)\b/, token: "keyword"}, + {regex: /^\s*(?:Abort|AddBrandingImage|AddSize|AllowRootDirInstall|AllowSkipFiles|AutoCloseWindow|BGFont|BGGradient|BrandingText|BringToFront|Call|CallInstDLL|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|CreateDirectory|CreateFont|CreateShortCut|Delete|DeleteINISec|DeleteINIStr|DeleteRegKey|DeleteRegValue|DetailPrint|DetailsButtonText|DirText|DirVar|DirVerify|EnableWindow|EnumRegKey|EnumRegValue|Exch|Exec|ExecShell|ExecShellWait|ExecWait|ExpandEnvStrings|File|FileBufSize|FileClose|FileErrorText|FileOpen|FileRead|FileReadByte|FileReadUTF16LE|FileReadWord|FileWriteUTF16LE|FileSeek|FileWrite|FileWriteByte|FileWriteWord|FindClose|FindFirst|FindNext|FindWindow|FlushINI|GetCurInstType|GetCurrentAddress|GetDlgItem|GetDLLVersion|GetDLLVersionLocal|GetErrorLevel|GetFileTime|GetFileTimeLocal|GetFullPathName|GetFunctionAddress|GetInstDirError|GetLabelAddress|GetTempFileName|Goto|HideWindow|Icon|IfAbort|IfErrors|IfFileExists|IfRebootFlag|IfSilent|InitPluginsDir|InstallButtonText|InstallColors|InstallDir|InstallDirRegKey|InstProgressFlags|InstType|InstTypeGetText|InstTypeSetText|IntCmp|IntCmpU|IntFmt|IntOp|IsWindow|LangString|LicenseBkColor|LicenseData|LicenseForceSelection|LicenseLangString|LicenseText|LoadLanguageFile|LockWindow|LogSet|LogText|ManifestDPIAware|ManifestSupportedOS|MessageBox|MiscButtonText|Name|Nop|OutFile|Page|PageCallbacks|Pop|Push|Quit|ReadEnvStr|ReadINIStr|ReadRegDWORD|ReadRegStr|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|SectionGetFlags|SectionGetInstTypes|SectionGetSize|SectionGetText|SectionIn|SectionSetFlags|SectionSetInstTypes|SectionSetSize|SectionSetText|SendMessage|SetAutoClose|SetBrandingImage|SetCompress|SetCompressor|SetCompressorDictSize|SetCtlColors|SetCurInstType|SetDatablockOptimize|SetDateSave|SetDetailsPrint|SetDetailsView|SetErrorLevel|SetErrors|SetFileAttributes|SetFont|SetOutPath|SetOverwrite|SetRebootFlag|SetRegView|SetShellVarContext|SetSilent|ShowInstDetails|ShowUninstDetails|ShowWindow|SilentInstall|SilentUnInstall|Sleep|SpaceTexts|StrCmp|StrCmpS|StrCpy|StrLen|SubCaption|Unicode|UninstallButtonText|UninstallCaption|UninstallIcon|UninstallSubCaption|UninstallText|UninstPage|UnRegDLL|Var|VIAddVersionKey|VIFileVersion|VIProductVersion|WindowIcon|WriteINIStr|WriteRegBin|WriteRegDWORD|WriteRegExpandStr|WriteRegMultiStr|WriteRegNone|WriteRegStr|WriteUninstaller|XPStyle)\b/, token: "keyword"}, {regex: /^\s*(?:Function|PageEx|Section(?:Group)?)\b/, token: "keyword", indent: true}, {regex: /^\s*(?:(Function|PageEx|Section(?:Group)?)End)\b/, token: "keyword", dedent: true}, // Command Options - {regex: /\b(?:ARCHIVE|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY|HIDDEN|HKCC|HKCR|HKCU|HKDD|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_DYN_DATA|HKEY_LOCAL_MACHINE|HKEY_PERFORMANCE_DATA|HKEY_USERS|HKLM|HKPD|HKU|IDABORT|IDCANCEL|IDD_DIR|IDD_INST|IDD_INSTFILES|IDD_LICENSE|IDD_SELCOM|IDD_UNINST|IDD_VERIFY|IDIGNORE|IDNO|IDOK|IDRETRY|IDYES|MB_ABORTRETRYIGNORE|MB_DEFBUTTON1|MB_DEFBUTTON2|MB_DEFBUTTON3|MB_DEFBUTTON4|MB_ICONEXCLAMATION|MB_ICONINFORMATION|MB_ICONQUESTION|MB_ICONSTOP|MB_OK|MB_OKCANCEL|MB_RETRYCANCEL|MB_RIGHT|MB_RTLREADING|MB_SETFOREGROUND|MB_TOPMOST|MB_USERICON|MB_YESNO|MB_YESNOCANCEL|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SW_HIDE|SW_SHOWDEFAULT|SW_SHOWMAXIMIZED|SW_SHOWMINIMIZED|SW_SHOWNORMAL|SYSTEM|TEMPORARY)\b/, token: "atom"}, - {regex: /\b(?:admin|all|auto|both|bottom|bzip2|components|current|custom|directory|force|hide|highest|ifdiff|ifnewer|instfiles|lastused|leave|left|license|listonly|lzma|nevershow|none|normal|notset|right|show|silent|silentlog|textonly|top|try|un\.components|un\.custom|un\.directory|un\.instfiles|un\.license|uninstConfirm|user|Win10|Win7|Win8|WinVista|zlib)\b/, token: "builtin"}, + {regex: /\b(?:ARCHIVE|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY|HIDDEN|HKCC|HKCR(32|64)?|HKCU(32|64)?|HKDD|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_DYN_DATA|HKEY_LOCAL_MACHINE|HKEY_PERFORMANCE_DATA|HKEY_USERS|HKLM(32|64)?|HKPD|HKU|IDABORT|IDCANCEL|IDD_DIR|IDD_INST|IDD_INSTFILES|IDD_LICENSE|IDD_SELCOM|IDD_UNINST|IDD_VERIFY|IDIGNORE|IDNO|IDOK|IDRETRY|IDYES|MB_ABORTRETRYIGNORE|MB_DEFBUTTON1|MB_DEFBUTTON2|MB_DEFBUTTON3|MB_DEFBUTTON4|MB_ICONEXCLAMATION|MB_ICONINFORMATION|MB_ICONQUESTION|MB_ICONSTOP|MB_OK|MB_OKCANCEL|MB_RETRYCANCEL|MB_RIGHT|MB_RTLREADING|MB_SETFOREGROUND|MB_TOPMOST|MB_USERICON|MB_YESNO|MB_YESNOCANCEL|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SW_HIDE|SW_SHOWDEFAULT|SW_SHOWMAXIMIZED|SW_SHOWMINIMIZED|SW_SHOWNORMAL|SYSTEM|TEMPORARY)\b/, token: "atom"}, + {regex: /\b(?:admin|all|auto|both|bottom|bzip2|components|current|custom|directory|false|force|hide|highest|ifdiff|ifnewer|instfiles|lastused|leave|left|license|listonly|lzma|nevershow|none|normal|notset|off|on|right|show|silent|silentlog|textonly|top|true|try|un\.components|un\.custom|un\.directory|un\.instfiles|un\.license|uninstConfirm|user|Win10|Win7|Win8|WinVista|zlib)\b/, token: "builtin"}, // LogicLib.nsh {regex: /\$\{(?:And(?:If(?:Not)?|Unless)|Break|Case(?:Else)?|Continue|Default|Do(?:Until|While)?|Else(?:If(?:Not)?|Unless)?|End(?:If|Select|Switch)|Exit(?:Do|For|While)|For(?:Each)?|If(?:Cmd|Not(?:Then)?|Then)?|Loop(?:Until|While)?|Or(?:If(?:Not)?|Unless)|Select|Switch|Unless|While)\}/, token: "variable-2", indent: true}, From 6bbdb75be5a839d6a9f92adaf7357a04af639705 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 28 Jul 2017 14:29:51 +0200 Subject: [PATCH 0562/1880] [continuecomment addon] Don't assume comment lines are a single token Issue codemirror/google-modes#8 --- addon/comment/continuecomment.js | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/addon/comment/continuecomment.js b/addon/comment/continuecomment.js index b11d51e6ca..d7385ef223 100644 --- a/addon/comment/continuecomment.js +++ b/addon/comment/continuecomment.js @@ -18,30 +18,28 @@ if (cm.getOption("disableInput")) return CodeMirror.Pass; var ranges = cm.listSelections(), mode, inserts = []; for (var i = 0; i < ranges.length; i++) { - var pos = ranges[i].head, token = cm.getTokenAt(pos); - if (token.type != "comment") return CodeMirror.Pass; - var modeHere = CodeMirror.innerMode(cm.getMode(), token.state).mode; + var pos = ranges[i].head + if (!/\bcomment\b/.test(cm.getTokenTypeAt(pos))) return CodeMirror.Pass; + var modeHere = cm.getModeAt(pos) if (!mode) mode = modeHere; else if (mode != modeHere) return CodeMirror.Pass; var insert = null; if (mode.blockCommentStart && mode.blockCommentContinue) { - var end = token.string.indexOf(mode.blockCommentEnd); - var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found; - if (end != -1 && end == token.string.length - mode.blockCommentEnd.length && pos.ch >= end) { + var line = cm.getLine(pos.line).slice(0, pos.ch) + var end = line.indexOf(mode.blockCommentEnd), found + if (end != -1 && end == pos.ch - mode.blockCommentEnd.length) { // Comment ended, don't continue it - } else if (token.string.indexOf(mode.blockCommentStart) == 0) { - insert = full.slice(0, token.start); - if (!/^\s*$/.test(insert)) { - insert = ""; - for (var j = 0; j < token.start; ++j) insert += " "; + } else if ((found = line.indexOf(mode.blockCommentStart)) > -1) { + insert = line.slice(0, found) + if (/\S/.test(insert)) { + insert = "" + for (var j = 0; j < found; ++j) insert += " " } - } else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 && - found + mode.blockCommentContinue.length > token.start && - /^\s*$/.test(full.slice(0, found))) { - insert = full.slice(0, found); + } else if ((found = line.indexOf(mode.blockCommentContinue)) > -1 && !/\S/.test(line.slice(0, found))) { + insert = line.slice(0, found) } - if (insert != null) insert += mode.blockCommentContinue; + if (insert != null) insert += mode.blockCommentContinue } if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) { var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment); From 2b8b8e72e70b6e8e4205be3f35a8b9a50983595b Mon Sep 17 00:00:00 2001 From: Benjamin Young Date: Fri, 28 Jul 2017 11:27:27 -0400 Subject: [PATCH 0563/1880] Add alternate media type for Shell Seems Apache has its own list for non-registered media types. --- mode/meta.js | 2 +- mode/shell/index.html | 2 +- mode/shell/shell.js | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mode/meta.js b/mode/meta.js index edaae033eb..20973ace3d 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -121,7 +121,7 @@ {name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]}, {name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]}, {name: "SCSS", mime: "text/x-scss", mode: "css", ext: ["scss"]}, - {name: "Shell", mime: "text/x-sh", mode: "shell", ext: ["sh", "ksh", "bash"], alias: ["bash", "sh", "zsh"], file: /^PKGBUILD$/}, + {name: "Shell", mimes: ["text/x-sh", "application/x-sh"], mode: "shell", ext: ["sh", "ksh", "bash"], alias: ["bash", "sh", "zsh"], file: /^PKGBUILD$/}, {name: "Sieve", mime: "application/sieve", mode: "sieve", ext: ["siv", "sieve"]}, {name: "Slim", mimes: ["text/x-slim", "application/x-slim"], mode: "slim", ext: ["slim"]}, {name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]}, diff --git a/mode/shell/index.html b/mode/shell/index.html index 0b56300b12..e42f4b5f3b 100644 --- a/mode/shell/index.html +++ b/mode/shell/index.html @@ -62,5 +62,5 @@

    Shell mode

    }); -

    MIME types defined: text/x-sh.

    +

    MIME types defined: text/x-sh, application/x-sh.

    diff --git a/mode/shell/shell.js b/mode/shell/shell.js index 6af814c43e..c5619afe7c 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -135,5 +135,8 @@ CodeMirror.defineMode('shell', function() { }); CodeMirror.defineMIME('text/x-sh', 'shell'); +// Apache uses a slightly different Media Type for Shell scripts +// http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types +CodeMirror.defineMIME('application/x-sh', 'shell'); }); From 81103a3f32220dfe4cf9027f863aa3da893ca6c2 Mon Sep 17 00:00:00 2001 From: Benjamin Young Date: Fri, 28 Jul 2017 11:32:12 -0400 Subject: [PATCH 0564/1880] Add application/pgp-encrypted MIME type Also .asc and .sig extensions Re: http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types --- mode/asciiarmor/asciiarmor.js | 1 + mode/asciiarmor/index.html | 2 +- mode/meta.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mode/asciiarmor/asciiarmor.js b/mode/asciiarmor/asciiarmor.js index d830903767..fa1b0f8c61 100644 --- a/mode/asciiarmor/asciiarmor.js +++ b/mode/asciiarmor/asciiarmor.js @@ -68,6 +68,7 @@ }); CodeMirror.defineMIME("application/pgp", "asciiarmor"); + CodeMirror.defineMIME("application/pgp-encrypted", "asciiarmor"); CodeMirror.defineMIME("application/pgp-keys", "asciiarmor"); CodeMirror.defineMIME("application/pgp-signature", "asciiarmor"); }); diff --git a/mode/asciiarmor/index.html b/mode/asciiarmor/index.html index 8ba1b5c76c..4d584efbcd 100644 --- a/mode/asciiarmor/index.html +++ b/mode/asciiarmor/index.html @@ -41,6 +41,6 @@

    ASCII Armor (PGP) mode

    MIME types -defined: application/pgp, application/pgp-keys, application/pgp-signature

    +defined: application/pgp, application/pgp-encrypted, application/pgp-keys, application/pgp-signature

    diff --git a/mode/meta.js b/mode/meta.js index 20973ace3d..b08ff933f4 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -13,7 +13,7 @@ CodeMirror.modeInfo = [ {name: "APL", mime: "text/apl", mode: "apl", ext: ["dyalog", "apl"]}, - {name: "PGP", mimes: ["application/pgp", "application/pgp-keys", "application/pgp-signature"], mode: "asciiarmor", ext: ["pgp"]}, + {name: "PGP", mimes: ["application/pgp", "application/pgp-encrypted", "application/pgp-keys", "application/pgp-signature"], mode: "asciiarmor", ext: ["asc", "pgp", "sig"]}, {name: "ASN.1", mime: "text/x-ttcn-asn", mode: "asn.1", ext: ["asn", "asn1"]}, {name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk", file: /^extensions\.conf$/i}, {name: "Brainfuck", mime: "text/x-brainfuck", mode: "brainfuck", ext: ["b", "bf"]}, From 902571b643c5df6b1cc8965377e5e35800ed706e Mon Sep 17 00:00:00 2001 From: Benjamin Young Date: Fri, 28 Jul 2017 11:51:35 -0400 Subject: [PATCH 0565/1880] Add additional CoffeeScript MIMES IANA registered application/vnd.coffeescript Also noted the text/coffeescript option in the demo --- mode/coffeescript/coffeescript.js | 4 ++++ mode/coffeescript/index.html | 2 +- mode/meta.js | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/mode/coffeescript/coffeescript.js b/mode/coffeescript/coffeescript.js index adf2184fd7..ae955db344 100644 --- a/mode/coffeescript/coffeescript.js +++ b/mode/coffeescript/coffeescript.js @@ -349,6 +349,10 @@ CodeMirror.defineMode("coffeescript", function(conf, parserConf) { return external; }); +// IANA registered media type +// https://www.iana.org/assignments/media-types/ +CodeMirror.defineMIME("application/vnd.coffeescript", "coffeescript"); + CodeMirror.defineMIME("text/x-coffeescript", "coffeescript"); CodeMirror.defineMIME("text/coffeescript", "coffeescript"); diff --git a/mode/coffeescript/index.html b/mode/coffeescript/index.html index 93a5f4f309..92d161e9dd 100644 --- a/mode/coffeescript/index.html +++ b/mode/coffeescript/index.html @@ -733,7 +733,7 @@

    CoffeeScript mode

    var editor = CodeMirror.fromTextArea(document.getElementById("code"), {}); -

    MIME types defined: text/x-coffeescript.

    +

    MIME types defined: application/vnd.coffeescript, text/coffeescript, text/x-coffeescript.

    The CoffeeScript mode was written by Jeff Pickhardt.

    diff --git a/mode/meta.js b/mode/meta.js index b08ff933f4..d1c42a03a7 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -25,7 +25,7 @@ {name: "ClojureScript", mime: "text/x-clojurescript", mode: "clojure", ext: ["cljs"]}, {name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]}, {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/}, - {name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]}, + {name: "CoffeeScript", mimes: ["application/vnd.coffeescript", "text/coffeescript", "text/x-coffeescript"], mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]}, {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]}, {name: "Cypher", mime: "application/x-cypher-query", mode: "cypher", ext: ["cyp", "cypher"]}, {name: "Cython", mime: "text/x-cython", mode: "python", ext: ["pyx", "pxd", "pxi"]}, From 910e3becbd8de199165e65e7bd1ade10937f9e0e Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Sat, 29 Jul 2017 00:41:32 +0200 Subject: [PATCH 0566/1880] [python mode] Add regression test for #4876 --- mode/python/test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mode/python/test.js b/mode/python/test.js index c1a9c6a990..950eed51e6 100644 --- a/mode/python/test.js +++ b/mode/python/test.js @@ -24,6 +24,11 @@ MT("matmulWithSpace:", "[variable a] [operator @] [variable b]"); MT("matmulWithoutSpace:", "[variable a][operator @][variable b]"); MT("matmulSpaceBefore:", "[variable a] [operator @][variable b]"); + var before_equal_sign = ["+", "-", "*", "/", "=", "!", ">", "<"]; + for (var i = 0; i < before_equal_sign.length; ++i) { + var c = before_equal_sign[i] + MT("before_equal_sign_" + c, "[variable a] [operator " + c + "=] [variable b]"); + } MT("fValidStringPrefix", "[string f'this is a {formatted} string']"); MT("uValidStringPrefix", "[string u'this is an unicode string']"); From 166959fcd0f1fe8c9c58479ec3abe4e3f34ebfd8 Mon Sep 17 00:00:00 2001 From: Kazuhito Hokamura Date: Mon, 31 Jul 2017 20:29:06 +0900 Subject: [PATCH 0567/1880] Fix broken links --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c0887ed5c..49290390fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,7 +50,7 @@ Calling the `Doc` constructor without `new` works again. [markdown mode](http://codemirror.net/mode/markdown/): Fix bug where markup was ignored on indented paragraph lines. -[vim bindings](http://codemirror.net/mode/demo/vim.html): Referencing invalid registers no longer causes an uncaught exception. +[vim bindings](http://codemirror.net/demo/vim.html): Referencing invalid registers no longer causes an uncaught exception. [rust mode](http://codemirror.net/mode/rust/): Add the correct MIME type. @@ -90,7 +90,7 @@ More careful restoration of selections in widgets, during editor redraw. ### New features -[vim bindings](http://codemirror.net/mode/demo/vim.html): Parse line offsets in line or range specs. +[vim bindings](http://codemirror.net/demo/vim.html): Parse line offsets in line or range specs. ## 5.25.2 (2017-04-20) @@ -148,7 +148,7 @@ Add `role=presentation` to more DOM elements to improve screen reader support. [continuelist addon](http://codemirror.net/doc/manual.html#addon_continuelist): Support continuing task lists. -[vim bindings](http://codemirror.net/mode/demo/vim.html): Make Y behave like yy. +[vim bindings](http://codemirror.net/demo/vim.html): Make Y behave like yy. [sql mode](http://codemirror.net/mode/sql/): Support sqlite dialect. @@ -194,7 +194,7 @@ Fix bug in handling of read-only marked text. Positions now support a `sticky` property which determines whether they should be associated with the character before (value `"before"`) or after (value `"after"`) them. -[vim bindings](http://codemirror.net/mode/demo/vim.html): Make it possible to remove built-in bindings through the API. +[vim bindings](http://codemirror.net/demo/vim.html): Make it possible to remove built-in bindings through the API. [comment addon](http://codemirror.net/doc/manual.html#addon_comment): Support a per-mode useInnerComments option to optionally suppress descending to the inner modes to get comment strings. From 4d448b29763032739a9fc356e3bdd326a23b3cd0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 1 Aug 2017 10:15:44 +0200 Subject: [PATCH 0568/1880] Also fix vim links in releases.html --- doc/releases.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/releases.html b/doc/releases.html index 86cadb1512..1c882dc310 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -63,7 +63,7 @@

    Version 5.x

  • sql mode: Handle nested comments.
  • javascript mode: Improve support for TypeScript syntax.
  • markdown mode: Fix bug where markup was ignored on indented paragraph lines.
  • -
  • vim bindings: Referencing invalid registers no longer causes an uncaught exception.
  • +
  • vim bindings: Referencing invalid registers no longer causes an uncaught exception.
  • rust mode: Add the correct MIME type.
  • matchbrackets addon: Document options.
  • Mouse button clicks can now be bound in keymaps by using names like "LeftClick" or "Ctrl-Alt-MiddleTripleClick". When bound to a function, that function will be passed the position of the click as second argument.
  • @@ -79,7 +79,7 @@

    Version 5.x

    • In textarea-mode, don't reset the input field during composition.
    • More careful restoration of selections in widgets, during editor redraw.
    • -
    • vim bindings: Parse line offsets in line or range specs.
    • +
    • vim bindings: Parse line offsets in line or range specs.
    • javascript mode: More TypeScript parsing fixes.
    • julia mode: Fix issue where the mode gets stuck.
    • markdown mode: Understand cross-line links, parse all bracketed things as links.
    • @@ -118,7 +118,7 @@

      Version 5.x

    • soy mode: Improve indentation.
    • lint addon: Support asynchronous linters that return promises.
    • continuelist addon: Support continuing task lists.
    • -
    • vim bindings: Make Y behave like yy.
    • +
    • vim bindings: Make Y behave like yy.
    • sql mode: Support sqlite dialect.
    @@ -133,7 +133,7 @@

    Version 5.x

    • Positions now support a sticky property which determines whether they should be associated with the character before (value "before") or after (value "after") them.
    • -
    • vim bindings: Make it possible to remove built-in bindings through the API.
    • +
    • vim bindings: Make it possible to remove built-in bindings through the API.
    • comment addon: Support a per-mode useInnerComments option to optionally suppress descending to the inner modes to get comment strings.
    • A cursor directly before a line-wrapping break is now drawn before or after the line break depending on which direction you arrived from.
    • Visual cursor motion in line-wrapped right-to-left text should be much more correct.
    • From d600b9479fbd830f0b6b8710241f2f346c7f05e5 Mon Sep 17 00:00:00 2001 From: dwelle Date: Sun, 23 Jul 2017 14:35:41 +0200 Subject: [PATCH 0569/1880] [markdown mode] improve setext & hr tokenization --- mode/markdown/markdown.js | 66 +++++++++++++++++++++++++------------ mode/markdown/test.js | 68 +++++++++++++++++++++++++++++++++++---- 2 files changed, 108 insertions(+), 26 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index d646d884b4..59a17012da 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -90,6 +90,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { , textRE = /^[^#!\[\]*_\\<>` "'(~:]+/ , fencedCodeRE = new RegExp("^(" + (modeCfg.fencedCodeBlocks === true ? "~~~+|```+" : modeCfg.fencedCodeBlocks) + ")[ \\t]*([\\w+#\-]*)") + , linkDefRE = /^\s*\[[^\]]+?\]:\s*\S+(\s*\S*\s*)?$/ // naive link-definition , punctuation = /[!\"#$%&\'()*+,\-\.\/:;<=>?@\[\\\]^_`{|}~—]/ , expandedTab = " " // CommonMark specifies tab as 4 spaces @@ -110,6 +111,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { // Blocks function blankLine(state) { + state.hr = false; // Reset linkTitle state state.linkTitle = false; // Reset EM state @@ -137,16 +139,18 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { function blockNormal(stream, state) { var sol = stream.sol(); + var prevLineLineIsEmpty = lineIsEmpty(state.prevLine); + var prevLineIsIndentedCode = state.indentedCode; + var prevLineIsHr = state.hr; + var prevLineIsList = state.list !== false; + var maxNonCodeIndentation = (state.listStack[state.listStack.length - 1] || 0) + 3; - var prevLineIsList = state.list !== false, - prevLineIsIndentedCode = state.indentedCode; - + state.hr = false; state.indentedCode = false; - var lineIndentation; + var lineIndentation = state.indentation; // compute once per line (on first token) if (state.indentationDiff === null) { - lineIndentation = state.indentation; state.indentationDiff = state.indentation; if (prevLineIsList) { state.list = null; @@ -168,8 +172,11 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } } + var isHr = (state.list === false || prevLineIsHr || prevLineLineIsEmpty) && + state.indentation <= maxNonCodeIndentation && stream.match(hrRE); + var match = null; - if (state.indentationDiff >= 4 && (prevLineIsIndentedCode || lineIsEmpty(state.prevLine))) { + if (state.indentationDiff >= 4 && (prevLineIsIndentedCode || prevLineLineIsEmpty)) { stream.skipToEnd(); state.indentedCode = true; return tokenTypes.code; @@ -180,23 +187,12 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { if (modeCfg.highlightFormatting) state.formatting = "header"; state.f = state.inline; return getType(state); - } else if (!lineIsEmpty(state.prevLine) && !state.quote && !prevLineIsList && - !prevLineIsIndentedCode && (match = stream.match(setextHeaderRE))) { - state.header = match[0].charAt(0) == '=' ? 1 : 2; - if (modeCfg.highlightFormatting) state.formatting = "header"; - state.f = state.inline; - return getType(state); } else if (stream.eat('>')) { state.quote = sol ? 1 : state.quote + 1; if (modeCfg.highlightFormatting) state.formatting = "quote"; stream.eatSpace(); return getType(state); - } else if (stream.peek() === '[') { - return switchInline(stream, state, footnoteLink); - } else if (stream.match(hrRE, true)) { - state.hr = true; - return tokenTypes.hr; - } else if (!state.quote && (match = stream.match(listRE))) { + } else if (!isHr && !state.quote && (match = stream.match(listRE))) { var listType = match[1] ? "ol" : "ul"; state.indentation = lineIndentation + stream.current().length; @@ -220,6 +216,35 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { if (modeCfg.highlightFormatting) state.formatting = "code-block"; state.code = -1 return getType(state); + // SETEXT has lowest block-scope precedence after HR, so check it after + // the others (code, blockquote, list...) + } else if ( + // if setext set, indicates line after ---/=== + state.setext || ( + // line before ---/=== + !state.quote && state.list === false && !state.code && !isHr && + !prevLineIsList && !linkDefRE.test(stream.string) && + (match = stream.lookAhead(1)) && (match = match.match(setextHeaderRE)) + ) + ) { + if ( !state.setext ) { + state.header = match[0].charAt(0) == '=' ? 1 : 2; + state.setext = state.header; + } else { + state.header = state.setext; + // has no effect on type so we can reset it now + state.setext = 0; + stream.skipToEnd(); + if (modeCfg.highlightFormatting) state.formatting = "header"; + } + state.f = state.inline; + return getType(state); + } else if (isHr) { + stream.skipToEnd(); + state.hr = true; + return tokenTypes.hr; + } else if (stream.peek() === '[') { + return switchInline(stream, state, footnoteLink); } return switchInline(stream, state, state.inline); @@ -703,6 +728,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { em: false, strong: false, header: 0, + setext: 0, hr: false, taskList: false, list: false, @@ -741,6 +767,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { strikethrough: s.strikethrough, emoji: s.emoji, header: s.header, + setext: s.setext, hr: s.hr, taskList: s.taskList, list: s.list, @@ -760,9 +787,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.formatting = false; if (stream != state.thisLine) { - // Reset state.header and state.hr + // Reset state.header state.header = 0; - state.hr = false; if (stream.match(/^\s*$/, true)) { blankLine(state); diff --git a/mode/markdown/test.js b/mode/markdown/test.js index c2ac548305..c2c9fb1120 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -67,7 +67,7 @@ "[header&header-1&formatting&formatting-header&formatting-header-1 # ][header&header-1 foo # bar ][header&header-1&formatting&formatting-header&formatting-header-1 #]"); FT("formatting_setextHeader", - "foo", + "[header&header-1 foo]", "[header&header-1&formatting&formatting-header&formatting-header-1 =]"); FT("formatting_blockquote", @@ -237,27 +237,27 @@ // // Check if single underlining = works MT("setextH1", - "foo", + "[header&header-1 foo]", "[header&header-1 =]"); // Check if 3+ ='s work MT("setextH1", - "foo", + "[header&header-1 foo]", "[header&header-1 ===]"); // Check if single underlining - works MT("setextH2", - "foo", + "[header&header-2 foo]", "[header&header-2 -]"); // Check if 3+ -'s work MT("setextH2", - "foo", + "[header&header-2 foo]", "[header&header-2 ---]"); // http://spec.commonmark.org/0.19/#example-45 MT("setextH2AllowSpaces", - "foo", + "[header&header-2 foo]", " [header&header-2 ---- ]"); // http://spec.commonmark.org/0.19/#example-44 @@ -265,15 +265,50 @@ " [comment foo]", "[hr ---]"); + MT("setextAfterFencedCode", + "[comment ```]", + "[comment foo]", + "[comment ```]", + "[header&header-2 bar]", + "[header&header-2 ---]"); + + MT("setextAferATX", + "[header&header-1 # foo]", + "[header&header-2 bar]", + "[header&header-2 ---]"); + // http://spec.commonmark.org/0.19/#example-51 MT("noSetextAfterQuote", "[quote"e-1 > foo]", + "[hr ---]", + "", + "[quote"e-1 > foo]", + "[quote"e-1 bar]", "[hr ---]"); MT("noSetextAfterList", "[variable-2 - foo]", + "[hr ---]", + "", + "[variable-2 - foo]", + "bar", + "[hr ---]"); + + MT("setext_nestedInlineMarkup", + "[header&header-1 foo ][em&header&header-1 *bar*]", + "[header&header-1 =]"); + + MT("setext_linkDef", + "[link [[aaa]]:] [string&url http://google.com 'title']", "[hr ---]"); + // currently, looks max one line ahead, thus won't catch valid CommonMark + // markup + MT("setext_oneLineLookahead", + "foo", + "[header&header-1 bar]", + "[header&header-1 =]"); + // Single-line blockquote with trailing space MT("blockquoteSpace", "[quote"e-1 > foo]"); @@ -394,6 +429,27 @@ "[variable-2 - foo]", "[hr -----]"); + MT("hrAfterFencedCode", + "[comment ```]", + "[comment code]", + "[comment ```]", + "[hr ---]"); + + // allow hr inside lists + // (require prev line to be empty or hr, TODO: non-CommonMark-compliant) + MT("hrInsideList", + "[variable-2 - foo]", + "", + " [hr ---]", + " [hr ---]", + "", + " [comment ---]"); + + MT("consecutiveHr", + "[hr ---]", + "[hr ---]", + "[hr ---]"); + // Formatting in lists (*) MT("listAsteriskFormatting", "[variable-2 * ][variable-2&em *foo*][variable-2 bar]", From 29fb2806bede834341dd8ea2b601084c31a35880 Mon Sep 17 00:00:00 2001 From: dwelle Date: Mon, 31 Jul 2017 19:22:35 +0200 Subject: [PATCH 0570/1880] [markdown mode] improve header, list & fencedCode behavior around blockquote & indentation --- mode/markdown/markdown.js | 10 +++++++--- mode/markdown/test.js | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 59a17012da..d7f225f82f 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -139,6 +139,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { function blockNormal(stream, state) { var sol = stream.sol(); + var firstTokenOnLine = stream.column() === state.indentation; var prevLineLineIsEmpty = lineIsEmpty(state.prevLine); var prevLineIsIndentedCode = state.indentedCode; var prevLineIsHr = state.hr; @@ -182,7 +183,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return tokenTypes.code; } else if (stream.eatSpace()) { return null; - } else if ((match = stream.match(atxHeaderRE)) && match[1].length <= 6) { + } else if (firstTokenOnLine && state.indentation <= maxNonCodeIndentation && (match = stream.match(atxHeaderRE)) && match[1].length <= 6) { + state.quote = 0; state.header = match[1].length; if (modeCfg.highlightFormatting) state.formatting = "header"; state.f = state.inline; @@ -192,11 +194,12 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { if (modeCfg.highlightFormatting) state.formatting = "quote"; stream.eatSpace(); return getType(state); - } else if (!isHr && !state.quote && (match = stream.match(listRE))) { + } else if (!isHr && firstTokenOnLine && state.indentation <= maxNonCodeIndentation && (match = stream.match(listRE))) { var listType = match[1] ? "ol" : "ul"; state.indentation = lineIndentation + stream.current().length; state.list = true; + state.quote = 0; // Add this list item's content's indentation to the stack state.listStack.push(state.indentation); @@ -207,7 +210,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.f = state.inline; if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType]; return getType(state); - } else if (modeCfg.fencedCodeBlocks && !state.quote && (match = stream.match(fencedCodeRE, true))) { + } else if (modeCfg.fencedCodeBlocks && firstTokenOnLine && state.indentation <= maxNonCodeIndentation && (match = stream.match(fencedCodeRE, true))) { + state.quote = 0; state.fencedChars = match[1] // try switching mode state.localMode = getMode(match[2]); diff --git a/mode/markdown/test.js b/mode/markdown/test.js index c2c9fb1120..d01b07300a 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -228,6 +228,19 @@ MT("atxH1inline", "[header&header-1 # foo ][header&header-1&em *bar*]"); + MT("atxIndentedTooMuch", + "[header&header-1 # foo]", + " # bar"); + + // disable atx inside blockquote until we implement proper blockquote inner mode + // TODO: fix to be CommonMark-compliant + MT("atxNestedInsideBlockquote", + "[quote"e-1 > # foo]"); + + MT("atxAfterBlockquote", + "[quote"e-1 > foo]", + "[header&header-1 # bar]"); + // Setext headers - H1, H2 // Per documentation, "Any number of underlining =’s or -’s will work." // http://daringfireball.net/projects/markdown/syntax#header @@ -588,6 +601,19 @@ "", "\t\t[variable-3 part of list2]"); + MT("listAfterBlockquote", + "[quote"e-1 > foo]", + "[variable-2 - bar]"); + + // shouldn't create sublist if it's indented more than allowed + MT("nestedListIndentedTooMuch", + "[variable-2 - foo]", + " [variable-2 - bar]"); + + MT("listIndentedTooMuchAfterParagraph", + "foo", + " - bar"); + // Blockquote MT("blockquote", "[variable-2 * foo]", @@ -1096,6 +1122,19 @@ "[comment ~~~]", "bar"); + FencedTest("fencedCodeBlocksAfterBlockquote", + "[quote"e-1 > foo]", + "[comment ```]", + "[comment bar]", + "[comment ```]"); + + // fencedCode indented too much should act as simple indentedCode + // (hence has no highlight formatting) + FT("tooMuchIndentedFencedCode", + " [comment ```]", + " [comment code]", + " [comment ```]"); + // Tests that require XML mode MT("xmlMode", From 170885a12d2a41aa46229b3f6101449355576cc0 Mon Sep 17 00:00:00 2001 From: dwelle Date: Mon, 31 Jul 2017 19:45:32 +0200 Subject: [PATCH 0571/1880] [markdown mode] auto-terminate fencedCode after exiting list --- mode/markdown/markdown.js | 7 +++++-- mode/markdown/test.js | 10 ++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index d7f225f82f..6082eab8b2 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -270,14 +270,17 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } function local(stream, state) { - if (state.fencedChars && stream.match(state.fencedChars)) { + var hasExitedList = state.indentation < state.listStack[state.listStack.length - 1]; + if (state.fencedChars && (hasExitedList || stream.match(state.fencedChars))) { if (modeCfg.highlightFormatting) state.formatting = "code-block"; - var returnType = getType(state) + var returnType; + if (!hasExitedList) returnType = getType(state) state.localMode = state.localState = null; state.block = blockNormal; state.f = inlineNormal; state.fencedChars = null; state.code = 0 + if (hasExitedList) return switchBlock(stream, state, state.block); return returnType; } else if (state.fencedChars && stream.skipTo(state.fencedChars)) { return "comment" diff --git a/mode/markdown/test.js b/mode/markdown/test.js index d01b07300a..e9025882f9 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -1135,6 +1135,16 @@ " [comment code]", " [comment ```]"); + FencedTest("autoTerminateFencedCodeWhenLeavingList", + "[variable-2 - list1]", + " [variable-3 - list2]", + " [variable-3&comment ```]", + " [comment code]", + " [variable-3 - list2]", + " [variable-2&comment ```]", + " [comment code]", + "[quote"e-1 > foo]"); + // Tests that require XML mode MT("xmlMode", From c81346e2c235961292ca5a7e797ee3e9e5fcf7a3 Mon Sep 17 00:00:00 2001 From: dwelle Date: Mon, 31 Jul 2017 19:55:02 +0200 Subject: [PATCH 0572/1880] [markdown mode] improve blockquote indentation behavior --- mode/markdown/markdown.js | 5 ++--- mode/markdown/test.js | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 6082eab8b2..0692f7eac3 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -138,7 +138,6 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } function blockNormal(stream, state) { - var sol = stream.sol(); var firstTokenOnLine = stream.column() === state.indentation; var prevLineLineIsEmpty = lineIsEmpty(state.prevLine); var prevLineIsIndentedCode = state.indentedCode; @@ -189,8 +188,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { if (modeCfg.highlightFormatting) state.formatting = "header"; state.f = state.inline; return getType(state); - } else if (stream.eat('>')) { - state.quote = sol ? 1 : state.quote + 1; + } else if (state.indentation <= maxNonCodeIndentation && stream.eat('>')) { + state.quote = firstTokenOnLine ? 1 : state.quote + 1; if (modeCfg.highlightFormatting) state.formatting = "quote"; stream.eatSpace(); return getType(state); diff --git a/mode/markdown/test.js b/mode/markdown/test.js index e9025882f9..21829afbd0 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -335,12 +335,22 @@ "foo", "[quote"e-1 > bar]"); - // Nested blockquote - MT("blockquoteSpace", + MT("blockquoteNested", "[quote"e-1 > foo]", "[quote"e-1 >][quote"e-2 > foo]", "[quote"e-1 >][quote"e-2 >][quote"e-3 > foo]"); + // ensure quote-level is inferred correctly even if indented + MT("blockquoteNestedIndented", + " [quote"e-1 > foo]", + " [quote"e-1 >][quote"e-2 > foo]", + " [quote"e-1 >][quote"e-2 >][quote"e-3 > foo]"); + + // ensure quote-level is inferred correctly even if indented + MT("blockquoteIndentedTooMuch", + "foo", + " > bar"); + // Single-line blockquote followed by normal paragraph MT("blockquoteThenParagraph", "[quote"e-1 >foo]", From f8b9eeca8f0e90e8a8e8627796f60b4c8bec7954 Mon Sep 17 00:00:00 2001 From: dwelle Date: Tue, 1 Aug 2017 20:10:00 +0200 Subject: [PATCH 0573/1880] [markdown mode] support fencedCodeBlocks in base markdown as per CommonMark --- mode/gfm/gfm.js | 1 - mode/gfm/test.js | 46 ----------------------------------- mode/markdown/index.html | 50 +++++++++++++++++++++++---------------- mode/markdown/markdown.js | 10 ++------ mode/markdown/test.js | 45 ++++++++++++++++++++++------------- 5 files changed, 61 insertions(+), 91 deletions(-) diff --git a/mode/gfm/gfm.js b/mode/gfm/gfm.js index aac04812d8..689cd6e2ec 100644 --- a/mode/gfm/gfm.js +++ b/mode/gfm/gfm.js @@ -114,7 +114,6 @@ CodeMirror.defineMode("gfm", function(config, modeConfig) { var markdownConfig = { taskLists: true, - fencedCodeBlocks: '```', strikethrough: true, emoji: true }; diff --git a/mode/gfm/test.js b/mode/gfm/test.js index 5c8b0332ac..9cda5c45a3 100644 --- a/mode/gfm/test.js +++ b/mode/gfm/test.js @@ -14,11 +14,6 @@ FT("doubleBackticks", "[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]"); - FT("codeBlock", - "[comment&formatting&formatting-code-block ```css]", - "[tag foo]", - "[comment&formatting&formatting-code-block ```]"); - FT("taskList", "[variable-2&formatting&formatting-list&formatting-list-ul - ][meta&formatting&formatting-task [ ]]][variable-2 foo]", "[variable-2&formatting&formatting-list&formatting-list-ul - ][property&formatting&formatting-task [x]]][variable-2 foo]"); @@ -41,31 +36,6 @@ MT("emStrongUnderscore", "[em&strong ___foo___] bar"); - MT("fencedCodeBlocks", - "[comment ```]", - "[comment foo]", - "", - "[comment ```]", - "bar"); - - MT("fencedCodeBlockModeSwitching", - "[comment ```javascript]", - "[variable foo]", - "", - "[comment ```]", - "bar"); - - MT("fencedCodeBlockModeSwitchingObjc", - "[comment ```objective-c]", - "[keyword @property] [variable NSString] [operator *] [variable foo];", - "[comment ```]", - "bar"); - - MT("fencedCodeBlocksNoTildes", - "~~~", - "foo", - "~~~"); - MT("taskListAsterisk", "[variable-2 * ][link&variable-2 [[]]][variable-2 foo]", // Invalid; must have space or x between [] "[variable-2 * ][link&variable-2 [[ ]]][variable-2 bar]", // Invalid; must have space after ] @@ -166,11 +136,6 @@ MT("notALink", "foo asfd:asdf bar"); - MT("notALink", - "[comment ```css]", - "[tag foo] {[property color]:[keyword black];}", - "[comment ```][link http://www.example.com/]"); - MT("notALink", "[comment ``foo `bar` http://www.example.com/``] hello"); @@ -181,17 +146,6 @@ "", "[link http://www.example.com/]"); - MT("headerCodeBlockGithub", - "[header&header-1 # heading]", - "", - "[comment ```]", - "[comment code]", - "[comment ```]", - "", - "Commit: [link be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2]", - "Issue: [link #1]", - "Link: [link http://www.example.com/]"); - MT("strikethrough", "[strikethrough ~~foo~~]"); diff --git a/mode/markdown/index.html b/mode/markdown/index.html index 15660c2618..77f56ab200 100644 --- a/mode/markdown/index.html +++ b/mode/markdown/index.html @@ -87,7 +87,7 @@

      Markdown mode

      A First Level Header ==================== - + A Second Level Header --------------------- @@ -97,11 +97,11 @@

      Markdown mode

      The quick brown fox jumped over the lazy dog's back. - + ### Header 3 > This is a blockquote. - > + > > This is the second paragraph in the blockquote. > > ## This is an H2 in a blockquote @@ -110,23 +110,23 @@

      Markdown mode

      Output: <h1>A First Level Header</h1> - + <h2>A Second Level Header</h2> - + <p>Now is the time for all good men to come to the aid of their country. This is just a regular paragraph.</p> - + <p>The quick brown fox jumped over the lazy dog's back.</p> - + <h3>Header 3</h3> - + <blockquote> <p>This is a blockquote.</p> - + <p>This is the second paragraph in the blockquote.</p> - + <h2>This is an H2 in a blockquote</h2> </blockquote> @@ -140,7 +140,7 @@

      Markdown mode

      Some of these words *are emphasized*. Some of these words _are emphasized also_. - + Use two asterisks for **strong emphasis**. Or, if you prefer, __use two underscores instead__. @@ -148,10 +148,10 @@

      Markdown mode

      <p>Some of these words <em>are emphasized</em>. Some of these words <em>are emphasized also</em>.</p> - + <p>Use two asterisks for <strong>strong emphasis</strong>. Or, if you prefer, <strong>use two underscores instead</strong>.</p> - + ## Lists ## @@ -204,7 +204,7 @@

      Markdown mode

      the paragraphs by 4 spaces or 1 tab: * A list item. - + With multiple paragraphs. * Another item in the list. @@ -216,7 +216,7 @@

      Markdown mode

      <p>With multiple paragraphs.</p></li> <li><p>Another item in the list.</p></li> </ul> - + ### Links ### @@ -311,7 +311,7 @@

      Markdown mode

      <p>I strongly recommend against using any <code>&lt;blink&gt;</code> tags.</p> - + <p>I wish SmartyPants used named entities like <code>&amp;mdash;</code> instead of decimal-encoded entites like <code>&amp;#8212;</code>.</p> @@ -334,11 +334,20 @@

      Markdown mode

      <p>If you want your page to validate under XHTML 1.0 Strict, you've got to put paragraph tags in your blockquotes:</p> - + <pre><code>&lt;blockquote&gt; &lt;p&gt;For example.&lt;/p&gt; &lt;/blockquote&gt; </code></pre> + +## Fenced code blocks (and syntax highlighting) + +```javascript +for (var i = 0; i < items.length; i++) { + console.log(items[i], i); // log them +} +``` + -

      You might want to use the Github-Flavored Markdown mode instead, which adds support for fenced code blocks and a few other things.

      +

      If you also want support strikethrough, emoji and few other goodies, check out Github-Flavored Markdown mode.

      + +

      Optionally depends on other modes for properly highlighted code blocks, + and XML mode for properly highlighted inline XML blocks.

      -

      Optionally depends on the XML mode for properly highlighted inline XML blocks.

      -

      MIME types defined: text/x-markdown.

      Parsing/Highlighting Tests: normal, verbose.

      diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 0692f7eac3..beb29dd1e6 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -35,11 +35,6 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { if (modeCfg.maxBlockquoteDepth === undefined) modeCfg.maxBlockquoteDepth = 0; - // Use `fencedCodeBlocks` to configure fenced code blocks. false to - // disable, string to specify a precise regexp that the fence should - // match, and true to allow three or more backticks or tildes (as - // per CommonMark). - // Turn on task lists? ("- [ ] " and "- [x] ") if (modeCfg.taskLists === undefined) modeCfg.taskLists = false; @@ -88,8 +83,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { , atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/ , setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/ , textRE = /^[^#!\[\]*_\\<>` "'(~:]+/ - , fencedCodeRE = new RegExp("^(" + (modeCfg.fencedCodeBlocks === true ? "~~~+|```+" : modeCfg.fencedCodeBlocks) + - ")[ \\t]*([\\w+#\-]*)") + , fencedCodeRE = /^(~~~+|```+)[ \t]*([\w+#-]*)/ , linkDefRE = /^\s*\[[^\]]+?\]:\s*\S+(\s*\S*\s*)?$/ // naive link-definition , punctuation = /[!\"#$%&\'()*+,\-\.\/:;<=>?@\[\\\]^_`{|}~—]/ , expandedTab = " " // CommonMark specifies tab as 4 spaces @@ -209,7 +203,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.f = state.inline; if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType]; return getType(state); - } else if (modeCfg.fencedCodeBlocks && firstTokenOnLine && state.indentation <= maxNonCodeIndentation && (match = stream.match(fencedCodeRE, true))) { + } else if (firstTokenOnLine && state.indentation <= maxNonCodeIndentation && (match = stream.match(fencedCodeRE, true))) { state.quote = 0; state.fencedChars = match[1] // try switching mode diff --git a/mode/markdown/test.js b/mode/markdown/test.js index 21829afbd0..eb9d856abe 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -9,8 +9,6 @@ function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); } var modeAtxNoSpace = CodeMirror.getMode(config, {name: "markdown", allowAtxHeaderWithoutSpace: true}); function AtxNoSpaceTest(name) { test.mode(name, modeAtxNoSpace, Array.prototype.slice.call(arguments, 1)); } - var modeFenced = CodeMirror.getMode(config, {name: "markdown", fencedCodeBlocks: true}); - function FencedTest(name) { test.mode(name, modeFenced, Array.prototype.slice.call(arguments, 1)); } var modeOverrideClasses = CodeMirror.getMode(config, { name: "markdown", strikethrough: true, @@ -97,6 +95,11 @@ FT("formatting_image", "[formatting&formatting-image&image&image-marker !][formatting&formatting-image&image&image-alt-text&link [[][image&image-alt-text&link alt text][formatting&formatting-image&image&image-alt-text&link ]]][formatting&formatting-link-string&string&url (][url&string http://link.to/image.jpg][formatting&formatting-link-string&string&url )]"); + FT("codeBlock", + "[comment&formatting&formatting-code-block ```css]", + "[tag foo]", + "[comment&formatting&formatting-code-block ```]"); + MT("plainText", "foo"); @@ -587,7 +590,7 @@ " [variable-2 de-indented text part of list1 again]", "", " [variable-2&comment ```]", - " [variable-2&comment code]", + " [comment code]", " [variable-2&comment ```]", "", " [variable-2 text after fenced code]"); @@ -1085,18 +1088,28 @@ MT("taskList", "[variable-2 * ][link&variable-2 [[ ]]][variable-2 bar]"); - MT("noFencedCodeBlocks", - "~~~", - "foo", - "~~~"); - - FencedTest("fencedCodeBlocks", + MT("fencedCodeBlocks", "[comment ```]", "[comment foo]", + "", + "[comment bar]", + "[comment ```]", + "baz"); + + MT("fencedCodeBlockModeSwitching", + "[comment ```javascript]", + "[variable foo]", + "", + "[comment ```]", + "bar"); + + MT("fencedCodeBlockModeSwitchingObjc", + "[comment ```objective-c]", + "[keyword @property] [variable NSString] [operator *] [variable foo];", "[comment ```]", "bar"); - FencedTest("fencedCodeBlocksMultipleChars", + MT("fencedCodeBlocksMultipleChars", "[comment `````]", "[comment foo]", "[comment ```]", @@ -1104,20 +1117,20 @@ "[comment `````]", "bar"); - FencedTest("fencedCodeBlocksTildes", + MT("fencedCodeBlocksTildes", "[comment ~~~]", "[comment foo]", "[comment ~~~]", "bar"); - FencedTest("fencedCodeBlocksTildesMultipleChars", + MT("fencedCodeBlocksTildesMultipleChars", "[comment ~~~~~]", "[comment ~~~]", "[comment foo]", "[comment ~~~~~]", "bar"); - FencedTest("fencedCodeBlocksMultipleChars", + MT("fencedCodeBlocksMultipleChars", "[comment `````]", "[comment foo]", "[comment ```]", @@ -1125,14 +1138,14 @@ "[comment `````]", "bar"); - FencedTest("fencedCodeBlocksMixed", + MT("fencedCodeBlocksMixed", "[comment ~~~]", "[comment ```]", "[comment foo]", "[comment ~~~]", "bar"); - FencedTest("fencedCodeBlocksAfterBlockquote", + MT("fencedCodeBlocksAfterBlockquote", "[quote"e-1 > foo]", "[comment ```]", "[comment bar]", @@ -1145,7 +1158,7 @@ " [comment code]", " [comment ```]"); - FencedTest("autoTerminateFencedCodeWhenLeavingList", + MT("autoTerminateFencedCodeWhenLeavingList", "[variable-2 - list1]", " [variable-3 - list2]", " [variable-3&comment ```]", From eb2cdcfa145660092d731ebcb6ceac58fb97869d Mon Sep 17 00:00:00 2001 From: dwelle Date: Tue, 1 Aug 2017 23:45:31 +0200 Subject: [PATCH 0574/1880] [markdown mode] allow to disable xml and fencedCodeBlock highlighting --- mode/markdown/markdown.js | 12 +++++++++--- mode/markdown/test.js | 12 ++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index beb29dd1e6..58f1dff8aa 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -45,6 +45,12 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { if (modeCfg.emoji === undefined) modeCfg.emoji = false; + if (modeCfg.fencedCodeBlockHighlighting === undefined) + modeCfg.fencedCodeBlockHighlighting = true; + + if (modeCfg.xml === undefined) + modeCfg.xml = true; + // Allow token types to be overridden by user-provided token types. if (modeCfg.tokenTypeOverrides === undefined) modeCfg.tokenTypeOverrides = {}; @@ -207,7 +213,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.quote = 0; state.fencedChars = match[1] // try switching mode - state.localMode = getMode(match[2]); + state.localMode = modeCfg.fencedCodeBlockHighlighting && getMode(match[2]); if (state.localMode) state.localState = CodeMirror.startState(state.localMode); state.f = state.block = local; if (modeCfg.highlightFormatting) state.formatting = "code-block"; @@ -510,7 +516,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return type + tokenTypes.linkEmail; } - if (ch === '<' && stream.match(/^(!--|[a-z]+(?:\s+[a-z_:.\-]+(?:\s*=\s*[^ >]+)?)*\s*>)/i, false)) { + if (modeCfg.xml && ch === '<' && stream.match(/^(!--|[a-z]+(?:\s+[a-z_:.\-]+(?:\s*=\s*[^ >]+)?)*\s*>)/i, false)) { var end = stream.string.indexOf(">", stream.pos); if (end != -1) { var atts = stream.string.substring(stream.start, end); @@ -521,7 +527,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return switchBlock(stream, state, htmlBlock); } - if (ch === '<' && stream.match(/^\/\w*?>/)) { + if (modeCfg.xml && ch === '<' && stream.match(/^\/\w*?>/)) { state.md_inside = false; return "tag"; } else if (ch === "*" || ch === "_") { diff --git a/mode/markdown/test.js b/mode/markdown/test.js index eb9d856abe..86935c9587 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -7,6 +7,10 @@ function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } var modeHighlightFormatting = CodeMirror.getMode(config, {name: "markdown", highlightFormatting: true}); function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); } + var modeMT_noXml = CodeMirror.getMode(config, {name: "markdown", xml: false}); + function MT_noXml(name) { test.mode(name, modeMT_noXml, Array.prototype.slice.call(arguments, 1)); } + var modeMT_noFencedHighlight = CodeMirror.getMode(config, {name: "markdown", fencedCodeBlockHighlighting: false}); + function MT_noFencedHighlight(name) { test.mode(name, modeMT_noFencedHighlight, Array.prototype.slice.call(arguments, 1)); } var modeAtxNoSpace = CodeMirror.getMode(config, {name: "markdown", allowAtxHeaderWithoutSpace: true}); function AtxNoSpaceTest(name) { test.mode(name, modeAtxNoSpace, Array.prototype.slice.call(arguments, 1)); } var modeOverrideClasses = CodeMirror.getMode(config, { @@ -1103,6 +1107,11 @@ "[comment ```]", "bar"); + MT_noFencedHighlight("fencedCodeBlock_noHighlight", + "[comment ```javascript]", + "[comment foo]", + "[comment ```]"); + MT("fencedCodeBlockModeSwitchingObjc", "[comment ```objective-c]", "[keyword @property] [variable NSString] [operator *] [variable foo];", @@ -1186,4 +1195,7 @@ "[tag&bracket <][tag div][tag&bracket >]", "[tag&bracket ]"); + MT_noXml("xmlHighlightDisabled", + "
      foo
      "); + })(); From ab83c3c80fb19333da876ed0a5eed76675324c33 Mon Sep 17 00:00:00 2001 From: dwelle Date: Tue, 1 Aug 2017 23:48:14 +0200 Subject: [PATCH 0575/1880] [markdown mode] update doc with available options --- mode/gfm/index.html | 28 ++++++++++++++++++++++++++++ mode/markdown/index.html | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/mode/gfm/index.html b/mode/gfm/index.html index bec130ca51..ea4bac15fe 100644 --- a/mode/gfm/index.html +++ b/mode/gfm/index.html @@ -103,6 +103,34 @@

      GFM mode

      Optionally depends on other modes for properly highlighted code blocks.

      +

      Gfm mode supports these options (apart those from base Markdown mode):

      +
        +
      • + +
        gitHubSpice: boolean
        +
        Hashes, issues... (default: true).
        +
        +
      • +
      • + +
        taskLists: boolean
        +
        - [ ] syntax (default: true).
        +
        +
      • +
      • + +
        strikethrough: boolean
        +
        ~~foo~~ syntax (default: true).
        +
        +
      • +
      • + +
        emoji: boolean
        +
        :emoji: syntax (default: true).
        +
        +
      • +
      +

      Parsing/Highlighting Tests: normal, verbose.

      diff --git a/mode/markdown/index.html b/mode/markdown/index.html index 77f56ab200..abb379f61a 100644 --- a/mode/markdown/index.html +++ b/mode/markdown/index.html @@ -364,6 +364,40 @@

      Markdown mode

      Optionally depends on other modes for properly highlighted code blocks, and XML mode for properly highlighted inline XML blocks.

      +

      Markdown mode supports these options:

      +
        +
      • + +
        highlightFormatting: boolean
        +
        Whether to separately highlight markdown meta characterts (*[]()etc.) (default: false).
        +
        +
      • +
      • + +
        maxBlockquoteDepth: boolean
        +
        Maximum allowed blockquote nesting (default: 0 - infinite nesting).
        +
        +
      • +
      • + +
        xml: boolean
        +
        Whether to highlight inline XML (default: true).
        +
        +
      • +
      • + +
        fencedCodeBlockHighlighting: boolean
        +
        Whether to syntax-highlight fenced code blocks, if given mode is included (default: true).
        +
        +
      • +
      • + +
        tokenTypeOverrides: Object
        +
        When you want ot override default token type names (e.g. {code: "code"}).
        +
        +
      • +
      +

      MIME types defined: text/x-markdown.

      Parsing/Highlighting Tests: normal, verbose.

      From f80468537d4c96907bd6489f2ffcb132a90e8056 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 2 Aug 2017 13:25:30 +0200 Subject: [PATCH 0576/1880] Properly call marker.find when scanning DOM text Issue #4889 --- src/input/ContentEditableInput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index d103d2d08f..67de3b1836 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -420,7 +420,7 @@ function domTextBetween(cm, from, to, fromLine, toLine) { let markerID = node.getAttribute("cm-marker"), range if (markerID) { let found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)) - if (found.length && (range = found[0].find())) + if (found.length && (range = found[0].find(0))) addText(getBetween(cm.doc, range.from, range.to).join(lineSep)) return } From 4c3d3c79a40fce2b38b4b507d3d0e944b56db9ff Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 3 Aug 2017 10:58:36 +0200 Subject: [PATCH 0577/1880] Copy over origin when splitting change for read-only spans --- src/model/changes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/changes.js b/src/model/changes.js index 214e0231ab..308dc6b399 100644 --- a/src/model/changes.js +++ b/src/model/changes.js @@ -60,7 +60,7 @@ export function makeChange(doc, change, ignoreReadOnly) { let split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to) if (split) { for (let i = split.length - 1; i >= 0; --i) - makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}) + makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}) } else { makeChangeInner(doc, change) } From 6e44a5118f105268f7f8979845b1d5269f46c472 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 4 Aug 2017 08:41:29 +0200 Subject: [PATCH 0578/1880] [css mode] Don't feed comment tokens to the state machine Closes #4892 --- mode/css/css.js | 3 ++- mode/css/test.js | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/mode/css/css.js b/mode/css/css.js index 056c48e680..bfe11d3b05 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -383,7 +383,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { style = style[0]; } override = style; - state.state = states[state.state](type, stream, state); + if (type != "comment") + state.state = states[state.state](type, stream, state); return override; }, diff --git a/mode/css/test.js b/mode/css/test.js index 7a496fb091..6fc6e33ca5 100644 --- a/mode/css/test.js +++ b/mode/css/test.js @@ -197,4 +197,10 @@ MT("counter-style-symbols", "[tag ol] { [property list-style]: [atom symbols]([atom cyclic] [string \"*\"] [string \"\\2020\"] [string \"\\2021\"] [string \"\\A7\"]); }"); + + MT("comment-does-not-disrupt", + "[def @font-face] [comment /* foo */] {", + " [property src]: [atom url]([string x]);", + " [property font-family]: [variable One];", + "}") })(); From d02b119870a82cfe1aa1bf7ade17d35fae3653d7 Mon Sep 17 00:00:00 2001 From: Yvonnick Esnault Date: Thu, 3 Aug 2017 19:10:56 +0200 Subject: [PATCH 0579/1880] [verilog mode] add .sv and .svh extensions Signed-off-by: Yvonnick Esnault --- mode/meta.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/meta.js b/mode/meta.js index d1c42a03a7..c49bd6c737 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -137,7 +137,7 @@ {name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]}, {name: "sTeX", mime: "text/x-stex", mode: "stex"}, {name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"], alias: ["tex"]}, - {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v"]}, + {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v", "sv", "svh"]}, {name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]}, {name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]}, {name: "TiddlyWiki ", mime: "text/x-tiddlywiki", mode: "tiddlywiki"}, From 2fcce279de70ed80f2c682f16ca1151f0e0e3886 Mon Sep 17 00:00:00 2001 From: Moshe Wajnberg Date: Sun, 6 Aug 2017 16:31:26 +0300 Subject: [PATCH 0580/1880] Fix(bidi): Fix for bug /codemirror/CodeMirror/issues/4897 Fix for bug https://github.com/codemirror/CodeMirror/issues/4897 --- demo/bidi.html | 12 ++++++++++++ lib/codemirror.css | 1 + 2 files changed, 13 insertions(+) diff --git a/demo/bidi.html b/demo/bidi.html index ceaffd32e6..645e648c86 100644 --- a/demo/bidi.html +++ b/demo/bidi.html @@ -60,6 +60,11 @@

      Bi-directional Text Demo

      +
      + HTML document direction: + + +
      @@ -80,6 +85,13 @@

      Bi-directional Text Demo

      editor.setOption("direction", dirRadios["rtl"].checked ? "rtl" : "ltr"); }; +var HtmlDirRadios = {ltr: document.getElementById("htmlltr"), + rtl: document.getElementById("htmlrtl")}; +HtmlDirRadios["ltr"].checked = true; +HtmlDirRadios["rtl"].onchange = HtmlDirRadios["ltr"].onchange = function() { + document.dir = (HtmlDirRadios["rtl"].checked ? "rtl" : "ltr"); +}; + var moveCheckbox = document.getElementById("rtlMoveVisually"); moveCheckbox.checked = editor.getOption("rtlMoveVisually"); moveCheckbox.onchange = function() { diff --git a/lib/codemirror.css b/lib/codemirror.css index f4d3c5f40b..9d8ff0ce66 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -5,6 +5,7 @@ font-family: monospace; height: 300px; color: black; + direction: ltr; } /* PADDING */ From 4b0ae027938a6ed83b9a2033db291bff8c0f8967 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 8 Aug 2017 22:12:49 +0200 Subject: [PATCH 0581/1880] [shell mode] Allow strings to span lines Closes #4902 --- mode/shell/shell.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/shell/shell.js b/mode/shell/shell.js index c5619afe7c..9b8b90b305 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -102,7 +102,7 @@ CodeMirror.defineMode('shell', function() { } escaped = !escaped && next === '\\'; } - if (end || !escaped) state.tokens.shift(); + if (end) state.tokens.shift(); return style; }; }; From 974b698fac730685ec51761338786e6801ae366c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 8 Aug 2017 23:07:27 +0200 Subject: [PATCH 0582/1880] [javascript mode] Support typescript-style type params to new Closes #4887 --- mode/javascript/javascript.js | 4 ++++ mode/javascript/test.js | 3 +++ 2 files changed, 7 insertions(+) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index d77862b1d5..50d33dde31 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -468,6 +468,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function maybeTarget(noComma) { return function(type) { if (type == ".") return cont(noComma ? targetNoComma : target); + else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma) else return pass(noComma ? expressionNoComma : expression); }; } @@ -588,6 +589,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "[") return cont(expect("]"), afterType) if (value == "extends") return cont(typeexpr) } + function maybeTypeArgs(_, value) { + if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) + } function vardef() { return pass(pattern, maybetype, maybeAssign, vardefCont); } diff --git a/mode/javascript/test.js b/mode/javascript/test.js index 8fd13aee49..2632fd1df5 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -343,6 +343,9 @@ "[keyword function] [def x][operator <][type T] [keyword extends] [keyword keyof] [type X][operator >]([def a]: [type T]) {", " [keyword return]") + TS("typescript_new_typeargs", + "[keyword let] [def x] [operator =] [keyword new] [variable Map][operator <][type string], [type Date][operator >]([string-2 `foo${][variable bar][string-2 }`])") + var jsonld_mode = CodeMirror.getMode( {indentUnit: 2}, {name: "javascript", jsonld: true} From 2add03c7efbbb1c685e7da0c4c3733778c6f35d9 Mon Sep 17 00:00:00 2001 From: Jeff Hanke Date: Wed, 9 Aug 2017 04:13:27 -0700 Subject: [PATCH 0583/1880] [html-line addon] Play more nicely with node/webpack. * Pass in and use the htmlhint module required. * Check for verify() and try HTMLHint.HTMLHint if missing because of module nesting. it's require('htmlhint').HTMLHint in node. --- addon/lint/html-lint.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/addon/lint/html-lint.js b/addon/lint/html-lint.js index 98c36b0b64..23de9bb204 100644 --- a/addon/lint/html-lint.js +++ b/addon/lint/html-lint.js @@ -11,8 +11,8 @@ else if (typeof define == "function" && define.amd) // AMD define(["../../lib/codemirror", "htmlhint"], mod); else // Plain browser env - mod(CodeMirror); -})(function(CodeMirror) { + mod(CodeMirror, window.HTMLHint); +})(function(CodeMirror, HTMLHint) { "use strict"; var defaultRules = { @@ -29,9 +29,11 @@ CodeMirror.registerHelper("lint", "html", function(text, options) { var found = []; - if (!window.HTMLHint) { + if (HTMLHint && !HTMLHint.verify) HTMLHint = HTMLHint.HTMLHint; + if (!HTMLHint) HTMLHint = window.HTMLHint; + if (!HTMLHint) { if (window.console) { - window.console.error("Error: window.HTMLHint not defined, CodeMirror HTML linting cannot run."); + window.console.error("Error: HTMLHint not found, not defined on window, or not available through define/require, CodeMirror HTML linting cannot run."); } return found; } From 616116ba326cf4164df28c62380f15e508f65e9a Mon Sep 17 00:00:00 2001 From: CodeBitt <30704531+CodeBitt@users.noreply.github.com> Date: Mon, 14 Aug 2017 17:32:17 -0400 Subject: [PATCH 0584/1880] [real-world uses] Add CodeBitt --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 3995f93e9d..7c5231ba81 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -43,6 +43,7 @@

      CodeMirror real-world uses

    • Complete.ly playground
    • Codeanywhere (multi-platform cloud editor)
    • Code per Node (Drupal module)
    • +
    • CodeBitt (Code snippet sharing)
    • Codebug (PHP Xdebug front-end)
    • CodeMirror Eclipse (embed CM in Eclipse)
    • CodeMirror movie (scripted editing demos)
    • From c06c273afc78781ed0735c8a27680f35397f3f42 Mon Sep 17 00:00:00 2001 From: Sarah McAlear and Wenlin Zhang Date: Mon, 14 Aug 2017 14:41:01 +0800 Subject: [PATCH 0585/1880] [sql-mode] Add greenplum dialect as gpsql --- mode/sql/index.html | 3 ++- mode/sql/sql.js | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/mode/sql/index.html b/mode/sql/index.html index dba069dc81..cd95872820 100644 --- a/mode/sql/index.html +++ b/mode/sql/index.html @@ -58,7 +58,8 @@

      SQL Mode for CodeMirror

      text/x-mssql, text/x-hive, text/x-pgsql, - text/x-gql. + text/x-gql, + text/x-gpsql.

      Demonstration of bi-directional text support. See diff --git a/test/test.js b/test/test.js index 32a6c28080..e61365d690 100644 --- a/test/test.js +++ b/test/test.js @@ -255,7 +255,7 @@ testCM("coordsCharBidi", function(cm) { }, {lineNumbers: true}); testCM("badBidiOptimization", function(cm) { - let coords = cm.charCoords(Pos(0, 34)) + var coords = cm.charCoords(Pos(0, 34)) eqCharPos(cm.coordsChar({left: coords.right, top: coords.top + 2}), Pos(0, 34)) }, {value: "----------

      هل يمكنك اختيار مستوى قسط التأمين الذي ترغب بدفعه؟

      "}) From 4ba596ea5af0a1f13fe0bb45588bbd7a12f48439 Mon Sep 17 00:00:00 2001 From: Aram Shatakhtsyan Date: Wed, 13 Sep 2017 17:50:45 -0700 Subject: [PATCH 0626/1880] Add CodeFights to the list of real-world users --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 7c5231ba81..f0a75abf72 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -45,6 +45,7 @@

      CodeMirror real-world uses

    • Code per Node (Drupal module)
    • CodeBitt (Code snippet sharing)
    • Codebug (PHP Xdebug front-end)
    • +
    • CodeFights (practice programming)
    • CodeMirror Eclipse (embed CM in Eclipse)
    • CodeMirror movie (scripted editing demos)
    • CodeMirror2-GWT (Google Web Toolkit wrapper)
    • From 0506dfc565217bf6e5eed5c2770e2dbf30e1f6b2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 14 Sep 2017 09:05:51 +0200 Subject: [PATCH 0627/1880] Remove accidentally committed debug changes --- demo/bidi.html | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/demo/bidi.html b/demo/bidi.html index 349a3dba3e..645e648c86 100644 --- a/demo/bidi.html +++ b/demo/bidi.html @@ -26,9 +26,8 @@

      Bi-directional Text Demo

      -
      -

      MIME types defined: +

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

      SQL Mode for CodeMirror

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

      MIME types defined: text/x-protobuf.

      diff --git a/mode/protobuf/protobuf.js b/mode/protobuf/protobuf.js index bcae276e8d..93cb3b0e05 100644 --- a/mode/protobuf/protobuf.js +++ b/mode/protobuf/protobuf.js @@ -19,7 +19,8 @@ "package", "message", "import", "syntax", "required", "optional", "repeated", "reserved", "default", "extensions", "packed", "bool", "bytes", "double", "enum", "float", "string", - "int32", "int64", "uint32", "uint64", "sint32", "sint64", "fixed32", "fixed64", "sfixed32", "sfixed64" + "int32", "int64", "uint32", "uint64", "sint32", "sint64", "fixed32", "fixed64", "sfixed32", "sfixed64", + "option", "service", "rpc", "returns" ]; var keywords = wordRegexp(keywordArray); From a073d18ea4b08d2e1aecdc075ecef8712c10e64f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 16 Oct 2017 11:19:27 +0200 Subject: [PATCH 0685/1880] Remove mode-mutating kludge in continuecomment --- addon/comment/continuecomment.js | 5 ----- mode/clike/clike.js | 1 + mode/css/css.js | 1 + mode/javascript/javascript.js | 1 + 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/addon/comment/continuecomment.js b/addon/comment/continuecomment.js index d7385ef223..6552b09bbf 100644 --- a/addon/comment/continuecomment.js +++ b/addon/comment/continuecomment.js @@ -9,11 +9,6 @@ else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { - var modes = ["clike", "css", "javascript"]; - - for (var i = 0; i < modes.length; ++i) - CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "}); - function continueComment(cm) { if (cm.getOption("disableInput")) return CodeMirror.Pass; var ranges = cm.listSelections(), mode, inserts = []; diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 0993ca4c4e..d6d12c7117 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -244,6 +244,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/, blockCommentStart: "/*", blockCommentEnd: "*/", + blockCommentContinue: " * ", lineComment: "//", fold: "brace" }; diff --git a/mode/css/css.js b/mode/css/css.js index bfe11d3b05..00e9b3df13 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -410,6 +410,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { electricChars: "}", blockCommentStart: "/*", blockCommentEnd: "*/", + blockCommentContinue: " * ", lineComment: lineComment, fold: "brace" }; diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index d92f8622d4..d6cc4771bd 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -821,6 +821,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, blockCommentStart: jsonMode ? null : "/*", blockCommentEnd: jsonMode ? null : "*/", + blockCommentContinue: jsonMode ? null : " ", lineComment: jsonMode ? null : "//", fold: "brace", closeBrackets: "()[]{}''\"\"``", From ad6635a5b40b20cc3f7ca9a77ef1b42634597790 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 16 Oct 2017 11:20:11 +0200 Subject: [PATCH 0686/1880] [vim bindings] Show fat cursor even in contentEditable mode Issue #3552 --- demo/vim.html | 3 ++- keymap/vim.js | 51 ++++++++++++++++++++++++++++++++++++++++++++-- lib/codemirror.css | 7 ++++++- 3 files changed, 57 insertions(+), 4 deletions(-) diff --git a/demo/vim.html b/demo/vim.html index f27b8b8e2b..bd704f7583 100644 --- a/demo/vim.html +++ b/demo/vim.html @@ -95,7 +95,8 @@

      Vim bindings demo

      mode: "text/x-csrc", keyMap: "vim", matchBrackets: true, - showCursorWhenSelecting: true + showCursorWhenSelecting: true, + inputStyle: "contenteditable" }); var commandDisplay = document.getElementById('command-display'); var keys = ''; diff --git a/keymap/vim.js b/keymap/vim.js index 13c39a1ea0..7cf5a956e0 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -255,20 +255,67 @@ } function detachVimMap(cm, next) { - if (this == CodeMirror.keyMap.vim) + if (this == CodeMirror.keyMap.vim) { CodeMirror.rmClass(cm.getWrapperElement(), "cm-fat-cursor"); + if (cm.getOption("inputStyle") == "contenteditable" && document.body.style.caretColor != null) { + disableFatCursorMark(cm); + cm.getInputField().style.caretColor = ""; + } + } if (!next || next.attach != attachVimMap) leaveVimMode(cm); } function attachVimMap(cm, prev) { - if (this == CodeMirror.keyMap.vim) + if (this == CodeMirror.keyMap.vim) { CodeMirror.addClass(cm.getWrapperElement(), "cm-fat-cursor"); + if (cm.getOption("inputStyle") == "contenteditable" && document.body.style.caretColor != null) { + enableFatCursorMark(cm); + cm.getInputField().style.caretColor = "transparent"; + } + } if (!prev || prev.attach != attachVimMap) enterVimMode(cm); } + function fatCursorMarks(cm) { + var ranges = cm.listSelections(), result = [] + for (var i = 0; i < ranges.length; i++) { + var range = ranges[i] + if (range.empty()) { + if (range.anchor.ch < cm.getLine(range.anchor.line).length) { + result.push(cm.markText(range.anchor, Pos(range.anchor.line, range.anchor.ch + 1), + {className: "cm-fat-cursor-mark"})) + } else { + var widget = document.createElement("span") + widget.textContent = "\u00a0" + widget.className = "cm-fat-cursor-mark" + result.push(cm.setBookmark(range.anchor, {widget: widget})) + } + } + } + return result + } + + function updateFatCursorMark(cm) { + var marks = cm.state.fatCursorMarks + if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear() + cm.state.fatCursorMarks = fatCursorMarks(cm) + } + + function enableFatCursorMark(cm) { + cm.state.fatCursorMarks = fatCursorMarks(cm) + cm.on("cursorActivity", updateFatCursorMark) + } + + function disableFatCursorMark(cm) { + var marks = cm.state.fatCursorMarks + if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear() + cm.state.fatCursorMarks = null + cm.off("cursorActivity", updateFatCursorMark) + } + // Deprecated, simply setting the keymap works again. CodeMirror.defineOption('vimMode', false, function(cm, val, prev) { if (val && cm.getOption("keyMap") != "vim") diff --git a/lib/codemirror.css b/lib/codemirror.css index 9d8ff0ce66..255de98606 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -59,7 +59,12 @@ .cm-fat-cursor div.CodeMirror-cursors { z-index: 1; } - +.cm-fat-cursor-mark { + background-color: rgba(20, 255, 20, 0.5); + -webkit-animation: blink 1.06s steps(1) infinite; + -moz-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; +} .cm-animate-fat-cursor { width: auto; border: 0; From 43d0324c4452e0d8bbc0782fb775cb4838f1d6cf Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 16 Oct 2017 11:30:59 +0200 Subject: [PATCH 0687/1880] [continuecomment addon] Fix issue with single-line block comments The addon would think it still was in a block comment when one was opened and closed earlier on the line. Issue codemirror/google-modes#58 --- addon/comment/continuecomment.js | 4 ++-- mode/javascript/javascript.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/comment/continuecomment.js b/addon/comment/continuecomment.js index 6552b09bbf..d92318b345 100644 --- a/addon/comment/continuecomment.js +++ b/addon/comment/continuecomment.js @@ -22,10 +22,10 @@ var insert = null; if (mode.blockCommentStart && mode.blockCommentContinue) { var line = cm.getLine(pos.line).slice(0, pos.ch) - var end = line.indexOf(mode.blockCommentEnd), found + var end = line.lastIndexOf(mode.blockCommentEnd), found if (end != -1 && end == pos.ch - mode.blockCommentEnd.length) { // Comment ended, don't continue it - } else if ((found = line.indexOf(mode.blockCommentStart)) > -1) { + } else if ((found = line.lastIndexOf(mode.blockCommentStart)) > -1 && found > end) { insert = line.slice(0, found) if (/\S/.test(insert)) { insert = "" diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index d6cc4771bd..61a6de4be7 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -821,7 +821,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { electricInput: /^\s*(?:case .*?:|default:|\{|\})$/, blockCommentStart: jsonMode ? null : "/*", blockCommentEnd: jsonMode ? null : "*/", - blockCommentContinue: jsonMode ? null : " ", + blockCommentContinue: jsonMode ? null : " * ", lineComment: jsonMode ? null : "//", fold: "brace", closeBrackets: "()[]{}''\"\"``", From 1951460e52e2ec1d3615b5240123fe3c284d2e17 Mon Sep 17 00:00:00 2001 From: mtaran-google Date: Wed, 11 Oct 2017 17:45:53 -0700 Subject: [PATCH 0688/1880] [sublime bindings] Export macSublime & pcSublime keymaps This will make it easier to get programmatic access to the content of these keymaps, per #5020 --- keymap/sublime.js | 247 +++++++++++++++++++++++++++++++--------------- 1 file changed, 169 insertions(+), 78 deletions(-) diff --git a/keymap/sublime.js b/keymap/sublime.js index 98266e44f0..eeccab1721 100644 --- a/keymap/sublime.js +++ b/keymap/sublime.js @@ -14,11 +14,8 @@ })(function(CodeMirror) { "use strict"; - var map = CodeMirror.keyMap.sublime = {fallthrough: "default"}; var cmds = CodeMirror.commands; var Pos = CodeMirror.Pos; - var mac = CodeMirror.keyMap["default"] == CodeMirror.keyMap.macDefault; - var ctrl = mac ? "Cmd-" : "Ctrl-"; // This is not exactly Sublime's algorithm. I couldn't make heads or tails of that. function findPosSubword(doc, start, dir) { @@ -52,16 +49,10 @@ }); } - var goSubwordCombo = mac ? "Ctrl-" : "Alt-"; + cmds.goSubwordLeft = function(cm) { moveSubword(cm, -1); }; + cmds.goSubwordRight = function(cm) { moveSubword(cm, 1); }; - cmds[map[goSubwordCombo + "Left"] = "goSubwordLeft"] = function(cm) { moveSubword(cm, -1); }; - cmds[map[goSubwordCombo + "Right"] = "goSubwordRight"] = function(cm) { moveSubword(cm, 1); }; - - if (mac) map["Cmd-Left"] = "goLineStartSmart"; - - var scrollLineCombo = mac ? "Ctrl-Alt-" : "Ctrl-"; - - cmds[map[scrollLineCombo + "Up"] = "scrollLineUp"] = function(cm) { + cmds.scrollLineUp = function(cm) { var info = cm.getScrollInfo(); if (!cm.somethingSelected()) { var visibleBottomLine = cm.lineAtHeight(info.top + info.clientHeight, "local"); @@ -70,7 +61,7 @@ } cm.scrollTo(null, info.top - cm.defaultTextHeight()); }; - cmds[map[scrollLineCombo + "Down"] = "scrollLineDown"] = function(cm) { + cmds.scrollLineDown = function(cm) { var info = cm.getScrollInfo(); if (!cm.somethingSelected()) { var visibleTopLine = cm.lineAtHeight(info.top, "local")+1; @@ -80,7 +71,7 @@ cm.scrollTo(null, info.top + cm.defaultTextHeight()); }; - cmds[map["Shift-" + ctrl + "L"] = "splitSelectionByLine"] = function(cm) { + cmds.splitSelectionByLine = function(cm) { var ranges = cm.listSelections(), lineRanges = []; for (var i = 0; i < ranges.length; i++) { var from = ranges[i].from(), to = ranges[i].to(); @@ -92,14 +83,12 @@ cm.setSelections(lineRanges, 0); }; - map["Shift-Tab"] = "indentLess"; - - cmds[map["Esc"] = "singleSelectionTop"] = function(cm) { + cmds.singleSelectionTop = function(cm) { var range = cm.listSelections()[0]; cm.setSelection(range.anchor, range.head, {scroll: false}); }; - cmds[map[ctrl + "L"] = "selectLine"] = function(cm) { + cmds.selectLine = function(cm) { var ranges = cm.listSelections(), extended = []; for (var i = 0; i < ranges.length; i++) { var range = ranges[i]; @@ -109,8 +98,6 @@ cm.setSelections(extended); }; - map["Shift-Ctrl-K"] = "deleteLine"; - function insertLine(cm, above) { if (cm.isReadOnly()) return CodeMirror.Pass cm.operation(function() { @@ -129,9 +116,9 @@ cm.execCommand("indentAuto"); } - cmds[map[ctrl + "Enter"] = "insertLineAfter"] = function(cm) { return insertLine(cm, false); }; + cmds.insertLineAfter = function(cm) { return insertLine(cm, false); }; - cmds[map["Shift-" + ctrl + "Enter"] = "insertLineBefore"] = function(cm) { return insertLine(cm, true); }; + cmds.insertLineBefore = function(cm) { return insertLine(cm, true); }; function wordAt(cm, pos) { var start = pos.ch, end = start, line = cm.getLine(pos.line); @@ -140,7 +127,7 @@ return {from: Pos(pos.line, start), to: Pos(pos.line, end), word: line.slice(start, end)}; } - cmds[map[ctrl + "D"] = "selectNextOccurrence"] = function(cm) { + cmds.selectNextOccurrence = function(cm) { var from = cm.getCursor("from"), to = cm.getCursor("to"); var fullWord = cm.state.sublimeFindFullWord == cm.doc.sel; if (CodeMirror.cmpPos(from, to) == 0) { @@ -177,10 +164,8 @@ } cm.setSelections(newRanges); } - - var addCursorToLineCombo = mac ? "Shift-Cmd" : 'Alt-Ctrl'; - cmds[map[addCursorToLineCombo + "Up"] = "addCursorToPrevLine"] = function(cm) { addCursorToSelection(cm, -1); }; - cmds[map[addCursorToLineCombo + "Down"] = "addCursorToNextLine"] = function(cm) { addCursorToSelection(cm, 1); }; + cmds.addCursorToPrevLine = function(cm) { addCursorToSelection(cm, -1); }; + cmds.addCursorToNextLine = function(cm) { addCursorToSelection(cm, 1); }; function isSelectedRange(ranges, from, to) { for (var i = 0; i < ranges.length; i++) @@ -209,14 +194,14 @@ return true; } - cmds[map["Shift-" + ctrl + "Space"] = "selectScope"] = function(cm) { + cmds.selectScope = function(cm) { selectBetweenBrackets(cm) || cm.execCommand("selectAll"); }; - cmds[map["Shift-" + ctrl + "M"] = "selectBetweenBrackets"] = function(cm) { + cmds.selectBetweenBrackets = function(cm) { if (!selectBetweenBrackets(cm)) return CodeMirror.Pass; }; - cmds[map[ctrl + "M"] = "goToBracket"] = function(cm) { + cmds.goToBracket = function(cm) { cm.extendSelectionsBy(function(range) { var next = cm.scanForBracket(range.head, 1); if (next && CodeMirror.cmpPos(next.pos, range.head) != 0) return next.pos; @@ -225,9 +210,7 @@ }); }; - var swapLineCombo = mac ? "Cmd-Ctrl-" : "Shift-Ctrl-"; - - cmds[map[swapLineCombo + "Up"] = "swapLineUp"] = function(cm) { + cmds.swapLineUp = function(cm) { if (cm.isReadOnly()) return CodeMirror.Pass var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1, newSels = []; for (var i = 0; i < ranges.length; i++) { @@ -254,7 +237,7 @@ }); }; - cmds[map[swapLineCombo + "Down"] = "swapLineDown"] = function(cm) { + cmds.swapLineDown = function(cm) { if (cm.isReadOnly()) return CodeMirror.Pass var ranges = cm.listSelections(), linesToMove = [], at = cm.lastLine() + 1; for (var i = ranges.length - 1; i >= 0; i--) { @@ -278,11 +261,11 @@ }); }; - cmds[map[ctrl + "/"] = "toggleCommentIndented"] = function(cm) { + cmds.toggleCommentIndented = function(cm) { cm.toggleComment({ indent: true }); } - cmds[map[ctrl + "J"] = "joinLines"] = function(cm) { + cmds.joinLines = function(cm) { var ranges = cm.listSelections(), joined = []; for (var i = 0; i < ranges.length; i++) { var range = ranges[i], from = range.from(); @@ -310,7 +293,7 @@ }); }; - cmds[map["Shift-" + ctrl + "D"] = "duplicateLine"] = function(cm) { + cmds.duplicateLine = function(cm) { cm.operation(function() { var rangeCount = cm.listSelections().length; for (var i = 0; i < rangeCount; i++) { @@ -324,7 +307,6 @@ }); }; - if (!mac) map[ctrl + "T"] = "transposeChars"; function sortLines(cm, caseSensitive) { if (cm.isReadOnly()) return CodeMirror.Pass @@ -362,10 +344,10 @@ }); } - cmds[map["F9"] = "sortLines"] = function(cm) { sortLines(cm, true); }; - cmds[map[ctrl + "F9"] = "sortLinesInsensitive"] = function(cm) { sortLines(cm, false); }; + cmds.sortLines = function(cm) { sortLines(cm, true); }; + cmds.sortLinesInsensitive = function(cm) { sortLines(cm, false); }; - cmds[map["F2"] = "nextBookmark"] = function(cm) { + cmds.nextBookmark = function(cm) { var marks = cm.state.sublimeBookmarks; if (marks) while (marks.length) { var current = marks.shift(); @@ -377,7 +359,7 @@ } }; - cmds[map["Shift-F2"] = "prevBookmark"] = function(cm) { + cmds.prevBookmark = function(cm) { var marks = cm.state.sublimeBookmarks; if (marks) while (marks.length) { marks.unshift(marks.pop()); @@ -389,7 +371,7 @@ } }; - cmds[map[ctrl + "F2"] = "toggleBookmark"] = function(cm) { + cmds.toggleBookmark = function(cm) { var ranges = cm.listSelections(); var marks = cm.state.sublimeBookmarks || (cm.state.sublimeBookmarks = []); for (var i = 0; i < ranges.length; i++) { @@ -409,13 +391,13 @@ } }; - cmds[map["Shift-" + ctrl + "F2"] = "clearBookmarks"] = function(cm) { + cmds.clearBookmarks = function(cm) { var marks = cm.state.sublimeBookmarks; if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear(); marks.length = 0; }; - cmds[map["Alt-F2"] = "selectBookmarks"] = function(cm) { + cmds.selectBookmarks = function(cm) { var marks = cm.state.sublimeBookmarks, ranges = []; if (marks) for (var i = 0; i < marks.length; i++) { var found = marks[i].find(); @@ -428,10 +410,6 @@ cm.setSelections(ranges, 0); }; - map["Alt-Q"] = "wrapLines"; - - var cK = ctrl + "K "; - function modifyWordOrSelection(cm, mod) { cm.operation(function() { var ranges = cm.listSelections(), indices = [], replacements = []; @@ -451,9 +429,7 @@ }); } - map[cK + ctrl + "Backspace"] = "delLineLeft"; - - cmds[map["Backspace"] = "smartBackspace"] = function(cm) { + cmds.smartBackspace = function(cm) { if (cm.somethingSelected()) return CodeMirror.Pass; cm.operation(function() { @@ -481,7 +457,7 @@ }); }; - cmds[map[cK + ctrl + "K"] = "delLineRight"] = function(cm) { + cmds.delLineRight = function(cm) { cm.operation(function() { var ranges = cm.listSelections(); for (var i = ranges.length - 1; i >= 0; i--) @@ -490,22 +466,22 @@ }); }; - cmds[map[cK + ctrl + "U"] = "upcaseAtCursor"] = function(cm) { + cmds.upcaseAtCursor = function(cm) { modifyWordOrSelection(cm, function(str) { return str.toUpperCase(); }); }; - cmds[map[cK + ctrl + "L"] = "downcaseAtCursor"] = function(cm) { + cmds.downcaseAtCursor = function(cm) { modifyWordOrSelection(cm, function(str) { return str.toLowerCase(); }); }; - cmds[map[cK + ctrl + "Space"] = "setSublimeMark"] = function(cm) { + cmds.setSublimeMark = function(cm) { if (cm.state.sublimeMark) cm.state.sublimeMark.clear(); cm.state.sublimeMark = cm.setBookmark(cm.getCursor()); }; - cmds[map[cK + ctrl + "A"] = "selectToSublimeMark"] = function(cm) { + cmds.selectToSublimeMark = function(cm) { var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); if (found) cm.setSelection(cm.getCursor(), found); }; - cmds[map[cK + ctrl + "W"] = "deleteToSublimeMark"] = function(cm) { + cmds.deleteToSublimeMark = function(cm) { var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); if (found) { var from = cm.getCursor(), to = found; @@ -514,7 +490,7 @@ cm.replaceRange("", from, to); } }; - cmds[map[cK + ctrl + "X"] = "swapWithSublimeMark"] = function(cm) { + cmds.swapWithSublimeMark = function(cm) { var found = cm.state.sublimeMark && cm.state.sublimeMark.find(); if (found) { cm.state.sublimeMark.clear(); @@ -522,19 +498,17 @@ cm.setCursor(found); } }; - cmds[map[cK + ctrl + "Y"] = "sublimeYank"] = function(cm) { + cmds.sublimeYank = function(cm) { if (cm.state.sublimeKilled != null) cm.replaceSelection(cm.state.sublimeKilled, null, "paste"); }; - map[cK + ctrl + "G"] = "clearBookmarks"; - cmds[map[cK + ctrl + "C"] = "showInCenter"] = function(cm) { + cmds.showInCenter = function(cm) { var pos = cm.cursorCoords(null, "local"); cm.scrollTo(null, (pos.top + pos.bottom) / 2 - cm.getScrollInfo().clientHeight / 2); }; - var selectLinesCombo = mac ? "Ctrl-Shift-" : "Ctrl-Alt-"; - cmds[map[selectLinesCombo + "Up"] = "selectLinesUpward"] = function(cm) { + cmds.selectLinesUpward = function(cm) { cm.operation(function() { var ranges = cm.listSelections(); for (var i = 0; i < ranges.length; i++) { @@ -544,7 +518,7 @@ } }); }; - cmds[map[selectLinesCombo + "Down"] = "selectLinesDownward"] = function(cm) { + cmds.selectLinesDownward = function(cm) { cm.operation(function() { var ranges = cm.listSelections(); for (var i = 0; i < ranges.length; i++) { @@ -583,9 +557,9 @@ cm.setSelection(target.from, target.to); } }; - cmds[map[ctrl + "F3"] = "findUnder"] = function(cm) { findAndGoTo(cm, true); }; - cmds[map["Shift-" + ctrl + "F3"] = "findUnderPrevious"] = function(cm) { findAndGoTo(cm,false); }; - cmds[map["Alt-F3"] = "findAllUnder"] = function(cm) { + cmds.findUnder = function(cm) { findAndGoTo(cm, true); }; + cmds.findUnderPrevious = function(cm) { findAndGoTo(cm,false); }; + cmds.findAllUnder = function(cm) { var target = getTarget(cm); if (!target) return; var cur = cm.getSearchCursor(target.query); @@ -599,15 +573,132 @@ cm.setSelections(matches, primaryIndex); }; - map["Shift-" + ctrl + "["] = "fold"; - map["Shift-" + ctrl + "]"] = "unfold"; - map[cK + ctrl + "0"] = map[cK + ctrl + "J"] = "unfoldAll"; - - map[ctrl + "I"] = "findIncremental"; - map["Shift-" + ctrl + "I"] = "findIncrementalReverse"; - map[ctrl + "H"] = "replace"; - map["F3"] = "findNext"; - map["Shift-F3"] = "findPrev"; - CodeMirror.normalizeKeyMap(map); + var keyMap = CodeMirror.keyMap; + keyMap.macSublime = { + "Cmd-Left": "goLineStartSmart", + "Shift-Tab": "indentLess", + "Shift-Ctrl-K": "deleteLine", + "Alt-Q": "wrapLines", + "Ctrl-Left": "goSubwordLeft", + "Ctrl-Right": "goSubwordRight", + "Ctrl-Alt-Up": "scrollLineUp", + "Ctrl-Alt-Down": "scrollLineDown", + "Cmd-L": "selectLine", + "Shift-Cmd-L": "splitSelectionByLine", + "Esc": "singleSelectionTop", + "Cmd-Enter": "insertLineAfter", + "Shift-Cmd-Enter": "insertLineBefore", + "Cmd-D": "selectNextOccurrence", + "Shift-Cmd-Up": "addCursorToPrevLine", + "Shift-Cmd-Down": "addCursorToNextLine", + "Shift-Cmd-Space": "selectScope", + "Shift-Cmd-M": "selectBetweenBrackets", + "Cmd-M": "goToBracket", + "Cmd-Ctrl-Up": "swapLineUp", + "Cmd-Ctrl-Down": "swapLineDown", + "Cmd-/": "toggleCommentIndented", + "Cmd-J": "joinLines", + "Shift-Cmd-D": "duplicateLine", + "F9": "sortLines", + "Cmd-F9": "sortLinesInsensitive", + "F2": "nextBookmark", + "Shift-F2": "prevBookmark", + "Cmd-F2": "toggleBookmark", + "Shift-Cmd-F2": "clearBookmarks", + "Alt-F2": "selectBookmarks", + "Backspace": "smartBackspace", + "Cmd-K Cmd-K": "delLineRight", + "Cmd-K Cmd-U": "upcaseAtCursor", + "Cmd-K Cmd-L": "downcaseAtCursor", + "Cmd-K Cmd-Space": "setSublimeMark", + "Cmd-K Cmd-A": "selectToSublimeMark", + "Cmd-K Cmd-W": "deleteToSublimeMark", + "Cmd-K Cmd-X": "swapWithSublimeMark", + "Cmd-K Cmd-Y": "sublimeYank", + "Cmd-K Cmd-C": "showInCenter", + "Cmd-K Cmd-G": "clearBookmarks", + "Cmd-K Cmd-Backspace": "delLineLeft", + "Cmd-K Cmd-0": "unfoldAll", + "Cmd-K Cmd-J": "unfoldAll", + "Ctrl-Shift-Up": "selectLinesUpward", + "Ctrl-Shift-Down": "selectLinesDownward", + "Cmd-F3": "findUnder", + "Shift-Cmd-F3": "findUnderPrevious", + "Alt-F3": "findAllUnder", + "Shift-Cmd-[": "fold", + "Shift-Cmd-]": "unfold", + "Cmd-I": "findIncremental", + "Shift-Cmd-I": "findIncrementalReverse", + "Cmd-H": "replace", + "F3": "findNext", + "Shift-F3": "findPrev", + "fallthrough": "pcDefault" + }; + CodeMirror.normalizeKeyMap(keyMap.macSublime); + + keyMap.pcSublime = { + "Shift-Tab": "indentLess", + "Shift-Ctrl-K": "deleteLine", + "Alt-Q": "wrapLines", + "Ctrl-T": "transposeChars", + "Alt-Left": "goSubwordLeft", + "Alt-Right": "goSubwordRight", + "Ctrl-Up": "scrollLineUp", + "Ctrl-Down": "scrollLineDown", + "Ctrl-L": "selectLine", + "Shift-Ctrl-L": "splitSelectionByLine", + "Esc": "singleSelectionTop", + "Ctrl-Enter": "insertLineAfter", + "Shift-Ctrl-Enter": "insertLineBefore", + "Ctrl-D": "selectNextOccurrence", + "Alt-CtrlUp": "addCursorToPrevLine", + "Alt-CtrlDown": "addCursorToNextLine", + "Shift-Ctrl-Space": "selectScope", + "Shift-Ctrl-M": "selectBetweenBrackets", + "Ctrl-M": "goToBracket", + "Shift-Ctrl-Up": "swapLineUp", + "Shift-Ctrl-Down": "swapLineDown", + "Ctrl-/": "toggleCommentIndented", + "Ctrl-J": "joinLines", + "Shift-Ctrl-D": "duplicateLine", + "F9": "sortLines", + "Ctrl-F9": "sortLinesInsensitive", + "F2": "nextBookmark", + "Shift-F2": "prevBookmark", + "Ctrl-F2": "toggleBookmark", + "Shift-Ctrl-F2": "clearBookmarks", + "Alt-F2": "selectBookmarks", + "Backspace": "smartBackspace", + "Ctrl-K Ctrl-K": "delLineRight", + "Ctrl-K Ctrl-U": "upcaseAtCursor", + "Ctrl-K Ctrl-L": "downcaseAtCursor", + "Ctrl-K Ctrl-Space": "setSublimeMark", + "Ctrl-K Ctrl-A": "selectToSublimeMark", + "Ctrl-K Ctrl-W": "deleteToSublimeMark", + "Ctrl-K Ctrl-X": "swapWithSublimeMark", + "Ctrl-K Ctrl-Y": "sublimeYank", + "Ctrl-K Ctrl-C": "showInCenter", + "Ctrl-K Ctrl-G": "clearBookmarks", + "Ctrl-K Ctrl-Backspace": "delLineLeft", + "Ctrl-K Ctrl-0": "unfoldAll", + "Ctrl-K Ctrl-J": "unfoldAll", + "Ctrl-Alt-Up": "selectLinesUpward", + "Ctrl-Alt-Down": "selectLinesDownward", + "Ctrl-F3": "findUnder", + "Shift-Ctrl-F3": "findUnderPrevious", + "Alt-F3": "findAllUnder", + "Shift-Ctrl-[": "fold", + "Shift-Ctrl-]": "unfold", + "Ctrl-I": "findIncremental", + "Shift-Ctrl-I": "findIncrementalReverse", + "Ctrl-H": "replace", + "F3": "findNext", + "Shift-F3": "findPrev", + "fallthrough": "pcDefault" + }; + CodeMirror.normalizeKeyMap(keyMap.pcSublime); + + var mac = keyMap.default == keyMap.macDefault; + keyMap.sublime = mac ? keyMap.macSublime : keyMap.pcSublime; }); From c1196ebc6260d4652ced5eee254d8c5d3cea10dd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 16 Oct 2017 16:17:48 +0200 Subject: [PATCH 0689/1880] [sublime keymap] Fix fallthrough for mac bindings Issue #5022 --- keymap/sublime.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keymap/sublime.js b/keymap/sublime.js index eeccab1721..08c9ebfb3f 100644 --- a/keymap/sublime.js +++ b/keymap/sublime.js @@ -633,7 +633,7 @@ "Cmd-H": "replace", "F3": "findNext", "Shift-F3": "findPrev", - "fallthrough": "pcDefault" + "fallthrough": "macDefault" }; CodeMirror.normalizeKeyMap(keyMap.macSublime); From e5e2aefd0874463ff5d9aeb955d869e7853658b5 Mon Sep 17 00:00:00 2001 From: Guan Gui Date: Mon, 16 Oct 2017 15:45:34 +1100 Subject: [PATCH 0690/1880] [closebrackets addon] Use editor line separator when exploding lines Issue #5031 --- addon/edit/closebrackets.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 36aec0d4b5..7b07f7fd8a 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -84,7 +84,8 @@ if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass; } cm.operation(function() { - cm.replaceSelection("\n\n", null); + var linesep = cm.lineSeparator() || "\n"; + cm.replaceSelection(linesep + linesep, null); cm.execCommand("goCharLeft"); ranges = cm.listSelections(); for (var i = 0; i < ranges.length; i++) { From deaa842dc6f1711874c1cacc6b984f7264932f83 Mon Sep 17 00:00:00 2001 From: Markus Olsson Date: Tue, 17 Oct 2017 12:15:40 +0200 Subject: [PATCH 0691/1880] [runmode addon] Include CodeMirror.innerMode in runmode.node.js The markdown mode uses `CodeMirror.innerMode` which isn't defined in the stripped down node runmode. Since markdown is the only mode (AFAICT) that uses it I'm not sure if it would make more sense rewrite it to not use it but this seemed like the least risky option. --- addon/runmode/runmode.node.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/addon/runmode/runmode.node.js b/addon/runmode/runmode.node.js index 093cb30876..21c72696c8 100644 --- a/addon/runmode/runmode.node.js +++ b/addon/runmode/runmode.node.js @@ -163,6 +163,18 @@ exports.getMode = function(options, spec) { return modeObj; }; + +exports.innerMode = function(mode, state) { + var info; + while (mode.innerMode) { + info = mode.innerMode(state); + if (!info || info.mode == mode) break; + state = info.state; + mode = info.mode; + } + return info || {mode: mode, state: state}; +} + exports.registerHelper = exports.registerGlobalHelper = Math.min; exports.runMode = function(string, modespec, callback, options) { From 79d266e60a8d02a865c7cf9340628a0f5d920394 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 29 Jun 2017 14:20:30 +0200 Subject: [PATCH 0692/1880] Add a baseToken method to string streams That overlay modes can use to access the underlying token info. --- doc/manual.html | 6 ++++++ src/line/highlight.js | 16 +++++++++++++++- src/util/StringStream.js | 4 ++++ test/test.js | 15 +++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index 67d5e4258a..0ab9cf0d79 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -3261,6 +3261,12 @@

      Writing CodeMirror Modes

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

      By default, blank lines are simply skipped when diff --git a/src/line/highlight.js b/src/line/highlight.js index 430d86a224..82e2aeee29 100644 --- a/src/line/highlight.js +++ b/src/line/highlight.js @@ -18,6 +18,8 @@ class Context { this.doc = doc this.line = line this.maxLookAhead = lookAhead || 0 + this.baseTokens = null + this.baseTokenPos = 1 } lookAhead(n) { @@ -26,6 +28,15 @@ class Context { return line } + baseToken(n) { + if (!this.baseTokens) return null + while (this.baseTokens[this.baseTokenPos] >= n) + this.baseTokenPos += 2 + let type = this.baseTokens[this.baseTokenPos + 1] + return {type: type && type.replace(/( |^)overlay .*/, ""), + size: this.baseTokens[this.baseTokenPos] - n} + } + nextLine() { this.line++ if (this.maxLookAhead > 0) this.maxLookAhead-- @@ -60,6 +71,7 @@ export function highlightLine(cm, line, context, forceToEnd) { // Run overlays, adjust style array. for (let o = 0; o < cm.state.overlays.length; ++o) { + context.baseTokens = st let overlay = cm.state.overlays[o], i = 1, at = 0 context.state = true runMode(cm, line.text, overlay.mode, context, (end, style) => { @@ -83,8 +95,10 @@ export function highlightLine(cm, line, context, forceToEnd) { } } }, lineClasses) + context.state = state + context.baseTokens = null + context.baseTokenPos = 1 } - context.state = state return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null} } diff --git a/src/util/StringStream.js b/src/util/StringStream.js index ac9555f1ce..a14b1b6430 100644 --- a/src/util/StringStream.js +++ b/src/util/StringStream.js @@ -81,6 +81,10 @@ class StringStream { let oracle = this.lineOracle return oracle && oracle.lookAhead(n) } + baseToken() { + let oracle = this.lineOracle + return oracle && oracle.baseToken(this.pos) + } } export default StringStream diff --git a/test/test.js b/test/test.js index 9c768e3f6b..415dd9f0bc 100644 --- a/test/test.js +++ b/test/test.js @@ -2218,6 +2218,21 @@ testCM("getTokenTypeAt", function(cm) { eq(cm.getTokenTypeAt(Pos(0, 6)), "string"); }, {value: "1 + 'foo'", mode: "javascript"}); +testCM("addOverlay", function(cm) { + cm.addOverlay({ + token: function(stream) { + var base = stream.baseToken() + if (!/comment/.test(base.type) && stream.match(/\d+/)) return "x" + stream.next() + } + }) + var x = byClassName(cm.getWrapperElement(), "cm-x") + is(x.length, 1) + is(x[0].textContent, "233") + cm.replaceRange("", Pos(0, 4), Pos(0, 6)) + is(byClassName(cm.getWrapperElement(), "cm-x").length, 2) +}, {value: "foo /* 100 */\nbar + 233;\nbaz", mode: "javascript"}) + testCM("resizeLineWidget", function(cm) { addDoc(cm, 200, 3); var widget = document.createElement("pre"); From 42a26328333a052583f1bd4623bfb8e42717e1dd Mon Sep 17 00:00:00 2001 From: vtripolitakis Date: Tue, 17 Oct 2017 21:59:21 +0300 Subject: [PATCH 0693/1880] [sql mode] Fix representation of table hinting in demo page --- mode/sql/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/sql/index.html b/mode/sql/index.html index e12b289bfa..b434f0f405 100644 --- a/mode/sql/index.html +++ b/mode/sql/index.html @@ -78,8 +78,8 @@

      SQL Mode for CodeMirror

      autofocus: true, extraKeys: {"Ctrl-Space": "autocomplete"}, hintOptions: {tables: { - users: {name: null, score: null, birthDate: null}, - countries: {name: null, population: null, size: null} + users: ["name", "score", "birthDate"], + countries: ["name", "population", "size"] }} }); }; From d14888a70bb4d172a60d968682f0e28ec5065c96 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 18 Oct 2017 11:11:11 +0200 Subject: [PATCH 0694/1880] [javascript mode] Fix bug in object literal spread parsing Closes #5036 --- mode/javascript/javascript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 61a6de4be7..ca9fe8ba86 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -514,7 +514,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } else if (type == "[") { return cont(expression, expect("]"), afterprop); } else if (type == "spread") { - return cont(expression, afterprop); + return cont(expressionNoComma, afterprop); } else if (value == "*") { cx.marked = "keyword"; return cont(objprop); From d323ad7236a4b611b7c0898fe660136df6faaf43 Mon Sep 17 00:00:00 2001 From: Pi Delport Date: Wed, 18 Oct 2017 14:20:24 +0200 Subject: [PATCH 0695/1880] (Update my name) --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 1264357043..e4206048bf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -529,7 +529,7 @@ Peter Kroon Philipp A Philip Stadermann Pierre Gerold -Piët Delport +Pi Delport Pieter Ouwerkerk Pontus Melke prasanthj From cf799958cf8f7ec89c808b7400fe248494b61674 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 18 Oct 2017 14:27:02 +0200 Subject: [PATCH 0696/1880] [bin/authors.sh] Make sure changed name doesn't resurface from git history Issue #5037 --- bin/authors.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/authors.sh b/bin/authors.sh index b3ee99c6dd..3f228c1fb0 100755 --- a/bin/authors.sh +++ b/bin/authors.sh @@ -1,6 +1,6 @@ # Combine existing list of authors with everyone known in git, sort, add header. tail --lines=+3 AUTHORS > AUTHORS.tmp -git log --format='%aN' >> AUTHORS.tmp +git log --format='%aN' | grep -v "Piët Delport" >> AUTHORS.tmp echo -e "List of CodeMirror contributors. Updated before every release.\n" > AUTHORS sort -u AUTHORS.tmp >> AUTHORS rm -f AUTHORS.tmp From 40a818295aef34d7fd73e9c036e720334336ae98 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 18 Oct 2017 17:02:48 +0200 Subject: [PATCH 0697/1880] Fix baseToken method See https://github.com/codemirror/CodeMirror/commit/79d266e60a8d02a865c7cf9340628a0f5d920394#commitcomment-25055107 --- src/line/highlight.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/line/highlight.js b/src/line/highlight.js index 82e2aeee29..13921585a7 100644 --- a/src/line/highlight.js +++ b/src/line/highlight.js @@ -30,7 +30,7 @@ class Context { baseToken(n) { if (!this.baseTokens) return null - while (this.baseTokens[this.baseTokenPos] >= n) + while (this.baseTokens[this.baseTokenPos] < n) this.baseTokenPos += 2 let type = this.baseTokens[this.baseTokenPos + 1] return {type: type && type.replace(/( |^)overlay .*/, ""), From a7f6e9f0a1ab1b1f3e9ca008579a17808e0e417f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 20 Oct 2017 16:01:41 +0200 Subject: [PATCH 0698/1880] Fix baseToken to actually return the token ahead when on boundary --- src/line/highlight.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/line/highlight.js b/src/line/highlight.js index 13921585a7..c5e6b8aacc 100644 --- a/src/line/highlight.js +++ b/src/line/highlight.js @@ -30,7 +30,7 @@ class Context { baseToken(n) { if (!this.baseTokens) return null - while (this.baseTokens[this.baseTokenPos] < n) + while (this.baseTokens[this.baseTokenPos] <= n) this.baseTokenPos += 2 let type = this.baseTokens[this.baseTokenPos + 1] return {type: type && type.replace(/( |^)overlay .*/, ""), From f936d89e4a2aa68eee964f57d14f875ee1d71ff4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 20 Oct 2017 17:35:00 +0200 Subject: [PATCH 0699/1880] Mark version 5.31.0 --- AUTHORS | 10 +++++++++- CHANGELOG.md | 18 ++++++++++++++++++ doc/manual.html | 4 ++-- doc/releases.html | 11 +++++++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 43 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index e4206048bf..f800b86b7d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -48,6 +48,7 @@ Andreas Reischuck Andres Taylor Andre von Houck Andrew Cheng +Andrew Dassonville Andrey Fedorov Andrey Klyuchnikov Andrey Lushnikov @@ -242,6 +243,7 @@ Grant Skinner greengiant Gregory Koberger Grzegorz Mazur +Guan Gui Guillaume Massé Guillaume Massé guraga @@ -253,6 +255,7 @@ Harshvardhan Gupta Hasan Karahan Hector Oswaldo Caballero Hendrik Wallbaum +Henrik Haugbølle Herculano Campos Hiroyuki Makino hitsthings @@ -308,6 +311,7 @@ jem (graphite) Jeremy Parmenter Jim Jim Avery +jkaplon JobJob jochenberger Jochen Berger @@ -341,6 +345,7 @@ ju1ius Juan Benavides Romero Jucovschi Constantin Juho Vuori +Julien CROUZET Julien Rebetez Justin Andresen Justin Hileman @@ -411,6 +416,7 @@ Mark Lentczner Marko Bonaci Mark Peace Markus Bordihn +Markus Olsson Martin Balek Martín Gaitán Martin Hasoň @@ -528,8 +534,8 @@ peterkroon Peter Kroon Philipp A Philip Stadermann -Pierre Gerold Pi Delport +Pierre Gerold Pieter Ouwerkerk Pontus Melke prasanthj @@ -633,6 +639,7 @@ thanasis TheHowl themrmax think +Thomas Brouard Thomas Dvornik Thomas Kluyver Thomas Schmid @@ -662,6 +669,7 @@ vf Victor Bocharsky Vincent Woo Volker Mische +vtripolitakis Weiyan Shao wenli Wes Cossick diff --git a/CHANGELOG.md b/CHANGELOG.md index ff7d6e2311..409c7234bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## 5.31.0 (2017-10-20) + +### Bug fixes + +Further improve selection drawing and cursor motion in right-to-left documents. + +[vim bindings](http://codemirror.net/demo/vim.html): Fix ctrl-w behavior, support quote-dot and backtick-dot marks, make the wide cursor visible in contentEditable [input mode](http://codemirror.net/doc/manual.html#option_contentEditable). + +[continuecomment addon](http://codemirror.net/doc/manual.html#addon_continuecomment): Fix bug when pressing enter after a single-line block comment. + +[markdown mode](http://codemirror.net/mode/markdown/): Fix issue with leaving indented fenced code blocks. + +[javascript mode](http://codemirror.net/mode/javascript/): Fix bad parsing of operators without spaces between them. Fix some corner cases around semicolon insertion and regexps. + +### New features + +Modes added with [`addOverlay`](http://codemirror.net/doc/manual.html#addOverlay) now have access to a [`baseToken`](http://codemirror.net/doc/manual.html#baseToken) method on their input stream, giving access to the tokens of the underlying mode. + ## 5.30.0 (2017-09-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 0ab9cf0d79..f2f04459b4 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

      User manual and reference guide - version 5.30.0 + version 5.31.0

      CodeMirror is a code-editor component that can be embedded in @@ -3262,7 +3262,7 @@

      Writing CodeMirror Modes

      you want to do this carefully, since looking far ahead will make mode state caching much less effective. -
      baseToken() → ?{type: ?string, size: number}
      +
      baseToken() → ?{type: ?string, size: number}
      Modes added through addOverlay (and only such modes) can use this method to inspect diff --git a/doc/releases.html b/doc/releases.html index e16ab6dd43..23de4c8023 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,17 @@

      Release notes and version history

      Version 5.x

      +

      20-10-2017: Version 5.31.0:

      + +
        +
      • Modes added with addOverlay now have access to a baseToken method on their input stream, giving access to the tokens of the underlying mode.
      • +
      • Further improve selection drawing and cursor motion in right-to-left documents.
      • +
      • vim bindings: Fix ctrl-w behavior, support quote-dot and backtick-dot marks, make the wide cursor visible in contentEditable input mode.
      • +
      • continuecomment addon: Fix bug when pressing enter after a single-line block comment.
      • +
      • markdown mode: Fix issue with leaving indented fenced code blocks.
      • +
      • javascript mode: Fix bad parsing of operators without spaces between them. Fix some corner cases around semicolon insertion and regexps.
      • +
      +

      20-09-2017: Version 5.30.0:

        diff --git a/index.html b/index.html index d161e77c6f..555e4804aa 100644 --- a/index.html +++ b/index.html @@ -96,7 +96,7 @@

        This is CodeMirror

    - Get the current version: 5.30.0.
    + Get the current version: 5.31.0.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index f251b238fd..2241ad9317 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.30.0", + "version": "5.31.0", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "description": "Full-featured in-browser code editor", diff --git a/src/edit/main.js b/src/edit/main.js index 4298c61ff1..b0fd5de810 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.30.0" +CodeMirror.version = "5.31.0" From d6fea23efc1a9c1e16b18541691893860c653a13 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 20 Oct 2017 17:36:29 +0200 Subject: [PATCH 0700/1880] Bump version number post-5.30.0 --- doc/manual.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index f2f04459b4..7666e0df63 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.31.0 + version 5.31.1

    CodeMirror is a code-editor component that can be embedded in diff --git a/package.json b/package.json index 2241ad9317..6eda061f17 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.31.0", + "version": "5.31.1", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "description": "Full-featured in-browser code editor", diff --git a/src/edit/main.js b/src/edit/main.js index b0fd5de810..6500e08d05 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy" addLegacyProps(CodeMirror) -CodeMirror.version = "5.31.0" +CodeMirror.version = "5.31.1" From 070c338b3b6fd07f9f4481cbe661d7ab0253de38 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 23 Oct 2017 22:22:36 +0200 Subject: [PATCH 0701/1880] [clike mode] Stop treating package as defining in Java mode Closes #5047 --- mode/clike/clike.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index d6d12c7117..02a85319ff 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -432,7 +432,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " + "Integer Long Number Object Short String StringBuffer StringBuilder Void"), blockKeywords: words("catch class do else finally for if switch try while"), - defKeywords: words("class interface package enum @interface"), + defKeywords: words("class interface enum @interface"), typeFirstDefinitions: true, atoms: words("true false null"), number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i, From 0b1d8183f27fba189e4b06b148203599f223b5d4 Mon Sep 17 00:00:00 2001 From: Jayaprabhakar Date: Mon, 23 Oct 2017 22:06:13 -0700 Subject: [PATCH 0702/1880] Add Codiva.io to realworld usage list Adding Codiva.io Online Java Compiler and IDE to the existing users list. This will highlight some of the advanced usage of Codemirror - Multiple Tabbed editor - Continuous compilation in the backend - Autocompletion - Mobile friendly - Read-only mode --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index f0a75abf72..2049bf26fd 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -59,6 +59,7 @@

    CodeMirror real-world uses

  • Codevolve (programming lessons as-a-service)
  • CodeZample (code snippet sharing)
  • Codio (Web IDE)
  • +
  • Codiva.io (Online Java Compiler and IDE with auto-completion and error highlighting)
  • Collaborative CodeMirror demo (CodeMirror + operational transforms)
  • Community Code Camp (code snippet sharing)
  • compilejava.net (online Java sandbox)
  • From edbc598959b1284f49f55f9f29b9fe6beeb8e920 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 29 Oct 2017 11:10:18 +0100 Subject: [PATCH 0703/1880] [closebrackets addon] Improve start-of-string heuristic To also make sure the last token isn't a string. Issue codemirror/google-modes#74 --- addon/edit/closebrackets.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 7b07f7fd8a..7592ef0071 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -203,6 +203,7 @@ function stringStartsAfter(cm, pos) { var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1)) - return /\bstring/.test(token.type) && token.start == pos.ch + return /\bstring/.test(token.type) && token.start == pos.ch && + (pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos))) } }); From e26db631d4f34d844b503ecffafc5d9665ac4e6a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 29 Oct 2017 11:28:10 +0100 Subject: [PATCH 0704/1880] [javascript mode] Support TS type parameter defaults Closes #5053 --- mode/javascript/javascript.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index ca9fe8ba86..c838e31628 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -607,6 +607,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function maybeTypeArgs(_, value) { if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) } + function typeparam() { + return pass(typeexpr, maybeTypeDefault) + } + function maybeTypeDefault(_, value) { + if (value == "=") return cont(typeexpr) + } function vardef() { return pass(pattern, maybetype, maybeAssign, vardefCont); } @@ -661,7 +667,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} if (type == "variable") {register(value); return cont(functiondef);} if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext); - if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, functiondef) + if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef) } function funarg(type, value) { if (value == "@") cont(expression, funarg) @@ -677,7 +683,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "variable") {register(value); return cont(classNameAfter);} } function classNameAfter(type, value) { - if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, classNameAfter) + if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter) if (value == "extends" || value == "implements" || (isTS && type == ",")) return cont(isTS ? typeexpr : expression, classNameAfter); if (type == "{") return cont(pushlex("}"), classBody, poplex); From f841fb779ea5f89fb22ccd48879ff034807dd10f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 29 Oct 2017 12:03:28 +0100 Subject: [PATCH 0705/1880] [merge addon] Fix issue where collapsed text markers could get half-cleared Issue #5054 --- addon/merge/merge.js | 3 +++ src/display/update_lines.js | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index c94b27a7b8..dc2e77c60e 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -738,6 +738,9 @@ mark.clear(); cm.removeLineClass(from, "wrap", "CodeMirror-merge-collapsed-line"); } + if (mark.explicitlyCleared) clear(); + CodeMirror.on(widget, "click", clear); + mark.on("clear", clear); CodeMirror.on(widget, "click", clear); return {mark: mark, clear: clear}; } diff --git a/src/display/update_lines.js b/src/display/update_lines.js index 7583f3c159..bc8a9c60e4 100644 --- a/src/display/update_lines.js +++ b/src/display/update_lines.js @@ -33,8 +33,10 @@ export function updateHeightsInViewport(cm) { // Read and store the height of line widgets associated with the // given line. function updateWidgetHeight(line) { - if (line.widgets) for (let i = 0; i < line.widgets.length; ++i) - line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight + if (line.widgets) for (let i = 0; i < line.widgets.length; ++i) { + let w = line.widgets[i], parent = w.node.parentNode; + if (parent) w.height = parent.offsetHeight + } } // Compute the lines that are visible in a given viewport (defaults From 48d2d264d34a2c366af617842c48c0685b641aad Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 29 Oct 2017 12:30:12 +0100 Subject: [PATCH 0706/1880] Fix lint issue --- src/display/update_lines.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display/update_lines.js b/src/display/update_lines.js index bc8a9c60e4..6c59188957 100644 --- a/src/display/update_lines.js +++ b/src/display/update_lines.js @@ -34,7 +34,7 @@ export function updateHeightsInViewport(cm) { // given line. function updateWidgetHeight(line) { if (line.widgets) for (let i = 0; i < line.widgets.length; ++i) { - let w = line.widgets[i], parent = w.node.parentNode; + let w = line.widgets[i], parent = w.node.parentNode if (parent) w.height = parent.offsetHeight } } From 97290a687e545bdad23794385b585fd9dfff3e2a Mon Sep 17 00:00:00 2001 From: Jonathan Hart Date: Sat, 21 Oct 2017 19:44:19 +0100 Subject: [PATCH 0707/1880] [continuelist addon] Increment numbers when item is added to the middle Per #5030, when adding new items to the middle of a Markdown list, the remaining list numbers should automatically increment --- addon/edit/continuelist.js | 39 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/addon/edit/continuelist.js b/addon/edit/continuelist.js index 02c8eff9fa..30893965fe 100644 --- a/addon/edit/continuelist.js +++ b/addon/edit/continuelist.js @@ -44,9 +44,48 @@ : (parseInt(match[3], 10) + 1) + match[4]; replacements[i] = "\n" + indent + bullet + after; + + incrementRemainingMarkdownListNumbers(cm, pos); } } cm.replaceSelections(replacements); }; + + // Auto-updating Markdown list numbers when a new item is added to the + // middle of a list + function incrementRemainingMarkdownListNumbers(cm, pos) { + var startLine = pos.line, lookAhead = 0, skipCount = 0; + var startItem = listRE.exec(cm.getLine(startLine)), startIndent = startItem[1]; + + do { + lookAhead += 1; + var nextLineNumber = startLine + lookAhead; + var nextLine = cm.getLine(nextLineNumber), nextItem = listRE.exec(nextLine); + + if (nextItem) { + var nextIndent = nextItem[1]; + var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount); + var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber; + + if (startIndent === nextIndent) { + if (newNumber === nextNumber) itemNumber = nextNumber + 1; + if (newNumber > nextNumber) itemNumber = newNumber + 1; + cm.replaceRange( + nextLine.replace(listRE, nextIndent + itemNumber + nextItem[4] + nextItem[5]), + { + line: nextLineNumber, ch: 0 + }, { + line: nextLineNumber, ch: nextLine.length + }); + } else { + if (startIndent.length > nextIndent.length) return; + // This doesn't run if the next line immediatley indents, as it is + // not clear of the users intention (new indented item or same level) + if ((startIndent.length < nextIndent.length) && (lookAhead === 1)) return; + skipCount += 1; + } + } + } while (nextItem); + } }); From 7e9190a646869db885ed73b239dc204d8e58a009 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 1 Nov 2017 11:17:21 +0100 Subject: [PATCH 0708/1880] [comment addon] Don't ignore content on last selected line when block-uncommenting Closes #5059 --- addon/comment/comment.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/addon/comment/comment.js b/addon/comment/comment.js index 568e639dcd..84c67edf78 100644 --- a/addon/comment/comment.js +++ b/addon/comment/comment.js @@ -172,10 +172,6 @@ if (open == -1) return false var endLine = end == start ? startLine : self.getLine(end) var close = endLine.indexOf(endString, end == start ? open + startString.length : 0); - if (close == -1 && start != end) { - endLine = self.getLine(--end); - close = endLine.indexOf(endString); - } var insideStart = Pos(start, open + 1), insideEnd = Pos(end, close + 1) if (close == -1 || !/comment/.test(self.getTokenTypeAt(insideStart)) || From a7907d37b2dcf1067a478bdc02064305461658ef Mon Sep 17 00:00:00 2001 From: Alexander Shvets Date: Tue, 31 Oct 2017 18:27:23 +0200 Subject: [PATCH 0709/1880] [searchcursor addon] Fix bug in case folding --- addon/search/searchcursor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/search/searchcursor.js b/addon/search/searchcursor.js index eccd81aab6..58bc47c2c3 100644 --- a/addon/search/searchcursor.js +++ b/addon/search/searchcursor.js @@ -159,7 +159,7 @@ for (var i = 1; i < lines.length - 1; i++) if (fold(doc.getLine(line + i)) != lines[i]) continue search var end = doc.getLine(line + lines.length - 1), endString = fold(end), lastLine = lines[lines.length - 1] - if (end.slice(0, lastLine.length) != lastLine) continue search + if (endString.slice(0, lastLine.length) != lastLine) continue search return {from: Pos(line, adjustPos(orig, string, cutFrom, fold) + ch), to: Pos(line + lines.length - 1, adjustPos(end, endString, lastLine.length, fold))} } From 66107010e9e34372c6736e6ca9379cf6ac044abc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 1 Nov 2017 11:52:12 +0100 Subject: [PATCH 0710/1880] Re-dispatch non-matching multi-key-strokes without their prefix Issue #5061 --- src/edit/key_events.js | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/edit/key_events.js b/src/edit/key_events.js index 2955e4ae0c..06f37be078 100644 --- a/src/edit/key_events.js +++ b/src/edit/key_events.js @@ -44,18 +44,26 @@ function lookupKeyForEditor(cm, name, handle) { // for bound mouse clicks. let stopSeq = new Delayed + export function dispatchKey(cm, name, e, handle) { let seq = cm.state.keySeq if (seq) { if (isModifierKey(name)) return "handled" - stopSeq.set(50, () => { - if (cm.state.keySeq == seq) { - cm.state.keySeq = null - cm.display.input.reset() - } - }) - name = seq + " " + name + if (/\'$/.test(name)) + cm.state.keySeq = null + else + stopSeq.set(50, () => { + if (cm.state.keySeq == seq) { + cm.state.keySeq = null + cm.display.input.reset() + } + }) + if (dispatchKeyInner(cm, seq + " " + name, e, handle)) return true } + return dispatchKeyInner(cm, name, e, handle) +} + +function dispatchKeyInner(cm, name, e, handle) { let result = lookupKeyForEditor(cm, name, handle) if (result == "multi") @@ -68,10 +76,6 @@ export function dispatchKey(cm, name, e, handle) { restartBlink(cm) } - if (seq && !result && /\'$/.test(name)) { - e_preventDefault(e) - return true - } return !!result } From 659cb7f3690a9e2b066faeba73143f291932aa30 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 2 Nov 2017 09:22:28 +0100 Subject: [PATCH 0711/1880] [javascript mode] Make TypeScript module/enum contextual keywords Closes #5064 --- mode/javascript/javascript.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index c838e31628..5c772526f2 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -47,8 +47,6 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { "interface": kw("class"), "implements": C, "namespace": C, - "module": kw("module"), - "enum": kw("module"), // scope modifiers "public": kw("modifier"), @@ -372,9 +370,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (isTS && value == "type") { cx.marked = "keyword" return cont(typeexpr, expect("operator"), typeexpr, expect(";")); - } if (isTS && value == "declare") { + } else if (isTS && value == "declare") { cx.marked = "keyword" return cont(statement) + } else if (isTS && (value == "module" || value == "enum") && cx.stream.match(/^\s*\w/, false)) { + cx.marked = "keyword" + return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex) } else { return cont(pushlex("stat"), maybelabel); } @@ -388,7 +389,6 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "class") return cont(pushlex("form"), className, poplex); if (type == "export") return cont(pushlex("stat"), afterExport, poplex); if (type == "import") return cont(pushlex("stat"), afterImport, poplex); - if (type == "module") return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex) if (type == "async") return cont(statement) if (value == "@") return cont(expression, statement) return pass(pushlex("stat"), expression, expect(";"), poplex); From c83e94a6412b9293362e59980d7ca26f58b4b9da Mon Sep 17 00:00:00 2001 From: Jayaprabhakar Date: Sun, 5 Nov 2017 19:02:03 -0800 Subject: [PATCH 0712/1880] Remove broken links in the realworld users page Removing the broken links in the realworld users list. I checked the backlinks using, https://www.deadlinkchecker.com/website-dead-link-checker.asp and manually verified these urls to be invalid. --- doc/realworld.html | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/doc/realworld.html b/doc/realworld.html index 2049bf26fd..da0f4e4e61 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -28,7 +28,6 @@

    CodeMirror real-world uses

  • Adobe Brackets (code editor)
  • ALM Tools (TypeScript powered IDE)
  • Amber (JavaScript-based Smalltalk system)
  • -
  • Apache GUI
  • APEye (tool for testing & documenting APIs)
  • Appengine Codiad
  • Better Text Viewer (plain text reader app for Chrome)
  • @@ -60,7 +59,6 @@

    CodeMirror real-world uses

  • CodeZample (code snippet sharing)
  • Codio (Web IDE)
  • Codiva.io (Online Java Compiler and IDE with auto-completion and error highlighting)
  • -
  • Collaborative CodeMirror demo (CodeMirror + operational transforms)
  • Community Code Camp (code snippet sharing)
  • compilejava.net (online Java sandbox)
  • CKWNC (UML editor)
  • @@ -70,7 +68,6 @@

    CodeMirror real-world uses

  • CSSDeck (CSS showcase)
  • Deck.js integration (slides with editors)
  • DbNinja (MySQL access interface)
  • -
  • Echoplexus (chat and collaborative coding)
  • eCSSpert (CSS demos and experiments)
  • Elm language examples
  • Eloquent JavaScript (book)
  • @@ -79,7 +76,6 @@

    CodeMirror real-world uses

  • Fastfig (online computation/math tool)
  • Farabi (modern Perl IDE)
  • FathomJS integration (slides with editors, again)
  • -
  • Phantomus (blogging platform)
  • Fiddle Salad (web development environment)
  • Filemanager
  • Firefox Developer Tools
  • @@ -101,7 +97,7 @@

    CodeMirror real-world uses

  • Homegenie (home automation server)
  • ICEcoder (web IDE)
  • IPython (interactive computing shell)
  • -
  • iTrading (Algorithmic Trading)
  • +
  • iTrading (Algorithmic Trading)
  • i-MOS (modeling and simulation platform)
  • Janvas (vector graphics editor)
  • Joomla plugin
  • @@ -116,18 +112,14 @@

    CodeMirror real-world uses

  • Kodit
  • Kodtest (HTML/JS/CSS playground)
  • Kotlin (web-based mini-IDE for Kotlin)
  • -
  • Laborate (collaborative coding)
  • Light Table (experimental IDE)
  • Liveweave (HTML/CSS/JS scratchpad)
  • Markdown Delight Editor (extensible markdown editor polymer component)
  • Marklight editor (lightweight markup editor)
  • Mergely (interactive diffing)
  • MIHTool (iOS web-app debugging tool)
  • -
  • Mongo MapReduce WebBrowser
  • -
  • Montage Studio (web app creator suite)
  • mscgen_js (online sequence chart editor)
  • MVC Playground
  • -
  • My2ndGeneration (social coding)
  • Navigate CMS
  • nodeMirror (IDE project)
  • NoTex (rST authoring)
  • @@ -143,8 +135,6 @@

    CodeMirror real-world uses

  • PubliForge (online publishing system)
  • Puzzlescript (puzzle game engine)
  • Quantum (code editor for Chrome OS)
  • -
  • ql.io (http API query helper)
  • -
  • QiYun web app platform
  • Qt+Webkit integration (building a desktop CodeMirror app)
  • Quivive File Manager
  • Rascal (tiny computer)
  • @@ -172,7 +162,6 @@

    CodeMirror real-world uses

  • TileMill (map design tool)
  • Tiki (wiki CMS groupware)
  • Toolsverse Data Explorer (database management)
  • -
  • Tributary (augmented editing)
  • Tumblr code highlighting shim
  • TurboPY (web publishing framework)
  • UmpleOnline (model-oriented programming tool)
  • From f02225b9ca000ddb098053b21acf3165d1e34beb Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 6 Nov 2017 11:33:40 +0100 Subject: [PATCH 0713/1880] Make the default colors for bracket matching more constrasting Issue #5063 --- lib/codemirror.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index 255de98606..8f4f22f5d6 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -145,8 +145,8 @@ /* Default styles for common addons */ -div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} -div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} +div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;} +div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } .CodeMirror-activeline-background {background: #e8f2ff;} From 36d7c7291fe7ecac442588a3a3c5c25a27e91455 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 7 Nov 2017 11:47:07 +0100 Subject: [PATCH 0714/1880] [closebrackets addon] Adjust check for when to insert two quotes Stop relying on mode tokens, use simple heuristic of not being after a word char Issue #5058 Issue #2657 --- addon/edit/closebrackets.js | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 7592ef0071..460f662f80 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -133,7 +133,8 @@ (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) { curType = "addFour"; } else if (identical) { - if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, ch)) curType = "both"; + var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur) + if (!CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev)) curType = "both"; else return CodeMirror.Pass; } else if (opening && (cm.getLine(cur.line).length == cur.ch || isClosingBracket(next, pairs) || @@ -185,22 +186,6 @@ return str.length == 2 ? str : null; } - // Project the token type that will exists after the given char is - // typed, and use it to determine whether it would cause the start - // of a string token. - function enteringString(cm, pos, ch) { - var line = cm.getLine(pos.line); - var token = cm.getTokenAt(pos); - if (/\bstring2?\b/.test(token.type) || stringStartsAfter(cm, pos)) return false; - var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4); - stream.pos = stream.start = token.start; - for (;;) { - var type1 = cm.getMode().token(stream, token.state); - if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1); - stream.start = stream.pos; - } - } - function stringStartsAfter(cm, pos) { var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1)) return /\bstring/.test(token.type) && token.start == pos.ch && From b6bfb4d09d14fa64d0993280c2761281d52ff958 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 8 Nov 2017 09:49:18 +0100 Subject: [PATCH 0715/1880] [solarized theme] Remove overly low-contrast color for cm-strong Closes #5075 --- theme/solarized.css | 1 - 1 file changed, 1 deletion(-) diff --git a/theme/solarized.css b/theme/solarized.css index d95f6c1b27..fcd1d70de6 100644 --- a/theme/solarized.css +++ b/theme/solarized.css @@ -87,7 +87,6 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png text-decoration: underline; text-decoration-style: dotted; } -.cm-s-solarized .cm-strong { color: #eee; } .cm-s-solarized .cm-error, .cm-s-solarized .cm-invalidchar { color: #586e75; From 2c741bd6742678f67e812307b2f78db4f4566d9d Mon Sep 17 00:00:00 2001 From: Casey Klebba Date: Tue, 7 Nov 2017 17:12:57 -0800 Subject: [PATCH 0716/1880] Fully qualify import paths --- src/codemirror.js | 2 +- src/display/Display.js | 6 +-- src/display/focus.js | 8 ++-- src/display/gutters.js | 6 +-- src/display/highlight_worker.js | 10 ++--- src/display/line_numbers.js | 8 ++-- src/display/mode_state.js | 6 +-- src/display/operations.js | 26 ++++++------- src/display/scroll_events.js | 8 ++-- src/display/scrollbars.js | 16 ++++---- src/display/scrolling.js | 18 ++++----- src/display/selection.js | 12 +++--- src/display/update_display.js | 30 +++++++-------- src/display/update_line.js | 10 ++--- src/display/update_lines.js | 8 ++-- src/display/view_tracking.js | 10 ++--- src/edit/CodeMirror.js | 50 ++++++++++++------------- src/edit/commands.js | 22 +++++------ src/edit/deleteNearSelection.js | 10 ++--- src/edit/drop_events.js | 26 ++++++------- src/edit/fromTextArea.js | 8 ++-- src/edit/global_events.js | 4 +- src/edit/key_events.js | 22 +++++------ src/edit/legacy.js | 34 ++++++++--------- src/edit/main.js | 24 ++++++------ src/edit/methods.js | 48 ++++++++++++------------ src/edit/mouse_events.js | 40 ++++++++++---------- src/edit/options.js | 36 +++++++++--------- src/edit/utils.js | 2 +- src/input/ContentEditableInput.js | 30 +++++++-------- src/input/TextareaInput.js | 24 ++++++------ src/input/indent.js | 14 +++---- src/input/input.js | 22 +++++------ src/input/keymap.js | 6 +-- src/input/movement.js | 8 ++-- src/line/highlight.js | 10 ++--- src/line/line_data.js | 18 ++++----- src/line/pos.js | 2 +- src/line/spans.js | 8 ++-- src/line/utils_line.js | 2 +- src/measurement/position_measurement.js | 26 ++++++------- src/measurement/widgets.js | 4 +- src/model/Doc.js | 40 ++++++++++---------- src/model/change_measurement.js | 6 +-- src/model/changes.js | 36 +++++++++--------- src/model/chunk.js | 6 +-- src/model/document_data.js | 20 +++++----- src/model/history.js | 18 ++++----- src/model/line_widget.js | 18 ++++----- src/model/mark_text.js | 30 +++++++-------- src/model/selection.js | 4 +- src/model/selection_updates.js | 18 ++++----- src/modes.js | 2 +- src/util/StringStream.js | 2 +- src/util/bidi.js | 2 +- src/util/dom.js | 2 +- src/util/event.js | 4 +- src/util/feature_detection.js | 4 +- src/util/operation_group.js | 2 +- 59 files changed, 449 insertions(+), 449 deletions(-) diff --git a/src/codemirror.js b/src/codemirror.js index 3c16cc875e..2a2f54e4c9 100644 --- a/src/codemirror.js +++ b/src/codemirror.js @@ -1,3 +1,3 @@ -import { CodeMirror } from "./edit/main" +import { CodeMirror } from "./edit/main.js" export default CodeMirror diff --git a/src/display/Display.js b/src/display/Display.js index ad0256bdfd..54b228a9b3 100644 --- a/src/display/Display.js +++ b/src/display/Display.js @@ -1,6 +1,6 @@ -import { gecko, ie, ie_version, mobile, webkit } from "../util/browser" -import { elt, eltP } from "../util/dom" -import { scrollerGap } from "../util/misc" +import { gecko, ie, ie_version, mobile, webkit } from "../util/browser.js" +import { elt, eltP } from "../util/dom.js" +import { scrollerGap } from "../util/misc.js" // The display handles the DOM integration, both for input reading // and content drawing. It holds references to DOM nodes and diff --git a/src/display/focus.js b/src/display/focus.js index ee52daffac..aa731b4353 100644 --- a/src/display/focus.js +++ b/src/display/focus.js @@ -1,7 +1,7 @@ -import { restartBlink } from "./selection" -import { webkit } from "../util/browser" -import { addClass, rmClass } from "../util/dom" -import { signal } from "../util/event" +import { restartBlink } from "./selection.js" +import { webkit } from "../util/browser.js" +import { addClass, rmClass } from "../util/dom.js" +import { signal } from "../util/event.js" export function ensureFocus(cm) { if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm) } diff --git a/src/display/gutters.js b/src/display/gutters.js index 7ccf119e80..37405b6d8c 100644 --- a/src/display/gutters.js +++ b/src/display/gutters.js @@ -1,7 +1,7 @@ -import { elt, removeChildren } from "../util/dom" -import { indexOf } from "../util/misc" +import { elt, removeChildren } from "../util/dom.js" +import { indexOf } from "../util/misc.js" -import { updateGutterSpace } from "./update_display" +import { updateGutterSpace } from "./update_display.js" // Rebuild the gutter elements, ensure the margin to the left of the // code matches their width. diff --git a/src/display/highlight_worker.js b/src/display/highlight_worker.js index e868c42f3c..6069815719 100644 --- a/src/display/highlight_worker.js +++ b/src/display/highlight_worker.js @@ -1,9 +1,9 @@ -import { getContextBefore, highlightLine, processLine } from "../line/highlight" -import { copyState } from "../modes" -import { bind } from "../util/misc" +import { getContextBefore, highlightLine, processLine } from "../line/highlight.js" +import { copyState } from "../modes.js" +import { bind } from "../util/misc.js" -import { runInOp } from "./operations" -import { regLineChange } from "./view_tracking" +import { runInOp } from "./operations.js" +import { regLineChange } from "./view_tracking.js" // HIGHLIGHT WORKER diff --git a/src/display/line_numbers.js b/src/display/line_numbers.js index c48f2204d5..3ab957509c 100644 --- a/src/display/line_numbers.js +++ b/src/display/line_numbers.js @@ -1,8 +1,8 @@ -import { lineNumberFor } from "../line/utils_line" -import { compensateForHScroll } from "../measurement/position_measurement" -import { elt } from "../util/dom" +import { lineNumberFor } from "../line/utils_line.js" +import { compensateForHScroll } from "../measurement/position_measurement.js" +import { elt } from "../util/dom.js" -import { updateGutterSpace } from "./update_display" +import { updateGutterSpace } from "./update_display.js" // Re-align line numbers and gutter marks to compensate for // horizontal scrolling. diff --git a/src/display/mode_state.js b/src/display/mode_state.js index ca0a534ca4..5d8ebf250e 100644 --- a/src/display/mode_state.js +++ b/src/display/mode_state.js @@ -1,7 +1,7 @@ -import { getMode } from "../modes" +import { getMode } from "../modes.js" -import { startWorker } from "./highlight_worker" -import { regChange } from "./view_tracking" +import { startWorker } from "./highlight_worker.js" +import { regChange } from "./view_tracking.js" // Used to get the editor into a consistent state again when options change. diff --git a/src/display/operations.js b/src/display/operations.js index c3004508e7..5cc26d265d 100644 --- a/src/display/operations.js +++ b/src/display/operations.js @@ -1,16 +1,16 @@ -import { clipPos } from "../line/pos" -import { findMaxLine } from "../line/spans" -import { displayWidth, measureChar, scrollGap } from "../measurement/position_measurement" -import { signal } from "../util/event" -import { activeElt } from "../util/dom" -import { finishOperation, pushOperation } from "../util/operation_group" - -import { ensureFocus } from "./focus" -import { measureForScrollbars, updateScrollbars } from "./scrollbars" -import { restartBlink } from "./selection" -import { maybeScrollWindow, scrollPosIntoView, setScrollLeft, setScrollTop } from "./scrolling" -import { DisplayUpdate, maybeClipScrollbars, postUpdateDisplay, setDocumentHeight, updateDisplayIfNeeded } from "./update_display" -import { updateHeightsInViewport } from "./update_lines" +import { clipPos } from "../line/pos.js" +import { findMaxLine } from "../line/spans.js" +import { displayWidth, measureChar, scrollGap } from "../measurement/position_measurement.js" +import { signal } from "../util/event.js" +import { activeElt } from "../util/dom.js" +import { finishOperation, pushOperation } from "../util/operation_group.js" + +import { ensureFocus } from "./focus.js" +import { measureForScrollbars, updateScrollbars } from "./scrollbars.js" +import { restartBlink } from "./selection.js" +import { maybeScrollWindow, scrollPosIntoView, setScrollLeft, setScrollTop } from "./scrolling.js" +import { DisplayUpdate, maybeClipScrollbars, postUpdateDisplay, setDocumentHeight, updateDisplayIfNeeded } from "./update_display.js" +import { updateHeightsInViewport } from "./update_lines.js" // Operations are used to wrap a series of changes to the editor // state in such a way that each change won't have to update the diff --git a/src/display/scroll_events.js b/src/display/scroll_events.js index d3902809e7..fbed426637 100644 --- a/src/display/scroll_events.js +++ b/src/display/scroll_events.js @@ -1,8 +1,8 @@ -import { chrome, gecko, ie, mac, presto, safari, webkit } from "../util/browser" -import { e_preventDefault } from "../util/event" +import { chrome, gecko, ie, mac, presto, safari, webkit } from "../util/browser.js" +import { e_preventDefault } from "../util/event.js" -import { updateDisplaySimple } from "./update_display" -import { setScrollLeft, updateScrollTop } from "./scrolling" +import { updateDisplaySimple } from "./update_display.js" +import { setScrollLeft, updateScrollTop } from "./scrolling.js" // Since the delta values reported on mouse wheel events are // unstandardized between browsers and even browser versions, and diff --git a/src/display/scrollbars.js b/src/display/scrollbars.js index 27060d18ef..7308c5e272 100644 --- a/src/display/scrollbars.js +++ b/src/display/scrollbars.js @@ -1,11 +1,11 @@ -import { addClass, elt, rmClass } from "../util/dom" -import { on } from "../util/event" -import { scrollGap, paddingVert } from "../measurement/position_measurement" -import { ie, ie_version, mac, mac_geMountainLion } from "../util/browser" -import { updateHeightsInViewport } from "./update_lines" -import { Delayed } from "../util/misc" - -import { setScrollLeft, updateScrollTop } from "./scrolling" +import { addClass, elt, rmClass } from "../util/dom.js" +import { on } from "../util/event.js" +import { scrollGap, paddingVert } from "../measurement/position_measurement.js" +import { ie, ie_version, mac, mac_geMountainLion } from "../util/browser.js" +import { updateHeightsInViewport } from "./update_lines.js" +import { Delayed } from "../util/misc.js" + +import { setScrollLeft, updateScrollTop } from "./scrolling.js" // SCROLLBARS diff --git a/src/display/scrolling.js b/src/display/scrolling.js index e16cf9ecac..26ec993b0f 100644 --- a/src/display/scrolling.js +++ b/src/display/scrolling.js @@ -1,12 +1,12 @@ -import { Pos } from "../line/pos" -import { cursorCoords, displayHeight, displayWidth, estimateCoords, paddingTop, paddingVert, scrollGap, textHeight } from "../measurement/position_measurement" -import { gecko, phantom } from "../util/browser" -import { elt } from "../util/dom" -import { signalDOMEvent } from "../util/event" - -import { startWorker } from "./highlight_worker" -import { alignHorizontally } from "./line_numbers" -import { updateDisplaySimple } from "./update_display" +import { Pos } from "../line/pos.js" +import { cursorCoords, displayHeight, displayWidth, estimateCoords, paddingTop, paddingVert, scrollGap, textHeight } from "../measurement/position_measurement.js" +import { gecko, phantom } from "../util/browser.js" +import { elt } from "../util/dom.js" +import { signalDOMEvent } from "../util/event.js" + +import { startWorker } from "./highlight_worker.js" +import { alignHorizontally } from "./line_numbers.js" +import { updateDisplaySimple } from "./update_display.js" // SCROLLING THINGS INTO VIEW diff --git a/src/display/selection.js b/src/display/selection.js index dca96a442b..c658c0a272 100644 --- a/src/display/selection.js +++ b/src/display/selection.js @@ -1,9 +1,9 @@ -import { Pos } from "../line/pos" -import { visualLine } from "../line/spans" -import { getLine } from "../line/utils_line" -import { charCoords, cursorCoords, displayWidth, paddingH, wrappedLineExtentChar } from "../measurement/position_measurement" -import { getOrder, iterateBidiSections } from "../util/bidi" -import { elt } from "../util/dom" +import { Pos } from "../line/pos.js" +import { visualLine } from "../line/spans.js" +import { getLine } from "../line/utils_line.js" +import { charCoords, cursorCoords, displayWidth, paddingH, wrappedLineExtentChar } from "../measurement/position_measurement.js" +import { getOrder, iterateBidiSections } from "../util/bidi.js" +import { elt } from "../util/dom.js" export function updateSelection(cm) { cm.display.input.showSelection(cm.display.input.prepareSelection()) diff --git a/src/display/update_display.js b/src/display/update_display.js index e58db48a51..86c7132131 100644 --- a/src/display/update_display.js +++ b/src/display/update_display.js @@ -1,19 +1,19 @@ -import { sawCollapsedSpans } from "../line/saw_special_spans" -import { heightAtLine, visualLineEndNo, visualLineNo } from "../line/spans" -import { getLine, lineNumberFor } from "../line/utils_line" -import { displayHeight, displayWidth, getDimensions, paddingVert, scrollGap } from "../measurement/position_measurement" -import { mac, webkit } from "../util/browser" -import { activeElt, removeChildren, contains } from "../util/dom" -import { hasHandler, signal } from "../util/event" -import { indexOf } from "../util/misc" +import { sawCollapsedSpans } from "../line/saw_special_spans.js" +import { heightAtLine, visualLineEndNo, visualLineNo } from "../line/spans.js" +import { getLine, lineNumberFor } from "../line/utils_line.js" +import { displayHeight, displayWidth, getDimensions, paddingVert, scrollGap } from "../measurement/position_measurement.js" +import { mac, webkit } from "../util/browser.js" +import { activeElt, removeChildren, contains } from "../util/dom.js" +import { hasHandler, signal } from "../util/event.js" +import { indexOf } from "../util/misc.js" -import { buildLineElement, updateLineForChanges } from "./update_line" -import { startWorker } from "./highlight_worker" -import { maybeUpdateLineNumberWidth } from "./line_numbers" -import { measureForScrollbars, updateScrollbars } from "./scrollbars" -import { updateSelection } from "./selection" -import { updateHeightsInViewport, visibleLines } from "./update_lines" -import { adjustView, countDirtyView, resetView } from "./view_tracking" +import { buildLineElement, updateLineForChanges } from "./update_line.js" +import { startWorker } from "./highlight_worker.js" +import { maybeUpdateLineNumberWidth } from "./line_numbers.js" +import { measureForScrollbars, updateScrollbars } from "./scrollbars.js" +import { updateSelection } from "./selection.js" +import { updateHeightsInViewport, visibleLines } from "./update_lines.js" +import { adjustView, countDirtyView, resetView } from "./view_tracking.js" // DISPLAY DRAWING diff --git a/src/display/update_line.js b/src/display/update_line.js index 15a2394257..db9df26d92 100644 --- a/src/display/update_line.js +++ b/src/display/update_line.js @@ -1,8 +1,8 @@ -import { buildLineContent } from "../line/line_data" -import { lineNumberFor } from "../line/utils_line" -import { ie, ie_version } from "../util/browser" -import { elt } from "../util/dom" -import { signalLater } from "../util/operation_group" +import { buildLineContent } from "../line/line_data.js" +import { lineNumberFor } from "../line/utils_line.js" +import { ie, ie_version } from "../util/browser.js" +import { elt } from "../util/dom.js" +import { signalLater } from "../util/operation_group.js" // When an aspect of a line changes, a string is added to // lineView.changes. This updates the relevant part of the line's diff --git a/src/display/update_lines.js b/src/display/update_lines.js index 6c59188957..7f06018d04 100644 --- a/src/display/update_lines.js +++ b/src/display/update_lines.js @@ -1,7 +1,7 @@ -import { heightAtLine } from "../line/spans" -import { getLine, lineAtHeight, updateLineHeight } from "../line/utils_line" -import { paddingTop, textHeight } from "../measurement/position_measurement" -import { ie, ie_version } from "../util/browser" +import { heightAtLine } from "../line/spans.js" +import { getLine, lineAtHeight, updateLineHeight } from "../line/utils_line.js" +import { paddingTop, textHeight } from "../measurement/position_measurement.js" +import { ie, ie_version } from "../util/browser.js" // Read the actual heights of the rendered lines, and update their // stored heights to match. diff --git a/src/display/view_tracking.js b/src/display/view_tracking.js index b9abd2fc40..41464f2350 100644 --- a/src/display/view_tracking.js +++ b/src/display/view_tracking.js @@ -1,8 +1,8 @@ -import { buildViewArray } from "../line/line_data" -import { sawCollapsedSpans } from "../line/saw_special_spans" -import { visualLineEndNo, visualLineNo } from "../line/spans" -import { findViewIndex } from "../measurement/position_measurement" -import { indexOf } from "../util/misc" +import { buildViewArray } from "../line/line_data.js" +import { sawCollapsedSpans } from "../line/saw_special_spans.js" +import { visualLineEndNo, visualLineNo } from "../line/spans.js" +import { findViewIndex } from "../measurement/position_measurement.js" +import { indexOf } from "../util/misc.js" // Updates the display.view data structure for a given change to the // document. From and to are in pre-change coordinates. Lendiff is diff --git a/src/edit/CodeMirror.js b/src/edit/CodeMirror.js index 0f0e58900c..4759209cf2 100644 --- a/src/edit/CodeMirror.js +++ b/src/edit/CodeMirror.js @@ -1,28 +1,28 @@ -import { Display } from "../display/Display" -import { onFocus, onBlur } from "../display/focus" -import { setGuttersForLineNumbers, updateGutters } from "../display/gutters" -import { maybeUpdateLineNumberWidth } from "../display/line_numbers" -import { endOperation, operation, startOperation } from "../display/operations" -import { initScrollbars } from "../display/scrollbars" -import { onScrollWheel } from "../display/scroll_events" -import { setScrollLeft, updateScrollTop } from "../display/scrolling" -import { clipPos, Pos } from "../line/pos" -import { posFromMouse } from "../measurement/position_measurement" -import { eventInWidget } from "../measurement/widgets" -import Doc from "../model/Doc" -import { attachDoc } from "../model/document_data" -import { Range } from "../model/selection" -import { extendSelection } from "../model/selection_updates" -import { captureRightClick, ie, ie_version, mobile, webkit } from "../util/browser" -import { e_preventDefault, e_stop, on, signal, signalDOMEvent } from "../util/event" -import { bind, copyObj, Delayed } from "../util/misc" - -import { clearDragCursor, onDragOver, onDragStart, onDrop } from "./drop_events" -import { ensureGlobalHandlers } from "./global_events" -import { onKeyDown, onKeyPress, onKeyUp } from "./key_events" -import { clickInGutter, onContextMenu, onMouseDown } from "./mouse_events" -import { themeChanged } from "./utils" -import { defaults, optionHandlers, Init } from "./options" +import { Display } from "../display/Display.js" +import { onFocus, onBlur } from "../display/focus.js" +import { setGuttersForLineNumbers, updateGutters } from "../display/gutters.js" +import { maybeUpdateLineNumberWidth } from "../display/line_numbers.js" +import { endOperation, operation, startOperation } from "../display/operations.js" +import { initScrollbars } from "../display/scrollbars.js" +import { onScrollWheel } from "../display/scroll_events.js" +import { setScrollLeft, updateScrollTop } from "../display/scrolling.js" +import { clipPos, Pos } from "../line/pos.js" +import { posFromMouse } from "../measurement/position_measurement.js" +import { eventInWidget } from "../measurement/widgets.js" +import Doc from "../model/Doc.js" +import { attachDoc } from "../model/document_data.js" +import { Range } from "../model/selection.js" +import { extendSelection } from "../model/selection_updates.js" +import { captureRightClick, ie, ie_version, mobile, webkit } from "../util/browser.js" +import { e_preventDefault, e_stop, on, signal, signalDOMEvent } from "../util/event.js" +import { bind, copyObj, Delayed } from "../util/misc.js" + +import { clearDragCursor, onDragOver, onDragStart, onDrop } from "./drop_events.js" +import { ensureGlobalHandlers } from "./global_events.js" +import { onKeyDown, onKeyPress, onKeyUp } from "./key_events.js" +import { clickInGutter, onContextMenu, onMouseDown } from "./mouse_events.js" +import { themeChanged } from "./utils.js" +import { defaults, optionHandlers, Init } from "./options.js" // A CodeMirror instance represents an editor. This is the object // that user code is usually dealing with. diff --git a/src/edit/commands.js b/src/edit/commands.js index e1a4327c8f..3916b129fb 100644 --- a/src/edit/commands.js +++ b/src/edit/commands.js @@ -1,14 +1,14 @@ -import { deleteNearSelection } from "./deleteNearSelection" -import { runInOp } from "../display/operations" -import { ensureCursorVisible } from "../display/scrolling" -import { endOfLine } from "../input/movement" -import { clipPos, Pos } from "../line/pos" -import { visualLine, visualLineEnd } from "../line/spans" -import { getLine, lineNo } from "../line/utils_line" -import { Range } from "../model/selection" -import { selectAll } from "../model/selection_updates" -import { countColumn, sel_dontScroll, sel_move, spaceStr } from "../util/misc" -import { getOrder } from "../util/bidi" +import { deleteNearSelection } from "./deleteNearSelection.js" +import { runInOp } from "../display/operations.js" +import { ensureCursorVisible } from "../display/scrolling.js" +import { endOfLine } from "../input/movement.js" +import { clipPos, Pos } from "../line/pos.js" +import { visualLine, visualLineEnd } from "../line/spans.js" +import { getLine, lineNo } from "../line/utils_line.js" +import { Range } from "../model/selection.js" +import { selectAll } from "../model/selection_updates.js" +import { countColumn, sel_dontScroll, sel_move, spaceStr } from "../util/misc.js" +import { getOrder } from "../util/bidi.js" // Commands are parameter-less actions that can be performed on an // editor, mostly used for keybindings. diff --git a/src/edit/deleteNearSelection.js b/src/edit/deleteNearSelection.js index 5a9bd2cfd5..82e331a5ff 100644 --- a/src/edit/deleteNearSelection.js +++ b/src/edit/deleteNearSelection.js @@ -1,8 +1,8 @@ -import { runInOp } from "../display/operations" -import { ensureCursorVisible } from "../display/scrolling" -import { cmp } from "../line/pos" -import { replaceRange } from "../model/changes" -import { lst } from "../util/misc" +import { runInOp } from "../display/operations.js" +import { ensureCursorVisible } from "../display/scrolling.js" +import { cmp } from "../line/pos.js" +import { replaceRange } from "../model/changes.js" +import { lst } from "../util/misc.js" // Helper for deleting text near the selection(s), used to implement // backspace, delete, and similar functionality. diff --git a/src/edit/drop_events.js b/src/edit/drop_events.js index 43e996fb68..12c760f0d6 100644 --- a/src/edit/drop_events.js +++ b/src/edit/drop_events.js @@ -1,16 +1,16 @@ -import { drawSelectionCursor } from "../display/selection" -import { operation } from "../display/operations" -import { clipPos } from "../line/pos" -import { posFromMouse } from "../measurement/position_measurement" -import { eventInWidget } from "../measurement/widgets" -import { makeChange, replaceRange } from "../model/changes" -import { changeEnd } from "../model/change_measurement" -import { simpleSelection } from "../model/selection" -import { setSelectionNoUndo, setSelectionReplaceHistory } from "../model/selection_updates" -import { ie, presto, safari } from "../util/browser" -import { elt, removeChildrenAndAdd } from "../util/dom" -import { e_preventDefault, e_stop, signalDOMEvent } from "../util/event" -import { indexOf } from "../util/misc" +import { drawSelectionCursor } from "../display/selection.js" +import { operation } from "../display/operations.js" +import { clipPos } from "../line/pos.js" +import { posFromMouse } from "../measurement/position_measurement.js" +import { eventInWidget } from "../measurement/widgets.js" +import { makeChange, replaceRange } from "../model/changes.js" +import { changeEnd } from "../model/change_measurement.js" +import { simpleSelection } from "../model/selection.js" +import { setSelectionNoUndo, setSelectionReplaceHistory } from "../model/selection_updates.js" +import { ie, presto, safari } from "../util/browser.js" +import { elt, removeChildrenAndAdd } from "../util/dom.js" +import { e_preventDefault, e_stop, signalDOMEvent } from "../util/event.js" +import { indexOf } from "../util/misc.js" // Kludge to work around strange IE behavior where it'll sometimes // re-fire a series of drag-related events right after the drop (#1551) diff --git a/src/edit/fromTextArea.js b/src/edit/fromTextArea.js index 5d920830b3..92498c1045 100644 --- a/src/edit/fromTextArea.js +++ b/src/edit/fromTextArea.js @@ -1,7 +1,7 @@ -import { CodeMirror } from "./CodeMirror" -import { activeElt } from "../util/dom" -import { off, on } from "../util/event" -import { copyObj } from "../util/misc" +import { CodeMirror } from "./CodeMirror.js" +import { activeElt } from "../util/dom.js" +import { off, on } from "../util/event.js" +import { copyObj } from "../util/misc.js" export function fromTextArea(textarea, options) { options = options ? copyObj(options) : {} diff --git a/src/edit/global_events.js b/src/edit/global_events.js index b2ab7d57c1..269e870ef1 100644 --- a/src/edit/global_events.js +++ b/src/edit/global_events.js @@ -1,5 +1,5 @@ -import { onBlur } from "../display/focus" -import { on } from "../util/event" +import { onBlur } from "../display/focus.js" +import { on } from "../util/event.js" // These must be handled carefully, because naively registering a // handler for each editor will cause the editors to never be diff --git a/src/edit/key_events.js b/src/edit/key_events.js index 06f37be078..f0521d070a 100644 --- a/src/edit/key_events.js +++ b/src/edit/key_events.js @@ -1,14 +1,14 @@ -import { signalLater } from "../util/operation_group" -import { restartBlink } from "../display/selection" -import { isModifierKey, keyName, lookupKey } from "../input/keymap" -import { eventInWidget } from "../measurement/widgets" -import { ie, ie_version, mac, presto } from "../util/browser" -import { activeElt, addClass, rmClass } from "../util/dom" -import { e_preventDefault, off, on, signalDOMEvent } from "../util/event" -import { hasCopyEvent } from "../util/feature_detection" -import { Delayed, Pass } from "../util/misc" - -import { commands } from "./commands" +import { signalLater } from "../util/operation_group.js" +import { restartBlink } from "../display/selection.js" +import { isModifierKey, keyName, lookupKey } from "../input/keymap.js" +import { eventInWidget } from "../measurement/widgets.js" +import { ie, ie_version, mac, presto } from "../util/browser.js" +import { activeElt, addClass, rmClass } from "../util/dom.js" +import { e_preventDefault, off, on, signalDOMEvent } from "../util/event.js" +import { hasCopyEvent } from "../util/feature_detection.js" +import { Delayed, Pass } from "../util/misc.js" + +import { commands } from "./commands.js" // Run a handler that was bound to a key. function doHandleBinding(cm, bound, dropShift) { diff --git a/src/edit/legacy.js b/src/edit/legacy.js index bc3df6c8f1..889badbe59 100644 --- a/src/edit/legacy.js +++ b/src/edit/legacy.js @@ -1,21 +1,21 @@ -import { scrollbarModel } from "../display/scrollbars" -import { wheelEventPixels } from "../display/scroll_events" -import { keyMap, keyName, isModifierKey, lookupKey, normalizeKeyMap } from "../input/keymap" -import { keyNames } from "../input/keynames" -import { Line } from "../line/line_data" -import { cmp, Pos } from "../line/pos" -import { changeEnd } from "../model/change_measurement" -import Doc from "../model/Doc" -import { LineWidget } from "../model/line_widget" -import { SharedTextMarker, TextMarker } from "../model/mark_text" -import { copyState, extendMode, getMode, innerMode, mimeModes, modeExtensions, modes, resolveMode, startState } from "../modes" -import { addClass, contains, rmClass } from "../util/dom" -import { e_preventDefault, e_stop, e_stopPropagation, off, on, signal } from "../util/event" -import { splitLinesAuto } from "../util/feature_detection" -import { countColumn, findColumn, isWordCharBasic, Pass } from "../util/misc" -import StringStream from "../util/StringStream" +import { scrollbarModel } from "../display/scrollbars.js" +import { wheelEventPixels } from "../display/scroll_events.js" +import { keyMap, keyName, isModifierKey, lookupKey, normalizeKeyMap } from "../input/keymap.js" +import { keyNames } from "../input/keynames.js" +import { Line } from "../line/line_data.js" +import { cmp, Pos } from "../line/pos.js" +import { changeEnd } from "../model/change_measurement.js" +import Doc from "../model/Doc.js" +import { LineWidget } from "../model/line_widget.js" +import { SharedTextMarker, TextMarker } from "../model/mark_text.js" +import { copyState, extendMode, getMode, innerMode, mimeModes, modeExtensions, modes, resolveMode, startState } from "../modes.js" +import { addClass, contains, rmClass } from "../util/dom.js" +import { e_preventDefault, e_stop, e_stopPropagation, off, on, signal } from "../util/event.js" +import { splitLinesAuto } from "../util/feature_detection.js" +import { countColumn, findColumn, isWordCharBasic, Pass } from "../util/misc.js" +import StringStream from "../util/StringStream.js" -import { commands } from "./commands" +import { commands } from "./commands.js" export function addLegacyProps(CodeMirror) { CodeMirror.off = off diff --git a/src/edit/main.js b/src/edit/main.js index 6500e08d05..6d9eb8790b 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -1,20 +1,20 @@ // EDITOR CONSTRUCTOR -import { CodeMirror } from "./CodeMirror" -export { CodeMirror } from "./CodeMirror" +import { CodeMirror } from "./CodeMirror.js" +export { CodeMirror } from "./CodeMirror.js" -import { eventMixin } from "../util/event" -import { indexOf } from "../util/misc" +import { eventMixin } from "../util/event.js" +import { indexOf } from "../util/misc.js" -import { defineOptions } from "./options" +import { defineOptions } from "./options.js" defineOptions(CodeMirror) -import addEditorMethods from "./methods" +import addEditorMethods from "./methods.js" addEditorMethods(CodeMirror) -import Doc from "../model/Doc" +import Doc from "../model/Doc.js" // Set up methods on CodeMirror's prototype to redirect to the editor's document. let dontDelegate = "iter insert remove copy getEditor constructor".split(" ") @@ -27,13 +27,13 @@ eventMixin(Doc) // INPUT HANDLING -import ContentEditableInput from "../input/ContentEditableInput" -import TextareaInput from "../input/TextareaInput" +import ContentEditableInput from "../input/ContentEditableInput.js" +import TextareaInput from "../input/TextareaInput.js" CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput} // MODE DEFINITION AND QUERYING -import { defineMIME, defineMode } from "../modes" +import { defineMIME, defineMode } from "../modes.js" // Extra arguments are stored as the mode's dependencies, which is // used by (legacy) mechanisms like loadmode.js to automatically @@ -58,11 +58,11 @@ CodeMirror.defineDocExtension = (name, func) => { Doc.prototype[name] = func } -import { fromTextArea } from "./fromTextArea" +import { fromTextArea } from "./fromTextArea.js" CodeMirror.fromTextArea = fromTextArea -import { addLegacyProps } from "./legacy" +import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) diff --git a/src/edit/methods.js b/src/edit/methods.js index 8dc692529e..5cefed7c18 100644 --- a/src/edit/methods.js +++ b/src/edit/methods.js @@ -1,27 +1,27 @@ -import { deleteNearSelection } from "./deleteNearSelection" -import { commands } from "./commands" -import { attachDoc } from "../model/document_data" -import { activeElt, addClass, rmClass } from "../util/dom" -import { eventMixin, signal } from "../util/event" -import { getLineStyles, getContextBefore, takeToken } from "../line/highlight" -import { indentLine } from "../input/indent" -import { triggerElectric } from "../input/input" -import { onKeyDown, onKeyPress, onKeyUp } from "./key_events" -import { onMouseDown } from "./mouse_events" -import { getKeyMap } from "../input/keymap" -import { endOfLine, moveLogically, moveVisually } from "../input/movement" -import { endOperation, methodOp, operation, runInOp, startOperation } from "../display/operations" -import { clipLine, clipPos, equalCursorPos, Pos } from "../line/pos" -import { charCoords, charWidth, clearCaches, clearLineMeasurementCache, coordsChar, cursorCoords, displayHeight, displayWidth, estimateLineHeights, fromCoordSystem, intoCoordSystem, scrollGap, textHeight } from "../measurement/position_measurement" -import { Range } from "../model/selection" -import { replaceOneSelection, skipAtomic } from "../model/selection_updates" -import { addToScrollTop, ensureCursorVisible, scrollIntoView, scrollToCoords, scrollToCoordsRange, scrollToRange } from "../display/scrolling" -import { heightAtLine } from "../line/spans" -import { updateGutterSpace } from "../display/update_display" -import { indexOf, insertSorted, isWordChar, sel_dontScroll, sel_move } from "../util/misc" -import { signalLater } from "../util/operation_group" -import { getLine, isLine, lineAtHeight } from "../line/utils_line" -import { regChange, regLineChange } from "../display/view_tracking" +import { deleteNearSelection } from "./deleteNearSelection.js" +import { commands } from "./commands.js" +import { attachDoc } from "../model/document_data.js" +import { activeElt, addClass, rmClass } from "../util/dom.js" +import { eventMixin, signal } from "../util/event.js" +import { getLineStyles, getContextBefore, takeToken } from "../line/highlight.js" +import { indentLine } from "../input/indent.js" +import { triggerElectric } from "../input/input.js" +import { onKeyDown, onKeyPress, onKeyUp } from "./key_events.js" +import { onMouseDown } from "./mouse_events.js" +import { getKeyMap } from "../input/keymap.js" +import { endOfLine, moveLogically, moveVisually } from "../input/movement.js" +import { endOperation, methodOp, operation, runInOp, startOperation } from "../display/operations.js" +import { clipLine, clipPos, equalCursorPos, Pos } from "../line/pos.js" +import { charCoords, charWidth, clearCaches, clearLineMeasurementCache, coordsChar, cursorCoords, displayHeight, displayWidth, estimateLineHeights, fromCoordSystem, intoCoordSystem, scrollGap, textHeight } from "../measurement/position_measurement.js" +import { Range } from "../model/selection.js" +import { replaceOneSelection, skipAtomic } from "../model/selection_updates.js" +import { addToScrollTop, ensureCursorVisible, scrollIntoView, scrollToCoords, scrollToCoordsRange, scrollToRange } from "../display/scrolling.js" +import { heightAtLine } from "../line/spans.js" +import { updateGutterSpace } from "../display/update_display.js" +import { indexOf, insertSorted, isWordChar, sel_dontScroll, sel_move } from "../util/misc.js" +import { signalLater } from "../util/operation_group.js" +import { getLine, isLine, lineAtHeight } from "../line/utils_line.js" +import { regChange, regLineChange } from "../display/view_tracking.js" // The publicly visible API. Note that methodOp(f) means // 'wrap f in an operation, performed on its `this` parameter'. diff --git a/src/edit/mouse_events.js b/src/edit/mouse_events.js index 57159e3a14..696a4bbfa2 100644 --- a/src/edit/mouse_events.js +++ b/src/edit/mouse_events.js @@ -1,23 +1,23 @@ -import { delayBlurEvent, ensureFocus } from "../display/focus" -import { operation } from "../display/operations" -import { visibleLines } from "../display/update_lines" -import { clipPos, cmp, maxPos, minPos, Pos } from "../line/pos" -import { getLine, lineAtHeight } from "../line/utils_line" -import { posFromMouse } from "../measurement/position_measurement" -import { eventInWidget } from "../measurement/widgets" -import { normalizeSelection, Range, Selection } from "../model/selection" -import { extendRange, extendSelection, replaceOneSelection, setSelection } from "../model/selection_updates" -import { captureRightClick, chromeOS, ie, ie_version, mac, webkit } from "../util/browser" -import { getOrder, getBidiPartAt } from "../util/bidi" -import { activeElt } from "../util/dom" -import { e_button, e_defaultPrevented, e_preventDefault, e_target, hasHandler, off, on, signal, signalDOMEvent } from "../util/event" -import { dragAndDrop } from "../util/feature_detection" -import { bind, countColumn, findColumn, sel_mouse } from "../util/misc" -import { addModifierNames } from "../input/keymap" -import { Pass } from "../util/misc" - -import { dispatchKey } from "./key_events" -import { commands } from "./commands" +import { delayBlurEvent, ensureFocus } from "../display/focus.js" +import { operation } from "../display/operations.js" +import { visibleLines } from "../display/update_lines.js" +import { clipPos, cmp, maxPos, minPos, Pos } from "../line/pos.js" +import { getLine, lineAtHeight } from "../line/utils_line.js" +import { posFromMouse } from "../measurement/position_measurement.js" +import { eventInWidget } from "../measurement/widgets.js" +import { normalizeSelection, Range, Selection } from "../model/selection.js" +import { extendRange, extendSelection, replaceOneSelection, setSelection } from "../model/selection_updates.js" +import { captureRightClick, chromeOS, ie, ie_version, mac, webkit } from "../util/browser.js" +import { getOrder, getBidiPartAt } from "../util/bidi.js" +import { activeElt } from "../util/dom.js" +import { e_button, e_defaultPrevented, e_preventDefault, e_target, hasHandler, off, on, signal, signalDOMEvent } from "../util/event.js" +import { dragAndDrop } from "../util/feature_detection.js" +import { bind, countColumn, findColumn, sel_mouse } from "../util/misc.js" +import { addModifierNames } from "../input/keymap.js" +import { Pass } from "../util/misc.js" + +import { dispatchKey } from "./key_events.js" +import { commands } from "./commands.js" const DOUBLECLICK_DELAY = 400 diff --git a/src/edit/options.js b/src/edit/options.js index 0601a83c3c..28f8bb60c6 100644 --- a/src/edit/options.js +++ b/src/edit/options.js @@ -1,21 +1,21 @@ -import { onBlur } from "../display/focus" -import { setGuttersForLineNumbers, updateGutters } from "../display/gutters" -import { alignHorizontally } from "../display/line_numbers" -import { loadMode, resetModeState } from "../display/mode_state" -import { initScrollbars, updateScrollbars } from "../display/scrollbars" -import { updateSelection } from "../display/selection" -import { regChange } from "../display/view_tracking" -import { getKeyMap } from "../input/keymap" -import { defaultSpecialCharPlaceholder } from "../line/line_data" -import { Pos } from "../line/pos" -import { findMaxLine } from "../line/spans" -import { clearCaches, compensateForHScroll, estimateLineHeights } from "../measurement/position_measurement" -import { replaceRange } from "../model/changes" -import { mobile, windows } from "../util/browser" -import { addClass, rmClass } from "../util/dom" -import { off, on } from "../util/event" - -import { themeChanged } from "./utils" +import { onBlur } from "../display/focus.js" +import { setGuttersForLineNumbers, updateGutters } from "../display/gutters.js" +import { alignHorizontally } from "../display/line_numbers.js" +import { loadMode, resetModeState } from "../display/mode_state.js" +import { initScrollbars, updateScrollbars } from "../display/scrollbars.js" +import { updateSelection } from "../display/selection.js" +import { regChange } from "../display/view_tracking.js" +import { getKeyMap } from "../input/keymap.js" +import { defaultSpecialCharPlaceholder } from "../line/line_data.js" +import { Pos } from "../line/pos.js" +import { findMaxLine } from "../line/spans.js" +import { clearCaches, compensateForHScroll, estimateLineHeights } from "../measurement/position_measurement.js" +import { replaceRange } from "../model/changes.js" +import { mobile, windows } from "../util/browser.js" +import { addClass, rmClass } from "../util/dom.js" +import { off, on } from "../util/event.js" + +import { themeChanged } from "./utils.js" export let Init = {toString: function(){return "CodeMirror.Init"}} diff --git a/src/edit/utils.js b/src/edit/utils.js index 61f795572d..fda0be7412 100644 --- a/src/edit/utils.js +++ b/src/edit/utils.js @@ -1,4 +1,4 @@ -import { clearCaches } from "../measurement/position_measurement" +import { clearCaches } from "../measurement/position_measurement.js" export function themeChanged(cm) { cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index 67de3b1836..e3af520a04 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -1,18 +1,18 @@ -import { operation, runInOp } from "../display/operations" -import { prepareSelection } from "../display/selection" -import { regChange } from "../display/view_tracking" -import { applyTextInput, copyableRanges, disableBrowserMagic, handlePaste, hiddenTextarea, lastCopied, setLastCopied } from "./input" -import { cmp, maxPos, minPos, Pos } from "../line/pos" -import { getBetween, getLine, lineNo } from "../line/utils_line" -import { findViewForLine, findViewIndex, mapFromLineView, nodeAndOffsetInLineMap } from "../measurement/position_measurement" -import { replaceRange } from "../model/changes" -import { simpleSelection } from "../model/selection" -import { setSelection } from "../model/selection_updates" -import { getBidiPartAt, getOrder } from "../util/bidi" -import { android, chrome, gecko, ie_version } from "../util/browser" -import { contains, range, removeChildrenAndAdd, selectInput } from "../util/dom" -import { on, signalDOMEvent } from "../util/event" -import { Delayed, lst, sel_dontScroll } from "../util/misc" +import { operation, runInOp } from "../display/operations.js" +import { prepareSelection } from "../display/selection.js" +import { regChange } from "../display/view_tracking.js" +import { applyTextInput, copyableRanges, disableBrowserMagic, handlePaste, hiddenTextarea, lastCopied, setLastCopied } from "./input.js" +import { cmp, maxPos, minPos, Pos } from "../line/pos.js" +import { getBetween, getLine, lineNo } from "../line/utils_line.js" +import { findViewForLine, findViewIndex, mapFromLineView, nodeAndOffsetInLineMap } from "../measurement/position_measurement.js" +import { replaceRange } from "../model/changes.js" +import { simpleSelection } from "../model/selection.js" +import { setSelection } from "../model/selection_updates.js" +import { getBidiPartAt, getOrder } from "../util/bidi.js" +import { android, chrome, gecko, ie_version } from "../util/browser.js" +import { contains, range, removeChildrenAndAdd, selectInput } from "../util/dom.js" +import { on, signalDOMEvent } from "../util/event.js" +import { Delayed, lst, sel_dontScroll } from "../util/misc.js" // CONTENTEDITABLE INPUT STYLE diff --git a/src/input/TextareaInput.js b/src/input/TextareaInput.js index 3262ea1ba6..c0f04aaaf2 100644 --- a/src/input/TextareaInput.js +++ b/src/input/TextareaInput.js @@ -1,15 +1,15 @@ -import { operation, runInOp } from "../display/operations" -import { prepareSelection } from "../display/selection" -import { applyTextInput, copyableRanges, handlePaste, hiddenTextarea, setLastCopied } from "./input" -import { cursorCoords, posFromMouse } from "../measurement/position_measurement" -import { eventInWidget } from "../measurement/widgets" -import { simpleSelection } from "../model/selection" -import { selectAll, setSelection } from "../model/selection_updates" -import { captureRightClick, ie, ie_version, ios, mac, mobile, presto, webkit } from "../util/browser" -import { activeElt, removeChildrenAndAdd, selectInput } from "../util/dom" -import { e_preventDefault, e_stop, off, on, signalDOMEvent } from "../util/event" -import { hasSelection } from "../util/feature_detection" -import { Delayed, sel_dontScroll } from "../util/misc" +import { operation, runInOp } from "../display/operations.js" +import { prepareSelection } from "../display/selection.js" +import { applyTextInput, copyableRanges, handlePaste, hiddenTextarea, setLastCopied } from "./input.js" +import { cursorCoords, posFromMouse } from "../measurement/position_measurement.js" +import { eventInWidget } from "../measurement/widgets.js" +import { simpleSelection } from "../model/selection.js" +import { selectAll, setSelection } from "../model/selection_updates.js" +import { captureRightClick, ie, ie_version, ios, mac, mobile, presto, webkit } from "../util/browser.js" +import { activeElt, removeChildrenAndAdd, selectInput } from "../util/dom.js" +import { e_preventDefault, e_stop, off, on, signalDOMEvent } from "../util/event.js" +import { hasSelection } from "../util/feature_detection.js" +import { Delayed, sel_dontScroll } from "../util/misc.js" // TEXTAREA INPUT STYLE diff --git a/src/input/indent.js b/src/input/indent.js index 024f5f9254..c88772cb6b 100644 --- a/src/input/indent.js +++ b/src/input/indent.js @@ -1,10 +1,10 @@ -import { getContextBefore } from "../line/highlight" -import { Pos } from "../line/pos" -import { getLine } from "../line/utils_line" -import { replaceRange } from "../model/changes" -import { Range } from "../model/selection" -import { replaceOneSelection } from "../model/selection_updates" -import { countColumn, Pass, spaceStr } from "../util/misc" +import { getContextBefore } from "../line/highlight.js" +import { Pos } from "../line/pos.js" +import { getLine } from "../line/utils_line.js" +import { replaceRange } from "../model/changes.js" +import { Range } from "../model/selection.js" +import { replaceOneSelection } from "../model/selection_updates.js" +import { countColumn, Pass, spaceStr } from "../util/misc.js" // Indent the given line. The how parameter can be "smart", // "add"/null, "subtract", or "prev". When aggressive is false diff --git a/src/input/input.js b/src/input/input.js index fa85209ee8..ff86c39d31 100644 --- a/src/input/input.js +++ b/src/input/input.js @@ -1,15 +1,15 @@ -import { runInOp } from "../display/operations" -import { ensureCursorVisible } from "../display/scrolling" -import { Pos } from "../line/pos" -import { getLine } from "../line/utils_line" -import { makeChange } from "../model/changes" -import { ios, webkit } from "../util/browser" -import { elt } from "../util/dom" -import { lst, map } from "../util/misc" -import { signalLater } from "../util/operation_group" -import { splitLinesAuto } from "../util/feature_detection" +import { runInOp } from "../display/operations.js" +import { ensureCursorVisible } from "../display/scrolling.js" +import { Pos } from "../line/pos.js" +import { getLine } from "../line/utils_line.js" +import { makeChange } from "../model/changes.js" +import { ios, webkit } from "../util/browser.js" +import { elt } from "../util/dom.js" +import { lst, map } from "../util/misc.js" +import { signalLater } from "../util/operation_group.js" +import { splitLinesAuto } from "../util/feature_detection.js" -import { indentLine } from "./indent" +import { indentLine } from "./indent.js" // This will be set to a {lineWise: bool, text: [string]} object, so // that, when pasting, we know what kind of selections the copied diff --git a/src/input/keymap.js b/src/input/keymap.js index 36ac3e61b9..1dfcf8aff6 100644 --- a/src/input/keymap.js +++ b/src/input/keymap.js @@ -1,7 +1,7 @@ -import { flipCtrlCmd, mac, presto } from "../util/browser" -import { map } from "../util/misc" +import { flipCtrlCmd, mac, presto } from "../util/browser.js" +import { map } from "../util/misc.js" -import { keyNames } from "./keynames" +import { keyNames } from "./keynames.js" export let keyMap = {} diff --git a/src/input/movement.js b/src/input/movement.js index 927ed6e14d..8d50fd2a04 100644 --- a/src/input/movement.js +++ b/src/input/movement.js @@ -1,7 +1,7 @@ -import { Pos } from "../line/pos" -import { prepareMeasureForLine, measureCharPrepared, wrappedLineExtentChar } from "../measurement/position_measurement" -import { getBidiPartAt, getOrder } from "../util/bidi" -import { findFirst, lst, skipExtendingChars } from "../util/misc" +import { Pos } from "../line/pos.js" +import { prepareMeasureForLine, measureCharPrepared, wrappedLineExtentChar } from "../measurement/position_measurement.js" +import { getBidiPartAt, getOrder } from "../util/bidi.js" +import { findFirst, lst, skipExtendingChars } from "../util/misc.js" function moveCharLogically(line, ch, dir) { let target = skipExtendingChars(line.text, ch + dir, dir) diff --git a/src/line/highlight.js b/src/line/highlight.js index c5e6b8aacc..79f0884511 100644 --- a/src/line/highlight.js +++ b/src/line/highlight.js @@ -1,9 +1,9 @@ -import { countColumn } from "../util/misc" -import { copyState, innerMode, startState } from "../modes" -import StringStream from "../util/StringStream" +import { countColumn } from "../util/misc.js" +import { copyState, innerMode, startState } from "../modes.js" +import StringStream from "../util/StringStream.js" -import { getLine, lineNo } from "./utils_line" -import { clipPos } from "./pos" +import { getLine, lineNo } from "./utils_line.js" +import { clipPos } from "./pos.js" class SavedContext { constructor(state, lookAhead) { diff --git a/src/line/line_data.js b/src/line/line_data.js index e444184bb0..74acdaffc0 100644 --- a/src/line/line_data.js +++ b/src/line/line_data.js @@ -1,13 +1,13 @@ -import { getOrder } from "../util/bidi" -import { ie, ie_version, webkit } from "../util/browser" -import { elt, eltP, joinClasses } from "../util/dom" -import { eventMixin, signal } from "../util/event" -import { hasBadBidiRects, zeroWidthElement } from "../util/feature_detection" -import { lst, spaceStr } from "../util/misc" +import { getOrder } from "../util/bidi.js" +import { ie, ie_version, webkit } from "../util/browser.js" +import { elt, eltP, joinClasses } from "../util/dom.js" +import { eventMixin, signal } from "../util/event.js" +import { hasBadBidiRects, zeroWidthElement } from "../util/feature_detection.js" +import { lst, spaceStr } from "../util/misc.js" -import { getLineStyles } from "./highlight" -import { attachMarkedSpans, compareCollapsedMarkers, detachMarkedSpans, lineIsHidden, visualLineContinued } from "./spans" -import { getLine, lineNo, updateLineHeight } from "./utils_line" +import { getLineStyles } from "./highlight.js" +import { attachMarkedSpans, compareCollapsedMarkers, detachMarkedSpans, lineIsHidden, visualLineContinued } from "./spans.js" +import { getLine, lineNo, updateLineHeight } from "./utils_line.js" // LINE DATA STRUCTURE diff --git a/src/line/pos.js b/src/line/pos.js index 4f5e4c5594..2a498f8f3c 100644 --- a/src/line/pos.js +++ b/src/line/pos.js @@ -1,4 +1,4 @@ -import { getLine } from "./utils_line" +import { getLine } from "./utils_line.js" // A Pos instance represents a position within the text. export function Pos(line, ch, sticky = null) { diff --git a/src/line/spans.js b/src/line/spans.js index 6c413d2fc2..f7e5f4b6e9 100644 --- a/src/line/spans.js +++ b/src/line/spans.js @@ -1,8 +1,8 @@ -import { indexOf, lst } from "../util/misc" +import { indexOf, lst } from "../util/misc.js" -import { cmp } from "./pos" -import { sawCollapsedSpans } from "./saw_special_spans" -import { getLine, isLine, lineNo } from "./utils_line" +import { cmp } from "./pos.js" +import { sawCollapsedSpans } from "./saw_special_spans.js" +import { getLine, isLine, lineNo } from "./utils_line.js" // TEXTMARKER SPANS diff --git a/src/line/utils_line.js b/src/line/utils_line.js index e4e6943f55..c886294353 100644 --- a/src/line/utils_line.js +++ b/src/line/utils_line.js @@ -1,4 +1,4 @@ -import { indexOf } from "../util/misc" +import { indexOf } from "../util/misc.js" // Find the line object corresponding to the given line number. export function getLine(doc, n) { diff --git a/src/measurement/position_measurement.js b/src/measurement/position_measurement.js index 78986e03db..aeff0e5b8d 100644 --- a/src/measurement/position_measurement.js +++ b/src/measurement/position_measurement.js @@ -1,16 +1,16 @@ -import { buildLineContent, LineView } from "../line/line_data" -import { clipPos, Pos } from "../line/pos" -import { collapsedSpanAtEnd, heightAtLine, lineIsHidden, visualLine } from "../line/spans" -import { getLine, lineAtHeight, lineNo, updateLineHeight } from "../line/utils_line" -import { bidiOther, getBidiPartAt, getOrder } from "../util/bidi" -import { chrome, android, ie, ie_version } from "../util/browser" -import { elt, removeChildren, range, removeChildrenAndAdd } from "../util/dom" -import { e_target } from "../util/event" -import { hasBadZoomedRects } from "../util/feature_detection" -import { countColumn, findFirst, isExtendingChar, scrollerGap, skipExtendingChars } from "../util/misc" -import { updateLineForChanges } from "../display/update_line" - -import { widgetHeight } from "./widgets" +import { buildLineContent, LineView } from "../line/line_data.js" +import { clipPos, Pos } from "../line/pos.js" +import { collapsedSpanAtEnd, heightAtLine, lineIsHidden, visualLine } from "../line/spans.js" +import { getLine, lineAtHeight, lineNo, updateLineHeight } from "../line/utils_line.js" +import { bidiOther, getBidiPartAt, getOrder } from "../util/bidi.js" +import { chrome, android, ie, ie_version } from "../util/browser.js" +import { elt, removeChildren, range, removeChildrenAndAdd } from "../util/dom.js" +import { e_target } from "../util/event.js" +import { hasBadZoomedRects } from "../util/feature_detection.js" +import { countColumn, findFirst, isExtendingChar, scrollerGap, skipExtendingChars } from "../util/misc.js" +import { updateLineForChanges } from "../display/update_line.js" + +import { widgetHeight } from "./widgets.js" // POSITION MEASUREMENT diff --git a/src/measurement/widgets.js b/src/measurement/widgets.js index 554cf80977..39d7553d1f 100644 --- a/src/measurement/widgets.js +++ b/src/measurement/widgets.js @@ -1,5 +1,5 @@ -import { contains, elt, removeChildrenAndAdd } from "../util/dom" -import { e_target } from "../util/event" +import { contains, elt, removeChildrenAndAdd } from "../util/dom.js" +import { e_target } from "../util/event.js" export function widgetHeight(widget) { if (widget.height != null) return widget.height diff --git a/src/model/Doc.js b/src/model/Doc.js index c3da76d74e..b64ac84373 100644 --- a/src/model/Doc.js +++ b/src/model/Doc.js @@ -1,23 +1,23 @@ -import CodeMirror from "../edit/CodeMirror" -import { docMethodOp } from "../display/operations" -import { Line } from "../line/line_data" -import { clipPos, clipPosArray, Pos } from "../line/pos" -import { visualLine } from "../line/spans" -import { getBetween, getLine, getLines, isLine, lineNo } from "../line/utils_line" -import { classTest } from "../util/dom" -import { splitLinesAuto } from "../util/feature_detection" -import { createObj, map, isEmpty, sel_dontScroll } from "../util/misc" -import { ensureCursorVisible, scrollToCoords } from "../display/scrolling" - -import { changeLine, makeChange, makeChangeFromHistory, replaceRange } from "./changes" -import { computeReplacedSel } from "./change_measurement" -import { BranchChunk, LeafChunk } from "./chunk" -import { directionChanged, linkedDocs, updateDoc } from "./document_data" -import { copyHistoryArray, History } from "./history" -import { addLineWidget } from "./line_widget" -import { copySharedMarkers, detachSharedMarkers, findSharedMarkers, markText } from "./mark_text" -import { normalizeSelection, Range, simpleSelection } from "./selection" -import { extendSelection, extendSelections, setSelection, setSelectionReplaceHistory, setSimpleSelection } from "./selection_updates" +import CodeMirror from "../edit/CodeMirror.js" +import { docMethodOp } from "../display/operations.js" +import { Line } from "../line/line_data.js" +import { clipPos, clipPosArray, Pos } from "../line/pos.js" +import { visualLine } from "../line/spans.js" +import { getBetween, getLine, getLines, isLine, lineNo } from "../line/utils_line.js" +import { classTest } from "../util/dom.js" +import { splitLinesAuto } from "../util/feature_detection.js" +import { createObj, map, isEmpty, sel_dontScroll } from "../util/misc.js" +import { ensureCursorVisible, scrollToCoords } from "../display/scrolling.js" + +import { changeLine, makeChange, makeChangeFromHistory, replaceRange } from "./changes.js" +import { computeReplacedSel } from "./change_measurement.js" +import { BranchChunk, LeafChunk } from "./chunk.js" +import { directionChanged, linkedDocs, updateDoc } from "./document_data.js" +import { copyHistoryArray, History } from "./history.js" +import { addLineWidget } from "./line_widget.js" +import { copySharedMarkers, detachSharedMarkers, findSharedMarkers, markText } from "./mark_text.js" +import { normalizeSelection, Range, simpleSelection } from "./selection.js" +import { extendSelection, extendSelections, setSelection, setSelectionReplaceHistory, setSimpleSelection } from "./selection_updates.js" let nextDocId = 0 let Doc = function(text, mode, firstLine, lineSep, direction) { diff --git a/src/model/change_measurement.js b/src/model/change_measurement.js index 881f39eb46..4d45313dee 100644 --- a/src/model/change_measurement.js +++ b/src/model/change_measurement.js @@ -1,7 +1,7 @@ -import { cmp, Pos } from "../line/pos" -import { lst } from "../util/misc" +import { cmp, Pos } from "../line/pos.js" +import { lst } from "../util/misc.js" -import { normalizeSelection, Range, Selection } from "./selection" +import { normalizeSelection, Range, Selection } from "./selection.js" // Compute the position of the end of a change (its 'to' property // refers to the pre-change end). diff --git a/src/model/changes.js b/src/model/changes.js index cfad529c68..b00e29b13d 100644 --- a/src/model/changes.js +++ b/src/model/changes.js @@ -1,21 +1,21 @@ -import { retreatFrontier } from "../line/highlight" -import { startWorker } from "../display/highlight_worker" -import { operation } from "../display/operations" -import { regChange, regLineChange } from "../display/view_tracking" -import { clipLine, clipPos, cmp, Pos } from "../line/pos" -import { sawReadOnlySpans } from "../line/saw_special_spans" -import { lineLength, removeReadOnlyRanges, stretchSpansOverChange, visualLine } from "../line/spans" -import { getBetween, getLine, lineNo } from "../line/utils_line" -import { estimateHeight } from "../measurement/position_measurement" -import { hasHandler, signal, signalCursorActivity } from "../util/event" -import { indexOf, lst, map, sel_dontScroll } from "../util/misc" -import { signalLater } from "../util/operation_group" - -import { changeEnd, computeSelAfterChange } from "./change_measurement" -import { isWholeLineUpdate, linkedDocs, updateDoc } from "./document_data" -import { addChangeToHistory, historyChangeFromChange, mergeOldSpans, pushSelectionToHistory } from "./history" -import { Range, Selection } from "./selection" -import { setSelection, setSelectionNoUndo } from "./selection_updates" +import { retreatFrontier } from "../line/highlight.js" +import { startWorker } from "../display/highlight_worker.js" +import { operation } from "../display/operations.js" +import { regChange, regLineChange } from "../display/view_tracking.js" +import { clipLine, clipPos, cmp, Pos } from "../line/pos.js" +import { sawReadOnlySpans } from "../line/saw_special_spans.js" +import { lineLength, removeReadOnlyRanges, stretchSpansOverChange, visualLine } from "../line/spans.js" +import { getBetween, getLine, lineNo } from "../line/utils_line.js" +import { estimateHeight } from "../measurement/position_measurement.js" +import { hasHandler, signal, signalCursorActivity } from "../util/event.js" +import { indexOf, lst, map, sel_dontScroll } from "../util/misc.js" +import { signalLater } from "../util/operation_group.js" + +import { changeEnd, computeSelAfterChange } from "./change_measurement.js" +import { isWholeLineUpdate, linkedDocs, updateDoc } from "./document_data.js" +import { addChangeToHistory, historyChangeFromChange, mergeOldSpans, pushSelectionToHistory } from "./history.js" +import { Range, Selection } from "./selection.js" +import { setSelection, setSelectionNoUndo } from "./selection_updates.js" // UPDATING diff --git a/src/model/chunk.js b/src/model/chunk.js index 056ef91bb9..d82716ded4 100644 --- a/src/model/chunk.js +++ b/src/model/chunk.js @@ -1,6 +1,6 @@ -import { cleanUpLine } from "../line/line_data" -import { indexOf } from "../util/misc" -import { signalLater } from "../util/operation_group" +import { cleanUpLine } from "../line/line_data.js" +import { indexOf } from "../util/misc.js" +import { signalLater } from "../util/operation_group.js" // The document is represented as a BTree consisting of leaves, with // chunk of lines in them, and branches, with up to ten leaves or diff --git a/src/model/document_data.js b/src/model/document_data.js index 7f6e3367d1..d946e7af10 100644 --- a/src/model/document_data.js +++ b/src/model/document_data.js @@ -1,13 +1,13 @@ -import { loadMode } from "../display/mode_state" -import { runInOp } from "../display/operations" -import { regChange } from "../display/view_tracking" -import { Line, updateLine } from "../line/line_data" -import { findMaxLine } from "../line/spans" -import { getLine } from "../line/utils_line" -import { estimateLineHeights } from "../measurement/position_measurement" -import { addClass, rmClass } from "../util/dom" -import { lst } from "../util/misc" -import { signalLater } from "../util/operation_group" +import { loadMode } from "../display/mode_state.js" +import { runInOp } from "../display/operations.js" +import { regChange } from "../display/view_tracking.js" +import { Line, updateLine } from "../line/line_data.js" +import { findMaxLine } from "../line/spans.js" +import { getLine } from "../line/utils_line.js" +import { estimateLineHeights } from "../measurement/position_measurement.js" +import { addClass, rmClass } from "../util/dom.js" +import { lst } from "../util/misc.js" +import { signalLater } from "../util/operation_group.js" // DOCUMENT DATA STRUCTURE diff --git a/src/model/history.js b/src/model/history.js index 83938cf4c1..753a89da92 100644 --- a/src/model/history.js +++ b/src/model/history.js @@ -1,12 +1,12 @@ -import { cmp, copyPos } from "../line/pos" -import { stretchSpansOverChange } from "../line/spans" -import { getBetween } from "../line/utils_line" -import { signal } from "../util/event" -import { indexOf, lst } from "../util/misc" - -import { changeEnd } from "./change_measurement" -import { linkedDocs } from "./document_data" -import { Selection } from "./selection" +import { cmp, copyPos } from "../line/pos.js" +import { stretchSpansOverChange } from "../line/spans.js" +import { getBetween } from "../line/utils_line.js" +import { signal } from "../util/event.js" +import { indexOf, lst } from "../util/misc.js" + +import { changeEnd } from "./change_measurement.js" +import { linkedDocs } from "./document_data.js" +import { Selection } from "./selection.js" export function History(startGen) { // Arrays of change events and selections. Doing something adds an diff --git a/src/model/line_widget.js b/src/model/line_widget.js index a11f9c2742..4a82d5389e 100644 --- a/src/model/line_widget.js +++ b/src/model/line_widget.js @@ -1,12 +1,12 @@ -import { runInOp } from "../display/operations" -import { addToScrollTop } from "../display/scrolling" -import { regLineChange } from "../display/view_tracking" -import { heightAtLine, lineIsHidden } from "../line/spans" -import { lineNo, updateLineHeight } from "../line/utils_line" -import { widgetHeight } from "../measurement/widgets" -import { changeLine } from "./changes" -import { eventMixin } from "../util/event" -import { signalLater } from "../util/operation_group" +import { runInOp } from "../display/operations.js" +import { addToScrollTop } from "../display/scrolling.js" +import { regLineChange } from "../display/view_tracking.js" +import { heightAtLine, lineIsHidden } from "../line/spans.js" +import { lineNo, updateLineHeight } from "../line/utils_line.js" +import { widgetHeight } from "../measurement/widgets.js" +import { changeLine } from "./changes.js" +import { eventMixin } from "../util/event.js" +import { signalLater } from "../util/operation_group.js" // Line widgets are block elements displayed above or below a line. diff --git a/src/model/mark_text.js b/src/model/mark_text.js index ccdcc9d3b8..955c72c4a7 100644 --- a/src/model/mark_text.js +++ b/src/model/mark_text.js @@ -1,19 +1,19 @@ -import { eltP } from "../util/dom" -import { eventMixin, hasHandler, on } from "../util/event" -import { endOperation, operation, runInOp, startOperation } from "../display/operations" -import { clipPos, cmp, Pos } from "../line/pos" -import { lineNo, updateLineHeight } from "../line/utils_line" -import { clearLineMeasurementCacheFor, findViewForLine, textHeight } from "../measurement/position_measurement" -import { seeReadOnlySpans, seeCollapsedSpans } from "../line/saw_special_spans" -import { addMarkedSpan, conflictingCollapsedRange, getMarkedSpanFor, lineIsHidden, lineLength, MarkedSpan, removeMarkedSpan, visualLine } from "../line/spans" -import { copyObj, indexOf, lst } from "../util/misc" -import { signalLater } from "../util/operation_group" -import { widgetHeight } from "../measurement/widgets" -import { regChange, regLineChange } from "../display/view_tracking" +import { eltP } from "../util/dom.js" +import { eventMixin, hasHandler, on } from "../util/event.js" +import { endOperation, operation, runInOp, startOperation } from "../display/operations.js" +import { clipPos, cmp, Pos } from "../line/pos.js" +import { lineNo, updateLineHeight } from "../line/utils_line.js" +import { clearLineMeasurementCacheFor, findViewForLine, textHeight } from "../measurement/position_measurement.js" +import { seeReadOnlySpans, seeCollapsedSpans } from "../line/saw_special_spans.js" +import { addMarkedSpan, conflictingCollapsedRange, getMarkedSpanFor, lineIsHidden, lineLength, MarkedSpan, removeMarkedSpan, visualLine } from "../line/spans.js" +import { copyObj, indexOf, lst } from "../util/misc.js" +import { signalLater } from "../util/operation_group.js" +import { widgetHeight } from "../measurement/widgets.js" +import { regChange, regLineChange } from "../display/view_tracking.js" -import { linkedDocs } from "./document_data" -import { addChangeToHistory } from "./history" -import { reCheckSelection } from "./selection_updates" +import { linkedDocs } from "./document_data.js" +import { addChangeToHistory } from "./history.js" +import { reCheckSelection } from "./selection_updates.js" // TEXTMARKERS diff --git a/src/model/selection.js b/src/model/selection.js index 97084fbc15..2e374aa822 100644 --- a/src/model/selection.js +++ b/src/model/selection.js @@ -1,5 +1,5 @@ -import { cmp, copyPos, equalCursorPos, maxPos, minPos } from "../line/pos" -import { indexOf } from "../util/misc" +import { cmp, copyPos, equalCursorPos, maxPos, minPos } from "../line/pos.js" +import { indexOf } from "../util/misc.js" // Selection objects are immutable. A new one is created every time // the selection changes. A selection is one or more non-overlapping diff --git a/src/model/selection_updates.js b/src/model/selection_updates.js index bf5ad8c76f..77986a9e9a 100644 --- a/src/model/selection_updates.js +++ b/src/model/selection_updates.js @@ -1,12 +1,12 @@ -import { signalLater } from "../util/operation_group" -import { ensureCursorVisible } from "../display/scrolling" -import { clipPos, cmp, Pos } from "../line/pos" -import { getLine } from "../line/utils_line" -import { hasHandler, signal, signalCursorActivity } from "../util/event" -import { lst, sel_dontScroll } from "../util/misc" - -import { addSelectionToHistory } from "./history" -import { normalizeSelection, Range, Selection, simpleSelection } from "./selection" +import { signalLater } from "../util/operation_group.js" +import { ensureCursorVisible } from "../display/scrolling.js" +import { clipPos, cmp, Pos } from "../line/pos.js" +import { getLine } from "../line/utils_line.js" +import { hasHandler, signal, signalCursorActivity } from "../util/event.js" +import { lst, sel_dontScroll } from "../util/misc.js" + +import { addSelectionToHistory } from "./history.js" +import { normalizeSelection, Range, Selection, simpleSelection } from "./selection.js" // The 'scroll' parameter given to many of these indicated whether // the new cursor position should be scrolled into view after diff --git a/src/modes.js b/src/modes.js index 065a463b5b..8384517027 100644 --- a/src/modes.js +++ b/src/modes.js @@ -1,4 +1,4 @@ -import { copyObj, createObj } from "./util/misc" +import { copyObj, createObj } from "./util/misc.js" // Known modes, by name and by MIME export let modes = {}, mimeModes = {} diff --git a/src/util/StringStream.js b/src/util/StringStream.js index a14b1b6430..022c4bc209 100644 --- a/src/util/StringStream.js +++ b/src/util/StringStream.js @@ -1,4 +1,4 @@ -import { countColumn } from "./misc" +import { countColumn } from "./misc.js" // STRING STREAM diff --git a/src/util/bidi.js b/src/util/bidi.js index 3d13dd86d2..33ab854d88 100644 --- a/src/util/bidi.js +++ b/src/util/bidi.js @@ -1,4 +1,4 @@ -import { lst } from "./misc" +import { lst } from "./misc.js" // BIDI HELPERS diff --git a/src/util/dom.js b/src/util/dom.js index 94823c21b9..04d2569d28 100644 --- a/src/util/dom.js +++ b/src/util/dom.js @@ -1,4 +1,4 @@ -import { ie, ios } from "./browser" +import { ie, ios } from "./browser.js" export function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") } diff --git a/src/util/event.js b/src/util/event.js index 29fd4c5981..4b6c770578 100644 --- a/src/util/event.js +++ b/src/util/event.js @@ -1,5 +1,5 @@ -import { mac } from "./browser" -import { indexOf } from "./misc" +import { mac } from "./browser.js" +import { indexOf } from "./misc.js" // EVENT HANDLING diff --git a/src/util/feature_detection.js b/src/util/feature_detection.js index e65881d4ca..c33734ebb9 100644 --- a/src/util/feature_detection.js +++ b/src/util/feature_detection.js @@ -1,5 +1,5 @@ -import { elt, range, removeChildren, removeChildrenAndAdd } from "./dom" -import { ie, ie_version } from "./browser" +import { elt, range, removeChildren, removeChildrenAndAdd } from "./dom.js" +import { ie, ie_version } from "./browser.js" // Detect drag-and-drop export let dragAndDrop = function() { diff --git a/src/util/operation_group.js b/src/util/operation_group.js index b8fa78ac48..f6815949d8 100644 --- a/src/util/operation_group.js +++ b/src/util/operation_group.js @@ -1,4 +1,4 @@ -import { getHandlers } from "./event" +import { getHandlers } from "./event.js" let operationGroup = null From 85fb7510976c8e0d443d44b7788c3066541fc470 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 9 Nov 2017 09:49:42 +0100 Subject: [PATCH 0717/1880] [javascript mode] Recognize async when in front of single-line block comment Closes #5078 --- mode/javascript/javascript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 5c772526f2..139e53dfe4 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -153,7 +153,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var kw = keywords[word] return ret(kw.type, kw.style, word) } - if (word == "async" && stream.match(/^\s*[\(\w]/, false)) + if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\(\w]/, false)) return ret("async", "keyword", word) } return ret("variable", "variable", word) From 1ba861a09f01f7205c36fb467660ed970a1c0054 Mon Sep 17 00:00:00 2001 From: Joel Einbinder Date: Wed, 8 Nov 2017 15:56:23 -0800 Subject: [PATCH 0718/1880] [javascript mode] Test for comments between async and function keywords --- mode/javascript/test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mode/javascript/test.js b/mode/javascript/test.js index 213bab06a8..d560fdbacb 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -230,6 +230,9 @@ "[keyword const] [def async] [operator =] {[property a]: [number 1]};", "[keyword const] [def foo] [operator =] [string-2 `bar ${][variable async].[property a][string-2 }`];") + MT("async_comment", + "[keyword async] [comment /**/] [keyword function] [def foo]([def args]) { [keyword return] [atom true]; }"); + MT("indent_switch", "[keyword switch] ([variable x]) {", " [keyword default]:", From a29e048d20e5a256dd48bc49e1afae6f9d1a252a Mon Sep 17 00:00:00 2001 From: Jakub Vrana Date: Fri, 10 Nov 2017 14:29:19 +0100 Subject: [PATCH 0719/1880] [soy mode] Support comments in all contexts --- mode/soy/soy.js | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/mode/soy/soy.js b/mode/soy/soy.js index 0e24457042..98f308658e 100644 --- a/mode/soy/soy.js +++ b/mode/soy/soy.js @@ -137,6 +137,25 @@ } return "comment"; + case "string": + var match = stream.match(/^.*?(["']|\\[\s\S])/); + if (!match) { + stream.skipToEnd(); + } else if (match[1] == state.quoteKind) { + state.quoteKind = null; + state.soyState.pop(); + } + return "string"; + } + + if (stream.match(/^\/\*/)) { + state.soyState.push("comment"); + return "comment"; + } else if (stream.match(stream.sol() || (state.soyState.length && last(state.soyState) != "literal") ? /^\s*\/\/.*/ : /^\s+\/\/.*/)) { + return "comment"; + } + + switch (last(state.soyState)) { case "templ-def": if (match = stream.match(/^\.?([\w]+(?!\.[\w]+)*)/)) { state.templates = prepend(state.templates, match[1]); @@ -242,36 +261,15 @@ return this.token(stream, state); } return tokenUntil(stream, state, /\{\/literal}/); - - case "string": - var match = stream.match(/^.*?(["']|\\[\s\S])/); - if (!match) { - stream.skipToEnd(); - } else if (match[1] == state.quoteKind) { - state.quoteKind = null; - state.soyState.pop(); - } - return "string"; } - if (stream.match(/^\/\*/)) { - state.soyState.push("comment"); - if (!state.scopes) { - state.variables = prepend(null, 'ij'); - } - return "comment"; - } else if (stream.match(stream.sol() ? /^\s*\/\/.*/ : /^\s+\/\/.*/)) { - if (!state.scopes) { - state.variables = prepend(null, 'ij'); - } - return "comment"; - } else if (stream.match(/^\{literal}/)) { + if (stream.match(/^\{literal}/)) { state.indent += config.indentUnit; state.soyState.push("literal"); return "keyword"; - // A tag-keyword must be followed by whitespace or a closing tag. - } else if (match = stream.match(/^\{([\/@\\]?\w+\??)(?=[\s\}])/)) { + // A tag-keyword must be followed by whitespace, comment or a closing tag. + } else if (match = stream.match(/^\{([\/@\\]?\w+\??)(?=[\s\}]|\/[/*])/)) { if (match[1] != "/switch") state.indent += (/^(\/|(else|elseif|ifempty|case|fallbackmsg|default)$)/.test(match[1]) && state.tag != "switch" ? 1 : 2) * config.indentUnit; state.tag = match[1]; From b881f2520461c7fc98ca1673071d0eb74ddd7c39 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 13 Nov 2017 09:40:40 +0100 Subject: [PATCH 0720/1880] [emacs mode] Prevent backspace/delete/etc from adding to the kill ring Closes #5084 --- keymap/emacs.js | 42 +++++++++++++++++++++--------------------- test/emacs_test.js | 2 ++ 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/keymap/emacs.js b/keymap/emacs.js index 33db0c15a2..3160453283 100644 --- a/keymap/emacs.js +++ b/keymap/emacs.js @@ -30,16 +30,16 @@ var lastKill = null; - function kill(cm, from, to, mayGrow, text) { + function kill(cm, from, to, ring, text) { if (text == null) text = cm.getRange(from, to); - if (mayGrow && lastKill && lastKill.cm == cm && posEq(from, lastKill.pos) && cm.isClean(lastKill.gen)) + if (ring == "grow" && lastKill && lastKill.cm == cm && posEq(from, lastKill.pos) && cm.isClean(lastKill.gen)) growRingTop(text); - else + else if (ring !== false) addToRing(text); cm.replaceRange("", from, to, "+delete"); - if (mayGrow) lastKill = {cm: cm, pos: from, gen: cm.changeGeneration()}; + if (ring == "grow") lastKill = {cm: cm, pos: from, gen: cm.changeGeneration()}; else lastKill = null; } @@ -151,22 +151,22 @@ return f; } - function killTo(cm, by, dir) { + function killTo(cm, by, dir, ring) { var selections = cm.listSelections(), cursor; var i = selections.length; while (i--) { cursor = selections[i].head; - kill(cm, cursor, findEnd(cm, cursor, by, dir), true); + kill(cm, cursor, findEnd(cm, cursor, by, dir), ring); } } - function killRegion(cm) { + function killRegion(cm, ring) { if (cm.somethingSelected()) { var selections = cm.listSelections(), selection; var i = selections.length; while (i--) { selection = selections[i]; - kill(cm, selection.anchor, selection.head); + kill(cm, selection.anchor, selection.head, ring); } return true; } @@ -276,7 +276,7 @@ // Actual keymap var keyMap = CodeMirror.keyMap.emacs = CodeMirror.normalizeKeyMap({ - "Ctrl-W": function(cm) {kill(cm, cm.getCursor("start"), cm.getCursor("end"));}, + "Ctrl-W": function(cm) {kill(cm, cm.getCursor("start"), cm.getCursor("end"), true);}, "Ctrl-K": repeated(function(cm) { var start = cm.getCursor(), end = cm.clipPos(Pos(start.line)); var text = cm.getRange(start, end); @@ -284,7 +284,7 @@ text += "\n"; end = Pos(start.line + 1, 0); } - kill(cm, start, end, true, text); + kill(cm, start, end, "grow", text); }), "Alt-W": function(cm) { addToRing(cm.getSelection()); @@ -301,14 +301,14 @@ "Ctrl-F": move(byChar, 1), "Ctrl-B": move(byChar, -1), "Right": move(byChar, 1), "Left": move(byChar, -1), - "Ctrl-D": function(cm) { killTo(cm, byChar, 1); }, - "Delete": function(cm) { killRegion(cm) || killTo(cm, byChar, 1); }, - "Ctrl-H": function(cm) { killTo(cm, byChar, -1); }, - "Backspace": function(cm) { killRegion(cm) || killTo(cm, byChar, -1); }, + "Ctrl-D": function(cm) { killTo(cm, byChar, 1, false); }, + "Delete": function(cm) { killRegion(cm, false) || killTo(cm, byChar, 1, false); }, + "Ctrl-H": function(cm) { killTo(cm, byChar, -1, false); }, + "Backspace": function(cm) { killRegion(cm, false) || killTo(cm, byChar, -1, false); }, "Alt-F": move(byWord, 1), "Alt-B": move(byWord, -1), - "Alt-D": function(cm) { killTo(cm, byWord, 1); }, - "Alt-Backspace": function(cm) { killTo(cm, byWord, -1); }, + "Alt-D": function(cm) { killTo(cm, byWord, 1, "grow"); }, + "Alt-Backspace": function(cm) { killTo(cm, byWord, -1, "grow"); }, "Ctrl-N": move(byLine, 1), "Ctrl-P": move(byLine, -1), "Down": move(byLine, 1), "Up": move(byLine, -1), @@ -321,11 +321,11 @@ "Ctrl-Up": move(byParagraph, -1), "Ctrl-Down": move(byParagraph, 1), "Alt-A": move(bySentence, -1), "Alt-E": move(bySentence, 1), - "Alt-K": function(cm) { killTo(cm, bySentence, 1); }, + "Alt-K": function(cm) { killTo(cm, bySentence, 1, "grow"); }, - "Ctrl-Alt-K": function(cm) { killTo(cm, byExpr, 1); }, - "Ctrl-Alt-Backspace": function(cm) { killTo(cm, byExpr, -1); }, - "Ctrl-Alt-F": move(byExpr, 1), "Ctrl-Alt-B": move(byExpr, -1), + "Ctrl-Alt-K": function(cm) { killTo(cm, byExpr, 1, "grow"); }, + "Ctrl-Alt-Backspace": function(cm) { killTo(cm, byExpr, -1, "grow"); }, + "Ctrl-Alt-F": move(byExpr, 1), "Ctrl-Alt-B": move(byExpr, -1, "grow"), "Shift-Ctrl-Alt-2": function(cm) { var cursor = cm.getCursor(); @@ -398,7 +398,7 @@ "Ctrl-X F": "open", "Ctrl-X U": repeated("undo"), "Ctrl-X K": "close", - "Ctrl-X Delete": function(cm) { kill(cm, cm.getCursor(), bySentence(cm, cm.getCursor(), 1), true); }, + "Ctrl-X Delete": function(cm) { kill(cm, cm.getCursor(), bySentence(cm, cm.getCursor(), 1), "grow"); }, "Ctrl-X H": "selectAll", "Ctrl-Q Tab": repeated("insertTab"), diff --git a/test/emacs_test.js b/test/emacs_test.js index b73eedaa6a..412dba4b42 100644 --- a/test/emacs_test.js +++ b/test/emacs_test.js @@ -131,6 +131,8 @@ sim("delRegion", "abcde", "Ctrl-Space", "Ctrl-F", "Ctrl-F", "Delete", txt("cde")); sim("backspaceRegion", "abcde", "Ctrl-Space", "Ctrl-F", "Ctrl-F", "Backspace", txt("cde")); + sim("backspaceDoesntAddToRing", "foobar", "Ctrl-F", "Ctrl-F", "Ctrl-F", "Ctrl-K", "Backspace", "Backspace", "Ctrl-Y", txt("fbar")); + testCM("save", function(cm) { var saved = false; CodeMirror.commands.save = function(cm) { saved = cm.getValue(); }; From 2cb90ecdce8e7814b0b45a10e3bf6aed48d9a2a7 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Fri, 17 Nov 2017 20:45:01 +0100 Subject: [PATCH 0721/1880] [javascript mode] Highlight type in generic call Closes #5048. --- mode/javascript/javascript.js | 1 + mode/javascript/test.js | 3 +++ 2 files changed, 4 insertions(+) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 139e53dfe4..e43543dd3c 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -438,6 +438,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); if (type == "operator") { if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me); + if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, maybeoperatorNoComma); if (value == "?") return cont(expression, expect(":"), expr); return cont(expr); } diff --git a/mode/javascript/test.js b/mode/javascript/test.js index d560fdbacb..972a345651 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -371,6 +371,9 @@ TS("arrow prop", "({[property a]: [def p] [operator =>] [variable-2 p]})") + TS("generic in function call", + "[keyword this].[property a][operator <][type Type][operator >]([variable foo]);") + var jsonld_mode = CodeMirror.getMode( {indentUnit: 2}, {name: "javascript", jsonld: true} From 490653454aa985feb60918eeddde823c550e416e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 20 Nov 2017 10:36:30 +0100 Subject: [PATCH 0722/1880] [javascript mode] Resolve ambiguity for type parameters vs less-than See https://github.com/Microsoft/TypeScript/blob/6c4c10c7cf294dc71f943314e29a7dd1b6e88c6a/doc/spec.md#4.15.3 Issue #5090 Issue #5048 --- mode/javascript/javascript.js | 3 ++- mode/javascript/test.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index e43543dd3c..0dcd8af391 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -438,7 +438,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); if (type == "operator") { if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me); - if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, maybeoperatorNoComma); + if (isTS && value == "<" && cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false)) + return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me); if (value == "?") return cont(expression, expect(":"), expr); return cont(expr); } diff --git a/mode/javascript/test.js b/mode/javascript/test.js index 972a345651..2437edcca5 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -372,7 +372,8 @@ "({[property a]: [def p] [operator =>] [variable-2 p]})") TS("generic in function call", - "[keyword this].[property a][operator <][type Type][operator >]([variable foo]);") + "[keyword this].[property a][operator <][type Type][operator >]([variable foo]);", + "[keyword this].[property a][operator <][variable Type][operator >][variable foo];") var jsonld_mode = CodeMirror.getMode( {indentUnit: 2}, From e51b94ff4890d01d0ee1b97da575440b65429edf Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 20 Nov 2017 12:16:06 +0100 Subject: [PATCH 0723/1880] [show-hint addon] Drop suspicious-looking logic Issue #4792 --- addon/hint/show-hint.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index f72a0a9c69..62c683cb8c 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -121,7 +121,6 @@ var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); if (this.widget) this.widget.close(); - if (data && this.data && isNewCompletion(this.data, data)) return; this.data = data; if (data && data.list.length) { @@ -135,11 +134,6 @@ } }; - function isNewCompletion(old, nw) { - var moved = CodeMirror.cmpPos(nw.from, old.from) - return moved > 0 && old.to.ch - old.from.ch != nw.to.ch - nw.from.ch - } - function parseOptions(cm, pos, options) { var editor = cm.options.hintOptions; var out = {}; From 66414ce35ba441b766117b5f8cf53a1850a7362e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 22 Nov 2017 09:59:21 +0100 Subject: [PATCH 0724/1880] [javascript mode] Recognize TypeScript type guards Closes #5093 --- mode/javascript/javascript.js | 14 +++++++++++++- mode/javascript/test.js | 8 ++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 0dcd8af391..4978d8d1e7 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -566,6 +566,18 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (value == "?") return cont(maybetype); } } + function mayberettype(type, value) { + if (isTS && type == ":") { + if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr) + else return cont(typeexpr) + } + } + function isKW(_, value) { + if (value == "is") { + cx.marked = "keyword" + return cont() + } + } function typeexpr(type, value) { if (type == "variable" || value == "void") { if (value == "keyof") { @@ -668,7 +680,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function functiondef(type, value) { if (value == "*") {cx.marked = "keyword"; return cont(functiondef);} if (type == "variable") {register(value); return cont(functiondef);} - if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext); + if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext); if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef) } function funarg(type, value) { diff --git a/mode/javascript/test.js b/mode/javascript/test.js index 2437edcca5..167e6d0165 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -375,6 +375,14 @@ "[keyword this].[property a][operator <][type Type][operator >]([variable foo]);", "[keyword this].[property a][operator <][variable Type][operator >][variable foo];") + TS("type guard", + "[keyword class] [def Appler] {", + " [keyword static] [property assertApple]([def fruit]: [type Fruit]): [variable-2 fruit] [keyword is] [type Apple] {", + " [keyword if] ([operator !]([variable-2 fruit] [keyword instanceof] [variable Apple]))", + " [keyword throw] [keyword new] [variable Error]();", + " }", + "}") + var jsonld_mode = CodeMirror.getMode( {indentUnit: 2}, {name: "javascript", jsonld: true} From d98aac7b948ef36d0611e5d50f461e3848b925b2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 22 Nov 2017 10:01:54 +0100 Subject: [PATCH 0725/1880] Please linter, remove unused arg --- CHANGELOG.md | 4 ++++ mode/javascript/javascript.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 409c7234bb..1fa5781617 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 5.32.0 (2017-11-22) + + + ## 5.31.0 (2017-10-20) ### Bug fixes diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 4978d8d1e7..514de1c8da 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -566,7 +566,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (value == "?") return cont(maybetype); } } - function mayberettype(type, value) { + function mayberettype(type) { if (isTS && type == ":") { if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr) else return cont(typeexpr) From 89595f55b19ea0584e4721128c149f918795a384 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 22 Nov 2017 10:10:50 +0100 Subject: [PATCH 0726/1880] Mark version 5.32.0 --- AUTHORS | 3 +++ CHANGELOG.md | 16 ++++++++++++++++ doc/manual.html | 2 +- doc/releases.html | 12 ++++++++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 35 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index f800b86b7d..65d8480893 100644 --- a/AUTHORS +++ b/AUTHORS @@ -118,6 +118,7 @@ Caitlin Potter Calin Barbat callodacity Camilo Roca +Casey Klebba Chad Jolly Chandra Sekhar Pydi Charles Skelton @@ -300,6 +301,7 @@ Jason Grout Jason Johnston Jason San Jose Jason Siefken +Jayaprabhakar Jaydeep Solanki Jean Boussier Jeff Blaisdell @@ -327,6 +329,7 @@ John Van Der Loo Jon Ander Peñalba Jonas Döbertin Jonas Helfer +Jonathan Hart Jonathan Malmaud Jon Gacnik jongalloway diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fa5781617..f81fcdd07b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,22 @@ ## 5.32.0 (2017-11-22) +### Bug fixes + +Increase contrast on default bracket-matching colors. + +[javascript mode](http://codemirror.net/mode/javascript/): Recognize TypeScript type parameters for calls, type guards, and type parameter defaults. Improve handling of `enum` and `module` keywords. + +[comment addon](http://codemirror.net/doc/manual.html#addon_comment): Fix bug when uncommenting a comment that spans all but the last selected line. + +[searchcursor addon](http://codemirror.net/doc/manual.html#addon_searchcursor): Fix bug in case folding. + +[emacs bindings](http://codemirror.net/demo/emacs.html): Prevent single-character deletions from resetting the kill ring. + +[closebrackets addon](http://codemirror.net/doc/manual.html#addon_closebrackets): Tweak quote matching behavior. + +### New features +[continuelist addon](http://codemirror.net/doc/manual.html#addon_continuelist): Increment ordered list numbers when adding one. ## 5.31.0 (2017-10-20) diff --git a/doc/manual.html b/doc/manual.html index 7666e0df63..f46e6bd5ab 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.31.1 + version 5.32.0

    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 23de4c8023..7fb8eebef1 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,18 @@

    Release notes and version history

    Version 5.x

    +

    22-11-2017: Version 5.32.0:

    + +
      +
    • Increase contrast on default bracket-matching colors.
    • +
    • javascript mode: Recognize TypeScript type parameters for calls, type guards, and type parameter defaults. Improve handling of enum and module keywords.
    • +
    • comment addon: Fix bug when uncommenting a comment that spans all but the last selected line.
    • +
    • searchcursor addon: Fix bug in case folding.
    • +
    • emacs bindings: Prevent single-character deletions from resetting the kill ring.
    • +
    • closebrackets addon: Tweak quote matching behavior.
    • +
    • continuelist addon: Increment ordered list numbers when adding one.
    • +
    +

    20-10-2017: Version 5.31.0:

      diff --git a/index.html b/index.html index 555e4804aa..d62ab84a39 100644 --- a/index.html +++ b/index.html @@ -96,7 +96,7 @@

      This is CodeMirror

    - Get the current version: 5.31.0.
    + Get the current version: 5.32.0.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index 6eda061f17..3e9f20c650 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.31.1", + "version": "5.32.0", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "description": "Full-featured in-browser code editor", diff --git a/src/edit/main.js b/src/edit/main.js index 6d9eb8790b..c89e5d8792 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.31.1" +CodeMirror.version = "5.32.0" From 2e857fa36604aebe0a7c1955a9ca5137ee00e3f5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 22 Nov 2017 10:12:55 +0100 Subject: [PATCH 0727/1880] Bump version number post-5.32 --- doc/manual.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index f46e6bd5ab..ea5642cdf9 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.32.0 + version 5.32.1

    CodeMirror is a code-editor component that can be embedded in diff --git a/package.json b/package.json index 3e9f20c650..3ffad1d5d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.32.0", + "version": "5.32.1", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "description": "Full-featured in-browser code editor", diff --git a/src/edit/main.js b/src/edit/main.js index c89e5d8792..260f7d0af5 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.32.0" +CodeMirror.version = "5.32.1" From 058e8219b2d040b131eb99ca7ad00b53bafe9886 Mon Sep 17 00:00:00 2001 From: satamas Date: Thu, 23 Nov 2017 16:32:43 +0300 Subject: [PATCH 0728/1880] Add new kotlin keywords. --- mode/clike/clike.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 02a85319ff..ff00cf5002 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -578,7 +578,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { "file import where by get set abstract enum open inner override private public internal " + "protected catch finally out final vararg reified dynamic companion constructor init " + "sealed field property receiver param sparam lateinit data inline noinline tailrec " + - "external annotation crossinline const operator infix suspend" + "external annotation crossinline const operator infix suspend actual expect" ), types: words( /* package java.lang */ From d60e0ccaadaaa2f9bc967594909def5f80231a22 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 27 Nov 2017 11:19:46 +0100 Subject: [PATCH 0729/1880] [tern addon] Guard against relatedTarget being null Closes #5095 --- addon/tern/tern.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/tern/tern.js b/addon/tern/tern.js index a80dc7e4b8..70202c6fc5 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -614,7 +614,8 @@ var mouseOnTip = false, old = false; CodeMirror.on(tip, "mousemove", function() { mouseOnTip = true; }); CodeMirror.on(tip, "mouseout", function(e) { - if (!CodeMirror.contains(tip, e.relatedTarget || e.toElement)) { + let related = e.relatedTarget || e.toElement + if (!related || !CodeMirror.contains(tip, related)) { if (old) clear(); else mouseOnTip = false; } From 95b64d1a1c8004aab0f9e9ea39a0c48689d4e028 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 27 Nov 2017 11:23:17 +0100 Subject: [PATCH 0730/1880] Fix es6-ism in addon --- addon/tern/tern.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/tern/tern.js b/addon/tern/tern.js index 70202c6fc5..6276b53893 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -614,7 +614,7 @@ var mouseOnTip = false, old = false; CodeMirror.on(tip, "mousemove", function() { mouseOnTip = true; }); CodeMirror.on(tip, "mouseout", function(e) { - let related = e.relatedTarget || e.toElement + var related = e.relatedTarget || e.toElement if (!related || !CodeMirror.contains(tip, related)) { if (old) clear(); else mouseOnTip = false; From 8bb35c475f0dfc05c4b2617e778fed1acf3f3a68 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 1 Dec 2017 10:24:21 +0100 Subject: [PATCH 0731/1880] [lint addon] Wrap display updates in an operation Closes #5106 --- addon/lint/lint.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/lint/lint.js b/addon/lint/lint.js index a9eb8fa66b..e00e77a20c 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -132,7 +132,7 @@ cm.off("change", abort) if (state.waitingFor != id) return if (arg2 && annotations instanceof CodeMirror) annotations = arg2 - updateLinting(cm, annotations) + cm.operation(function() {updateLinting(cm, annotations)}) }, passOptions, cm); } @@ -151,9 +151,9 @@ var annotations = getAnnotations(cm.getValue(), passOptions, cm); if (!annotations) return; if (annotations.then) annotations.then(function(issues) { - updateLinting(cm, issues); + cm.operation(function() {updateLinting(cm, issues)}) }); - else updateLinting(cm, annotations); + else cm.operation(function() {updateLinting(cm, annotations)}) } } From b1bf7b3ad53941dc81351de2a28896daf293d739 Mon Sep 17 00:00:00 2001 From: tophf Date: Fri, 1 Dec 2017 06:01:55 +0300 Subject: [PATCH 0732/1880] [css mode] Case-insensitive parsing of grammar tokens as per https://www.w3.org/TR/css-syntax-3/#rule-defs --- mode/css/css.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index 00e9b3df13..f5f3a41ba8 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -77,9 +77,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return ret("qualifier", "qualifier"); } else if (/[:;{}\[\]\(\)]/.test(ch)) { return ret(null, ch); - } else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) || - (ch == "d" && stream.match("omain(")) || - (ch == "r" && stream.match("egexp("))) { + } else if (((ch == "u" || ch == "U") && stream.match(/rl(-prefix)?\(/i)) || + ((ch == "d" || ch == "D") && stream.match("omain(", true, true)) || + ((ch == "r" || ch == "R") && stream.match("egexp(", true, true))) { stream.backUp(1); state.tokenize = tokenParenthesized; return ret("property", "word"); @@ -162,16 +162,16 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return pushContext(state, stream, "block"); } else if (type == "}" && state.context.prev) { return popContext(state); - } else if (supportsAtComponent && /@component/.test(type)) { + } else if (supportsAtComponent && /@component/i.test(type)) { return pushContext(state, stream, "atComponentBlock"); - } else if (/^@(-moz-)?document$/.test(type)) { + } else if (/^@(-moz-)?document$/i.test(type)) { return pushContext(state, stream, "documentTypes"); - } else if (/^@(media|supports|(-moz-)?document|import)$/.test(type)) { + } else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) { return pushContext(state, stream, "atBlock"); - } else if (/^@(font-face|counter-style)/.test(type)) { + } else if (/^@(font-face|counter-style)/i.test(type)) { state.stateArg = type; return "restricted_atBlock_before"; - } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) { + } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) { return "keyframes"; } else if (type && type.charAt(0) == "@") { return pushContext(state, stream, "at"); @@ -793,7 +793,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { }, "@": function(stream) { if (stream.eat("{")) return [null, "interpolation"]; - if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false; + if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false; stream.eatWhile(/[\w\\\-]/); if (stream.match(/^\s*:/, false)) return ["variable-2", "variable-definition"]; From 74e7447cf72205189e01eefced32fd2f2a7c79b9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 1 Dec 2017 10:45:55 +0100 Subject: [PATCH 0733/1880] [css mode] Add a test for an upper-case @-block Issue #5107 --- mode/css/test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mode/css/test.js b/mode/css/test.js index 6fc6e33ca5..e5c55d3999 100644 --- a/mode/css/test.js +++ b/mode/css/test.js @@ -24,6 +24,9 @@ MT("atMediaUnknownFeatureValueKeyword", "[def @media] ([property orientation]: [error upsidedown]) { }"); + MT("atMediaUppercase", + "[def @MEDIA] ([property orienTAtion]: [keyword landScape]) { }"); + MT("tagSelector", "[tag foo] { }"); From c7853a989c77bb9f520c9c530cbe1497856e96fc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 3 Dec 2017 12:00:32 +0100 Subject: [PATCH 0734/1880] [continuelist addon] Fix handling of unordered lists --- addon/edit/continuelist.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/addon/edit/continuelist.js b/addon/edit/continuelist.js index 30893965fe..b83dc505ff 100644 --- a/addon/edit/continuelist.js +++ b/addon/edit/continuelist.js @@ -39,13 +39,11 @@ replacements[i] = "\n"; } else { var indent = match[1], after = match[5]; - var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0 - ? match[2].replace("x", " ") - : (parseInt(match[3], 10) + 1) + match[4]; - + var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0); + var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " "); replacements[i] = "\n" + indent + bullet + after; - incrementRemainingMarkdownListNumbers(cm, pos); + if (numbered) incrementRemainingMarkdownListNumbers(cm, pos); } } From 6353583cdf780aaa74d9afd88df404b34a4c31ad Mon Sep 17 00:00:00 2001 From: Stephane Moore Date: Mon, 4 Dec 2017 16:56:18 -0800 Subject: [PATCH 0735/1880] =?UTF-8?q?[languages]=20Fix=20the=20name=20of?= =?UTF-8?q?=20Objective-C=20=F0=9F=93=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The language is named "Objective-C" rather than "Objective C". Reference: https://en.wikipedia.org/wiki/Objective-C --- mode/meta.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/meta.js b/mode/meta.js index 34da269f33..91a925268e 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -94,7 +94,7 @@ {name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]}, {name: "NTriples", mimes: ["application/n-triples", "application/n-quads", "text/n-triples"], mode: "ntriples", ext: ["nt", "nq"]}, - {name: "Objective C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"], alias: ["objective-c", "objc"]}, + {name: "Objective-C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"], alias: ["objective-c", "objc"]}, {name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]}, {name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]}, {name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]}, From 04d39f236a541104c3fccdfdf6ea164d6e4c74e7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 5 Dec 2017 10:03:37 +0100 Subject: [PATCH 0736/1880] [htmlembedded mode] Support %-style comments Closes #5102 --- mode/htmlembedded/htmlembedded.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mode/htmlembedded/htmlembedded.js b/mode/htmlembedded/htmlembedded.js index 464dc57f83..8099d370be 100644 --- a/mode/htmlembedded/htmlembedded.js +++ b/mode/htmlembedded/htmlembedded.js @@ -14,7 +14,16 @@ "use strict"; CodeMirror.defineMode("htmlembedded", function(config, parserConfig) { + var closeComment = parserConfig.closeComment || "--%>" return CodeMirror.multiplexingMode(CodeMirror.getMode(config, "htmlmixed"), { + open: parserConfig.openComment || "<%--", + close: closeComment, + delimStyle: "comment", + mode: {token: function(stream) { + stream.skipTo(closeComment) || stream.skipToEnd() + return "comment" + }} + }, { open: parserConfig.open || parserConfig.scriptStartRegex || "<%", close: parserConfig.close || parserConfig.scriptEndRegex || "%>", mode: CodeMirror.getMode(config, parserConfig.scriptingModeSpec) From 7e480de547d7b87690c654522d603d7aa213e64b Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Tue, 5 Dec 2017 22:43:37 +0100 Subject: [PATCH 0737/1880] [vim] Support more bases for increment and decrement Closes #5110. --- keymap/vim.js | 21 ++-- test/vim_test.js | 246 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 260 insertions(+), 7 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 7cf5a956e0..b082268183 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2637,25 +2637,32 @@ incrementNumberToken: function(cm, actionArgs) { var cur = cm.getCursor(); var lineStr = cm.getLine(cur.line); - var re = /-?\d+/g; + var re = /(-?)(?:(0x)([\da-f]+)|(0b|0|)(\d+))/gi; var match; var start; var end; var numberStr; - var token; while ((match = re.exec(lineStr)) !== null) { - token = match[0]; start = match.index; - end = start + token.length; + end = start + match[0].length; if (cur.ch < end)break; } if (!actionArgs.backtrack && (end <= cur.ch))return; - if (token) { + if (match) { + var baseStr = match[2] || match[4] + var digits = match[3] || match[5] var increment = actionArgs.increase ? 1 : -1; - var number = parseInt(token) + (increment * actionArgs.repeat); + var base = {'0b': 2, '0': 8, '': 10, '0x': 16}[baseStr.toLowerCase()]; + var number = parseInt(match[1] + digits, base) + (increment * actionArgs.repeat); + numberStr = number.toString(base); + var zeroPadding = baseStr ? new Array(digits.length - numberStr.length + 1 + match[1].length).join('0') : '' + if (numberStr.charAt(0) === '-') { + numberStr = '-' + baseStr + zeroPadding + numberStr.substr(1); + } else { + numberStr = baseStr + zeroPadding + numberStr; + } var from = Pos(cur.line, start); var to = Pos(cur.line, end); - numberStr = number.toString(); cm.replaceRange(numberStr, from, to); } else { return; diff --git a/test/vim_test.js b/test/vim_test.js index 18268ee789..5a42b90fa8 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -4235,4 +4235,250 @@ testVim('beforeSelectionChange', function(cm, vim, helpers) { eqCursorPos(cm.getCursor('head'), cm.getCursor('anchor')); }, { value: 'abc' }); +testVim('increment_binary', function(cm, vim, helpers) { + cm.setCursor(0, 4); + helpers.doKeys(''); + eq('0b001', cm.getValue()); + helpers.doKeys(''); + eq('0b010', cm.getValue()); + helpers.doKeys(''); + eq('0b001', cm.getValue()); + helpers.doKeys(''); + eq('0b000', cm.getValue()); + cm.setCursor(0, 0); + helpers.doKeys(''); + eq('0b001', cm.getValue()); + helpers.doKeys(''); + eq('0b010', cm.getValue()); + helpers.doKeys(''); + eq('0b001', cm.getValue()); + helpers.doKeys(''); + eq('0b000', cm.getValue()); +}, { value: '0b000' }); + +testVim('increment_octal', function(cm, vim, helpers) { + cm.setCursor(0, 2); + helpers.doKeys(''); + eq('001', cm.getValue()); + helpers.doKeys(''); + eq('002', cm.getValue()); + helpers.doKeys(''); + eq('003', cm.getValue()); + helpers.doKeys(''); + eq('004', cm.getValue()); + helpers.doKeys(''); + eq('005', cm.getValue()); + helpers.doKeys(''); + eq('006', cm.getValue()); + helpers.doKeys(''); + eq('007', cm.getValue()); + helpers.doKeys(''); + eq('010', cm.getValue()); + helpers.doKeys(''); + eq('007', cm.getValue()); + helpers.doKeys(''); + eq('006', cm.getValue()); + helpers.doKeys(''); + eq('005', cm.getValue()); + helpers.doKeys(''); + eq('004', cm.getValue()); + helpers.doKeys(''); + eq('003', cm.getValue()); + helpers.doKeys(''); + eq('002', cm.getValue()); + helpers.doKeys(''); + eq('001', cm.getValue()); + helpers.doKeys(''); + eq('000', cm.getValue()); + cm.setCursor(0, 0); + helpers.doKeys(''); + eq('001', cm.getValue()); + helpers.doKeys(''); + eq('002', cm.getValue()); + helpers.doKeys(''); + eq('001', cm.getValue()); + helpers.doKeys(''); + eq('000', cm.getValue()); +}, { value: '000' }); + +testVim('increment_decimal', function(cm, vim, helpers) { + cm.setCursor(0, 2); + helpers.doKeys(''); + eq('101', cm.getValue()); + helpers.doKeys(''); + eq('102', cm.getValue()); + helpers.doKeys(''); + eq('103', cm.getValue()); + helpers.doKeys(''); + eq('104', cm.getValue()); + helpers.doKeys(''); + eq('105', cm.getValue()); + helpers.doKeys(''); + eq('106', cm.getValue()); + helpers.doKeys(''); + eq('107', cm.getValue()); + helpers.doKeys(''); + eq('108', cm.getValue()); + helpers.doKeys(''); + eq('109', cm.getValue()); + helpers.doKeys(''); + eq('110', cm.getValue()); + helpers.doKeys(''); + eq('109', cm.getValue()); + helpers.doKeys(''); + eq('108', cm.getValue()); + helpers.doKeys(''); + eq('107', cm.getValue()); + helpers.doKeys(''); + eq('106', cm.getValue()); + helpers.doKeys(''); + eq('105', cm.getValue()); + helpers.doKeys(''); + eq('104', cm.getValue()); + helpers.doKeys(''); + eq('103', cm.getValue()); + helpers.doKeys(''); + eq('102', cm.getValue()); + helpers.doKeys(''); + eq('101', cm.getValue()); + helpers.doKeys(''); + eq('100', cm.getValue()); + cm.setCursor(0, 0); + helpers.doKeys(''); + eq('101', cm.getValue()); + helpers.doKeys(''); + eq('102', cm.getValue()); + helpers.doKeys(''); + eq('101', cm.getValue()); + helpers.doKeys(''); + eq('100', cm.getValue()); +}, { value: '100' }); + +testVim('increment_decimal_single_zero', function(cm, vim, helpers) { + helpers.doKeys(''); + eq('1', cm.getValue()); + helpers.doKeys(''); + eq('2', cm.getValue()); + helpers.doKeys(''); + eq('3', cm.getValue()); + helpers.doKeys(''); + eq('4', cm.getValue()); + helpers.doKeys(''); + eq('5', cm.getValue()); + helpers.doKeys(''); + eq('6', cm.getValue()); + helpers.doKeys(''); + eq('7', cm.getValue()); + helpers.doKeys(''); + eq('8', cm.getValue()); + helpers.doKeys(''); + eq('9', cm.getValue()); + helpers.doKeys(''); + eq('10', cm.getValue()); + helpers.doKeys(''); + eq('9', cm.getValue()); + helpers.doKeys(''); + eq('8', cm.getValue()); + helpers.doKeys(''); + eq('7', cm.getValue()); + helpers.doKeys(''); + eq('6', cm.getValue()); + helpers.doKeys(''); + eq('5', cm.getValue()); + helpers.doKeys(''); + eq('4', cm.getValue()); + helpers.doKeys(''); + eq('3', cm.getValue()); + helpers.doKeys(''); + eq('2', cm.getValue()); + helpers.doKeys(''); + eq('1', cm.getValue()); + helpers.doKeys(''); + eq('0', cm.getValue()); + cm.setCursor(0, 0); + helpers.doKeys(''); + eq('1', cm.getValue()); + helpers.doKeys(''); + eq('2', cm.getValue()); + helpers.doKeys(''); + eq('1', cm.getValue()); + helpers.doKeys(''); + eq('0', cm.getValue()); +}, { value: '0' }); +testVim('increment_hexadecimal', function(cm, vim, helpers) { + cm.setCursor(0, 2); + helpers.doKeys(''); + eq('0x1', cm.getValue()); + helpers.doKeys(''); + eq('0x2', cm.getValue()); + helpers.doKeys(''); + eq('0x3', cm.getValue()); + helpers.doKeys(''); + eq('0x4', cm.getValue()); + helpers.doKeys(''); + eq('0x5', cm.getValue()); + helpers.doKeys(''); + eq('0x6', cm.getValue()); + helpers.doKeys(''); + eq('0x7', cm.getValue()); + helpers.doKeys(''); + eq('0x8', cm.getValue()); + helpers.doKeys(''); + eq('0x9', cm.getValue()); + helpers.doKeys(''); + eq('0xa', cm.getValue()); + helpers.doKeys(''); + eq('0xb', cm.getValue()); + helpers.doKeys(''); + eq('0xc', cm.getValue()); + helpers.doKeys(''); + eq('0xd', cm.getValue()); + helpers.doKeys(''); + eq('0xe', cm.getValue()); + helpers.doKeys(''); + eq('0xf', cm.getValue()); + helpers.doKeys(''); + eq('0x10', cm.getValue()); + helpers.doKeys(''); + eq('0x0f', cm.getValue()); + helpers.doKeys(''); + eq('0x0e', cm.getValue()); + helpers.doKeys(''); + eq('0x0d', cm.getValue()); + helpers.doKeys(''); + eq('0x0c', cm.getValue()); + helpers.doKeys(''); + eq('0x0b', cm.getValue()); + helpers.doKeys(''); + eq('0x0a', cm.getValue()); + helpers.doKeys(''); + eq('0x09', cm.getValue()); + helpers.doKeys(''); + eq('0x08', cm.getValue()); + helpers.doKeys(''); + eq('0x07', cm.getValue()); + helpers.doKeys(''); + eq('0x06', cm.getValue()); + helpers.doKeys(''); + eq('0x05', cm.getValue()); + helpers.doKeys(''); + eq('0x04', cm.getValue()); + helpers.doKeys(''); + eq('0x03', cm.getValue()); + helpers.doKeys(''); + eq('0x02', cm.getValue()); + helpers.doKeys(''); + eq('0x01', cm.getValue()); + helpers.doKeys(''); + eq('0x00', cm.getValue()); + cm.setCursor(0, 0); + helpers.doKeys(''); + eq('0x01', cm.getValue()); + helpers.doKeys(''); + eq('0x02', cm.getValue()); + helpers.doKeys(''); + eq('0x01', cm.getValue()); + helpers.doKeys(''); + eq('0x00', cm.getValue()); +}, { value: '0x0' }); From a4a75b1c7c1ab4733df852eaba303cd47d46ec2e Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Wed, 6 Dec 2017 19:47:02 +0100 Subject: [PATCH 0738/1880] Escape all occurences of & and < in mode test output --- test/mode_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mode_test.js b/test/mode_test.js index 9773f80126..f4c4dbfe0c 100644 --- a/test/mode_test.js +++ b/test/mode_test.js @@ -67,7 +67,7 @@ }; function esc(str) { - return str.replace('&', '&').replace('<', '<').replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); + return str.replace(/&/g, '&').replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); } function compare(text, expected, mode) { From 7cefd7dacb53b71f6cfe14479a4f3fb4fa0c92b3 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Wed, 6 Dec 2017 19:46:20 +0100 Subject: [PATCH 0739/1880] [jsx mode] Add support for JSXFragments Closes #5101. --- mode/jsx/jsx.js | 2 +- mode/jsx/test.js | 3 +++ mode/xml/xml.js | 7 +++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mode/jsx/jsx.js b/mode/jsx/jsx.js index 45c3024aba..039e37bb5e 100644 --- a/mode/jsx/jsx.js +++ b/mode/jsx/jsx.js @@ -26,7 +26,7 @@ } CodeMirror.defineMode("jsx", function(config, modeConfig) { - var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false}) + var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false, allowMissingTagName: true}) var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript") function flatXMLIndent(state) { diff --git a/mode/jsx/test.js b/mode/jsx/test.js index 61f84ebe82..891f98830d 100644 --- a/mode/jsx/test.js +++ b/mode/jsx/test.js @@ -11,6 +11,9 @@ MT("openclose", "([bracket&tag <][tag foo][bracket&tag >]hello [atom &][bracket&tag ][operator ++])") + MT("openclosefragment", + "([bracket&tag <><][tag foo][bracket&tag >]hello [atom &][bracket&tag ][operator ++])") + MT("attr", "([bracket&tag <][tag foo] [attribute abc]=[string 'value'][bracket&tag >]hello [atom &][bracket&tag ][operator ++])") diff --git a/mode/xml/xml.js b/mode/xml/xml.js index f987a3a3ce..0f1c9b175e 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -52,6 +52,7 @@ var xmlConfig = { doNotIndent: {}, allowUnquoted: false, allowMissing: false, + allowMissingTagName: false, caseFold: false } @@ -226,6 +227,9 @@ CodeMirror.defineMode("xml", function(editorConf, config_) { state.tagName = stream.current(); setStyle = "tag"; return attrState; + } else if (config.allowMissingTagName && type == "endTag") { + setStyle = "tag bracket"; + return attrState(type, stream, state); } else { setStyle = "error"; return tagNameState; @@ -244,6 +248,9 @@ CodeMirror.defineMode("xml", function(editorConf, config_) { setStyle = "tag error"; return closeStateErr; } + } else if (config.allowMissingTagName && type == "endTag") { + setStyle = "tag bracket"; + return closeState(type, stream, state); } else { setStyle = "error"; return closeStateErr; From 32f63fc31de851699f5189d7701e0c06a2520b00 Mon Sep 17 00:00:00 2001 From: Cristian Prieto Date: Wed, 6 Dec 2017 16:14:49 +0100 Subject: [PATCH 0740/1880] [mllike mode] Improve OCaml support * Add reserved words for OCaml * Add {| |} string literal type * Add support for binary numbers * Add support for hex number literals * Add support for floats * Add octal and long integer literals --- mode/mllike/index.html | 19 ++++++++++++++++++ mode/mllike/mllike.js | 44 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/mode/mllike/index.html b/mode/mllike/index.html index 5923af8f87..b1ed6c7d78 100644 --- a/mode/mllike/index.html +++ b/mode/mllike/index.html @@ -132,6 +132,25 @@

    OCaml mode

    (* A Hundred Lines of Caml - http://caml.inria.fr/about/taste.en.html *) (* OCaml page on Wikipedia - http://en.wikipedia.org/wiki/OCaml *) + +module type S = sig type t end + +let x = {| + this is a long string + with many lines and stuff + |} + +let b = 0b00110 +let h = 0x123abcd +let e = 1e-10 +let i = 1. +let x = 30_000 +let o = 0o1234 + +[1; 2; 3] (* lists *) + +1 @ 2 +1. +. 2.

    F# mode

    diff --git a/mode/mllike/mllike.js b/mode/mllike/mllike.js index 4d0be609c4..90e5b41a63 100644 --- a/mode/mllike/mllike.js +++ b/mode/mllike/mllike.js @@ -54,6 +54,13 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) { state.tokenize = tokenString; return state.tokenize(stream, state); } + if (ch === '{') { + if (stream.eat('|')) { + state.longString = true; + state.tokenize = tokenLongString; + return state.tokenize(stream, state); + } + } if (ch === '(') { if (stream.eat('*')) { state.commentLevel++; @@ -74,13 +81,24 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) { return 'comment'; } if (/\d/.test(ch)) { - stream.eatWhile(/[\d]/); - if (stream.eat('.')) { - stream.eatWhile(/[\d]/); + if (ch === '0' && stream.eat(/[bB]/)) { + stream.eatWhile(/[01]/); + } if (ch === '0' && stream.eat(/[xX]/)) { + stream.eatWhile(/[0-9a-fA-F]/) + } if (ch === '0' && stream.eat(/[oO]/)) { + stream.eatWhile(/[0-7]/); + } else { + stream.eatWhile(/[\d_]/); + if (stream.eat('.')) { + stream.eatWhile(/[\d]/); + } + if (stream.eat(/[eE]/)) { + stream.eatWhile(/[\d\-+]/); + } } return 'number'; } - if ( /[+\-*&%=<>!?|]/.test(ch)) { + if ( /[+\-*&%=<>!?|@]/.test(ch)) { return 'operator'; } if (/[\w\xa1-\uffff]/.test(ch)) { @@ -119,8 +137,20 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) { return 'comment'; } + function tokenLongString(stream, state) { + var prev, next; + while (state.longString && (next = stream.next()) != null) { + if (prev === '|' && next === '}') state.longString = false; + prev = next; + } + if (!state.longString) { + state.tokenize = tokenBase; + } + return 'string'; + } + return { - startState: function() {return {tokenize: tokenBase, commentLevel: 0};}, + startState: function() {return {tokenize: tokenBase, commentLevel: 0, longString: false};}, token: function(stream, state) { if (stream.eatSpace()) return null; return state.tokenize(stream, state); @@ -142,7 +172,9 @@ CodeMirror.defineMIME('text/x-ocaml', { 'print_endline': 'builtin', 'true': 'atom', 'false': 'atom', - 'raise': 'keyword' + 'raise': 'keyword', + 'module': 'keyword', + 'sig': 'keyword' } }); From ecad7206ef2458bcb22bcaf13263178e2bb3a0dc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 7 Dec 2017 12:03:15 +0100 Subject: [PATCH 0741/1880] Document lineSeparator argument do Doc constructor Issue #5112 --- doc/manual.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index ea5642cdf9..9d95e39c75 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1523,8 +1523,8 @@

    Document management methods

    represents the editor content, plus a selection, an undo history, and a mode. A document can only be associated with a single editor at a time. You can create new - documents by calling the CodeMirror.Doc(text, mode, - firstLineNumber) constructor. The last two arguments are + documents by calling the CodeMirror.Doc(text: string, mode: Object, + firstLineNumber: ?number, lineSeparator: ?string) constructor. The last two arguments are optional and can be used to set a mode for the document and make it start at a line number other than 0, respectively.

    From c05c5956ef5ed327cfdb32d23a92c6786b6ac629 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 8 Dec 2017 09:56:44 +0100 Subject: [PATCH 0742/1880] Fix documentation of Doc constructor Issue #5112 --- doc/manual.html | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 9d95e39c75..5500b9904b 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1523,10 +1523,11 @@

    Document management methods

    represents the editor content, plus a selection, an undo history, and a mode. A document can only be associated with a single editor at a time. You can create new - documents by calling the CodeMirror.Doc(text: string, mode: Object, - firstLineNumber: ?number, lineSeparator: ?string) constructor. The last two arguments are - optional and can be used to set a mode for the document and make - it start at a line number other than 0, respectively.

    + documents by calling the CodeMirror.Doc(text: string, mode: + Object, firstLineNumber: ?number, lineSeparator: ?string) + constructor. The last three arguments are optional and can be used + to set a mode for the document, make it start at a line number + other than 0, and set a specific line separator respectively.

    cm.getDoc() → Doc
    From a7e29eee89aed63727e46d1e422cfa95b1200859 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Sun, 10 Dec 2017 20:57:37 +0100 Subject: [PATCH 0743/1880] [swift mode] Correctly highlight nested comments --- mode/swift/swift.js | 13 +++++++++++-- mode/swift/test.js | 7 +++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/mode/swift/swift.js b/mode/swift/swift.js index 43ab7c8fb4..1795d86e94 100644 --- a/mode/swift/swift.js +++ b/mode/swift/swift.js @@ -138,8 +138,17 @@ } function tokenComment(stream, state) { - stream.match(/^(?:[^*]|\*(?!\/))*/) - if (stream.match("*/")) state.tokenize.pop() + var ch + while (true) { + stream.match(/^[^/*]+/, true) + ch = stream.next() + if (!ch) break + if (ch === "/" && stream.eat("*")) { + state.tokenize.push(tokenComment) + } else if (ch === "*" && stream.eat("/")) { + state.tokenize.pop() + } + } return "comment" } diff --git a/mode/swift/test.js b/mode/swift/test.js index 786b89e299..4091ac6f4c 100644 --- a/mode/swift/test.js +++ b/mode/swift/test.js @@ -142,6 +142,13 @@ "[variable print][punctuation (][variable foo][property ._123][punctuation )]", "[variable print][punctuation (]") + MT("nested_comments", + "[comment /*]", + "[comment But wait /* this is a nested comment */ for real]", + "[comment /**** let * me * show * you ****/]", + "[comment ///// let / me / show / you /////]", + "[comment */]"); + // TODO: correctly identify when multiple variables are being declared // by use of a comma-separated list. // TODO: correctly identify when variables are being declared in a tuple. From ff21fec1a71e9c5de3c9faec84c3c61eaef60104 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Sun, 10 Dec 2017 21:08:36 +0100 Subject: [PATCH 0744/1880] [scala mode] Correctly highlight nested comments The implementation is mostly copied from dart as implemented in d4dbbcef22e3aadf25dad811a9faa988a50a0df4. --- mode/clike/clike.js | 27 +++++++++++++++++++++++++++ mode/clike/test.js | 10 ++++++++++ 2 files changed, 37 insertions(+) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index ff00cf5002..7706429063 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -489,6 +489,27 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { return "string"; } + function tokenNestedComment(depth) { + return function (stream, state) { + var ch + while (ch = stream.next()) { + if (ch == "*" && stream.eat("/")) { + if (depth == 1) { + state.tokenize = null + break + } else { + state.tokenize = tokenNestedComment(depth - 1) + return state.tokenize(stream, state) + } + } else if (ch == "/" && stream.eat("*")) { + state.tokenize = tokenNestedComment(depth + 1) + return state.tokenize(stream, state) + } + } + return "comment" + } + } + def("text/x-scala", { name: "clike", keywords: words( @@ -544,6 +565,12 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { } else { return false } + }, + + "/": function(stream, state) { + if (!stream.eat("*")) return false + state.tokenize = tokenNestedComment(1) + return state.tokenize(stream, state) } }, modeProps: {closeBrackets: {triples: '"'}} diff --git a/mode/clike/test.js b/mode/clike/test.js index dad2e246ae..e3bde772a5 100644 --- a/mode/clike/test.js +++ b/mode/clike/test.js @@ -56,4 +56,14 @@ MTCPP("ctor_dtor", "[def Foo::Foo]() {}", "[def Foo::~Foo]() {}"); + + var mode_scala = CodeMirror.getMode({indentUnit: 2}, "text/x-scala"); + function MTSCALA(name) { test.mode("scala_" + name, mode_scala, Array.prototype.slice.call(arguments, 1)); } + MTSCALA("nested_comments", + "[comment /*]", + "[comment But wait /* this is a nested comment */ for real]", + "[comment /**** let * me * show * you ****/]", + "[comment ///// let / me / show / you /////]", + "[comment */]"); + })(); From edc74c3ef360132afc69b2f22d51f7c6a711c305 Mon Sep 17 00:00:00 2001 From: Lior Goldberg Date: Thu, 7 Dec 2017 14:54:27 +0200 Subject: [PATCH 0745/1880] [sublime keymap] Support expanding brackets selection in selectBetweenBrackets --- keymap/sublime.js | 12 +++++++++--- test/sublime_test.js | 4 +++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/keymap/sublime.js b/keymap/sublime.js index 08c9ebfb3f..37ae6fec27 100644 --- a/keymap/sublime.js +++ b/keymap/sublime.js @@ -183,9 +183,15 @@ var closing = cm.scanForBracket(pos, 1); if (!closing) return false; if (closing.ch == mirror.charAt(mirror.indexOf(opening.ch) + 1)) { - newRanges.push({anchor: Pos(opening.pos.line, opening.pos.ch + 1), - head: closing.pos}); - break; + var startPos = Pos(opening.pos.line, opening.pos.ch + 1); + if (CodeMirror.cmpPos(startPos, range.from()) == 0 && + CodeMirror.cmpPos(closing.pos, range.to()) == 0) { + opening = cm.scanForBracket(opening.pos, -1); + if (!opening) return false; + } else { + newRanges.push({anchor: startPos, head: closing.pos}); + break; + } } pos = Pos(closing.pos.line, closing.pos.ch + 1); } diff --git a/test/sublime_test.js b/test/sublime_test.js index e9cd342ff4..27132d16a7 100644 --- a/test/sublime_test.js +++ b/test/sublime_test.js @@ -152,7 +152,9 @@ Pos(0, 8), "selectScope", hasSel(0, 8, 2, 0), Pos(1, 2), "selectScope", hasSel(0, 8, 2, 0), Pos(1, 6), "selectScope", hasSel(1, 6, 1, 10), - Pos(1, 9), "selectScope", hasSel(1, 6, 1, 10)); + Pos(1, 9), "selectScope", hasSel(1, 6, 1, 10), + "selectScope", hasSel(0, 8, 2, 0), + "selectScope", hasSel(0, 0, 2, 1)); stTest("goToBracket", "foo(a) {\n bar[1, 2];\n}", Pos(0, 0), "goToBracket", at(0, 0), From b3cdfee46a320e646a298141861b4e80dc6f1bd0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 12 Dec 2017 22:16:41 +0100 Subject: [PATCH 0746/1880] Drop bin/compress Leave compression up to people's own custom build setups Closes #5127 --- bin/compress | 92 ---------------------------------------------------- 1 file changed, 92 deletions(-) delete mode 100755 bin/compress diff --git a/bin/compress b/bin/compress deleted file mode 100755 index d358f9c3a0..0000000000 --- a/bin/compress +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env node - -// Compression helper for CodeMirror -// -// Example: -// -// bin/compress codemirror runmode javascript xml -// -// Will take lib/codemirror.js, addon/runmode/runmode.js, -// mode/javascript/javascript.js, and mode/xml/xml.js, run them though -// the online minifier at http://marijnhaverbeke.nl/uglifyjs, and spit -// out the result. -// -// bin/compress codemirror --local /path/to/bin/UglifyJS -// -// Will use a local minifier instead of the online default one. -// -// Script files are specified without .js ending. Prefixing them with -// their full (local) path is optional. So you may say lib/codemirror -// or mode/xml/xml to be more precise. In fact, even the .js suffix -// may be specified, if wanted. - -"use strict"; - -var fs = require("fs"); - -function help(ok) { - console.log("usage: " + process.argv[1] + " [--local /path/to/uglifyjs] files..."); - process.exit(ok ? 0 : 1); -} - -var local = null, args = [], extraArgs = null, files = [], blob = ""; - -for (var i = 2; i < process.argv.length; ++i) { - var arg = process.argv[i]; - if (arg == "--local" && i + 1 < process.argv.length) { - var parts = process.argv[++i].split(/\s+/); - local = parts[0]; - extraArgs = parts.slice(1); - if (!extraArgs.length) extraArgs = ["-c", "-m"]; - } else if (arg == "--help") { - help(true); - } else if (arg[0] != "-") { - files.push({name: arg, re: new RegExp("(?:\\/|^)" + arg + (/\.js$/.test(arg) ? "$" : "\\.js$"))}); - } else help(false); -} - -function walk(dir) { - fs.readdirSync(dir).forEach(function(fname) { - if (/^[_\.]/.test(fname)) return; - var file = dir + fname; - if (fs.statSync(file).isDirectory()) return walk(file + "/"); - if (files.some(function(spec, i) { - var match = spec.re.test(file); - if (match) files.splice(i, 1); - return match; - })) { - if (local) args.push(file); - else blob += fs.readFileSync(file, "utf8"); - } - }); -} - -walk("lib/"); -walk("addon/"); -walk("mode/"); - -if (!local && !blob) help(false); - -if (files.length) { - console.log("Some specified files were not found: " + - files.map(function(a){return a.name;}).join(", ")); - process.exit(1); -} - -if (local) { - require("child_process").spawn(local, args.concat(extraArgs), {stdio: ["ignore", process.stdout, process.stderr]}); -} else { - var data = new Buffer("js_code=" + require("querystring").escape(blob), "utf8"); - var req = require("http").request({ - host: "marijnhaverbeke.nl", - port: 80, - method: "POST", - path: "/uglifyjs", - headers: {"content-type": "application/x-www-form-urlencoded", - "content-length": data.length} - }); - req.on("response", function(resp) { - resp.on("data", function (chunk) { process.stdout.write(chunk); }); - }); - req.end(data); -} From d9f05c90a1f6e07faf4ec3cf239621f1cce44f32 Mon Sep 17 00:00:00 2001 From: Sorab Bisht Date: Mon, 11 Dec 2017 19:44:15 +0530 Subject: [PATCH 0747/1880] [closetag addon] Add an option to disable auto indenting --- addon/edit/closetag.js | 16 +++++++++++----- src/edit/options.js | 1 + 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index a518da3ec1..83f133a5e7 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -53,13 +53,14 @@ function autoCloseGT(cm) { if (cm.getOption("disableInput")) return CodeMirror.Pass; var ranges = cm.listSelections(), replacements = []; + var opt = cm.getOption("autoCloseTags"); for (var i = 0; i < ranges.length; i++) { if (!ranges[i].empty()) return CodeMirror.Pass; var pos = ranges[i].head, tok = cm.getTokenAt(pos); var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass; - var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html"; + var html = inner.mode.configuration == "html"; var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); @@ -81,13 +82,14 @@ newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)}; } + var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnAutoClose); for (var i = ranges.length - 1; i >= 0; i--) { var info = replacements[i]; cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert"); var sel = cm.listSelections().slice(0); sel[i] = {head: info.newPos, anchor: info.newPos}; cm.setSelections(sel); - if (info.indent) { + if (!dontIndentOnAutoClose && info.indent) { cm.indentLine(info.newPos.line, null, true); cm.indentLine(info.newPos.line + 1, null, true); } @@ -97,6 +99,8 @@ function autoCloseCurrent(cm, typingSlash) { var ranges = cm.listSelections(), replacements = []; var head = typingSlash ? "/" : " { cm.doc.lineSep = val if (!val) return From 56c271ff88efbf3726a4f0fa0a131942ebf804ff Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 16 Dec 2017 18:47:06 +0100 Subject: [PATCH 0748/1880] [javascript mode] Stop treating TS contextual keywords as regular keywords Closes #5133 --- mode/javascript/javascript.js | 68 +++++++++++++---------------------- 1 file changed, 25 insertions(+), 43 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 514de1c8da..edab99f3d7 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -26,7 +26,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d"); var operator = kw("operator"), atom = {type: "atom", style: "atom"}; - var jsKeywords = { + return { "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, "return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C, "debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"), @@ -38,33 +38,6 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { "yield": C, "export": kw("export"), "import": kw("import"), "extends": C, "await": C }; - - // Extend the 'normal' keywords with the TypeScript language extensions - if (isTS) { - var type = {type: "variable", style: "type"}; - var tsKeywords = { - // object-like things - "interface": kw("class"), - "implements": C, - "namespace": C, - - // scope modifiers - "public": kw("modifier"), - "private": kw("modifier"), - "protected": kw("modifier"), - "abstract": kw("modifier"), - "readonly": kw("modifier"), - - // types - "string": type, "number": type, "boolean": type, "any": type - }; - - for (var attr in tsKeywords) { - jsKeywords[attr] = tsKeywords[attr]; - } - } - - return jsKeywords; }(); var isOperatorChar = /[+\-*&%=<>!?|~^@]/; @@ -310,6 +283,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } } + function isModifier(name) { + return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly" + } + // Combinators var defaultVars = {name: "this", next: {name: "arguments"}}; @@ -366,6 +343,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } if (type == "function") return cont(functiondef); if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); + if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), className, poplex); } if (type == "variable") { if (isTS && value == "type") { cx.marked = "keyword" @@ -376,6 +354,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } else if (isTS && (value == "module" || value == "enum") && cx.stream.match(/^\s*\w/, false)) { cx.marked = "keyword" return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex) + } else if (isTS && value == "namespace") { + cx.marked = "keyword" + return cont(pushlex("form"), expression, block, poplex) } else { return cont(pushlex("stat"), maybelabel); } @@ -386,24 +367,23 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "default") return cont(expect(":")); if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), statement, poplex, popcontext); - if (type == "class") return cont(pushlex("form"), className, poplex); if (type == "export") return cont(pushlex("stat"), afterExport, poplex); if (type == "import") return cont(pushlex("stat"), afterImport, poplex); if (type == "async") return cont(statement) if (value == "@") return cont(expression, statement) return pass(pushlex("stat"), expression, expect(";"), poplex); } - function expression(type) { - return expressionInner(type, false); + function expression(type, value) { + return expressionInner(type, value, false); } - function expressionNoComma(type) { - return expressionInner(type, true); + function expressionNoComma(type, value) { + return expressionInner(type, value, true); } function parenExpr(type) { if (type != "(") return pass() return cont(pushlex(")"), expression, expect(")"), poplex) } - function expressionInner(type, noComma) { + function expressionInner(type, value, noComma) { if (cx.state.fatArrowAt == cx.stream.start) { var body = noComma ? arrowBodyNoComma : arrowBody; if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext); @@ -413,7 +393,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); if (type == "function") return cont(functiondef, maybeop); - if (type == "class") return cont(pushlex("form"), classExpression, poplex); + if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); } if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression); if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop); if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression); @@ -511,10 +491,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return cont(afterprop); } else if (type == "jsonld-keyword") { return cont(afterprop); - } else if (type == "modifier") { + } else if (isTS && isModifier(value)) { + cx.marked = "keyword" return cont(objprop) } else if (type == "[") { - return cont(expression, expect("]"), afterprop); + return cont(expression, maybetype, expect("]"), afterprop); } else if (type == "spread") { return cont(expressionNoComma, afterprop); } else if (value == "*") { @@ -616,7 +597,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) if (value == "|" || type == ".") return cont(typeexpr) if (type == "[") return cont(expect("]"), afterType) - if (value == "extends") return cont(typeexpr) + if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) } } function maybeTypeArgs(_, value) { if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType) @@ -631,7 +612,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return pass(pattern, maybetype, maybeAssign, vardefCont); } function pattern(type, value) { - if (type == "modifier") return cont(pattern) + if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) } if (type == "variable") { register(value); return cont(); } if (type == "spread") return cont(pattern); if (type == "[") return contCommasep(pattern, "]"); @@ -685,7 +666,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function funarg(type, value) { if (value == "@") cont(expression, funarg) - if (type == "spread" || type == "modifier") return cont(funarg); + if (type == "spread") return cont(funarg); + if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); } return pass(pattern, maybetype, maybeAssign); } function classExpression(type, value) { @@ -703,9 +685,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "{") return cont(pushlex("}"), classBody, poplex); } function classBody(type, value) { - if (type == "modifier" || type == "async" || + if (type == "async" || (type == "variable" && - (value == "static" || value == "get" || value == "set") && + (value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) && cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) { cx.marked = "keyword"; return cont(classBody); @@ -715,7 +697,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return cont(isTS ? classfield : functiondef, classBody); } if (type == "[") - return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody) + return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody) if (value == "*") { cx.marked = "keyword"; return cont(classBody); From 9e3665211ac2427b55acf8006bd7f783a640f16b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Dec 2017 10:22:33 +0100 Subject: [PATCH 0749/1880] Use a different way to force line widget margins to stay inside container Issue #5137 --- lib/codemirror.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index 8f4f22f5d6..c7a8ae7047 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -270,7 +270,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} .CodeMirror-linewidget { position: relative; z-index: 2; - overflow: auto; + padding: 0.1px; /* Force widget margins to stay inside of the container */ } .CodeMirror-widget {} From 40570ddc5ba1410c7bf2c38f1b1e8ac6a502fa2f Mon Sep 17 00:00:00 2001 From: Tobias Bertelsen Date: Wed, 6 Dec 2017 22:52:31 +0100 Subject: [PATCH 0750/1880] [sublime keymap] Fixing hotkeys for addCursorTo(Prev|Next)Line Fix for issue #5109 --- keymap/sublime.js | 33 ++++----------------------------- test/sublime_test.js | 25 ------------------------- 2 files changed, 4 insertions(+), 54 deletions(-) diff --git a/keymap/sublime.js b/keymap/sublime.js index 37ae6fec27..5925b7c51f 100644 --- a/keymap/sublime.js +++ b/keymap/sublime.js @@ -514,27 +514,6 @@ cm.scrollTo(null, (pos.top + pos.bottom) / 2 - cm.getScrollInfo().clientHeight / 2); }; - cmds.selectLinesUpward = function(cm) { - cm.operation(function() { - var ranges = cm.listSelections(); - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i]; - if (range.head.line > cm.firstLine()) - cm.addSelection(Pos(range.head.line - 1, range.head.ch)); - } - }); - }; - cmds.selectLinesDownward = function(cm) { - cm.operation(function() { - var ranges = cm.listSelections(); - for (var i = 0; i < ranges.length; i++) { - var range = ranges[i]; - if (range.head.line < cm.lastLine()) - cm.addSelection(Pos(range.head.line + 1, range.head.ch)); - } - }); - }; - function getTarget(cm) { var from = cm.getCursor("from"), to = cm.getCursor("to"); if (CodeMirror.cmpPos(from, to) == 0) { @@ -596,8 +575,6 @@ "Cmd-Enter": "insertLineAfter", "Shift-Cmd-Enter": "insertLineBefore", "Cmd-D": "selectNextOccurrence", - "Shift-Cmd-Up": "addCursorToPrevLine", - "Shift-Cmd-Down": "addCursorToNextLine", "Shift-Cmd-Space": "selectScope", "Shift-Cmd-M": "selectBetweenBrackets", "Cmd-M": "goToBracket", @@ -627,8 +604,8 @@ "Cmd-K Cmd-Backspace": "delLineLeft", "Cmd-K Cmd-0": "unfoldAll", "Cmd-K Cmd-J": "unfoldAll", - "Ctrl-Shift-Up": "selectLinesUpward", - "Ctrl-Shift-Down": "selectLinesDownward", + "Ctrl-Shift-Up": "addCursorToPrevLine", + "Ctrl-Shift-Down": "addCursorToNextLine", "Cmd-F3": "findUnder", "Shift-Cmd-F3": "findUnderPrevious", "Alt-F3": "findAllUnder", @@ -658,8 +635,6 @@ "Ctrl-Enter": "insertLineAfter", "Shift-Ctrl-Enter": "insertLineBefore", "Ctrl-D": "selectNextOccurrence", - "Alt-CtrlUp": "addCursorToPrevLine", - "Alt-CtrlDown": "addCursorToNextLine", "Shift-Ctrl-Space": "selectScope", "Shift-Ctrl-M": "selectBetweenBrackets", "Ctrl-M": "goToBracket", @@ -689,8 +664,8 @@ "Ctrl-K Ctrl-Backspace": "delLineLeft", "Ctrl-K Ctrl-0": "unfoldAll", "Ctrl-K Ctrl-J": "unfoldAll", - "Ctrl-Alt-Up": "selectLinesUpward", - "Ctrl-Alt-Down": "selectLinesDownward", + "Ctrl-Alt-Up": "addCursorToPrevLine", + "Ctrl-Alt-Down": "addCursorToNextLine", "Ctrl-F3": "findUnder", "Shift-Ctrl-F3": "findUnderPrevious", "Alt-F3": "findAllUnder", diff --git a/test/sublime_test.js b/test/sublime_test.js index 27132d16a7..09bb951247 100644 --- a/test/sublime_test.js +++ b/test/sublime_test.js @@ -221,31 +221,6 @@ 2, 4, 2, 6, 2, 7, 2, 7)); - stTest("selectLinesUpward", "123\n345\n789\n012", - setSel(0, 1, 0, 1, - 1, 1, 1, 3, - 2, 0, 2, 0, - 3, 0, 3, 0), - "selectLinesUpward", - hasSel(0, 1, 0, 1, - 0, 3, 0, 3, - 1, 0, 1, 0, - 1, 1, 1, 3, - 2, 0, 2, 0, - 3, 0, 3, 0)); - - stTest("selectLinesDownward", "123\n345\n789\n012", - setSel(0, 1, 0, 1, - 1, 1, 1, 3, - 2, 0, 2, 0, - 3, 0, 3, 0), - "selectLinesDownward", - hasSel(0, 1, 0, 1, - 1, 1, 1, 3, - 2, 0, 2, 0, - 2, 3, 2, 3, - 3, 0, 3, 0)); - stTest("sortLines", "c\nb\na\nC\nB\nA", "sortLines", val("A\nB\nC\na\nb\nc"), "undo", From 2f4fb8053021c01d1f246de2e663ac3719877610 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Dec 2017 14:59:33 +0100 Subject: [PATCH 0751/1880] Mark version 5.33.0 --- AUTHORS | 6 ++++++ CHANGELOG.md | 22 ++++++++++++++++++++++ doc/manual.html | 2 +- doc/releases.html | 13 +++++++++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 45 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 65d8480893..47c79d1577 100644 --- a/AUTHORS +++ b/AUTHORS @@ -144,6 +144,7 @@ CodeBitt coderaiser Cole R Lawrence ComFreek +Cristian Prieto Curtis Gagliardi dagsta daines @@ -385,6 +386,7 @@ Leon Sorokin Leonya Khachaturov Liam Newman Libo Cannici +Lior Goldberg LloydMilligan LM lochel @@ -611,6 +613,7 @@ sinkuu snasa soliton4 sonson +Sorab Bisht spastorelli srajanpaliwal Stanislav Oaserele @@ -619,6 +622,7 @@ Stefan Borsje Steffen Beyer Steffen Bruchmann Steffen Kowalski +Stephane Moore Stephen Lavelle Steve Champagne Steve Hoover @@ -651,6 +655,7 @@ Tim Baumann Timothy Farrell Timothy Gu Timothy Hatcher +Tobias Bertelsen TobiasBg Todd Berman Todd Kennedy @@ -660,6 +665,7 @@ Tom Erik Støwer Tom Klancer Tom MacWright Tony Jian +tophf Travis Heppe Triangle717 Tristan Tarrant diff --git a/CHANGELOG.md b/CHANGELOG.md index f81fcdd07b..855e6e4d9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ +## 5.33.0 (2017-12-21) + +### Bug fixes + +[lint addon](http://codemirror.net/doc/manual.html#addon_lint): Make updates more efficient. + +[css mode](http://codemirror.net/mode/css/): The mode is now properly case-insensitive. + +[continuelist addon](http://codemirror.net/doc/manual.html#addon_continuelist): Fix broken handling of unordered lists introduced in previous release. + +[swift](http://codemirror.net/mode/swift) and [scala](http://codemirror.net/mode/clike/) modes: Support nested block comments. + +[mllike mode](http://codemirror.net/mode/mllike/index.html): Improve OCaml support. + +[sublime bindings](http://codemirror.net/demo/sublime.html): Use the proper key bindings for `addCursorToNextLine` and `addCursorToPrevLine`. + +### New features + +[jsx mode](http://codemirror.net/mode/jsx/index.html): Support JSX fragments. + +[closetag addon](http://codemirror.net/demo/closetag.html): Add an option to disable auto-indenting. + ## 5.32.0 (2017-11-22) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 5500b9904b..37275fd9d7 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.32.1 + version 5.33.0

    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 7fb8eebef1..4051a32c55 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,19 @@

    Release notes and version history

    Version 5.x

    +

    21-12-2017: Version 5.33.0:

    + +
      +
    • lint addon: Make updates more efficient.
    • +
    • css mode: The mode is now properly case-insensitive.
    • +
    • continuelist addon: Fix broken handling of unordered lists introduced in previous release.
    • +
    • swift and scala modes: Support nested block comments.
    • +
    • mllike mode: Improve OCaml support.
    • +
    • sublime bindings: Use the proper key bindings for addCursorToNextLine and addCursorToPrevLine.
    • +
    • jsx mode: Support JSX fragments.
    • +
    • closetag addon: Add an option to disable auto-indenting.
    • +
    +

    22-11-2017: Version 5.32.0:

      diff --git a/index.html b/index.html index d62ab84a39..1e4df9328a 100644 --- a/index.html +++ b/index.html @@ -96,7 +96,7 @@

      This is CodeMirror

    - Get the current version: 5.32.0.
    + Get the current version: 5.33.0.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index 3ffad1d5d1..9894b4f0d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.32.1", + "version": "5.33.0", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "description": "Full-featured in-browser code editor", diff --git a/src/edit/main.js b/src/edit/main.js index 260f7d0af5..a49a7c2f39 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.32.1" +CodeMirror.version = "5.33.0" From c727c997264451a11573ec121889bc76b071bfe2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Dec 2017 15:01:04 +0100 Subject: [PATCH 0752/1880] Bump version number post-5.33.0 --- doc/manual.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 37275fd9d7..01721009d7 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -69,7 +69,7 @@

    User manual and reference guide - version 5.33.0 + version 5.33.1

    CodeMirror is a code-editor component that can be embedded in diff --git a/package.json b/package.json index 9894b4f0d3..28a2925884 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.33.0", + "version": "5.33.1", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "description": "Full-featured in-browser code editor", diff --git a/src/edit/main.js b/src/edit/main.js index a49a7c2f39..a12e4e3bb7 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.33.0" +CodeMirror.version = "5.33.1" From b36cf986c7288e6019d11338867a5730fee70b95 Mon Sep 17 00:00:00 2001 From: tophf Date: Fri, 22 Dec 2017 10:32:36 +0300 Subject: [PATCH 0753/1880] [stylus mode] parse CSS4 hex colors - #RGBA and #RRGGBBAA --- mode/stylus/stylus.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/stylus/stylus.js b/mode/stylus/stylus.js index b83be16f42..a9f50c05d1 100644 --- a/mode/stylus/stylus.js +++ b/mode/stylus/stylus.js @@ -76,7 +76,7 @@ if (ch == "#") { stream.next(); // Hex color - if (stream.match(/^[0-9a-f]{6}|[0-9a-f]{3}/i)) { + if (stream.match(/^[0-9a-f]{3}([0-9a-f]([0-9a-f]{2}){0,2})?\b/i)) { return ["atom", "atom"]; } // ID selector From 9ed3674fbb8bb35726e73d63732b011cb4facf5f Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 24 Dec 2017 12:10:50 +0300 Subject: [PATCH 0754/1880] Recognize ScrollLock and Pause with Ctrl modifier --- src/input/keymap.js | 3 +++ src/input/keynames.js | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/input/keymap.js b/src/input/keymap.js index 1dfcf8aff6..63f18b58a9 100644 --- a/src/input/keymap.js +++ b/src/input/keymap.js @@ -137,6 +137,9 @@ export function keyName(event, noShift) { if (presto && event.keyCode == 34 && event["char"]) return false let name = keyNames[event.keyCode] if (name == null || event.altGraphKey) return false + // Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause, + // so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+) + if (event.keyCode == 3 && event.code) name = event.code return addModifierNames(name, event, noShift) } diff --git a/src/input/keynames.js b/src/input/keynames.js index 66bc80010c..9a61d152b8 100644 --- a/src/input/keynames.js +++ b/src/input/keynames.js @@ -1,9 +1,9 @@ export let keyNames = { - 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", + 3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", - 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", + 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", 145: "ScrollLock", 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert" From d096403f470630c9019c4bf847aa8bab57ccc8d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9lio?= Date: Thu, 28 Dec 2017 18:18:16 -0300 Subject: [PATCH 0755/1880] [markdown mode] Support for the official mimetype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tl;dr: `text/markdown` since March 2016 --- In March 2016, `text/markdown` was registered as [RFC7763 at IETF](https://tools.ietf.org/html/rfc7763). Previously, it should have been `text/x-markdown`. The text below describes the situation before March 2016, when RFC7763 was still a draft. --- There is no official recommendation on [Gruber’s definition](http://daringfireball.net/projects/markdown/), but the topic was discussed quite heavily on the [official mailing-list](http://six.pairlist.net/pipermail/markdown-discuss/2007-June/thread.html#640), and reached the choice of `text/x-markdown`. This conclusion was [challenged later](http://six.pairlist.net/pipermail/markdown-discuss/2008-February/000960.html), has been confirmed and can be, IMO, considered consensus. This is the only logical conclusion in the lack of an official mime type: `text/` will provide proper default almost everywhere, `x-` because we're not using an official type, `markdown` and not `gruber.` or whatever because the type is now so common. There are still [unknowns](http://six.pairlist.net/pipermail/markdown-discuss/2007-June/000652.html) regarding the different “flavors” of Markdown, though. I guess someone should register an official type, which is supposedly [easy](http://tools.ietf.org/html/rfc4288#section-3.4), but I doubt anyone dares do it beyond John Gruber, as he very recently [proved](http://blog.codinghorror.com/standard-markdown-is-now-common-markdown/) his attachment to Markdown. There is a [draft](https://datatracker.ietf.org/doc/draft-ietf-appsawg-text-markdown/) on the IETF for `text/markdown`, but the contents do not seem to describe Markdown at all, so I wouldn't use it until it gets more complete. --- mode/markdown/markdown.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index b2f79fc302..60f1b30026 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -856,6 +856,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return mode; }, "xml"); +CodeMirror.defineMIME("text/markdown", "markdown"); + CodeMirror.defineMIME("text/x-markdown", "markdown"); }); From 865102a071e79ea2301bcb710f6051f593deddc9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 29 Dec 2017 13:18:43 +0100 Subject: [PATCH 0756/1880] [nginx mode] Fix documented mime type Issue #5148 --- mode/nginx/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/nginx/index.html b/mode/nginx/index.html index 03cf671498..dde54574d5 100644 --- a/mode/nginx/index.html +++ b/mode/nginx/index.html @@ -1,4 +1,4 @@ - + CodeMirror: NGINX mode @@ -176,6 +176,6 @@

    NGINX mode

    var editor = CodeMirror.fromTextArea(document.getElementById("code"), {}); -

    MIME types defined: text/nginx.

    +

    MIME types defined: text/x-nginx-conf.

    From b045bfa732c2ec44a66dde944dd9be1ef5da99df Mon Sep 17 00:00:00 2001 From: 4oo4 <4oo4@users.noreply.github.com> Date: Sat, 30 Dec 2017 15:52:33 +0000 Subject: [PATCH 0757/1880] [mode/meta] Add .ino to C --- mode/meta.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/meta.js b/mode/meta.js index 91a925268e..89b2ced87c 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -17,7 +17,7 @@ {name: "ASN.1", mime: "text/x-ttcn-asn", mode: "asn.1", ext: ["asn", "asn1"]}, {name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk", file: /^extensions\.conf$/i}, {name: "Brainfuck", mime: "text/x-brainfuck", mode: "brainfuck", ext: ["b", "bf"]}, - {name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h"]}, + {name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h", "ino"]}, {name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]}, {name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]}, {name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]}, From 8b9d8e337eb7c1d48d42589a5caee0a2215f620c Mon Sep 17 00:00:00 2001 From: Takuya Matsuyama Date: Mon, 1 Jan 2018 20:51:12 +0900 Subject: [PATCH 0758/1880] [php mode] Fix invalid mime definition --- mode/meta.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/meta.js b/mode/meta.js index 89b2ced87c..4ab3e08e3e 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -101,7 +101,7 @@ {name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]}, {name: "PEG.js", mime: "null", mode: "pegjs", ext: ["jsonld"]}, {name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]}, - {name: "PHP", mime: ["application/x-httpd-php", "text/x-php"], mode: "php", ext: ["php", "php3", "php4", "php5", "php7", "phtml"]}, + {name: "PHP", mimes: ["text/x-php", "application/x-httpd-php", "application/x-httpd-php-open"], mode: "php", ext: ["php", "php3", "php4", "php5", "php7", "phtml"]}, {name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]}, {name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]}, {name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]}, From cacaa54596272e6ffadf24322123f773bc3c2d80 Mon Sep 17 00:00:00 2001 From: Shane Liesegang Date: Tue, 2 Jan 2018 18:01:27 -0500 Subject: [PATCH 0759/1880] [makdown mode] Don't let inline styles persist across list items --- mode/markdown/markdown.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 60f1b30026..7dfddccd39 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -113,6 +113,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { function blankLine(state) { // Reset linkTitle state state.linkTitle = false; + state.linkHref = false; + state.linkText = false; // Reset EM state state.em = false; // Reset STRONG state @@ -151,6 +153,12 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { if (state.indentationDiff === null) { state.indentationDiff = state.indentation; if (prevLineIsList) { + // Reset inline styles which shouldn't propagate aross list items + state.em = false; + state.strong = false; + state.code = false; + state.strikethrough = false; + state.list = null; // While this list item's marker's indentation is less than the deepest // list item's content's indentation,pop the deepest list item From d2798d22509e33f3aeb79bb7f7437ba0de4605bf Mon Sep 17 00:00:00 2001 From: Neil Anderson Date: Sat, 6 Jan 2018 13:16:31 -0500 Subject: [PATCH 0760/1880] [sql mode] Include LC_CTYPE and LC_COLLATE keywords in x-pgsql The CREATE DATABASE command supports LC_CTYPE and LC_COLLATE keywords as per https://www.postgresql.org/docs/10/static/sql-createdatabase.html. This commit adds them to the postgres sql mode. --- mode/sql/sql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/sql/sql.js b/mode/sql/sql.js index da416f2048..63e87733bf 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -400,7 +400,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { name: "sql", client: set("source"), // https://www.postgresql.org/docs/10/static/sql-keywords-appendix.html - keywords: set(sqlKeywords + "a abort abs absent absolute access according action ada add admin after aggregate all allocate also always analyse analyze any are array array_agg array_max_cardinality asensitive assertion assignment asymmetric at atomic attribute attributes authorization avg backward base64 before begin begin_frame begin_partition bernoulli binary bit_length blob blocked bom both breadth c cache call called cardinality cascade cascaded case cast catalog catalog_name ceil ceiling chain characteristics characters character_length character_set_catalog character_set_name character_set_schema char_length check checkpoint class class_origin clob close cluster coalesce cobol collate collation collation_catalog collation_name collation_schema collect column columns column_name command_function command_function_code comment comments commit committed concurrently condition condition_number configuration conflict connect connection connection_name constraint constraints constraint_catalog constraint_name constraint_schema constructor contains content continue control conversion convert copy corr corresponding cost covar_pop covar_samp cross csv cube cume_dist current current_catalog current_date current_default_transform_group current_path current_role current_row current_schema current_time current_timestamp current_transform_group_for_type current_user cursor cursor_name cycle data database datalink datetime_interval_code datetime_interval_precision day db deallocate dec declare default defaults deferrable deferred defined definer degree delimiter delimiters dense_rank depth deref derived describe descriptor deterministic diagnostics dictionary disable discard disconnect dispatch dlnewcopy dlpreviouscopy dlurlcomplete dlurlcompleteonly dlurlcompletewrite dlurlpath dlurlpathonly dlurlpathwrite dlurlscheme dlurlserver dlvalue do document domain dynamic dynamic_function dynamic_function_code each element else empty enable encoding encrypted end end-exec end_frame end_partition enforced enum equals escape event every except exception exclude excluding exclusive exec execute exists exp explain expression extension external extract false family fetch file filter final first first_value flag float floor following for force foreign fortran forward found frame_row free freeze fs full function functions fusion g general generated get global go goto grant granted greatest grouping groups handler header hex hierarchy hold hour id identity if ignore ilike immediate immediately immutable implementation implicit import including increment indent index indexes indicator inherit inherits initially inline inner inout input insensitive instance instantiable instead integrity intersect intersection invoker isnull isolation k key key_member key_type label lag language large last last_value lateral lead leading leakproof least left length level library like_regex link listen ln load local localtime localtimestamp location locator lock locked logged lower m map mapping match matched materialized max maxvalue max_cardinality member merge message_length message_octet_length message_text method min minute minvalue mod mode modifies module month more move multiset mumps name names namespace national natural nchar nclob nesting new next nfc nfd nfkc nfkd nil no none normalize normalized nothing notify notnull nowait nth_value ntile null nullable nullif nulls number object occurrences_regex octets octet_length of off offset oids old only open operator option options ordering ordinality others out outer output over overlaps overlay overriding owned owner p pad parallel parameter parameter_mode parameter_name parameter_ordinal_position parameter_specific_catalog parameter_specific_name parameter_specific_schema parser partial partition pascal passing passthrough password percent percentile_cont percentile_disc percent_rank period permission placing plans pli policy portion position position_regex power precedes preceding prepare prepared preserve primary prior privileges procedural procedure program public quote range rank read reads reassign recheck recovery recursive ref references referencing refresh regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy regr_syy reindex relative release rename repeatable replace replica requiring reset respect restart restore restrict restricted result return returned_cardinality returned_length returned_octet_length returned_sqlstate returning returns revoke right role rollback rollup routine routine_catalog routine_name routine_schema row rows row_count row_number rule savepoint scale schema schema_name scope scope_catalog scope_name scope_schema scroll search second section security selective self sensitive sequence sequences serializable server server_name session session_user setof sets share show similar simple size skip snapshot some source space specific specifictype specific_name sql sqlcode sqlerror sqlexception sqlstate sqlwarning sqrt stable standalone start state statement static statistics stddev_pop stddev_samp stdin stdout storage strict strip structure style subclass_origin submultiset substring substring_regex succeeds sum symmetric sysid system system_time system_user t tables tablesample tablespace table_name temp template temporary then ties timezone_hour timezone_minute to token top_level_count trailing transaction transactions_committed transactions_rolled_back transaction_active transform transforms translate translate_regex translation treat trigger trigger_catalog trigger_name trigger_schema trim trim_array true truncate trusted type types uescape unbounded uncommitted under unencrypted unique unknown unlink unlisten unlogged unnamed unnest until untyped upper uri usage user user_defined_type_catalog user_defined_type_code user_defined_type_name user_defined_type_schema using vacuum valid validate validator value value_of varbinary variadic var_pop var_samp verbose version versioning view views volatile when whenever whitespace width_bucket window within work wrapper write xmlagg xmlattributes xmlbinary xmlcast xmlcomment xmlconcat xmldeclaration xmldocument xmlelement xmlexists xmlforest xmliterate xmlnamespaces xmlparse xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltext xmlvalidate year yes loop repeat attach path depends detach zone"), + keywords: set(sqlKeywords + "a abort abs absent absolute access according action ada add admin after aggregate all allocate also always analyse analyze any are array array_agg array_max_cardinality asensitive assertion assignment asymmetric at atomic attribute attributes authorization avg backward base64 before begin begin_frame begin_partition bernoulli binary bit_length blob blocked bom both breadth c cache call called cardinality cascade cascaded case cast catalog catalog_name ceil ceiling chain characteristics characters character_length character_set_catalog character_set_name character_set_schema char_length check checkpoint class class_origin clob close cluster coalesce cobol collate collation collation_catalog collation_name collation_schema collect column columns column_name command_function command_function_code comment comments commit committed concurrently condition condition_number configuration conflict connect connection connection_name constraint constraints constraint_catalog constraint_name constraint_schema constructor contains content continue control conversion convert copy corr corresponding cost covar_pop covar_samp cross csv cube cume_dist current current_catalog current_date current_default_transform_group current_path current_role current_row current_schema current_time current_timestamp current_transform_group_for_type current_user cursor cursor_name cycle data database datalink datetime_interval_code datetime_interval_precision day db deallocate dec declare default defaults deferrable deferred defined definer degree delimiter delimiters dense_rank depth deref derived describe descriptor deterministic diagnostics dictionary disable discard disconnect dispatch dlnewcopy dlpreviouscopy dlurlcomplete dlurlcompleteonly dlurlcompletewrite dlurlpath dlurlpathonly dlurlpathwrite dlurlscheme dlurlserver dlvalue do document domain dynamic dynamic_function dynamic_function_code each element else empty enable encoding encrypted end end-exec end_frame end_partition enforced enum equals escape event every except exception exclude excluding exclusive exec execute exists exp explain expression extension external extract false family fetch file filter final first first_value flag float floor following for force foreign fortran forward found frame_row free freeze fs full function functions fusion g general generated get global go goto grant granted greatest grouping groups handler header hex hierarchy hold hour id identity if ignore ilike immediate immediately immutable implementation implicit import including increment indent index indexes indicator inherit inherits initially inline inner inout input insensitive instance instantiable instead integrity intersect intersection invoker isnull isolation k key key_member key_type label lag language large last last_value lateral lc_collate lc_ctype lead leading leakproof least left length level library like_regex link listen ln load local localtime localtimestamp location locator lock locked logged lower m map mapping match matched materialized max maxvalue max_cardinality member merge message_length message_octet_length message_text method min minute minvalue mod mode modifies module month more move multiset mumps name names namespace national natural nchar nclob nesting new next nfc nfd nfkc nfkd nil no none normalize normalized nothing notify notnull nowait nth_value ntile null nullable nullif nulls number object occurrences_regex octets octet_length of off offset oids old only open operator option options ordering ordinality others out outer output over overlaps overlay overriding owned owner p pad parallel parameter parameter_mode parameter_name parameter_ordinal_position parameter_specific_catalog parameter_specific_name parameter_specific_schema parser partial partition pascal passing passthrough password percent percentile_cont percentile_disc percent_rank period permission placing plans pli policy portion position position_regex power precedes preceding prepare prepared preserve primary prior privileges procedural procedure program public quote range rank read reads reassign recheck recovery recursive ref references referencing refresh regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy regr_syy reindex relative release rename repeatable replace replica requiring reset respect restart restore restrict restricted result return returned_cardinality returned_length returned_octet_length returned_sqlstate returning returns revoke right role rollback rollup routine routine_catalog routine_name routine_schema row rows row_count row_number rule savepoint scale schema schema_name scope scope_catalog scope_name scope_schema scroll search second section security selective self sensitive sequence sequences serializable server server_name session session_user setof sets share show similar simple size skip snapshot some source space specific specifictype specific_name sql sqlcode sqlerror sqlexception sqlstate sqlwarning sqrt stable standalone start state statement static statistics stddev_pop stddev_samp stdin stdout storage strict strip structure style subclass_origin submultiset substring substring_regex succeeds sum symmetric sysid system system_time system_user t tables tablesample tablespace table_name temp template temporary then ties timezone_hour timezone_minute to token top_level_count trailing transaction transactions_committed transactions_rolled_back transaction_active transform transforms translate translate_regex translation treat trigger trigger_catalog trigger_name trigger_schema trim trim_array true truncate trusted type types uescape unbounded uncommitted under unencrypted unique unknown unlink unlisten unlogged unnamed unnest until untyped upper uri usage user user_defined_type_catalog user_defined_type_code user_defined_type_name user_defined_type_schema using vacuum valid validate validator value value_of varbinary variadic var_pop var_samp verbose version versioning view views volatile when whenever whitespace width_bucket window within work wrapper write xmlagg xmlattributes xmlbinary xmlcast xmlcomment xmlconcat xmldeclaration xmldocument xmlelement xmlexists xmlforest xmliterate xmlnamespaces xmlparse xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltext xmlvalidate year yes loop repeat attach path depends detach zone"), // https://www.postgresql.org/docs/10/static/datatype.html builtin: set("bigint int8 bigserial serial8 bit varying varbit boolean bool box bytea character char varchar cidr circle date double precision float8 inet integer int int4 interval json jsonb line lseg macaddr macaddr8 money numeric decimal path pg_lsn point polygon real float4 smallint int2 smallserial serial2 serial serial4 text time without zone with timetz timestamp timestamptz tsquery tsvector txid_snapshot uuid xml"), atoms: set("false true null unknown"), From ce2fb7c8ebd31df403264fda8640bf8a1c22df02 Mon Sep 17 00:00:00 2001 From: Shane Liesegang Date: Sun, 7 Jan 2018 11:31:49 -0500 Subject: [PATCH 0761/1880] [markdown mode] xlinkHref status should get copied along with the rest of the state. --- mode/markdown/markdown.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 7dfddccd39..24e2468026 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -785,6 +785,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { formatting: false, linkText: s.linkText, linkTitle: s.linkTitle, + linkHref: s.linkHref, code: s.code, em: s.em, strong: s.strong, From ed9f4e3901bdece6d756ef8c167c026665778005 Mon Sep 17 00:00:00 2001 From: Cristian Prieto Date: Sun, 7 Jan 2018 20:20:42 +0100 Subject: [PATCH 0762/1880] [mllike mode] Add additional OCaml types, ML keywords --- mode/mllike/mllike.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/mode/mllike/mllike.js b/mode/mllike/mllike.js index 90e5b41a63..e25e6627af 100644 --- a/mode/mllike/mllike.js +++ b/mode/mllike/mllike.js @@ -37,7 +37,9 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) { 'open': 'builtin', 'ignore': 'builtin', 'begin': 'keyword', - 'end': 'keyword' + 'end': 'keyword', + 'when': 'keyword', + 'as': 'keyword' }; var extraWords = parserConfig.extraWords || {}; @@ -174,7 +176,14 @@ CodeMirror.defineMIME('text/x-ocaml', { 'false': 'atom', 'raise': 'keyword', 'module': 'keyword', - 'sig': 'keyword' + 'sig': 'keyword', + 'exception': 'keyword', + 'int': 'builtin', + 'float': 'builtin', + 'char': 'builtin', + 'string': 'builtin', + 'bool': 'builtin', + 'unit': 'builtin' } }); From 45345505a5c16171889aa4f7d3162cee9f806165 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Jan 2018 12:13:24 +0100 Subject: [PATCH 0763/1880] [sublime bindings] Fix toggleBookMark This had been broken since 5.12 due to a change in the behavior of findMarksAt. Closes #5171 --- keymap/sublime.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keymap/sublime.js b/keymap/sublime.js index 5925b7c51f..7a9aadd330 100644 --- a/keymap/sublime.js +++ b/keymap/sublime.js @@ -382,7 +382,7 @@ var marks = cm.state.sublimeBookmarks || (cm.state.sublimeBookmarks = []); for (var i = 0; i < ranges.length; i++) { var from = ranges[i].from(), to = ranges[i].to(); - var found = cm.findMarks(from, to); + var found = ranges[i].empty() ? cm.findMarksAt(from) : cm.findMarks(from, to); for (var j = 0; j < found.length; j++) { if (found[j].sublimeBookmark) { found[j].clear(); From 774575d6f05f94cab0ec922f11c2e819906f2d11 Mon Sep 17 00:00:00 2001 From: Cristian Prieto Date: Tue, 9 Jan 2018 16:50:16 +0100 Subject: [PATCH 0764/1880] [mllike mode[ Refactor, add SML MIME * Add common keywords for ML languages * Add builtins for OCaml and F# * Add Standard ML as ML language --- mode/meta.js | 1 + mode/mllike/mllike.js | 202 ++++++++++++++++++++++++++++++++---------- 2 files changed, 154 insertions(+), 49 deletions(-) diff --git a/mode/meta.js b/mode/meta.js index 4ab3e08e3e..298074db21 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -128,6 +128,7 @@ {name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]}, {name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]}, {name: "Solr", mime: "text/x-solr", mode: "solr"}, + {name: "SML", mime: "text/x-sml", mode: "mllike", ext: ["sml", "sig", "fun", "smackspec"]}, {name: "Soy", mime: "text/x-soy", mode: "soy", ext: ["soy"], alias: ["closure template"]}, {name: "SPARQL", mime: "application/sparql-query", mode: "sparql", ext: ["rq", "sparql"], alias: ["sparul"]}, {name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]}, diff --git a/mode/mllike/mllike.js b/mode/mllike/mllike.js index e25e6627af..7038a33992 100644 --- a/mode/mllike/mllike.js +++ b/mode/mllike/mllike.js @@ -13,33 +13,26 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) { var words = { - 'let': 'keyword', - 'rec': 'keyword', + 'as': 'keyword', + 'do': 'keyword', + 'else': 'keyword', + 'end': 'keyword', + 'exception': 'keyword', + 'fun': 'keyword', + 'functor': 'keyword', + 'if': 'keyword', 'in': 'keyword', + 'include': 'keyword', + 'let': 'keyword', 'of': 'keyword', - 'and': 'keyword', - 'if': 'keyword', + 'open': 'keyword', + 'rec': 'keyword', + 'struct': 'keyword', 'then': 'keyword', - 'else': 'keyword', - 'for': 'keyword', - 'to': 'keyword', - 'while': 'keyword', - 'do': 'keyword', - 'done': 'keyword', - 'fun': 'keyword', - 'function': 'keyword', - 'val': 'keyword', 'type': 'keyword', - 'mutable': 'keyword', - 'match': 'keyword', - 'with': 'keyword', - 'try': 'keyword', - 'open': 'builtin', - 'ignore': 'builtin', - 'begin': 'keyword', - 'end': 'keyword', - 'when': 'keyword', - 'as': 'keyword' + 'val': 'keyword', + 'while': 'keyword', + 'with': 'keyword' }; var extraWords = parserConfig.extraWords || {}; @@ -70,7 +63,7 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) { return state.tokenize(stream, state); } } - if (ch === '~') { + if (ch === '~' || ch === '?') { stream.eatWhile(/\w/); return 'variable-2'; } @@ -100,7 +93,7 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) { } return 'number'; } - if ( /[+\-*&%=<>!?|@]/.test(ch)) { + if ( /[+\-*&%=<>!?|@]?\./.test(ch)) { return 'operator'; } if (/[\w\xa1-\uffff]/.test(ch)) { @@ -167,23 +160,61 @@ CodeMirror.defineMode('mllike', function(_config, parserConfig) { CodeMirror.defineMIME('text/x-ocaml', { name: 'mllike', extraWords: { - 'succ': 'keyword', + 'and': 'keyword', + 'assert': 'keyword', + 'begin': 'keyword', + 'class': 'keyword', + 'constraint': 'keyword', + 'done': 'keyword', + 'downto': 'keyword', + 'external': 'keyword', + 'initializer': 'keyword', + 'lazy': 'keyword', + 'match': 'keyword', + 'method': 'keyword', + 'module': 'keyword', + 'mutable': 'keyword', + 'new': 'keyword', + 'nonrec': 'keyword', + 'object': 'keyword', + 'private': 'keyword', + 'sig': 'keyword', + 'to': 'keyword', + 'try': 'keyword', + 'value': 'keyword', + 'virtual': 'keyword', + 'when': 'keyword', + + // builtins + 'raise': 'builtin', + 'failwith': 'builtin', + 'true': 'builtin', + 'false': 'builtin', + + // Pervasives builtins + 'asr': 'builtin', + 'land': 'builtin', + 'lor': 'builtin', + 'lsl': 'builtin', + 'lsr': 'builtin', + 'lxor': 'builtin', + 'mod': 'builtin', + 'or': 'builtin', + + // More Pervasives + 'raise_notrace': 'builtin', 'trace': 'builtin', 'exit': 'builtin', 'print_string': 'builtin', 'print_endline': 'builtin', - 'true': 'atom', - 'false': 'atom', - 'raise': 'keyword', - 'module': 'keyword', - 'sig': 'keyword', - 'exception': 'keyword', - 'int': 'builtin', - 'float': 'builtin', - 'char': 'builtin', - 'string': 'builtin', - 'bool': 'builtin', - 'unit': 'builtin' + + // Types + 'int': 'atom', + 'float': 'atom', + 'bool': 'atom', + 'char': 'atom', + 'string': 'atom', + 'unit': 'atom', } }); @@ -191,18 +222,21 @@ CodeMirror.defineMIME('text/x-fsharp', { name: 'mllike', extraWords: { 'abstract': 'keyword', - 'as': 'keyword', 'assert': 'keyword', 'base': 'keyword', + 'begin': 'keyword', 'class': 'keyword', 'default': 'keyword', 'delegate': 'keyword', + 'do!': 'keyword', + 'done': 'keyword', 'downcast': 'keyword', 'downto': 'keyword', 'elif': 'keyword', - 'exception': 'keyword', 'extern': 'keyword', 'finally': 'keyword', + 'for': 'keyword', + 'function': 'keyword', 'global': 'keyword', 'inherit': 'keyword', 'inline': 'keyword', @@ -210,38 +244,108 @@ CodeMirror.defineMIME('text/x-fsharp', { 'internal': 'keyword', 'lazy': 'keyword', 'let!': 'keyword', - 'member' : 'keyword', + 'match': 'keyword', + 'member': 'keyword', 'module': 'keyword', + 'mutable': 'keyword', 'namespace': 'keyword', 'new': 'keyword', 'null': 'keyword', 'override': 'keyword', 'private': 'keyword', 'public': 'keyword', - 'return': 'keyword', 'return!': 'keyword', + 'return': 'keyword', 'select': 'keyword', 'static': 'keyword', - 'struct': 'keyword', + 'to': 'keyword', + 'try': 'keyword', 'upcast': 'keyword', - 'use': 'keyword', 'use!': 'keyword', - 'val': 'keyword', + 'use': 'keyword', + 'void': 'keyword', 'when': 'keyword', - 'yield': 'keyword', 'yield!': 'keyword', + 'yield': 'keyword', + + // Reserved words + 'atomic': 'keyword', + 'break': 'keyword', + 'checked': 'keyword', + 'component': 'keyword', + 'const': 'keyword', + 'constraint': 'keyword', + 'constructor': 'keyword', + 'continue': 'keyword', + 'eager': 'keyword', + 'event': 'keyword', + 'external': 'keyword', + 'fixed': 'keyword', + 'method': 'keyword', + 'mixin': 'keyword', + 'object': 'keyword', + 'parallel': 'keyword', + 'process': 'keyword', + 'protected': 'keyword', + 'pure': 'keyword', + 'sealed': 'keyword', + 'tailcall': 'keyword', + 'trait': 'keyword', + 'virtual': 'keyword', + 'volatile': 'keyword', + // builtins 'List': 'builtin', 'Seq': 'builtin', 'Map': 'builtin', 'Set': 'builtin', + 'Option': 'builtin', 'int': 'builtin', 'string': 'builtin', - 'raise': 'builtin', - 'failwith': 'builtin', 'not': 'builtin', 'true': 'builtin', - 'false': 'builtin' + 'false': 'builtin', + + 'raise': 'builtin', + 'failwith': 'builtin' + }, + slashComments: true +}); + + +CodeMirror.defineMIME('text/x-sml', { + name: 'mllike', + extraWords: { + 'abstype': 'keyword', + 'and': 'keyword', + 'andalso': 'keyword', + 'case': 'keyword', + 'datatype': 'keyword', + 'fn': 'keyword', + 'handle': 'keyword', + 'infix': 'keyword', + 'infixr': 'keyword', + 'local': 'keyword', + 'nonfix': 'keyword', + 'op': 'keyword', + 'orelse': 'keyword', + 'raise': 'keyword', + 'withtype': 'keyword', + 'eqtype': 'keyword', + 'sharing': 'keyword', + 'sig': 'keyword', + 'signature': 'keyword', + 'structure': 'keyword', + 'where': 'keyword', + 'true': 'keyword', + 'false': 'keyword', + + // types + 'int': 'builtin', + 'real': 'builtin', + 'string': 'builtin', + 'char': 'builtin', + 'bool': 'builtin' }, slashComments: true }); From e35f5bbc0c147c15460a189e0a8f291020a9ba8c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 10 Jan 2018 09:39:04 +0100 Subject: [PATCH 0765/1880] [placeholder plugin] Use editor direction Closes #5174 --- addon/display/placeholder.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/display/placeholder.js b/addon/display/placeholder.js index 2f8b1f84ae..65753ebf3f 100644 --- a/addon/display/placeholder.js +++ b/addon/display/placeholder.js @@ -38,6 +38,7 @@ clearPlaceholder(cm); var elt = cm.state.placeholder = document.createElement("pre"); elt.style.cssText = "height: 0; overflow: visible"; + elt.style.direction = cm.getOption("direction"); elt.className = "CodeMirror-placeholder"; var placeHolder = cm.getOption("placeholder") if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder) From 2786ff0a86f32911429351a6aca4cec65e1a5b85 Mon Sep 17 00:00:00 2001 From: neon-dev <1169307+neon-dev@users.noreply.github.com> Date: Mon, 8 Jan 2018 12:55:04 +0100 Subject: [PATCH 0766/1880] [sql-hint addon] Switch order of hints Show column hints (if a defaultTable is set) above table hints, since you are far more often in clauses where you need those. --- addon/hint/sql-hint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/hint/sql-hint.js b/addon/hint/sql-hint.js index f5ec2cac1f..5600c8390d 100644 --- a/addon/hint/sql-hint.js +++ b/addon/hint/sql-hint.js @@ -273,8 +273,8 @@ if (search.charAt(0) == "." || search.charAt(0) == identifierQuote) { start = nameCompletion(cur, token, result, editor); } else { - addMatches(result, search, tables, function(w) {return w;}); addMatches(result, search, defaultTable, function(w) {return w;}); + addMatches(result, search, tables, function(w) {return w;}); if (!disableKeywords) addMatches(result, search, keywords, function(w) {return w.toUpperCase();}); } From 350f71b09d166f1a149514503dc86ff00963faa1 Mon Sep 17 00:00:00 2001 From: neon-dev <1169307+neon-dev@users.noreply.github.com> Date: Mon, 8 Jan 2018 12:50:23 +0100 Subject: [PATCH 0767/1880] [sql-hint addon] Fix nullpointer If you try to autocomplete at line 0, column 0 after previoulsy having edited for example a WHERE clause, the autocompletion triggers with an invalid position, since prevItem is null. Maybe my fix isn't the best solution, and you could even avoid to enter findTableByAlias enitrely, I don't know. --- addon/hint/sql-hint.js | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/addon/hint/sql-hint.js b/addon/hint/sql-hint.js index 5600c8390d..5d20eea625 100644 --- a/addon/hint/sql-hint.js +++ b/addon/hint/sql-hint.js @@ -222,18 +222,20 @@ prevItem = separator[i]; } - var query = doc.getRange(validRange.start, validRange.end, false); - - for (var i = 0; i < query.length; i++) { - var lineText = query[i]; - eachWord(lineText, function(word) { - var wordUpperCase = word.toUpperCase(); - if (wordUpperCase === aliasUpperCase && getTable(previousWord)) - table = previousWord; - if (wordUpperCase !== CONS.ALIAS_KEYWORD) - previousWord = word; - }); - if (table) break; + if (validRange.start) { + var query = doc.getRange(validRange.start, validRange.end, false); + + for (var i = 0; i < query.length; i++) { + var lineText = query[i]; + eachWord(lineText, function(word) { + var wordUpperCase = word.toUpperCase(); + if (wordUpperCase === aliasUpperCase && getTable(previousWord)) + table = previousWord; + if (wordUpperCase !== CONS.ALIAS_KEYWORD) + previousWord = word; + }); + if (table) break; + } } return table; } From dccaafe5200267dc9a2d605c6caee592bfb0408b Mon Sep 17 00:00:00 2001 From: Filype Pereira Date: Sat, 30 Dec 2017 09:52:02 +1300 Subject: [PATCH 0768/1880] [oceanic-next theme] Add --- demo/theme.html | 2 ++ theme/oceanic-next.css | 44 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 theme/oceanic-next.css diff --git a/demo/theme.html b/demo/theme.html index 9194dcea8b..0c52d256d9 100644 --- a/demo/theme.html +++ b/demo/theme.html @@ -34,6 +34,7 @@ + @@ -119,6 +120,7 @@

    Theme Demo

    + diff --git a/theme/oceanic-next.css b/theme/oceanic-next.css new file mode 100644 index 0000000000..296277ba04 --- /dev/null +++ b/theme/oceanic-next.css @@ -0,0 +1,44 @@ +/* + + Name: oceanic-next + Author: Filype Pereira (https://github.com/fpereira1) + + Original oceanic-next color scheme by Dmitri Voronianski (https://github.com/voronianski/oceanic-next-color-scheme) + +*/ + +.cm-s-oceanic-next.CodeMirror { background: #304148; color: #f8f8f2; } +.cm-s-oceanic-next div.CodeMirror-selected { background: rgba(101, 115, 126, 0.33); } +.cm-s-oceanic-next .CodeMirror-line::selection, .cm-s-oceanic-next .CodeMirror-line > span::selection, .cm-s-oceanic-next .CodeMirror-line > span > span::selection { background: rgba(101, 115, 126, 0.33); } +.cm-s-oceanic-next .CodeMirror-line::-moz-selection, .cm-s-oceanic-next .CodeMirror-line > span::-moz-selection, .cm-s-oceanic-next .CodeMirror-line > span > span::-moz-selection { background: rgba(101, 115, 126, 0.33); } +.cm-s-oceanic-next .CodeMirror-gutters { background: #304148; border-right: 10px; } +.cm-s-oceanic-next .CodeMirror-guttermarker { color: white; } +.cm-s-oceanic-next .CodeMirror-guttermarker-subtle { color: #d0d0d0; } +.cm-s-oceanic-next .CodeMirror-linenumber { color: #d0d0d0; } +.cm-s-oceanic-next .CodeMirror-cursor { border-left: 1px solid #f8f8f0; } + +.cm-s-oceanic-next span.cm-comment { color: #65737E; } +.cm-s-oceanic-next span.cm-atom { color: #C594C5; } +.cm-s-oceanic-next span.cm-number { color: #F99157; } + +.cm-s-oceanic-next span.cm-property { color: #99C794; } +.cm-s-oceanic-next span.cm-attribute, +.cm-s-oceanic-next span.cm-keyword { color: #C594C5; } +.cm-s-oceanic-next span.cm-builtin { color: #66d9ef; } +.cm-s-oceanic-next span.cm-string { color: #99C794; } + +.cm-s-oceanic-next span.cm-variable, +.cm-s-oceanic-next span.cm-variable-2, +.cm-s-oceanic-next span.cm-variable-3 { color: #f8f8f2; } +.cm-s-oceanic-next span.cm-def { color: #6699CC; } +.cm-s-oceanic-next span.cm-bracket { color: #5FB3B3; } +.cm-s-oceanic-next span.cm-tag { color: #C594C5; } +.cm-s-oceanic-next span.cm-header { color: #C594C5; } +.cm-s-oceanic-next span.cm-link { color: #C594C5; } +.cm-s-oceanic-next span.cm-error { background: #C594C5; color: #f8f8f0; } + +.cm-s-oceanic-next .CodeMirror-activeline-background { background: rgba(101, 115, 126, 0.33); } +.cm-s-oceanic-next .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} From e9e5f23b81ec86f84680d8b13ff422408e1a9428 Mon Sep 17 00:00:00 2001 From: overdodactyl Date: Sat, 6 Jan 2018 21:28:00 -0700 Subject: [PATCH 0769/1880] [shadowfox theme] Add --- demo/theme.html | 2 ++ theme/shadowfox.css | 52 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 theme/shadowfox.css diff --git a/demo/theme.html b/demo/theme.html index 0c52d256d9..e01f79a70f 100644 --- a/demo/theme.html +++ b/demo/theme.html @@ -42,6 +42,7 @@ + @@ -128,6 +129,7 @@

    Theme Demo

    + diff --git a/theme/shadowfox.css b/theme/shadowfox.css new file mode 100644 index 0000000000..32d59b139a --- /dev/null +++ b/theme/shadowfox.css @@ -0,0 +1,52 @@ +/* + + Name: shadowfox + Author: overdodactyl (http://github.com/overdodactyl) + + Original shadowfox color scheme by Firefox + +*/ + +.cm-s-shadowfox.CodeMirror { background: #2a2a2e; color: #b1b1b3; } +.cm-s-shadowfox div.CodeMirror-selected { background: #353B48; } +.cm-s-shadowfox .CodeMirror-line::selection, .cm-s-shadowfox .CodeMirror-line > span::selection, .cm-s-shadowfox .CodeMirror-line > span > span::selection { background: #353B48; } +.cm-s-shadowfox .CodeMirror-line::-moz-selection, .cm-s-shadowfox .CodeMirror-line > span::-moz-selection, .cm-s-shadowfox .CodeMirror-line > span > span::-moz-selection { background: #353B48; } +.cm-s-shadowfox .CodeMirror-gutters { background: #0c0c0d ; border-right: 1px solid #0c0c0d; } +.cm-s-shadowfox .CodeMirror-guttermarker { color: #555; } +.cm-s-shadowfox .CodeMirror-linenumber { color: #939393; } +.cm-s-shadowfox .CodeMirror-cursor { border-left: 1px solid #fff; } + +.cm-s-shadowfox span.cm-comment { color: #939393; } +.cm-s-shadowfox span.cm-atom { color: #FF7DE9; } +.cm-s-shadowfox span.cm-quote { color: #FF7DE9; } +.cm-s-shadowfox span.cm-builtin { color: #FF7DE9; } +.cm-s-shadowfox span.cm-attribute { color: #FF7DE9; } +.cm-s-shadowfox span.cm-keyword { color: #FF7DE9; } +.cm-s-shadowfox span.cm-error { color: #FF7DE9; } + +.cm-s-shadowfox span.cm-number { color: #6B89FF; } +.cm-s-shadowfox span.cm-string { color: #6B89FF; } +.cm-s-shadowfox span.cm-string-2 { color: #6B89FF; } + +.cm-s-shadowfox span.cm-meta { color: #939393; } +.cm-s-shadowfox span.cm-hr { color: #939393; } + +.cm-s-shadowfox span.cm-header { color: #75BFFF; } +.cm-s-shadowfox span.cm-qualifier { color: #75BFFF; } +.cm-s-shadowfox span.cm-variable-2 { color: #75BFFF; } + +.cm-s-shadowfox span.cm-property { color: #86DE74; } + +.cm-s-shadowfox span.cm-def { color: #75BFFF; } +.cm-s-shadowfox span.cm-bracket { color: #75BFFF; } +.cm-s-shadowfox span.cm-tag { color: #75BFFF; } +.cm-s-shadowfox span.cm-link:visited { color: #75BFFF; } + +.cm-s-shadowfox span.cm-variable { color: #B98EFF; } +.cm-s-shadowfox span.cm-variable-3 { color: #d7d7db; } +.cm-s-shadowfox span.cm-link { color: #737373; } +.cm-s-shadowfox span.cm-operator { color: #b1b1b3; } +.cm-s-shadowfox span.cm-special { color: #d7d7db; } + +.cm-s-shadowfox .CodeMirror-activeline-background { background: rgba(185, 215, 253, .15) } +.cm-s-shadowfox .CodeMirror-matchingbracket { outline: solid 1px rgba(255, 255, 255, .25); color: white !important; } From e4bf8dff42d80a4bfab366733dfd992b62a66880 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 11 Jan 2018 08:56:15 +0100 Subject: [PATCH 0770/1880] [closebrackets addon] Avoid annoying behavior when closing a triple-quoted string Issue #5177 --- addon/edit/closebrackets.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 460f662f80..86b2fe1c95 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -129,8 +129,8 @@ else curType = "skip"; } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 && - cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch && - (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) { + cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) { + if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass; curType = "addFour"; } else if (identical) { var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur) From 2a168994fba2a6c9250edb59b7dc56dc46767053 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 12 Jan 2018 08:26:55 +0100 Subject: [PATCH 0771/1880] [javascript mode] Fix highlighting of TS implements keyword Closes #5178 --- mode/javascript/javascript.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index edab99f3d7..29085a21c4 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -680,8 +680,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function classNameAfter(type, value) { if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter) - if (value == "extends" || value == "implements" || (isTS && type == ",")) + if (value == "extends" || value == "implements" || (isTS && type == ",")) { + cx.marked = "keyword"; return cont(isTS ? typeexpr : expression, classNameAfter); + } if (type == "{") return cont(pushlex("}"), classBody, poplex); } function classBody(type, value) { From d89267681d21f46a78a90002a9b18dc95acac1f4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 12 Jan 2018 08:36:22 +0100 Subject: [PATCH 0772/1880] [javascript mode] Fix previous patch --- mode/javascript/javascript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 29085a21c4..64c910d849 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -681,7 +681,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function classNameAfter(type, value) { if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter) if (value == "extends" || value == "implements" || (isTS && type == ",")) { - cx.marked = "keyword"; + if (value == "implements") cx.marked = "keyword"; return cont(isTS ? typeexpr : expression, classNameAfter); } if (type == "{") return cont(pushlex("}"), classBody, poplex); From 4fa785ea875aade5beb64ebc317969f3fb653125 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 13 Jan 2018 10:34:10 +0100 Subject: [PATCH 0773/1880] [xml-fold addon] Handle line-broken opening tags better No longer creates a fold spot for both lines of a line-broken tag. Closes #5179 --- addon/fold/xml-fold.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/fold/xml-fold.js b/addon/fold/xml-fold.js index 08e2149553..3acf952d9d 100644 --- a/addon/fold/xml-fold.js +++ b/addon/fold/xml-fold.js @@ -138,7 +138,7 @@ var iter = new Iter(cm, start.line, 0); for (;;) { var openTag = toNextTag(iter), end; - if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return; + if (!openTag || !(end = toTagEnd(iter)) || iter.line != start.line) return; if (!openTag[1] && end != "selfClose") { var startPos = Pos(iter.line, iter.ch); var endPos = findMatchingClose(iter, openTag[2]); From e03ef21df390753eb35ff8426dd99b1be4d29d74 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 13 Jan 2018 17:52:27 +0100 Subject: [PATCH 0774/1880] [javascript mode] Further improve handling of TS contextual keywords Closes #5180 Closes #5181 --- mode/javascript/javascript.js | 20 +++++++++++++------- mode/javascript/test.js | 10 ++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 64c910d849..9eb50ba974 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -345,15 +345,14 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "for") return cont(pushlex("form"), forspec, statement, poplex); if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), className, poplex); } if (type == "variable") { - if (isTS && value == "type") { - cx.marked = "keyword" - return cont(typeexpr, expect("operator"), typeexpr, expect(";")); - } else if (isTS && value == "declare") { + if (isTS && value == "declare") { cx.marked = "keyword" return cont(statement) - } else if (isTS && (value == "module" || value == "enum") && cx.stream.match(/^\s*\w/, false)) { + } else if (isTS && (value == "module" || value == "enum" || value == "type") && cx.stream.match(/^\s*\w/, false)) { cx.marked = "keyword" - return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex) + if (value == "enum") return cont(enumdef); + else if (value == "type") return cont(typeexpr, expect("operator"), typeexpr, expect(";")); + else return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex) } else if (isTS && value == "namespace") { cx.marked = "keyword" return cont(pushlex("form"), expression, block, poplex) @@ -608,7 +607,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function maybeTypeDefault(_, value) { if (value == "=") return cont(typeexpr) } - function vardef() { + function vardef(_, value) { + if (value == "enum") {cx.marked = "keyword"; return cont(enumdef)} return pass(pattern, maybetype, maybeAssign, vardefCont); } function pattern(type, value) { @@ -747,6 +747,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "]") return cont(); return pass(commasep(expressionNoComma, "]")); } + function enumdef() { + return pass(pushlex("form"), pattern, expect("{"), pushlex("}"), commasep(enummember, "}"), poplex, poplex) + } + function enummember() { + return pass(pattern, maybeAssign); + } function isContinuedStatement(state, textAfter) { return state.lastType == "operator" || state.lastType == "," || diff --git a/mode/javascript/test.js b/mode/javascript/test.js index 167e6d0165..14a5183cab 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -383,6 +383,16 @@ " }", "}") + TS("type as variable", + "[variable type] [operator =] [variable x] [keyword as] [type Bar];"); + + TS("enum body", + "[keyword export] [keyword const] [keyword enum] [def CodeInspectionResultType] {", + " [def ERROR] [operator =] [string 'problem_type_error'],", + " [def WARNING] [operator =] [string 'problem_type_warning'],", + " [def META],", + "}") + var jsonld_mode = CodeMirror.getMode( {indentUnit: 2}, {name: "javascript", jsonld: true} From 974182466ba8165f15ccc6b5b07b785bcbc39c63 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 17 Jan 2018 09:37:55 +0100 Subject: [PATCH 0775/1880] [shell mode] Improve handling of quotes inside parentheses Closes #5187 --- mode/shell/shell.js | 23 ++++++++++++++++------- mode/shell/test.js | 3 +++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/mode/shell/shell.js b/mode/shell/shell.js index 9b8b90b305..9fcd671cf5 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -84,29 +84,38 @@ CodeMirror.defineMode('shell', function() { function tokenString(quote, style) { var close = quote == "(" ? ")" : quote == "{" ? "}" : quote return function(stream, state) { - var next, end = false, escaped = false; + var next, escaped = false; while ((next = stream.next()) != null) { if (next === close && !escaped) { - end = true; + state.tokens.shift(); break; - } - if (next === '$' && !escaped && quote !== "'") { + } else if (next === '$' && !escaped && quote !== "'") { escaped = true; stream.backUp(1); state.tokens.unshift(tokenDollar); break; - } - if (!escaped && next === quote && quote !== close) { + } else if (!escaped && quote !== close && next === quote) { state.tokens.unshift(tokenString(quote, style)) return tokenize(stream, state) + } else if (!escaped && /['"]/.test(next) && !/['"]/.test(quote)) { + state.tokens.unshift(tokenStringStart(next, "string")); + stream.backUp(1); + break; } escaped = !escaped && next === '\\'; } - if (end) state.tokens.shift(); return style; }; }; + function tokenStringStart(quote, style) { + return function(stream, state) { + state.tokens[0] = tokenString(quote, style) + stream.next() + return tokenize(stream, state) + } + } + var tokenDollar = function(stream, state) { if (state.tokens.length > 1) stream.eat('$'); var ch = stream.next() diff --git a/mode/shell/test.js b/mode/shell/test.js index 86e344c572..05f07d22b1 100644 --- a/mode/shell/test.js +++ b/mode/shell/test.js @@ -61,4 +61,7 @@ MT("nested braces", "[builtin echo] [def ${A[${B}]]}]") + + MT("strings in parens", + "[def FOO][operator =]([quote $(<][string \"][def $MYDIR][string \"][quote /myfile grep ][string 'hello$'][quote )])") })(); From d8d68a8a86cce37fd3b19d0c3025e1a38df20ead Mon Sep 17 00:00:00 2001 From: neon-dev <1169307+neon-dev@users.noreply.github.com> Date: Tue, 16 Jan 2018 14:16:47 +0100 Subject: [PATCH 0776/1880] [javascript-lint addon] Fix incorrect severity When enabling strict equality checks via `lint: {options: {eqeqeq: true}}`, found problems showed up as errors instead of warnings. To fix it, the `fixWith()` logic had to be changed since simply adding the phrase to the warnings array would not have worked. This is because both the warnings and errors array matched this exact error and therefore the severity could never be "warning" (errors were checked after warnings). I didn't include "Missing property name" and "Unmatched " in the new error array since they already are errors with the new logic. "Stopping, unable to continue" also got removed since it didn't appear anywhere in the current jshint.js. For now I've implemented everything to not break previous behavior/hinting, except the strict equality hint severity. Although I want to suggest removing the following codes from the new error array (so they can stay warnings): - W033 (Missing semicolon) - since erroneous missing semicolons have their own code: E058 - W084 (Expected a conditional expression and instead saw an assignment) - since something like `switch (var2 = var1 + 42)` is valid js code, though not recommendable - maybe W023/24/30/90, since there are many more " and instead saw an" hints that are already errors with their own codes, so I think they should be pretty accurate. Unfortunately I couldn't force these warnings so I couldn't check. --- addon/lint/javascript-lint.js | 49 +++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/addon/lint/javascript-lint.js b/addon/lint/javascript-lint.js index c58f785025..f73aaa51a0 100644 --- a/addon/lint/javascript-lint.js +++ b/addon/lint/javascript-lint.js @@ -14,12 +14,20 @@ var bogus = [ "Dangerous comment" ]; - var warnings = [ [ "Expected '{'", + var replacements = [ [ "Expected '{'", "Statement body should be inside '{ }' braces." ] ]; - var errors = [ "Missing semicolon", "Extra comma", "Missing property name", - "Unmatched ", " and instead saw", " is not defined", - "Unclosed string", "Stopping, unable to continue" ]; + var forcedErrorCodes = [ + "W033", // Missing semicolon. + "W070", // Extra comma. (it breaks older versions of IE) + "W112", // Unclosed string. + "W117", // '{a}' is not defined. + "W023", // Expected an identifier in an assignment and instead saw a function invocation. + "W024", // Expected an identifier and instead saw '{a}' (a reserved word). + "W030", // Expected an assignment or function call and instead saw an expression. + "W084", // Expected a conditional expression and instead saw an assignment. + "W095" // Expected a string and instead saw {a}. + ]; function validator(text, options) { if (!window.JSHINT) { @@ -37,29 +45,35 @@ CodeMirror.registerHelper("lint", "javascript", validator); function cleanup(error) { - // All problems are warnings by default - fixWith(error, warnings, "warning", true); - fixWith(error, errors, "error"); + fixWith(error, forcedErrorCodes, replacements); return isBogus(error) ? null : error; } - function fixWith(error, fixes, severity, force) { - var description, fix, find, replace, found; + function fixWith(error, forcedErrorCodes, replacements) { + var errorCode, description, i, fix, find, replace, found; + errorCode = error.code; description = error.description; - for ( var i = 0; i < fixes.length; i++) { - fix = fixes[i]; - find = (typeof fix === "string" ? fix : fix[0]); - replace = (typeof fix === "string" ? null : fix[1]); + if (error.severity !== "error") { + for (i = 0; i < forcedErrorCodes.length; i++) { + if (errorCode === forcedErrorCodes[i]) { + error.severity = "error"; + break; + } + } + } + + for (i = 0; i < replacements.length; i++) { + fix = replacements[i]; + find = fix[0]; found = description.indexOf(find) !== -1; - if (force || found) { - error.severity = severity; - } - if (found && replace) { + if (found) { + replace = fix[1]; error.description = replace; + break; } } } @@ -128,6 +142,7 @@ error.description = error.reason;// + "(jshint)"; error.start = error.character; error.end = end; + error.severity = error.code.startsWith('W') ? "warning" : "error"; error = cleanup(error); if (error) From dac3bdec7a5678c9adedfe3d8f2ce86f9823361c Mon Sep 17 00:00:00 2001 From: neon-dev <1169307+neon-dev@users.noreply.github.com> Date: Tue, 16 Jan 2018 16:08:53 +0100 Subject: [PATCH 0777/1880] [javascript-lint addon] Remove obsolete function --- addon/lint/javascript-lint.js | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/addon/lint/javascript-lint.js b/addon/lint/javascript-lint.js index f73aaa51a0..a6d31210a2 100644 --- a/addon/lint/javascript-lint.js +++ b/addon/lint/javascript-lint.js @@ -12,8 +12,6 @@ "use strict"; // declare global: JSHINT - var bogus = [ "Dangerous comment" ]; - var replacements = [ [ "Expected '{'", "Statement body should be inside '{ }' braces." ] ]; @@ -46,8 +44,6 @@ function cleanup(error) { fixWith(error, forcedErrorCodes, replacements); - - return isBogus(error) ? null : error; } function fixWith(error, forcedErrorCodes, replacements) { @@ -78,16 +74,6 @@ } } - function isBogus(error) { - var description = error.description; - for ( var i = 0; i < bogus.length; i++) { - if (description.indexOf(bogus[i]) !== -1) { - return true; - } - } - return false; - } - function parseErrors(errors, output) { for ( var i = 0; i < errors.length; i++) { var error = errors[i]; @@ -143,7 +129,7 @@ error.start = error.character; error.end = end; error.severity = error.code.startsWith('W') ? "warning" : "error"; - error = cleanup(error); + cleanup(error); if (error) output.push({message: error.description, From 81391e6ad9b30d1238d10843325ef375e5f91356 Mon Sep 17 00:00:00 2001 From: neon-dev <1169307+neon-dev@users.noreply.github.com> Date: Wed, 17 Jan 2018 11:37:47 +0100 Subject: [PATCH 0778/1880] [lint demo] Use a more recent version of JSHint --- demo/lint.html | 2 +- demo/widget.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/lint.html b/demo/lint.html index 96009b4e1f..2a1c30b47d 100644 --- a/demo/lint.html +++ b/demo/lint.html @@ -9,7 +9,7 @@ - + diff --git a/demo/widget.html b/demo/widget.html index da39a9297a..58ebb4d97a 100644 --- a/demo/widget.html +++ b/demo/widget.html @@ -7,7 +7,7 @@ - +
    From c8c4565d09f240afc33a31561e42943dfeee4784 Mon Sep 17 00:00:00 2001 From: Bin Ni Date: Mon, 20 Jul 2020 13:09:25 -0700 Subject: [PATCH 1419/1880] [show-hint addon] Introduced option 'scrollMargin' --- addon/hint/show-hint.js | 12 +++++++----- doc/manual.html | 3 +++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index c55deab3a6..cd0d6a7bd5 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -379,12 +379,14 @@ }, scrollToActive: function() { - var node = this.hints.childNodes[this.selectedHint] + var margin = this.completion.options.scrollMargin || 0; + var node1 = this.hints.childNodes[Math.max(0, this.selectedHint - margin)]; + var node2 = this.hints.childNodes[Math.min(this.data.list.length - 1, this.selectedHint + margin)]; var firstNode = this.hints.firstChild; - if (node.offsetTop < this.hints.scrollTop) - this.hints.scrollTop = node.offsetTop - firstNode.offsetTop; - else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) - this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + firstNode.offsetTop; + if (node1.offsetTop < this.hints.scrollTop) + this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop; + else if (node2.offsetTop + node2.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) + this.hints.scrollTop = node2.offsetTop + node2.offsetHeight - this.hints.clientHeight + firstNode.offsetTop; }, screenAmount: function() { diff --git a/doc/manual.html b/doc/manual.html index a76378470d..1bcd395e63 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2790,6 +2790,9 @@

    Addons

    Like customKeys above, but the bindings will be added to the set of default bindings, instead of replacing them.
    +
    scrollMargin: integer
    +
    Show this many lines before and after the selected item. + Default is 0.
    The following events will be fired on the completions object during completion: From 772d09e697612889ec5dbed2cc058e754232c29d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 20 Jul 2020 22:28:58 +0200 Subject: [PATCH 1420/1880] Mark version 5.56.0 --- AUTHORS | 2 ++ CHANGELOG.md | 20 +++++++++++++++++++- doc/manual.html | 2 +- doc/releases.html | 12 ++++++++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 37 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index f041a0572a..a9e79126b6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -441,6 +441,7 @@ jwallers@gmail.com kaniga karevn Karol +Kaushik Kulkarni Kayur Patel Kazuhito Hokamura kcwiakala @@ -657,6 +658,7 @@ Patrick Strawderman Paul Garvin Paul Ivanov Paul Masson +Paul Schmidt Pavel Pavel Feldman Pavel Petržela diff --git a/CHANGELOG.md b/CHANGELOG.md index b87340b524..13039b9701 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,22 @@ -## 5.55.0 (2020-05-20) +## 5.56.0 (2020-07-20) + +### Bug fixes + +Line-wise pasting was fixed on Chrome Windows. + +[wast mode](https://codemirror.net/mode/wast/): Follow standard changes. + +[soy mode](https://codemirror.net/mode/soy/): Support import expressions, template type, and loop indices. + +[sql-hint addon](https://codemirror.net/doc/manual.html#addon_sql-hint): Improve handling of double quotes. + +### New features + +[show-hint addon](https://codemirror.net/doc/manual.html#addon_show-hint): New option `scrollMargin` to control how many options are visible beyond the selected one. + +[hardwrap addon](https://codemirror.net/doc/manual.html#addon_hardwrap): New option `forceBreak` to disable breaking of words that are longer than a line. + +## 5.55.0 (2020-06-21) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 1bcd395e63..ba46c099f0 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

    User manual and reference guide - version 5.55.0 + version 5.56.0

    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index fd02a7fbd9..6ab175a7b3 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,18 @@

    Release notes and version history

    Version 5.x

    +

    20-07-2020: Version 5.56.0:

    + +
      +
    • Line-wise pasting was fixed on Chrome Windows.
    • +
    • wast mode: Follow standard changes.
    • +
    • soy mode: Support import expressions, template type, and loop indices.
    • +
    • sql-hint addon: Improve handling of double quotes.
    • +
    • New features

    • +
    • show-hint addon: New option scrollMargin to control how many options are visible beyond the selected one.
    • +
    • hardwrap addon: New option forceBreak to disable breaking of words that are longer than a line.
    • +
    +

    21-06-2020: Version 5.55.0:

      diff --git a/index.html b/index.html index 27cf8fc7fe..8ee9b384b2 100644 --- a/index.html +++ b/index.html @@ -99,7 +99,7 @@

      This is CodeMirror

    - Get the current version: 5.55.0.
    + Get the current version: 5.56.0.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index dcffa6d998..374bd877d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.55.0", + "version": "5.56.0", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 04efb81564..3b378e8f33 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.55.0" +CodeMirror.version = "5.56.0" From fdbc04a94a3b0064b896effa6da6544f1c2bb39a Mon Sep 17 00:00:00 2001 From: Howard Date: Thu, 23 Jul 2020 14:45:56 -0400 Subject: [PATCH 1421/1880] [vim bindings] Support tag text objects in xml / htmlmixed mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User can use `t` to operate on tag text objects. For example, given the following html: ```
    hello world!
    ``` If the user's cursor (denoted by █) is inside "hello world!": ```
    hello█world!
    ``` And they enter `dit` (delete inner tag), then the text inside the enclosing tag is deleted -- the following is the expected result: ```
    ``` If they enter `dat` (delete around tag), then the surrounding tags are deleted as well: ```
    ``` This logic depends on the following: - mode/xml/xml.js - addon/fold/xml-fold.js - editor is in htmlmixedmode / xml mode Caveats This is _NOT_ a 100% accurate implementation of vim tag text objects. For example, the following cases noop / are inconsistent with vim behavior: - Does not work inside comments: ``` ``` - Does not work when tags have different cases: ```
    broken
    ``` - Does not work when inside a broken tag: ```
    ``` This addresses #3828. --- keymap/vim.js | 47 ++++++++++++++++++++++++++++++++++++++++++++++- test/index.html | 1 + test/vim_test.js | 30 ++++++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index bca6d46d72..5a4860c65a 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2069,6 +2069,8 @@ if (operatorArgs) { operatorArgs.linewise = true; } tmp.end.line--; } + } else if (character === 't') { + tmp = expandTagUnderCursor(cm, head, inclusive); } else { // No text object defined for this, don't move. return null; @@ -3295,6 +3297,49 @@ return { start: Pos(cur.line, start), end: Pos(cur.line, end) }; } + /** + * Depends on the following: + * + * - editor mode should be htmlmixedmode / xml + * - mode/xml/xml.js should be loaded + * - addon/fold/xml-fold.js should be loaded + * + * If any of the above requirements are not true, this function noops. + * + * This is _NOT_ a 100% accurate implementation of vim tag text objects. + * The following caveats apply (based off cursory testing, I'm sure there + * are other discrepancies): + * + * - Does not work inside comments: + * ``` + * + * ``` + * - Does not work when tags have different cases: + * ``` + *
    broken
    + * ``` + * - Does not work when cursor is inside a broken tag: + * ``` + *
    + * ``` + */ + function expandTagUnderCursor(cm, head, inclusive) { + var cur = head; + if (!CodeMirror.findMatchingTag || !CodeMirror.findEnclosingTag) { + return { start: cur, end: cur }; + } + + var tags = CodeMirror.findMatchingTag(cm, head) || CodeMirror.findEnclosingTag(cm, head); + if (!tags || !tags.open || !tags.close) { + return { start: cur, end: cur }; + } + + if (inclusive) { + return { start: tags.open.from, end: tags.close.to }; + } + return { start: tags.open.to, end: tags.close.from }; + } + function recordJumpPosition(cm, oldCur, newCur) { if (!cursorEqual(oldCur, newCur)) { vimGlobalState.jumpList.add(cm, oldCur, newCur); @@ -3836,7 +3881,7 @@ return Pos(curr_index.ln, curr_index.pos); } - // TODO: perhaps this finagling of start and end positions belonds + // TODO: perhaps this finagling of start and end positions belongs // in codemirror/replaceRange? function selectCompanionObject(cm, head, symb, inclusive) { var cur = head, start, end; diff --git a/test/index.html b/test/index.html index b68ce18964..6566fc436e 100644 --- a/test/index.html +++ b/test/index.html @@ -156,6 +156,7 @@

    Test Suite

    + diff --git a/test/vim_test.js b/test/vim_test.js index 71284bdf59..57d276e871 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1317,9 +1317,13 @@ testVim('=', function(cm, vim, helpers) { eq(expectedValue, cm.getValue()); }, { value: ' word1\n word2\n word3', indentUnit: 2 }); -// Edit tests -function testEdit(name, before, pos, edit, after) { +// Edit tests - configureCm is an optional argument that gives caller +// access to the cm object. +function testEdit(name, before, pos, edit, after, configureCm) { return testVim(name, function(cm, vim, helpers) { + if (configureCm) { + configureCm(cm); + } var ch = before.search(pos) var line = before.substring(0, ch).split('\n').length - 1; if (line) { @@ -1424,6 +1428,28 @@ testEdit('di>_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'di>', 'a\t<>b'); testEdit('da<_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'da<', 'a\tb'); testEdit('da>_middle_spc', 'a\t<\n\tbar\n>b', /r/, 'da>', 'a\tb'); +// deleting tag objects +testEdit('dat_noop', 'hello', /n/, 'dat', 'hello'); +testEdit('dat_open_tag', 'hello', /n/, 'dat', '', function(cm) { + cm.setOption('mode', 'xml'); +}); +testEdit('dat_inside_tag', 'hello', /l/, 'dat', '', function(cm) { + cm.setOption('mode', 'xml'); +}); +testEdit('dat_close_tag', 'hello', /\//, 'dat', '', function(cm) { + cm.setOption('mode', 'xml'); +}); + +testEdit('dit_open_tag', 'hello', /n/, 'dit', '', function(cm) { + cm.setOption('mode', 'xml'); +}); +testEdit('dit_inside_tag', 'hello', /l/, 'dit', '', function(cm) { + cm.setOption('mode', 'xml'); +}); +testEdit('dit_close_tag', 'hello', /\//, 'dit', '', function(cm) { + cm.setOption('mode', 'xml'); +}); + function testSelection(name, before, pos, keys, sel) { return testVim(name, function(cm, vim, helpers) { var ch = before.search(pos) From 3e3c21cbe5d10ac14ab69c16da5a0fa035a22b33 Mon Sep 17 00:00:00 2001 From: Haoran Yu Date: Thu, 30 Jul 2020 15:42:44 +0800 Subject: [PATCH 1422/1880] [real-world uses] Add CodeMirror-Record (#6360) --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index a08d754550..1cde8ace62 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -52,6 +52,7 @@

    CodeMirror real-world uses

  • CodeFights (practice programming)
  • CodeMirror Eclipse (embed CM in Eclipse)
  • CodeMirror movie (scripted editing demos)
  • +
  • CodeMirror Record (codemirror activity recording and playback)
  • CodeMirror2-GWT (Google Web Toolkit wrapper)
  • Code Monster & Code Maven (learning environment)
  • Codepen (gallery of animations)
  • From 68d4da261d1e24b744773467b4d06c62c965b34a Mon Sep 17 00:00:00 2001 From: orionlee Date: Thu, 30 Jul 2020 21:32:35 -0700 Subject: [PATCH 1423/1880] [real-world uses] Add Violentmonkey --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 1cde8ace62..bb2dc7f8b3 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -182,6 +182,7 @@

    CodeMirror real-world uses

  • TurboPY (web publishing framework)
  • UmpleOnline (model-oriented programming tool)
  • Upsource (code browser and review tool)
  • +
  • Violentmonkey (userscript manager / editor)
  • Waliki (wiki engine)
  • Wamer (web application builder)
  • webappfind (windows file bindings for webapps)
  • From 5bff5502c813ef773c0a6a47a7c761d017f0361d Mon Sep 17 00:00:00 2001 From: orionlee Date: Thu, 30 Jul 2020 20:52:29 -0700 Subject: [PATCH 1424/1880] [css] add missing 1) property all, 2) media feature prefers-color-scheme --- mode/css/css.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index 441ba4abfd..85f1bdc767 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -442,17 +442,18 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "monochrome", "min-monochrome", "max-monochrome", "resolution", "min-resolution", "max-resolution", "scan", "grid", "orientation", "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio", - "pointer", "any-pointer", "hover", "any-hover" + "pointer", "any-pointer", "hover", "any-hover", "prefers-color-scheme" ], mediaFeatures = keySet(mediaFeatures_); var mediaValueKeywords_ = [ "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover", - "interlace", "progressive" + "interlace", "progressive", + "dark", "light" ], mediaValueKeywords = keySet(mediaValueKeywords_); var propertyKeywords_ = [ "align-content", "align-items", "align-self", "alignment-adjust", - "alignment-baseline", "anchor-point", "animation", "animation-delay", + "alignment-baseline", "all", "anchor-point", "animation", "animation-delay", "animation-direction", "animation-duration", "animation-fill-mode", "animation-iteration-count", "animation-name", "animation-play-state", "animation-timing-function", "appearance", "azimuth", "backdrop-filter", From fd3e439fd07121b58e2efd4b7c92ee1201d9be64 Mon Sep 17 00:00:00 2001 From: Lucas Buchala Date: Thu, 6 Aug 2020 03:38:54 -0300 Subject: [PATCH 1425/1880] [mode meta] Escape dot in mode's filename regex --- mode/meta.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/meta.js b/mode/meta.js index 9f64f41048..d3efdc172f 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -24,7 +24,7 @@ {name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj", "cljc", "cljx"]}, {name: "ClojureScript", mime: "text/x-clojurescript", mode: "clojure", ext: ["cljs"]}, {name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]}, - {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/}, + {name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists\.txt$/}, {name: "CoffeeScript", mimes: ["application/vnd.coffeescript", "text/coffeescript", "text/x-coffeescript"], mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]}, {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]}, {name: "Cypher", mime: "application/x-cypher-query", mode: "cypher", ext: ["cyp", "cypher"]}, @@ -55,7 +55,7 @@ {name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]}, {name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]}, {name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]}, - {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history).md$/i}, + {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history)\.md$/i}, {name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]}, {name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy", "gradle"], file: /^Jenkinsfile$/}, {name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]}, From 26b739ffef2187ce942474cef4a636e9c65f9294 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 7 Aug 2020 17:44:41 +0200 Subject: [PATCH 1426/1880] [comment addon] Keep selection in front of closing marker when block-commenting ... with fullLines==false when the end of the selection is directly on the closing marker. Closes #6375 --- addon/comment/comment.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addon/comment/comment.js b/addon/comment/comment.js index 8394e85a4d..dac48d0387 100644 --- a/addon/comment/comment.js +++ b/addon/comment/comment.js @@ -13,7 +13,7 @@ var noOptions = {}; var nonWS = /[^\s\u00a0]/; - var Pos = CodeMirror.Pos; + var Pos = CodeMirror.Pos, cmp = CodeMirror.cmpPos; function firstNonWS(str) { var found = str.search(nonWS); @@ -126,7 +126,9 @@ if (i != end || lastLineHasText) self.replaceRange(lead + pad, Pos(i, 0)); } else { + var atCursor = cmp(self.getCursor("to"), to) == 0, empty = !self.somethingSelected() self.replaceRange(endString, to); + if (atCursor) self.setSelection(empty ? to : self.getCursor("from"), to) self.replaceRange(startString, from); } }); From def6f5b125a77607085ce17c371e0995be96832a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 8 Aug 2020 10:15:34 +0200 Subject: [PATCH 1427/1880] [julia mode] Make sure dedent tokens end in a word boundary Closes #6376 --- 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 2aadf36724..f1d2cd5c4b 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -401,8 +401,8 @@ CodeMirror.defineMode("julia", function(config, parserConf) { indent: function(state, textAfter) { var delta = 0; - if ( textAfter === ']' || textAfter === ')' || /^end/.test(textAfter) || - /^else/.test(textAfter) || /^catch/.test(textAfter) || /^elseif/.test(textAfter) || + if ( textAfter === ']' || textAfter === ')' || /^end\b/.test(textAfter) || + /^else/.test(textAfter) || /^catch\b/.test(textAfter) || /^elseif\b/.test(textAfter) || /^finally/.test(textAfter) ) { delta = -1; } From a2e86b6211518abd2bd1820e4810edf461fdee9a Mon Sep 17 00:00:00 2001 From: orionlee Date: Sat, 1 Aug 2020 13:14:49 -0700 Subject: [PATCH 1428/1880] [css mode] Add missing standard property names per MDN --- mode/css/css.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index 85f1bdc767..e7e5dca837 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -504,7 +504,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "list-style-image", "list-style-position", "list-style-type", "margin", "margin-bottom", "margin-left", "margin-right", "margin-top", "marks", "marquee-direction", "marquee-loop", "marquee-play-count", "marquee-speed", - "marquee-style", "max-block-size", "max-height", "max-inline-size", + "marquee-style", "mask-clip", "mask-composite", "mask-image", "mask-mode", + "mask-origin", "mask-position", "mask-repeat", "mask-size","mask-type", + "max-block-size", "max-height", "max-inline-size", "max-width", "min-block-size", "min-height", "min-inline-size", "min-width", "mix-blend-mode", "move-to", "nav-down", "nav-index", "nav-left", "nav-right", "nav-up", "object-fit", "object-position", "offset", "offset-anchor", @@ -541,7 +543,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "text-height", "text-indent", "text-justify", "text-orientation", "text-outline", "text-overflow", "text-rendering", "text-shadow", "text-size-adjust", "text-space-collapse", "text-transform", - "text-underline-position", "text-wrap", "top", "transform", "transform-origin", + "text-underline-position", "text-wrap", "top", "touch-action", "transform", "transform-origin", "transform-style", "transition", "transition-delay", "transition-duration", "transition-property", "transition-timing-function", "translate", "unicode-bidi", "user-select", "vertical-align", "visibility", "voice-balance", @@ -553,11 +555,11 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", "color-interpolation", "color-interpolation-filters", "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", - "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke", + "marker", "marker-end", "marker-mid", "marker-start", "paint-order", "shape-rendering", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", - "glyph-orientation-vertical", "text-anchor", "writing-mode" + "glyph-orientation-vertical", "text-anchor", "writing-mode", ], propertyKeywords = keySet(propertyKeywords_); var nonStandardPropertyKeywords_ = [ @@ -725,8 +727,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { var maybeEnd = false, ch; while ((ch = stream.next()) != null) { if (maybeEnd && ch == "/") { - state.tokenize = null; - break; + state.tokenize = null; break; } maybeEnd = (ch == "*"); } From 1ac4e320224eb00643129e29f4800edbe77d9f49 Mon Sep 17 00:00:00 2001 From: orionlee Date: Sat, 1 Aug 2020 14:00:07 -0700 Subject: [PATCH 1429/1880] [css] missing CSS property values - for mask-image, mask-origin, touch-action just added --- mode/css/css.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index e7e5dca837..77ca0c10e2 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -626,7 +626,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page", - "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary", + "avoid-region", "axis-pan", "background", "backwards", "baseline", "below", "bidi-override", "binary", "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian", @@ -650,7 +650,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed", - "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", + "extra-expanded", "fantasy", "fast", "fill", "fill-box", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes", "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove", "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew", "help", "hidden", "hide", "higher", "highlight", "highlighttext", @@ -665,7 +665,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", - "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d", + "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "manipulation", "match", "matrix", "matrix3d", "media-controls-background", "media-current-time-display", "media-fullscreen-button", "media-mute-button", "media-play-button", "media-return-to-realtime-button", "media-rewind-button", @@ -674,13 +674,13 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "media-volume-slider-container", "media-volume-sliderthumb", "medium", "menu", "menulist", "menulist-button", "menulist-text", "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", - "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize", + "mix", "mongolian", "monospace", "move", "multiple", "multiple_mask_images", "multiply", "myanmar", "n-resize", "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote", "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", - "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter", + "painted", "page", "paused", "persian", "perspective", "pinch-zoom", "plus-darker", "plus-lighter", "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button", "radial-gradient", "radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region", @@ -698,8 +698,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali", "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square", - "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub", - "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table", + "square-button", "start", "static", "status-bar", "stretch", "stroke", "stroke-box", "sub", + "subpixel-antialiased", "svg_masks", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row", "table-row-group", "tamil", @@ -709,10 +709,10 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", "trad-chinese-formal", "trad-chinese-informal", "transform", "translate", "translate3d", "translateX", "translateY", "translateZ", - "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up", + "transparent", "ultra-condensed", "ultra-expanded", "underline", "unidirectional-pan", "unset", "up", "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", - "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", + "var", "vertical", "vertical-text", "view-box", "visible", "visibleFill", "visiblePainted", "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor", "xx-large", "xx-small" @@ -727,7 +727,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { var maybeEnd = false, ch; while ((ch = stream.next()) != null) { if (maybeEnd && ch == "/") { - state.tokenize = null; break; + state.tokenize = null; + break; } maybeEnd = (ch == "*"); } From 43822831dc670ab1ee18eeb54f4d57ac44b080fc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 13 Aug 2020 08:33:21 +0200 Subject: [PATCH 1430/1880] Document the scrollpastend addon Closes #6381 --- doc/manual.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/manual.html b/doc/manual.html index ba46c099f0..9c04d7fadf 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -3147,6 +3147,11 @@

    Addons

    A demo of the addon is available here. +
    scroll/scrollpastend.js
    +
    Defines an option `"scrollPastEnd"` that, when set to a + truthy value, allows the user to scroll one editor height of + empty space into view at the bottom of the editor.
    +
    merge/merge.js
    Implements an interface for merging changes, using either a 2-way or a 3-way view. The CodeMirror.MergeView From 50cd959fe7939eba01d4647d9081976f48df9bb7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 13 Aug 2020 09:10:52 +0200 Subject: [PATCH 1431/1880] Add issue and pr templates that warn about common problems --- .github/ISSUE_TEMPLATE.md | 5 +++++ .github/PULL_REQUEST_TEMPLATE.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..49e2dcb09d --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..ea7cbc75db --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,5 @@ + From 83b9f82f411274407755f80f403a48448faf81d0 Mon Sep 17 00:00:00 2001 From: "Jan T. Sott" Date: Fri, 14 Aug 2020 10:12:06 +0200 Subject: [PATCH 1432/1880] [nsis mode] Add NSIS 3.06 commands --- mode/nsis/nsis.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/nsis/nsis.js b/mode/nsis/nsis.js index 10816608c1..636940f502 100644 --- a/mode/nsis/nsis.js +++ b/mode/nsis/nsis.js @@ -31,7 +31,7 @@ CodeMirror.defineSimpleMode("nsis",{ {regex: /^\s*(?:\!(else|endif|macroend))\b/, token: "keyword", dedent: true}, // Runtime Commands - {regex: /^\s*(?:Abort|AddBrandingImage|AddSize|AllowRootDirInstall|AllowSkipFiles|AutoCloseWindow|BGFont|BGGradient|BrandingText|BringToFront|Call|CallInstDLL|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|CreateDirectory|CreateFont|CreateShortCut|Delete|DeleteINISec|DeleteINIStr|DeleteRegKey|DeleteRegValue|DetailPrint|DetailsButtonText|DirText|DirVar|DirVerify|EnableWindow|EnumRegKey|EnumRegValue|Exch|Exec|ExecShell|ExecShellWait|ExecWait|ExpandEnvStrings|File|FileBufSize|FileClose|FileErrorText|FileOpen|FileRead|FileReadByte|FileReadUTF16LE|FileReadWord|FileWriteUTF16LE|FileSeek|FileWrite|FileWriteByte|FileWriteWord|FindClose|FindFirst|FindNext|FindWindow|FlushINI|GetCurInstType|GetCurrentAddress|GetDlgItem|GetDLLVersion|GetDLLVersionLocal|GetErrorLevel|GetFileTime|GetFileTimeLocal|GetFullPathName|GetFunctionAddress|GetInstDirError|GetLabelAddress|GetTempFileName|Goto|HideWindow|Icon|IfAbort|IfErrors|IfFileExists|IfRebootFlag|IfSilent|InitPluginsDir|InstallButtonText|InstallColors|InstallDir|InstallDirRegKey|InstProgressFlags|InstType|InstTypeGetText|InstTypeSetText|Int64Cmp|Int64CmpU|Int64Fmt|IntCmp|IntCmpU|IntFmt|IntOp|IntPtrCmp|IntPtrCmpU|IntPtrOp|IsWindow|LangString|LicenseBkColor|LicenseData|LicenseForceSelection|LicenseLangString|LicenseText|LoadAndSetImage|LoadLanguageFile|LockWindow|LogSet|LogText|ManifestDPIAware|ManifestLongPathAware|ManifestMaxVersionTested|ManifestSupportedOS|MessageBox|MiscButtonText|Name|Nop|OutFile|Page|PageCallbacks|PEAddResource|PEDllCharacteristics|PERemoveResource|PESubsysVer|Pop|Push|Quit|ReadEnvStr|ReadINIStr|ReadRegDWORD|ReadRegStr|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|SectionGetFlags|SectionGetInstTypes|SectionGetSize|SectionGetText|SectionIn|SectionSetFlags|SectionSetInstTypes|SectionSetSize|SectionSetText|SendMessage|SetAutoClose|SetBrandingImage|SetCompress|SetCompressor|SetCompressorDictSize|SetCtlColors|SetCurInstType|SetDatablockOptimize|SetDateSave|SetDetailsPrint|SetDetailsView|SetErrorLevel|SetErrors|SetFileAttributes|SetFont|SetOutPath|SetOverwrite|SetRebootFlag|SetRegView|SetShellVarContext|SetSilent|ShowInstDetails|ShowUninstDetails|ShowWindow|SilentInstall|SilentUnInstall|Sleep|SpaceTexts|StrCmp|StrCmpS|StrCpy|StrLen|SubCaption|Unicode|UninstallButtonText|UninstallCaption|UninstallIcon|UninstallSubCaption|UninstallText|UninstPage|UnRegDLL|Var|VIAddVersionKey|VIFileVersion|VIProductVersion|WindowIcon|WriteINIStr|WriteRegBin|WriteRegDWORD|WriteRegExpandStr|WriteRegMultiStr|WriteRegNone|WriteRegStr|WriteUninstaller|XPStyle)\b/, token: "keyword"}, + {regex: /^\s*(?:Abort|AddBrandingImage|AddSize|AllowRootDirInstall|AllowSkipFiles|AutoCloseWindow|BGFont|BGGradient|BrandingText|BringToFront|Call|CallInstDLL|Caption|ChangeUI|CheckBitmap|ClearErrors|CompletedText|ComponentText|CopyFiles|CRCCheck|CreateDirectory|CreateFont|CreateShortCut|Delete|DeleteINISec|DeleteINIStr|DeleteRegKey|DeleteRegValue|DetailPrint|DetailsButtonText|DirText|DirVar|DirVerify|EnableWindow|EnumRegKey|EnumRegValue|Exch|Exec|ExecShell|ExecShellWait|ExecWait|ExpandEnvStrings|File|FileBufSize|FileClose|FileErrorText|FileOpen|FileRead|FileReadByte|FileReadUTF16LE|FileReadWord|FileWriteUTF16LE|FileSeek|FileWrite|FileWriteByte|FileWriteWord|FindClose|FindFirst|FindNext|FindWindow|FlushINI|GetCurInstType|GetCurrentAddress|GetDlgItem|GetDLLVersion|GetDLLVersionLocal|GetErrorLevel|GetFileTime|GetFileTimeLocal|GetFullPathName|GetFunctionAddress|GetInstDirError|GetKnownFolderPath|GetLabelAddress|GetTempFileName|Goto|HideWindow|Icon|IfAbort|IfErrors|IfFileExists|IfRebootFlag|IfRtlLanguage|IfShellVarContextAll|IfSilent|InitPluginsDir|InstallButtonText|InstallColors|InstallDir|InstallDirRegKey|InstProgressFlags|InstType|InstTypeGetText|InstTypeSetText|Int64Cmp|Int64CmpU|Int64Fmt|IntCmp|IntCmpU|IntFmt|IntOp|IntPtrCmp|IntPtrCmpU|IntPtrOp|IsWindow|LangString|LicenseBkColor|LicenseData|LicenseForceSelection|LicenseLangString|LicenseText|LoadAndSetImage|LoadLanguageFile|LockWindow|LogSet|LogText|ManifestDPIAware|ManifestLongPathAware|ManifestMaxVersionTested|ManifestSupportedOS|MessageBox|MiscButtonText|Name|Nop|OutFile|Page|PageCallbacks|PEAddResource|PEDllCharacteristics|PERemoveResource|PESubsysVer|Pop|Push|Quit|ReadEnvStr|ReadINIStr|ReadRegDWORD|ReadRegStr|Reboot|RegDLL|Rename|RequestExecutionLevel|ReserveFile|Return|RMDir|SearchPath|SectionGetFlags|SectionGetInstTypes|SectionGetSize|SectionGetText|SectionIn|SectionSetFlags|SectionSetInstTypes|SectionSetSize|SectionSetText|SendMessage|SetAutoClose|SetBrandingImage|SetCompress|SetCompressor|SetCompressorDictSize|SetCtlColors|SetCurInstType|SetDatablockOptimize|SetDateSave|SetDetailsPrint|SetDetailsView|SetErrorLevel|SetErrors|SetFileAttributes|SetFont|SetOutPath|SetOverwrite|SetRebootFlag|SetRegView|SetShellVarContext|SetSilent|ShowInstDetails|ShowUninstDetails|ShowWindow|SilentInstall|SilentUnInstall|Sleep|SpaceTexts|StrCmp|StrCmpS|StrCpy|StrLen|SubCaption|Unicode|UninstallButtonText|UninstallCaption|UninstallIcon|UninstallSubCaption|UninstallText|UninstPage|UnRegDLL|Var|VIAddVersionKey|VIFileVersion|VIProductVersion|WindowIcon|WriteINIStr|WriteRegBin|WriteRegDWORD|WriteRegExpandStr|WriteRegMultiStr|WriteRegNone|WriteRegStr|WriteUninstaller|XPStyle)\b/, token: "keyword"}, {regex: /^\s*(?:Function|PageEx|Section(?:Group)?)\b/, token: "keyword", indent: true}, {regex: /^\s*(?:(Function|PageEx|Section(?:Group)?)End)\b/, token: "keyword", dedent: true}, From 55d04842e2abeeb305d722859cfb8ba18eadd47a Mon Sep 17 00:00:00 2001 From: tokafew420 Date: Tue, 18 Aug 2020 23:05:37 -0400 Subject: [PATCH 1433/1880] Annotate scrollbar when matches are folded --- addon/scroll/annotatescrollbar.js | 12 ++++++- test/annotatescrollbar.js | 55 +++++++++++++++++++++++++++++++ test/index.html | 2 ++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 test/annotatescrollbar.js diff --git a/addon/scroll/annotatescrollbar.js b/addon/scroll/annotatescrollbar.js index 9fe61ec1ff..0eb9e84fa2 100644 --- a/addon/scroll/annotatescrollbar.js +++ b/addon/scroll/annotatescrollbar.js @@ -72,10 +72,20 @@ var wrapping = cm.getOption("lineWrapping"); var singleLineH = wrapping && cm.defaultTextHeight() * 1.5; var curLine = null, curLineObj = null; + + function getFoldLineHandle(pos) { + var marks = cm.findMarksAt(pos); + for (var i = 0; i < marks.length; ++i) { + if (marks[i].collapsed) + return marks[i].lines[0]; + } + } + function getY(pos, top) { if (curLine != pos.line) { curLine = pos.line; - curLineObj = cm.getLineHandle(curLine); + if(!(curLineObj = getFoldLineHandle(pos))) + curLineObj = cm.getLineHandle(curLine); } if ((curLineObj.widgets && curLineObj.widgets.length) || (wrapping && curLineObj.height > singleLineH)) diff --git a/test/annotatescrollbar.js b/test/annotatescrollbar.js new file mode 100644 index 0000000000..4a4d05333c --- /dev/null +++ b/test/annotatescrollbar.js @@ -0,0 +1,55 @@ +namespace = "annotatescrollbar_"; + +(function () { + function test(name, run, content, query, expected) { + return testCM(name, function (cm) { + var annotation = cm.annotateScrollbar({ + listenForChanges: false, + className: "CodeMirror-search-match" + }); + var matches = []; + var cursor = cm.getSearchCursor(query, CodeMirror.Pos(0, 0)); + while (cursor.findNext()) { + var match = { + from: cursor.from(), + to: cursor.to() + }; + matches.push(match) + } + + if (run) run(cm); + + cm.display.barWidth = 5; + annotation.update(matches); + + var annotations = cm.getWrapperElement().getElementsByClassName(annotation.options.className); + eq(annotations.length, expected, "Expected " + expected + " annotations on the scrollbar.") + }, { + value: content, + mode: "javascript", + foldOptions: { + rangeFinder: CodeMirror.fold.brace + } + }); + } + + function doFold(cm) { + cm.foldCode(cm.getCursor()); + } + var simpleProg = "function foo() {\n\n return \"foo\";\n\n}\n\nfoo();\n"; + var consecutiveLineMatches = "function foo() {\n return \"foo\";\n}\nfoo();\n"; + var singleLineMatches = "function foo() { return \"foo\"; }foo();\n"; + + // Base case - expect 3 matches and 3 annotations + test("simple", null, simpleProg, "foo", 3); + // Consecutive line matches are combines into a single annotation - expect 3 matches and 2 annotations + test("combineConsecutiveLine", null, consecutiveLineMatches, "foo", 2); + // Matches on a single line get a single annotation - expect 3 matches and 1 annotation + test("combineSingleLine", null, singleLineMatches, "foo", 1); + // Matches within a fold are annotated on the folded line - expect 3 matches and 2 annotations + test("simpleFold", doFold, simpleProg, "foo", 2); + // Combination of combineConsecutiveLine and simpleFold cases - expect 3 matches and 1 annotation + test("foldedMatch", doFold, consecutiveLineMatches, "foo", 1); + // Hidden matches within a fold are annotated on the folded line - expect 1 match and 1 annotation + test("hiddenMatch", doFold, simpleProg, "return", 1); +})(); \ No newline at end of file diff --git a/test/index.html b/test/index.html index 6566fc436e..3369beac1f 100644 --- a/test/index.html +++ b/test/index.html @@ -157,12 +157,14 @@

    Test Suite

    + + diff --git a/keymap/vim.js b/keymap/vim.js index aca99cfbbe..789e1e55b3 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -141,6 +141,8 @@ { keys: 'gU', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, isEdit: true }, { keys: 'n', type: 'motion', motion: 'findNext', motionArgs: { forward: true, toJumplist: true }}, { keys: 'N', type: 'motion', motion: 'findNext', motionArgs: { forward: false, toJumplist: true }}, + { keys: 'gn', type: 'motion', motion: 'findAndSelectNextInclusive', motionArgs: { forward: true }}, + { keys: 'gN', type: 'motion', motion: 'findAndSelectNextInclusive', motionArgs: { forward: false }}, // Operator-Motion dual commands { keys: 'x', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorMotionArgs: { visualLine: false }}, { keys: 'X', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: false }, operatorMotionArgs: { visualLine: true }}, @@ -1576,7 +1578,7 @@ motionArgs.repeat = repeat; clearInputState(cm); if (motion) { - var motionResult = motions[motion](cm, origHead, motionArgs, vim); + var motionResult = motions[motion](cm, origHead, motionArgs, vim, inputState); vim.lastMotion = motions[motion]; if (!motionResult) { return; @@ -1774,6 +1776,87 @@ highlightSearchMatches(cm, query); return findNext(cm, prev/** prev */, query, motionArgs.repeat); }, + /** + * Find and select the next occurrence of the search query. If the cursor is currently + * within a match, then find and select the current match. Otherwise, find the next occurrence in the + * appropriate direction. + * + * This differs from `findNext` in the following ways: + * + * 1. Instead of only returning the "from", this returns a "from", "to" range. + * 2. If the cursor is currently inside a search match, this selects the current match + * instead of the next match. + * 3. If there is no associated operator, this will turn on visual mode. + */ + findAndSelectNextInclusive: function(cm, _head, motionArgs, vim, prevInputState) { + var state = getSearchState(cm); + var query = state.getQuery(); + + if (!query) { + return; + } + + var prev = !motionArgs.forward; + prev = (state.isReversed()) ? !prev : prev; + + // next: [from, to] | null + var next = findNextFromAndToInclusive(cm, prev, query, motionArgs.repeat, vim); + + // No matches. + if (!next) { + return; + } + + // If there's an operator that will be executed, return the selection. + if (prevInputState.operator) { + return next; + } + + // At this point, we know that there is no accompanying operator -- let's + // deal with visual mode in order to select an appropriate match. + + var from = next[0]; + // For whatever reason, when we use the "to" as returned by searchcursor.js directly, + // the resulting selection is extended by 1 char. Let's shrink it so that only the + // match is selected. + var to = Pos(next[1].line, next[1].ch - 1); + + if (vim.visualMode) { + // If we were in visualLine or visualBlock mode, get out of it. + if (vim.visualLine || vim.visualBlock) { + vim.visualLine = false; + vim.visualBlock = false; + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: ""}); + } + + // If we're currently in visual mode, we should extend the selection to include + // the search result. + var anchor = vim.sel.anchor; + if (anchor) { + if (state.isReversed()) { + if (motionArgs.forward) { + return [anchor, from]; + } + + return [anchor, to]; + } else { + if (motionArgs.forward) { + return [anchor, to]; + } + + return [anchor, from]; + } + } + } else { + // Let's turn visual mode on. + vim.visualMode = true; + vim.visualLine = false; + vim.visualBlock = false; + CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: ""}); + } + + return prev ? [to, from] : [from, to]; + }, goToMark: function(cm, _head, motionArgs, vim) { var pos = getMarkPos(cm, vim, motionArgs.selectedCharacter); if (pos) { @@ -1869,8 +1952,8 @@ // move to previous/next line is triggered. if (line < first && cur.line == first){ return this.moveToStartOfLine(cm, head, motionArgs, vim); - }else if (line > last && cur.line == last){ - return this.moveToEol(cm, head, motionArgs, vim, true); + } else if (line > last && cur.line == last){ + return moveToEol(cm, head, motionArgs, vim, true); } if (motionArgs.toFirstChar){ endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line)); @@ -1972,16 +2055,8 @@ vim.lastHSPos = cm.charCoords(head,'div').left; return moveToColumn(cm, repeat); }, - moveToEol: function(cm, head, motionArgs, vim, keepHPos) { - var cur = head; - var retval= Pos(cur.line + motionArgs.repeat - 1, Infinity); - var end=cm.clipPos(retval); - end.ch--; - if (!keepHPos) { - vim.lastHPos = Infinity; - vim.lastHSPos = cm.charCoords(end,'div').left; - } - return retval; + moveToEol: function(cm, head, motionArgs, vim) { + return moveToEol(cm, head, motionArgs, vim, false); }, moveToFirstNonWhiteSpaceCharacter: function(cm, head) { // Go to the start of the line where the text begins, or the end for @@ -3609,6 +3684,18 @@ } } + function moveToEol(cm, head, motionArgs, vim, keepHPos) { + var cur = head; + var retval= Pos(cur.line + motionArgs.repeat - 1, Infinity); + var end=cm.clipPos(retval); + end.ch--; + if (!keepHPos) { + vim.lastHPos = Infinity; + vim.lastHSPos = cm.charCoords(end,'div').left; + } + return retval; + } + function moveToCharacter(cm, repeat, forward, character) { var cur = cm.getCursor(); var start = cur.ch; @@ -4350,6 +4437,42 @@ return cursor.from(); }); } + /** + * Pretty much the same as `findNext`, except for the following differences: + * + * 1. Before starting the search, move to the previous search. This way if our cursor is + * already inside a match, we should return the current match. + * 2. Rather than only returning the cursor's from, we return the cursor's from and to as a tuple. + */ + function findNextFromAndToInclusive(cm, prev, query, repeat, vim) { + if (repeat === undefined) { repeat = 1; } + return cm.operation(function() { + var pos = cm.getCursor(); + var cursor = cm.getSearchCursor(query, pos); + + // Go back one result to ensure that if the cursor is currently a match, we keep it. + var found = cursor.find(!prev); + + // If we haven't moved, go back one more (similar to if i==0 logic in findNext). + if (!vim.visualMode && found && cursorEqual(cursor.from(), pos)) { + cursor.find(!prev); + } + + for (var i = 0; i < repeat; i++) { + found = cursor.find(prev); + if (!found) { + // SearchCursor may have returned null because it hit EOF, wrap + // around and try again. + cursor = cm.getSearchCursor(query, + (prev) ? Pos(cm.lastLine()) : Pos(cm.firstLine(), 0) ); + if (!cursor.find(prev)) { + return; + } + } + } + return [cursor.from(), cursor.to()]; + }); + } function clearSearchHighlight(cm) { var state = getSearchState(cm); cm.removeOverlay(getSearchState(cm).getOverlay()); diff --git a/test/vim_test.js b/test/vim_test.js index 9743041404..c75a1646cf 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -2579,6 +2579,91 @@ testVim('/ and n/N', function(cm, vim, helpers) { helpers.doKeys('2', '/'); helpers.assertCursorAt(1, 6); }, { value: 'match nope match \n nope Match' }); +testVim('/ and gn selects the appropriate word', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('match'); + helpers.doKeys('/'); + helpers.assertCursorAt(0, 11); + + // gn should highlight the the current word while it is within a match. + + // gn when cursor is in beginning of match + helpers.doKeys('gn', ''); + helpers.assertCursorAt(0, 15); + + // gn when cursor is at end of match + helpers.doKeys('gn', ''); + helpers.doKeys(''); + helpers.assertCursorAt(0, 15); + + // consecutive gns should extend the selection + helpers.doKeys('gn'); + helpers.assertCursorAt(0, 16); + helpers.doKeys('gn'); + helpers.assertCursorAt(1, 11); + + // we should have selected the second and third "match" + helpers.doKeys('d'); + eq('match nope ', cm.getValue()); +}, { value: 'match nope match \n nope Match' }); +testVim('/ and gN selects the appropriate word', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('match'); + helpers.doKeys('/'); + helpers.assertCursorAt(0, 11); + + // gN when cursor is at beginning of match + helpers.doKeys('gN', ''); + helpers.assertCursorAt(0, 11); + + // gN when cursor is at end of match + helpers.doKeys('e', 'gN', ''); + helpers.assertCursorAt(0, 11); + + // consecutive gNs should extend the selection + helpers.doKeys('gN'); + helpers.assertCursorAt(0, 11); + helpers.doKeys('gN'); + helpers.assertCursorAt(0, 0); + + // we should have selected the first and second "match" + helpers.doKeys('d'); + eq(' \n nope Match', cm.getValue()); +}, { value: 'match nope match \n nope Match' }) +testVim('/ and gn with an associated operator', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('match'); + helpers.doKeys('/'); + helpers.assertCursorAt(0, 11); + + helpers.doKeys('c', 'gn', 'changed', ''); + + // change the current match. + eq('match nope changed \n nope Match', cm.getValue()); + + // change the next match. + helpers.doKeys('.'); + eq('match nope changed \n nope changed', cm.getValue()); + + // change the final match. + helpers.doKeys('.'); + eq('changed nope changed \n nope changed', cm.getValue()); +}, { value: 'match nope match \n nope Match' }); +testVim('/ and gN with an associated operator', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('match'); + helpers.doKeys('/'); + helpers.assertCursorAt(0, 11); + + helpers.doKeys('c', 'gN', 'changed', ''); + + // change the current match. + eq('match nope changed \n nope Match', cm.getValue()); + + // change the next match. + helpers.doKeys('.'); + eq('changed nope changed \n nope Match', cm.getValue()); + + // change the final match. + helpers.doKeys('.'); + eq('changed nope changed \n nope changed', cm.getValue()); +}, { value: 'match nope match \n nope Match' }); testVim('/_case', function(cm, vim, helpers) { cm.openDialog = helpers.fakeOpenDialog('Match'); helpers.doKeys('/'); @@ -2679,6 +2764,90 @@ testVim('? and n/N', function(cm, vim, helpers) { helpers.doKeys('2', '?'); helpers.assertCursorAt(0, 11); }, { value: 'match nope match \n nope Match' }); +testVim('? and gn selects the appropriate word', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('match'); + helpers.doKeys('?', 'n'); + helpers.assertCursorAt(0, 11); + + // gn should highlight the the current word while it is within a match. + + // gn when cursor is in beginning of match + helpers.doKeys('gn', ''); + helpers.assertCursorAt(0, 11); + + // gn when cursor is at end of match + helpers.doKeys('e', 'gn', ''); + helpers.assertCursorAt(0, 11); + + // consecutive gns should extend the selection + helpers.doKeys('gn'); + helpers.assertCursorAt(0, 11); + helpers.doKeys('gn'); + helpers.assertCursorAt(0, 0); + + // we should have selected the first and second "match" + helpers.doKeys('d'); + eq(' \n nope Match', cm.getValue()); +}, { value: 'match nope match \n nope Match' }); +testVim('? and gN selects the appropriate word', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('match'); + helpers.doKeys('?', 'n'); + helpers.assertCursorAt(0, 11); + + // gN when cursor is at beginning of match + helpers.doKeys('gN', ''); + helpers.assertCursorAt(0, 15); + + // gN when cursor is at end of match + helpers.doKeys('gN', ''); + helpers.assertCursorAt(0, 15); + + // consecutive gNs should extend the selection + helpers.doKeys('gN'); + helpers.assertCursorAt(0, 16); + helpers.doKeys('gN'); + helpers.assertCursorAt(1, 11); + + // we should have selected the second and third "match" + helpers.doKeys('d'); + eq('match nope ', cm.getValue()); +}, { value: 'match nope match \n nope Match' }) +testVim('? and gn with an associated operator', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('match'); + helpers.doKeys('?', 'n'); + helpers.assertCursorAt(0, 11); + + helpers.doKeys('c', 'gn', 'changed', ''); + + // change the current match. + eq('match nope changed \n nope Match', cm.getValue()); + + // change the next match. + helpers.doKeys('.'); + eq('changed nope changed \n nope Match', cm.getValue()); + + // change the final match. + helpers.doKeys('.'); + eq('changed nope changed \n nope changed', cm.getValue()); +}, { value: 'match nope match \n nope Match' }); +testVim('? and gN with an associated operator', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('match'); + helpers.doKeys('?', 'n'); + helpers.assertCursorAt(0, 11); + + helpers.doKeys('c', 'gN', 'changed', ''); + + // change the current match. + eq('match nope changed \n nope Match', cm.getValue()); + + // change the next match. + helpers.doKeys('.'); + eq('match nope changed \n nope changed', cm.getValue()); + + // change the final match. + helpers.doKeys('.'); + eq('changed nope changed \n nope changed', cm.getValue()); +}, { value: 'match nope match \n nope Match' }); testVim('*', function(cm, vim, helpers) { cm.setCursor(0, 9); helpers.doKeys('*'); From db719a2e37f802e79d5e0abeed58721ed95fbaa9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 15 Sep 2020 09:09:24 +0200 Subject: [PATCH 1449/1880] Fix drawing of marked text with only attributes Closes #6414 --- src/line/line_data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/line/line_data.js b/src/line/line_data.js index 20dd432831..e650b3e306 100644 --- a/src/line/line_data.js +++ b/src/line/line_data.js @@ -178,7 +178,7 @@ function buildToken(builder, text, style, startStyle, endStyle, css, attributes) } } builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32 - if (style || startStyle || endStyle || mustWrap || css) { + if (style || startStyle || endStyle || mustWrap || css || attributes) { let fullStyle = style || "" if (startStyle) fullStyle += startStyle if (endStyle) fullStyle += endStyle From 18aa69e17cc7703f106fbe03992456b8e59e8cdc Mon Sep 17 00:00:00 2001 From: Adrian Kunz Date: Thu, 17 Sep 2020 11:32:20 +0200 Subject: [PATCH 1450/1880] [lint addon] Use separate CSS classes for common lint styles This changes lint.css to be less reliant on the predefined severities (error and warning), in turn making it easier to define custom ones. Now all that needs to be done in order to define a new severity, e.g. `note`, is to add the following CSS: ```css /* underline */ .CodeMirror-lint-mark-note { background-image: ...; } /* icon */ .CodeMirror-lint-marker-note, .CodeMirror-lint-message-note { background-image: ...; } ``` Previously, it was necessary to copy many styles that were only available under the `CodeMirror-lint-*-error` and `CodeMirror-lint-*-warning` classes. --- addon/lint/lint.css | 6 +++--- addon/lint/lint.js | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/addon/lint/lint.css b/addon/lint/lint.css index f097cfe345..fef620a492 100644 --- a/addon/lint/lint.css +++ b/addon/lint/lint.css @@ -25,7 +25,7 @@ -ms-transition: opacity .4s; } -.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { +.CodeMirror-lint-mark { background-position: left bottom; background-repeat: repeat-x; } @@ -40,7 +40,7 @@ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); } -.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { +.CodeMirror-lint-marker { background-position: center center; background-repeat: no-repeat; cursor: pointer; @@ -51,7 +51,7 @@ position: relative; } -.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { +.CodeMirror-lint-message { padding-left: 18px; background-position: top left; background-repeat: no-repeat; diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 5bc1af18ae..963f2cf227 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -83,10 +83,10 @@ function makeMarker(cm, labels, severity, multiple, tooltips) { var marker = document.createElement("div"), inner = marker; - marker.className = "CodeMirror-lint-marker-" + severity; + marker.className = "CodeMirror-lint-marker CodeMirror-lint-marker-" + severity; if (multiple) { inner = marker.appendChild(document.createElement("div")); - inner.className = "CodeMirror-lint-marker-multiple"; + inner.className = "CodeMirror-lint-marker CodeMirror-lint-marker-multiple"; } if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) { @@ -114,7 +114,7 @@ var severity = ann.severity; if (!severity) severity = "error"; var tip = document.createElement("div"); - tip.className = "CodeMirror-lint-message-" + severity; + tip.className = "CodeMirror-lint-message CodeMirror-lint-message-" + severity; if (typeof ann.messageHTML != 'undefined') { tip.innerHTML = ann.messageHTML; } else { @@ -183,7 +183,7 @@ if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { - className: "CodeMirror-lint-mark-" + severity, + className: "CodeMirror-lint-mark CodeMirror-lint-mark-" + severity, __annotation: ann })); } From 376c0d9a9e67f42fa2c77e3529b1740097ea68b3 Mon Sep 17 00:00:00 2001 From: Adrian Kunz Date: Sun, 20 Sep 2020 14:36:24 +0200 Subject: [PATCH 1451/1880] [lint addon] Put error CSS after warning By swapping the CSS rules, the error rules take priority in case there are markers with both severities on the same token. That token is now underlined red instead of yellow, making it consistent with how errors take priority in the gutter. --- addon/lint/lint.css | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/addon/lint/lint.css b/addon/lint/lint.css index fef620a492..0871865959 100644 --- a/addon/lint/lint.css +++ b/addon/lint/lint.css @@ -30,16 +30,14 @@ background-repeat: repeat-x; } -.CodeMirror-lint-mark-error { - background-image: - url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") - ; -} - .CodeMirror-lint-mark-warning { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); } +.CodeMirror-lint-mark-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg=="); +} + .CodeMirror-lint-marker { background-position: center center; background-repeat: no-repeat; @@ -57,14 +55,14 @@ background-repeat: no-repeat; } -.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); -} - .CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); } +.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); +} + .CodeMirror-lint-marker-multiple { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); background-repeat: no-repeat; From 66a96a567b7b1e3da6319bd933c94b284811f161 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 20 Sep 2020 19:37:00 +0200 Subject: [PATCH 1452/1880] Set the readonly attribute on the hidden textarea when the editor is read-only This prevents cut/paste from showing up in the context menu on Chrome (but doesn't help on Firefox). Closes #6418 --- src/input/TextareaInput.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/input/TextareaInput.js b/src/input/TextareaInput.js index 8fe14bb413..977eb22723 100644 --- a/src/input/TextareaInput.js +++ b/src/input/TextareaInput.js @@ -366,6 +366,7 @@ export default class TextareaInput { readOnlyChanged(val) { if (!val) this.reset() this.textarea.disabled = val == "nocursor" + this.textarea.readOnly = !!val } setUneditable() {} From 7b63084691b9c56baf02e5f2c2a9d5aebd435dc1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Sep 2020 09:46:57 +0200 Subject: [PATCH 1453/1880] Update placeholder visibility during composition Closes #6420: --- addon/display/placeholder.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/addon/display/placeholder.js b/addon/display/placeholder.js index 4eabe3d901..19e9a3418c 100644 --- a/addon/display/placeholder.js +++ b/addon/display/placeholder.js @@ -15,11 +15,13 @@ cm.on("blur", onBlur); cm.on("change", onChange); cm.on("swapDoc", onChange); + CodeMirror.on(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose = () => onComposition(cm)) onChange(cm); } else if (!val && prev) { cm.off("blur", onBlur); cm.off("change", onChange); cm.off("swapDoc", onChange); + CodeMirror.off(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose) clearPlaceholder(cm); var wrapper = cm.getWrapperElement(); wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); @@ -46,6 +48,16 @@ cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild); } + function onComposition(cm) { + var empty = true, input = cm.getInputField() + if (input.nodeName == "TEXTAREA") + empty = !input.value + else if (cm.lineCount() == 1) + empty = !/[^\u200b]/.test(input.querySelector(".CodeMirror-line").textContent) + if (empty) clearPlaceholder(cm) + else setPlaceholder(cm) + } + function onBlur(cm) { if (isEmpty(cm)) setPlaceholder(cm); } From 76590dcb0683c0ef94c19133d64afe8bb43373ba Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Sep 2020 09:52:29 +0200 Subject: [PATCH 1454/1880] Mark version 5.58.0 --- AUTHORS | 3 +++ CHANGELOG.md | 20 ++++++++++++++++++++ doc/manual.html | 2 +- doc/releases.html | 12 ++++++++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 39 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 3fa6199e41..bb017e9574 100644 --- a/AUTHORS +++ b/AUTHORS @@ -15,6 +15,7 @@ Adán Lobato Aditya Toshniwal Adrian Aichner Adrian Heine +Adrian Kunz Adrien Bertrand aeroson Ahmad Amireh @@ -332,6 +333,7 @@ Hiroyuki Makino hitsthings Hocdoc Howard +Howard Jing Hugues Malphettes Ian Beck Ian Davies @@ -348,6 +350,7 @@ ilvalle Ilya Kharlamov Ilya Zverev Ingo Richter +Intervue Irakli Gozalishvili Ivan Kurnosov Ivoah diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e651ec7ec..782f493af6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,23 @@ +## 5.58.0 (2020-09-21) + +### Bug fixes + +Make backspace delete by code point, not glyph. + +Suppress flickering focus outline when clicking on scrollbars in Chrome. + +Fix a bug that prevented attributes added via `markText` from showing up unless the span also had some other styling. + +Suppress cut and paste context menu entries in readonly editors in Chrome. + +[placeholder addon](https://codemirror.net/doc/manual.html#addon_placeholder): Update placeholder visibility during composition. + +### New features + +Make it less cumbersome to style new lint message types. + +[vim bindings](https://codemirror.net/demo/vim.html): Support black hole register, `gn` and `gN` + ## 5.57.0 (2020-08-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 8635a1e060..e193f9929b 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

    User manual and reference guide - version 5.57.0 + version 5.58.0

    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 334a0184c6..3e0adcda6e 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,18 @@

    Release notes and version history

    Version 5.x

    +

    21-09-2020: Version 5.58.0:

    + +
      +
    • Make backspace delete by code point, not glyph.
    • +
    • Suppress flickering focus outline when clicking on scrollbars in Chrome.
    • +
    • Fix a bug that prevented attributes added via markText from showing up unless the span also had some other styling.
    • +
    • Suppress cut and paste context menu entries in readonly editors in Chrome.
    • +
    • placeholder addon: Update placeholder visibility during composition.
    • +
    • Make it less cumbersome to style new lint message types.
    • +
    • vim bindings: Support black hole register, gn and gN
    • +
    +

    20-08-2020: Version 5.57.0:

      diff --git a/index.html b/index.html index 21fe3ef0eb..b6b595b9c4 100644 --- a/index.html +++ b/index.html @@ -99,7 +99,7 @@

      This is CodeMirror

    - Get the current version: 5.57.0.
    + Get the current version: 5.58.0.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index faf0ca08b6..4472c6be3d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.57.0", + "version": "5.58.0", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 64e94929dd..00990e1601 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.57.0" +CodeMirror.version = "5.58.0" From c74a1cafc01a7e34af1b19dd4c82ff821c2e1442 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Sep 2020 09:55:45 +0200 Subject: [PATCH 1455/1880] Fix use of ES6 in addon --- addon/display/placeholder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/display/placeholder.js b/addon/display/placeholder.js index 19e9a3418c..eb8332ac4b 100644 --- a/addon/display/placeholder.js +++ b/addon/display/placeholder.js @@ -15,7 +15,7 @@ cm.on("blur", onBlur); cm.on("change", onChange); cm.on("swapDoc", onChange); - CodeMirror.on(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose = () => onComposition(cm)) + CodeMirror.on(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose = function() { onComposition(cm) }) onChange(cm); } else if (!val && prev) { cm.off("blur", onBlur); From ca046d7d2fe737a0f09b90e2ae455093ca60faa5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 22 Sep 2020 21:19:03 +0200 Subject: [PATCH 1456/1880] [placeholder addon] Fix composition handling Issue #6422 --- addon/display/placeholder.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/addon/display/placeholder.js b/addon/display/placeholder.js index eb8332ac4b..89bb93f378 100644 --- a/addon/display/placeholder.js +++ b/addon/display/placeholder.js @@ -49,13 +49,15 @@ } function onComposition(cm) { - var empty = true, input = cm.getInputField() - if (input.nodeName == "TEXTAREA") - empty = !input.value - else if (cm.lineCount() == 1) - empty = !/[^\u200b]/.test(input.querySelector(".CodeMirror-line").textContent) - if (empty) clearPlaceholder(cm) - else setPlaceholder(cm) + setTimeout(function() { + var empty = false, input = cm.getInputField() + if (input.nodeName == "TEXTAREA") + empty = !input.value + else if (cm.lineCount() == 1) + empty = !/[^\u200b]/.test(input.querySelector(".CodeMirror-line").textContent) + if (empty) setPlaceholder(cm) + else clearPlaceholder(cm) + }, 20) } function onBlur(cm) { From 1c60749b6882bd67b2a11a3f2e21cffa5eb4c5d3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 23 Sep 2020 10:11:42 +0200 Subject: [PATCH 1457/1880] Mark version 5.58.1 --- CHANGELOG.md | 6 ++++++ doc/manual.html | 2 +- doc/releases.html | 8 ++++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 6 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 782f493af6..d3e3fe4223 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 5.58.1 (2020-09-23) + +### Bug fixes + +[placeholder addon](https://codemirror.net/doc/manual.html#addon_placeholder): Remove arrow function that ended up in the code. + ## 5.58.0 (2020-09-21) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index e193f9929b..42ab5491ed 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

    User manual and reference guide - version 5.58.0 + version 5.58.1

    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 3e0adcda6e..3b4378f3f1 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -32,6 +32,14 @@

    Version 5.x

    21-09-2020: Version 5.58.0:

    + + +

    Version 5.x

    + +

    21-09-2020: Version 5.58.0:

    +
    • Make backspace delete by code point, not glyph.
    • Suppress flickering focus outline when clicking on scrollbars in Chrome.
    • diff --git a/index.html b/index.html index b6b595b9c4..ff27b925b7 100644 --- a/index.html +++ b/index.html @@ -99,7 +99,7 @@

      This is CodeMirror

    - Get the current version: 5.58.0.
    + Get the current version: 5.58.1.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index 4472c6be3d..ba8e7fc79d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.58.0", + "version": "5.58.1", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 00990e1601..4f9152d892 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.58.0" +CodeMirror.version = "5.58.1" From f3dde7c60552daea3de7d4141ba9553197f20543 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 26 Sep 2020 21:56:10 +0200 Subject: [PATCH 1458/1880] [julia mode] Fix infinite recursion I couldn't figure out what the original code was intended to do, but I've tried to fix the problem without changing it more than necessary. Closes #6428 --- mode/julia/julia.js | 63 +++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/mode/julia/julia.js b/mode/julia/julia.js index f1d2cd5c4b..3942492042 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -255,41 +255,43 @@ CodeMirror.defineMode("julia", function(config, parserConf) { } function tokenCallOrDef(stream, state) { - var match = stream.match(/^(\(\s*)/); - if (match) { - if (state.firstParenPos < 0) - state.firstParenPos = state.scopes.length; - state.scopes.push('('); - state.charsAdvanced += match[1].length; - } - if (currentScope(state) == '(' && stream.match(/^\)/)) { - state.scopes.pop(); - state.charsAdvanced += 1; - if (state.scopes.length <= state.firstParenPos) { - var isDefinition = stream.match(/^(\s*where\s+[^\s=]+)*\s*?=(?!=)/, false); - stream.backUp(state.charsAdvanced); + for (;;) { + var match = stream.match(/^(\(\s*)/), charsAdvanced = 0; + if (match) { + if (state.firstParenPos < 0) + state.firstParenPos = state.scopes.length; + state.scopes.push('('); + charsAdvanced += match[1].length; + } + if (currentScope(state) == '(' && stream.match(/^\)/)) { + state.scopes.pop(); + charsAdvanced += 1; + if (state.scopes.length <= state.firstParenPos) { + var isDefinition = stream.match(/^(\s*where\s+[^\s=]+)*\s*?=(?!=)/, false); + stream.backUp(charsAdvanced); + state.firstParenPos = -1; + state.tokenize = tokenBase; + if (isDefinition) + return "def"; + return "builtin"; + } + } + // Unfortunately javascript does not support multiline strings, so we have + // to undo anything done upto here if a function call or definition splits + // over two or more lines. + if (stream.match(/^$/g, false)) { + stream.backUp(charsAdvanced); + while (state.scopes.length > state.firstParenPos) + state.scopes.pop(); state.firstParenPos = -1; - state.charsAdvanced = 0; state.tokenize = tokenBase; - if (isDefinition) - return "def"; return "builtin"; } + if (!stream.match(/^[^()]+/)) { + stream.next() + return null + } } - // Unfortunately javascript does not support multiline strings, so we have - // to undo anything done upto here if a function call or definition splits - // over two or more lines. - if (stream.match(/^$/g, false)) { - stream.backUp(state.charsAdvanced); - while (state.scopes.length > state.firstParenPos) - state.scopes.pop(); - state.firstParenPos = -1; - state.charsAdvanced = 0; - state.tokenize = tokenBase; - return "builtin"; - } - state.charsAdvanced += stream.match(/^([^()]*)/)[1].length; - return state.tokenize(stream, state); } function tokenAnnotation(stream, state) { @@ -383,7 +385,6 @@ CodeMirror.defineMode("julia", function(config, parserConf) { nestedComments: 0, nestedGenerators: 0, nestedParameters: 0, - charsAdvanced: 0, firstParenPos: -1 }; }, From 58c553470fe6d65d494d4dbaf471f6ec97f9ab9d Mon Sep 17 00:00:00 2001 From: Nina Pypchenko <22447785+nina-py@users.noreply.github.com> Date: Mon, 28 Sep 2020 12:11:52 +1000 Subject: [PATCH 1459/1880] Fixes #6331. Backticks are stripped from SQL query words before comparison --- addon/hint/sql-hint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/hint/sql-hint.js b/addon/hint/sql-hint.js index de84707db3..5b65e29105 100644 --- a/addon/hint/sql-hint.js +++ b/addon/hint/sql-hint.js @@ -187,7 +187,7 @@ function eachWord(lineText, f) { var words = lineText.split(/\s+/) for (var i = 0; i < words.length; i++) - if (words[i]) f(words[i].replace(/[,;]/g, '')) + if (words[i]) f(words[i].replace(/[`,;]/g, '')) } function findTableByAlias(alias, editor) { From fdc2de3856f928d04fdac222294870edb9ce639b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 28 Sep 2020 14:45:21 +0200 Subject: [PATCH 1460/1880] [tern demo] Use unpkg, now that the URL structure of ternjs.net changed --- demo/tern.html | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/demo/tern.html b/demo/tern.html index c6834e8899..e331fd5cf8 100644 --- a/demo/tern.html +++ b/demo/tern.html @@ -13,16 +13,16 @@ - - - + + + - - - - - - + + + + + + @@ -109,7 +109,7 @@

    Tern Demo

    } var server; - getURL("//ternjs.net/defs/ecmascript.json", function(err, code) { + getURL("https://unpkg.com/tern/defs/ecmascript.json", function(err, code) { if (err) throw new Error("Request for ecmascript.json: " + err); server = new CodeMirror.TernServer({defs: [JSON.parse(code)]}); editor.setOption("extraKeys", { From 8bc57f76383e62e1a03c7d97c9eac74493fdbedc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 2 Oct 2020 23:40:06 +0200 Subject: [PATCH 1461/1880] Remove link to gitter room It never took off, and I very much prefer communicating through the forum and bug tracker. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 2a7b1f5eba..92debf4488 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [![Build Status](https://travis-ci.org/codemirror/CodeMirror.svg)](https://travis-ci.org/codemirror/CodeMirror) [![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror) -[![Join the chat at https://gitter.im/codemirror/CodeMirror](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/codemirror/CodeMirror) CodeMirror is a versatile text editor implemented in JavaScript for the browser. It is specialized for editing code, and comes with over From 719a91275352a5b551b7b450726b056f11d22685 Mon Sep 17 00:00:00 2001 From: Nina Pypchenko <22447785+nina-py@users.noreply.github.com> Date: Mon, 5 Oct 2020 19:15:49 +1100 Subject: [PATCH 1462/1880] Fixes #6402. Adds option to turn off highlighting of non-standard CSS properties --- mode/css/css.js | 7 ++++--- mode/css/index.html | 6 ++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index 77ca0c10e2..240c270a90 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -29,7 +29,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { valueKeywords = parserConfig.valueKeywords || {}, allowNested = parserConfig.allowNested, lineComment = parserConfig.lineComment, - supportsAtComponent = parserConfig.supportsAtComponent === true; + supportsAtComponent = parserConfig.supportsAtComponent === true, + highlightNonStandardPropertyKeywords = config.highlightNonStandardPropertyKeywords !== false; var type, override; function ret(style, tp) { type = tp; return style; } @@ -197,7 +198,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { override = "property"; return "maybeprop"; } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { - override = "string-2"; + override = highlightNonStandardPropertyKeywords ? "string-2" : "property"; return "maybeprop"; } else if (allowNested) { override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag"; @@ -291,7 +292,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { else if (propertyKeywords.hasOwnProperty(word)) override = "property"; else if (nonStandardPropertyKeywords.hasOwnProperty(word)) - override = "string-2"; + override = highlightNonStandardPropertyKeywords ? "string-2" : "property"; else if (valueKeywords.hasOwnProperty(word)) override = "atom"; else if (colorKeywords.hasOwnProperty(word)) diff --git a/mode/css/index.html b/mode/css/index.html index 6588c408ac..42b327ca66 100644 --- a/mode/css/index.html +++ b/mode/css/index.html @@ -68,6 +68,12 @@

    CSS mode

    }); +

    CSS mode supports this option:

    + +
    highlightNonStandardPropertyKeywords: boolean
    +
    Whether to highlight non-standard CSS property keywords such as margin-inline or zoom (default: true).
    +
    +

    MIME types defined: text/css, text/x-scss (demo), text/x-less (demo).

    Parsing/Highlighting Tests: normal, verbose.

    From 1cb6de23c7e2b965201972ac5c6dcd2317e9eacf Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 5 Oct 2020 14:05:36 +0200 Subject: [PATCH 1463/1880] Fix doc/releases.html copy-paste mistake --- doc/releases.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/releases.html b/doc/releases.html index 3b4378f3f1..0b466970fc 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,14 +30,12 @@

    Release notes and version history

    Version 5.x

    -

    21-09-2020: Version 5.58.0:

    +

    21-09-2020: Version 5.58.1:

    -

    Version 5.x

    -

    21-09-2020: Version 5.58.0:

      From cdb228ac736369c685865b122b736cd0d397836c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 9 Oct 2020 10:00:16 +0200 Subject: [PATCH 1464/1880] Fix horizontal scrolling-into-view with non-fixed gutters Closes #6436 --- src/display/scrolling.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/display/scrolling.js b/src/display/scrolling.js index 6d97247d92..75d6fc7ee4 100644 --- a/src/display/scrolling.js +++ b/src/display/scrolling.js @@ -91,14 +91,15 @@ function calculateScrollPos(cm, rect) { if (newTop != screentop) result.scrollTop = newTop } - let screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft - let screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0) + let gutterSpace = cm.options.fixedGutter ? 0 : display.gutters.offsetWidth + let screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft - gutterSpace + let screenw = displayWidth(cm) - display.gutters.offsetWidth let tooWide = rect.right - rect.left > screenw if (tooWide) rect.right = rect.left + screenw if (rect.left < 10) result.scrollLeft = 0 else if (rect.left < screenleft) - result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)) + result.scrollLeft = Math.max(0, rect.left + gutterSpace - (tooWide ? 0 : 10)) else if (rect.right > screenw + screenleft - 3) result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw return result From 55d0333907117c9231ffdf555ae8824705993bbb Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 9 Oct 2020 15:38:39 +0200 Subject: [PATCH 1465/1880] [javascript mode] Fix potentially-exponential regexp --- mode/javascript/javascript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 66e5a308d4..3139fd00d2 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -126,7 +126,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var kw = keywords[word] return ret(kw.type, kw.style, word) } - if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\[\(\w]/, false)) + if (word == "async" && stream.match(/^(\s|\/\*([^*]|\*(?!\/))*?\*\/)*[\[\(\w]/, false)) return ret("async", "keyword", word) } return ret("variable", "variable", word) From 9caacec1900d71a971561147ba1e8acb2f08609c Mon Sep 17 00:00:00 2001 From: Mark Boyes Date: Thu, 15 Oct 2020 21:06:38 +0100 Subject: [PATCH 1466/1880] [sparql mode] Improve parsing of IRI atoms * Do not treat the opening '<' of an expanded IRI atom as an operator The existing code would not highlight the IRI atom "" in the following line as an atom. FILTER( ?x = "42"^^ ) for example everything after the # would be highlighted as a comment. This is because the sequence "^^<" while all "operator characters", are not all SPARQL operators in this case: the "<" introduces the IRI atom. I special-case the "^^". * Improve PN_LOCAL parsing to SPARQL 1.1 The following legal sequences of characters from SPARQL 1.1 are additionally parsed as being the right-hand-side of a prefixed IRI. 1) Colons 2) PERCENT escaping 3) PN_LOCAL_ESCAPE escaping --- mode/sparql/sparql.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/mode/sparql/sparql.js b/mode/sparql/sparql.js index bb79abff7f..73997c667f 100644 --- a/mode/sparql/sparql.js +++ b/mode/sparql/sparql.js @@ -60,12 +60,18 @@ CodeMirror.defineMode("sparql", function(config) { stream.skipToEnd(); return "comment"; } + else if (ch === "^") { + ch = stream.peek(); + if (ch === "^") stream.eat("^"); + else stream.eatWhile(operatorChars); + return "operator"; + } else if (operatorChars.test(ch)) { stream.eatWhile(operatorChars); return "operator"; } else if (ch == ":") { - stream.eatWhile(/[\w\d\._\-]/); + eatPnLocal(stream); return "atom"; } else if (ch == "@") { @@ -75,7 +81,7 @@ CodeMirror.defineMode("sparql", function(config) { else { stream.eatWhile(/[_\w\d]/); if (stream.eat(":")) { - stream.eatWhile(/[\w\d_\-]/); + eatPnLocal(stream); return "atom"; } var word = stream.current(); @@ -88,6 +94,10 @@ CodeMirror.defineMode("sparql", function(config) { } } + function eatPnLocal(stream) { + while (stream.match(/([:\w\d._-]|\\[-\\_~.!$&'()*+,;=/?#@%]|%[a-fA-F0-9][a-fA-F0-9])/)); + } + function tokenLiteral(quote) { return function(stream, state) { var escaped = false, ch; From 9885241fe9dee2415f988d3a3619421f45ce8c6b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 16 Oct 2020 09:53:55 +0200 Subject: [PATCH 1467/1880] [javascript mode] Don't indent in template strings Closes #6442 --- mode/javascript/javascript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 3139fd00d2..63eaa241b7 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -868,7 +868,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { }, indent: function(state, textAfter) { - if (state.tokenize == tokenComment) return CodeMirror.Pass; + if (state.tokenize == tokenComment || state.tokenize == tokenQuasi) return CodeMirror.Pass; if (state.tokenize != tokenBase) return 0; var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top // Kludge to prevent 'maybelse' from blocking lexical scope pops From 212bafa8ab7837abebc1d326ed943540a9a47200 Mon Sep 17 00:00:00 2001 From: tophf Date: Thu, 22 Oct 2020 14:42:10 +0300 Subject: [PATCH 1468/1880] [stylus mode] Recognize "url-prefix" token properly --- mode/stylus/stylus.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mode/stylus/stylus.js b/mode/stylus/stylus.js index 653958e83b..281118efee 100644 --- a/mode/stylus/stylus.js +++ b/mode/stylus/stylus.js @@ -731,7 +731,8 @@ var tagKeywords_ = ["a","abbr","address","area","article","aside","audio", "b", "base","bdi", "bdo","bgsound","blockquote","body","br","button","canvas","caption","cite", "code","col","colgroup","data","datalist","dd","del","details","dfn","div", "dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1", "h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe", "img","input","ins","kbd","keygen","label","legend","li","link","main","map", "mark","marquee","menu","menuitem","meta","meter","nav","nobr","noframes", "noscript","object","ol","optgroup","option","output","p","param","pre", "progress","q","rp","rt","ruby","s","samp","script","section","select", "small","source","span","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","track", "u","ul","var","video"]; // github.com/codemirror/CodeMirror/blob/master/mode/css/css.js - var documentTypes_ = ["domain", "regexp", "url", "url-prefix"]; + // Note, "url-prefix" should precede "url" in order to match correctly in documentTypesRegexp + var documentTypes_ = ["domain", "regexp", "url-prefix", "url"]; var mediaTypes_ = ["all","aural","braille","handheld","print","projection","screen","tty","tv","embossed"]; var mediaFeatures_ = ["width","min-width","max-width","height","min-height","max-height","device-width","min-device-width","max-device-width","device-height","min-device-height","max-device-height","aspect-ratio","min-aspect-ratio","max-aspect-ratio","device-aspect-ratio","min-device-aspect-ratio","max-device-aspect-ratio","color","min-color","max-color","color-index","min-color-index","max-color-index","monochrome","min-monochrome","max-monochrome","resolution","min-resolution","max-resolution","scan","grid"]; var propertyKeywords_ = ["align-content","align-items","align-self","alignment-adjust","alignment-baseline","anchor-point","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","appearance","azimuth","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","baseline-shift","binding","bleed","bookmark-label","bookmark-level","bookmark-state","bookmark-target","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","color","color-profile","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","crop","cue","cue-after","cue-before","cursor","direction","display","dominant-baseline","drop-initial-after-adjust","drop-initial-after-align","drop-initial-before-adjust","drop-initial-before-align","drop-initial-size","drop-initial-value","elevation","empty-cells","fit","fit-position","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","float-offset","flow-from","flow-into","font","font-feature-settings","font-family","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-synthesis","font-variant","font-variant-alternates","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-weight","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-position","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","inline-box-align","justify-content","left","letter-spacing","line-break","line-height","line-stacking","line-stacking-ruby","line-stacking-shift","line-stacking-strategy","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marker-offset","marks","marquee-direction","marquee-loop","marquee-play-count","marquee-speed","marquee-style","max-height","max-width","min-height","min-width","move-to","nav-down","nav-index","nav-left","nav-right","nav-up","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-style","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page","page-break-after","page-break-before","page-break-inside","page-policy","pause","pause-after","pause-before","perspective","perspective-origin","pitch","pitch-range","play-during","position","presentation-level","punctuation-trim","quotes","region-break-after","region-break-before","region-break-inside","region-fragment","rendering-intent","resize","rest","rest-after","rest-before","richness","right","rotation","rotation-point","ruby-align","ruby-overhang","ruby-position","ruby-span","shape-image-threshold","shape-inside","shape-margin","shape-outside","size","speak","speak-as","speak-header","speak-numeral","speak-punctuation","speech-rate","stress","string-set","tab-size","table-layout","target","target-name","target-new","target-position","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-skip","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-height","text-indent","text-justify","text-outline","text-overflow","text-shadow","text-size-adjust","text-space-collapse","text-transform","text-underline-position","text-wrap","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","z-index","clip-path","clip-rule","mask","enable-background","filter","flood-color","flood-opacity","lighting-color","stop-color","stop-opacity","pointer-events","color-interpolation","color-interpolation-filters","color-rendering","fill","fill-opacity","fill-rule","image-rendering","marker","marker-end","marker-mid","marker-start","shape-rendering","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-rendering","baseline-shift","dominant-baseline","glyph-orientation-horizontal","glyph-orientation-vertical","text-anchor","writing-mode","font-smoothing","osx-font-smoothing"]; From 23b7a9924b5f9460a091e97392dd00d3834e8cc6 Mon Sep 17 00:00:00 2001 From: "David R. Myers" Date: Fri, 23 Oct 2020 15:12:03 -0400 Subject: [PATCH 1469/1880] Add WebAssembly to meta --- mode/meta.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mode/meta.js b/mode/meta.js index d3efdc172f..c7738a514c 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -169,7 +169,8 @@ {name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]}, {name: "mscgen", mime: "text/x-mscgen", mode: "mscgen", ext: ["mscgen", "mscin", "msc"]}, {name: "xu", mime: "text/x-xu", mode: "mscgen", ext: ["xu"]}, - {name: "msgenny", mime: "text/x-msgenny", mode: "mscgen", ext: ["msgenny"]} + {name: "msgenny", mime: "text/x-msgenny", mode: "mscgen", ext: ["msgenny"]}, + {name: "WebAssembly", mime: "text/webassembly", mode: "wast", ext: ["wat", "wast"]}, ]; // Ensure all modes have a mime property for backwards compatibility for (var i = 0; i < CodeMirror.modeInfo.length; i++) { From 264022ee4af4abca1c158944dc299a8faf8696d6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 26 Oct 2020 09:08:51 +0100 Subject: [PATCH 1470/1880] Mark version 5.58.2 --- AUTHORS | 3 +++ CHANGELOG.md | 8 ++++++++ doc/manual.html | 2 +- doc/releases.html | 7 +++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 22 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index bb017e9574..b8087133a8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -208,6 +208,7 @@ David Barnett David H. Bronke David Mignot David Pathakjee +David R. Myers David Rodrigues David Santana David Vázquez @@ -524,6 +525,7 @@ Marijn Haverbeke Mário Gonçalves Mario Pietsch Mark Anderson +Mark Boyes Mark Dalgleish Mark Hamstra Mark Lentczner @@ -634,6 +636,7 @@ Nikolaj Kappler Nikolay Kostov nilp0inter Nils Knappmeier +Nina Pypchenko Nisarg Jhaveri nlwillia noragrossman diff --git a/CHANGELOG.md b/CHANGELOG.md index d3e3fe4223..80200fc784 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 5.58.2 (2020-10-23) + +### Bug fixes + +Fix a bug where horizontally scrolling the cursor into view sometimes failed with a non-fixed gutter. + +[julia mode](https://codemirror.net/mode/julia/): Fix an infinite recursion bug. + ## 5.58.1 (2020-09-23) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 42ab5491ed..1da41d3ccb 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

      User manual and reference guide - version 5.58.1 + version 5.58.2

      CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 0b466970fc..bdf24ed2f7 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,13 @@

      Release notes and version history

      Version 5.x

      +

      23-10-2020: Version 5.58.2:

      + +
        +
      • Fix a bug where horizontally scrolling the cursor into view sometimes failed with a non-fixed gutter.
      • +
      • julia mode: Fix an infinite recursion bug.
      • +
      +

      21-09-2020: Version 5.58.1:

        diff --git a/index.html b/index.html index ff27b925b7..6d41dcc79e 100644 --- a/index.html +++ b/index.html @@ -99,7 +99,7 @@

        This is CodeMirror

    - Get the current version: 5.58.1.
    + Get the current version: 5.58.2.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index ba8e7fc79d..2103e1c325 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.58.1", + "version": "5.58.2", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 4f9152d892..800ee766f2 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.58.1" +CodeMirror.version = "5.58.2" From 138d1b75791f8bb0b9a07fd19cbc2bb81e13dd8f Mon Sep 17 00:00:00 2001 From: tophf Date: Wed, 28 Oct 2020 21:30:38 +0300 Subject: [PATCH 1471/1880] [stylus mode] allow block comments --- mode/stylus/stylus.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mode/stylus/stylus.js b/mode/stylus/stylus.js index 281118efee..eecc554bc0 100644 --- a/mode/stylus/stylus.js +++ b/mode/stylus/stylus.js @@ -722,6 +722,9 @@ return indent; }, electricChars: "}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + blockCommentContinue: " * ", lineComment: "//", fold: "indent" }; From 4fddb355dead97ca7fc3e096ea5eb0ade62b306d Mon Sep 17 00:00:00 2001 From: Phil DeJarnett Date: Thu, 29 Oct 2020 15:27:22 -0400 Subject: [PATCH 1472/1880] [xml-hint addon] Replace nested function with function expression --- addon/hint/xml-hint.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/hint/xml-hint.js b/addon/hint/xml-hint.js index 543d19b61c..2b3153124e 100644 --- a/addon/hint/xml-hint.js +++ b/addon/hint/xml-hint.js @@ -101,12 +101,12 @@ } replaceToken = true; } - function returnHintsFromAtValues(atValues) { + var returnHintsFromAtValues = function(atValues) { if (atValues) for (var i = 0; i < atValues.length; ++i) if (!prefix || matches(atValues[i], prefix, matchInMiddle)) result.push(quote + atValues[i] + quote); return returnHints(); - } + }; if (atValues && atValues.then) return atValues.then(returnHintsFromAtValues); return returnHintsFromAtValues(atValues); } else { // An attribute name From 230cc2e3f70d3e4fc55617437fd4f4995e6817a5 Mon Sep 17 00:00:00 2001 From: iteriani Date: Fri, 30 Oct 2020 00:39:51 -0700 Subject: [PATCH 1473/1880] [soy mode] Add support for Element Composition Add support for Soy Element Composition. It has the syntax in the form of <{foo()}> This adds support to pass through allowEmptyTag and to support this mode in closetag. --- mode/htmlmixed/htmlmixed.js | 3 ++- mode/soy/soy.js | 4 +++- mode/soy/test.js | 16 ++++++++++++++++ mode/xml/xml.js | 4 ++-- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/mode/htmlmixed/htmlmixed.js b/mode/htmlmixed/htmlmixed.js index 8341ac8261..66a158274c 100644 --- a/mode/htmlmixed/htmlmixed.js +++ b/mode/htmlmixed/htmlmixed.js @@ -74,7 +74,8 @@ name: "xml", htmlMode: true, multilineTagIndentFactor: parserConfig.multilineTagIndentFactor, - multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag + multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag, + allowMissingTagName: parserConfig.allowMissingTagName, }); var tags = {}; diff --git a/mode/soy/soy.js b/mode/soy/soy.js index d31c947eed..bd3d947145 100644 --- a/mode/soy/soy.js +++ b/mode/soy/soy.js @@ -16,6 +16,8 @@ "alias": { noEndTag: true }, "delpackage": { noEndTag: true }, "namespace": { noEndTag: true, soyState: "namespace-def" }, + "@attribute": paramData, + "@attribute?": paramData, "@param": paramData, "@param?": paramData, "@inject": paramData, @@ -53,7 +55,7 @@ CodeMirror.defineMode("soy", function(config) { var textMode = CodeMirror.getMode(config, "text/plain"); var modes = { - html: CodeMirror.getMode(config, {name: "text/html", multilineTagIndentFactor: 2, multilineTagIndentPastTag: false}), + html: CodeMirror.getMode(config, {name: "text/html", multilineTagIndentFactor: 2, multilineTagIndentPastTag: false, allowMissingTagName: true}), attributes: textMode, text: textMode, uri: textMode, diff --git a/mode/soy/test.js b/mode/soy/test.js index 57cd4be477..78faddb9aa 100644 --- a/mode/soy/test.js +++ b/mode/soy/test.js @@ -26,6 +26,10 @@ '[keyword {] [callee&variable index]([variable-2&error $list])[keyword }]' + '[string "][tag&bracket />]'); + MT('soy-element-composition-test', + '[tag&bracket <][keyword {][callee&variable foo]()[keyword }]', + '[tag&bracket >]'); + MT('namespace-test', '[keyword {namespace] [variable namespace][keyword }]') @@ -176,6 +180,18 @@ '[keyword {/template}]', ''); + MT('attribute-type', + '[keyword {template] [def .foo][keyword }]', + ' [keyword {@attribute] [def bar]: [type string][keyword }]', + '[keyword {/template}]', + ''); + + MT('attribute-type-optional', + '[keyword {template] [def .foo][keyword }]', + ' [keyword {@attribute] [def bar]: [type string][keyword }]', + '[keyword {/template}]', + ''); + MT('state-variable-reference', '[keyword {template] [def .foo][keyword }]', ' [keyword {@param] [def bar]:= [atom true][keyword }]', diff --git a/mode/xml/xml.js b/mode/xml/xml.js index 73c6e0e0dd..46806ac425 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -189,7 +189,7 @@ CodeMirror.defineMode("xml", function(editorConf, config_) { function Context(state, tagName, startOfLine) { this.prev = state.context; - this.tagName = tagName; + this.tagName = tagName || ""; this.indent = state.indented; this.startOfLine = startOfLine; if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent)) @@ -399,7 +399,7 @@ CodeMirror.defineMode("xml", function(editorConf, config_) { xmlCurrentContext: function(state) { var context = [] for (var cx = state.context; cx; cx = cx.prev) - if (cx.tagName) context.push(cx.tagName) + context.push(cx.tagName) return context.reverse() } }; From 8e7f6728bf1d36963fafdf997b12858f25d7711a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 26 Oct 2020 09:08:36 +0100 Subject: [PATCH 1474/1880] Delay blur events during dragging and clicking Issue #6427 --- src/display/focus.js | 9 ++++++--- src/edit/mouse_events.js | 10 ++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/display/focus.js b/src/display/focus.js index aa731b4353..0337327e12 100644 --- a/src/display/focus.js +++ b/src/display/focus.js @@ -4,19 +4,22 @@ import { addClass, rmClass } from "../util/dom.js" import { signal } from "../util/event.js" export function ensureFocus(cm) { - if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm) } + if (!cm.hasFocus()) { + cm.display.input.focus() + if (!cm.state.focused) onFocus(cm) + } } export function delayBlurEvent(cm) { cm.state.delayingBlurEvent = true setTimeout(() => { if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false - onBlur(cm) + if (cm.state.focused) onBlur(cm) } }, 100) } export function onFocus(cm, e) { - if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false + if (cm.state.delayingBlurEvent && !cm.state.draggingText) cm.state.delayingBlurEvent = false if (cm.options.readOnly == "nocursor") return if (!cm.state.focused) { diff --git a/src/edit/mouse_events.js b/src/edit/mouse_events.js index 5fcc437021..1c820fdb6e 100644 --- a/src/edit/mouse_events.js +++ b/src/edit/mouse_events.js @@ -1,4 +1,4 @@ -import { delayBlurEvent, ensureFocus } from "../display/focus.js" +import { delayBlurEvent, ensureFocus, onBlur } from "../display/focus.js" import { operation } from "../display/operations.js" import { visibleLines } from "../display/update_lines.js" import { clipPos, cmp, maxPos, minPos, Pos } from "../line/pos.js" @@ -149,6 +149,7 @@ function leftButtonStartDrag(cm, event, pos, behavior) { let dragEnd = operation(cm, e => { if (webkit) display.scroller.draggable = false cm.state.draggingText = false + if (cm.state.delayingBlurEvent) delayBlurEvent(cm) off(display.wrapper.ownerDocument, "mouseup", dragEnd) off(display.wrapper.ownerDocument, "mousemove", mouseMove) off(display.scroller, "dragstart", dragStart) @@ -172,15 +173,15 @@ function leftButtonStartDrag(cm, event, pos, behavior) { if (webkit) display.scroller.draggable = true cm.state.draggingText = dragEnd dragEnd.copy = !behavior.moveOnDrag - // IE's approach to draggable - if (display.scroller.dragDrop) display.scroller.dragDrop() on(display.wrapper.ownerDocument, "mouseup", dragEnd) on(display.wrapper.ownerDocument, "mousemove", mouseMove) on(display.scroller, "dragstart", dragStart) on(display.scroller, "drop", dragEnd) - delayBlurEvent(cm) + cm.state.delayingBlurEvent = true setTimeout(() => display.input.focus(), 20) + // IE's approach to draggable + if (display.scroller.dragDrop) display.scroller.dragDrop() } function rangeForUnit(cm, pos, unit) { @@ -193,6 +194,7 @@ function rangeForUnit(cm, pos, unit) { // Normal selection, as opposed to text dragging. function leftButtonSelect(cm, event, start, behavior) { + if (ie) delayBlurEvent(cm) let display = cm.display, doc = cm.doc e_preventDefault(event) From f006f3d867c62813309a6f16f5fc242092a73b7b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 4 Nov 2020 16:30:32 +0100 Subject: [PATCH 1475/1880] Remove unused import --- src/edit/mouse_events.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edit/mouse_events.js b/src/edit/mouse_events.js index 1c820fdb6e..401eadf431 100644 --- a/src/edit/mouse_events.js +++ b/src/edit/mouse_events.js @@ -1,4 +1,4 @@ -import { delayBlurEvent, ensureFocus, onBlur } from "../display/focus.js" +import { delayBlurEvent, ensureFocus } from "../display/focus.js" import { operation } from "../display/operations.js" import { visibleLines } from "../display/update_lines.js" import { clipPos, cmp, maxPos, minPos, Pos } from "../line/pos.js" From 57ba96eb392401d209b63dd187f2f2c087f1885b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 5 Nov 2020 09:03:33 +0100 Subject: [PATCH 1476/1880] Fix handling of insertAt option to addLineWidget Issue #6460 --- src/model/line_widget.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/line_widget.js b/src/model/line_widget.js index 5444d89df0..f94727e5f8 100644 --- a/src/model/line_widget.js +++ b/src/model/line_widget.js @@ -63,7 +63,7 @@ export function addLineWidget(doc, handle, node, options) { changeLine(doc, handle, "widget", line => { let widgets = line.widgets || (line.widgets = []) if (widget.insertAt == null) widgets.push(widget) - else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget) + else widgets.splice(Math.min(widgets.length, Math.max(0, widget.insertAt)), 0, widget) widget.line = line if (cm && !lineIsHidden(doc, line)) { let aboveVisible = heightAtLine(line) < doc.scrollTop From 6ba05b288eb2fb948653b597f6f7f11770bb9aef Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 12 Nov 2020 09:28:39 +0100 Subject: [PATCH 1477/1880] [shell mode] Add support for Bash-style heredoc quoting Closes #6468 --- mode/shell/shell.js | 15 +++++++++++++++ mode/shell/test.js | 15 +++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/mode/shell/shell.js b/mode/shell/shell.js index 5af12413b0..2bc1eaf948 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -70,6 +70,13 @@ CodeMirror.defineMode('shell', function() { stream.eatWhile(/\w/); return 'attribute'; } + if (ch == "<") { + let heredoc = stream.match(/^<-?\s+(.*)/) + if (heredoc) { + state.tokens.unshift(tokenHeredoc(heredoc[1])) + return 'string-2' + } + } if (/\d/.test(ch)) { stream.eatWhile(/\d/); if(stream.eol() || !/\w/.test(stream.peek())) { @@ -129,6 +136,14 @@ CodeMirror.defineMode('shell', function() { return 'def'; }; + function tokenHeredoc(delim) { + return function(stream, state) { + if (stream.sol() && stream.string == delim) state.tokens.shift() + stream.skipToEnd() + return "string-2" + } + } + function tokenize(stream, state) { return (state.tokens[0] || tokenBase) (stream, state); }; diff --git a/mode/shell/test.js b/mode/shell/test.js index 7571d907de..237375d451 100644 --- a/mode/shell/test.js +++ b/mode/shell/test.js @@ -65,9 +65,16 @@ MT("strings in parens", "[def FOO][operator =]([quote $(<][string \"][def $MYDIR][string \"][quote /myfile grep ][string 'hello$'][quote )])") - MT ("string ending in dollar", - '[def a][operator =][string "xyz$"]; [def b][operator =][string "y"]') + MT("string ending in dollar", + '[def a][operator =][string "xyz$"]; [def b][operator =][string "y"]') - MT ("quote ending in dollar", - "[quote $(echo a$)]") + MT("quote ending in dollar", + "[quote $(echo a$)]") + + MT("heredoc", + "[builtin cat] [string-2 <<- end]", + "[string-2 content one]", + "[string-2 content two end]", + "[string-2 end]", + "[builtin echo]") })(); From ffc17920ed39779f3a18b3f6333bbf6a2bc3a537 Mon Sep 17 00:00:00 2001 From: Christopher Wallis Date: Thu, 12 Nov 2020 01:43:36 -0700 Subject: [PATCH 1478/1880] [soy mode] Add support for {@attribute *} - forks the state at param-def to detect * as a type --- mode/soy/soy.js | 5 +++++ mode/soy/test.js | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/mode/soy/soy.js b/mode/soy/soy.js index bd3d947145..cac59bb3df 100644 --- a/mode/soy/soy.js +++ b/mode/soy/soy.js @@ -276,6 +276,11 @@ return null; case "param-def": + if (match = stream.match(/^\*/)) { + state.soyState.pop(); + state.soyState.push("param-type"); + return "type"; + } if (match = stream.match(/^\w+/)) { state.variables = prepend(state.variables, match[0]); state.soyState.pop(); diff --git a/mode/soy/test.js b/mode/soy/test.js index 78faddb9aa..8c764c7a2b 100644 --- a/mode/soy/test.js +++ b/mode/soy/test.js @@ -192,6 +192,12 @@ '[keyword {/template}]', ''); + MT('attribute-type-all', + '[keyword {template] [def .foo][keyword }]', + ' [keyword {@attribute] [type *][keyword }]', + '[keyword {/template}]', + ''); + MT('state-variable-reference', '[keyword {template] [def .foo][keyword }]', ' [keyword {@param] [def bar]:= [atom true][keyword }]', From eb345ef70e75805bf7d7d02b9d87c30ec1db2937 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 13 Nov 2020 10:06:33 +0100 Subject: [PATCH 1479/1880] Fix lint error --- mode/shell/shell.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/shell/shell.js b/mode/shell/shell.js index 2bc1eaf948..2b0d8a91bc 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -71,7 +71,7 @@ CodeMirror.defineMode('shell', function() { return 'attribute'; } if (ch == "<") { - let heredoc = stream.match(/^<-?\s+(.*)/) + var heredoc = stream.match(/^<-?\s+(.*)/) if (heredoc) { state.tokens.unshift(tokenHeredoc(heredoc[1])) return 'string-2' From dda3f9d6b8d2450b87b619ed5db761cb20b892b8 Mon Sep 17 00:00:00 2001 From: iteriani Date: Fri, 13 Nov 2020 01:08:19 -0800 Subject: [PATCH 1480/1880] [soy mode] Natively support Soy Element Composition * Add support for Soy Element Composition. Add support for Soy Element Composition. It has the syntax in the form of <{foo()}> This adds support to pass through allowEmptyTag and to support this mode in closetag. * Disable allowMissingTagName and handle Soy Element Composition directly. Disable allowMissingTagName and handle Soy Element Composition directly. This also adds a case in closetag.js to handle autocompletes for soy element composition. Right now, if you were to do something like <{foo()}> it would autocomplet with . This change makes it autocomplete with --- addon/edit/closetag.js | 5 +++-- mode/soy/soy.js | 20 ++++++++++++++++++++ mode/soy/test.js | 9 +++++++-- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index 8689765eec..7c22a50ecf 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -128,9 +128,10 @@ replacement = head + "style"; } else { var context = inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) - if (!context || (context.length && closingTagExists(cm, context, context[context.length - 1], pos))) + var top = context.length ? context[context.length - 1] : "" + if (!context || (context.length && closingTagExists(cm, context, top, pos))) return CodeMirror.Pass; - replacement = head + context[context.length - 1] + replacement = head + top } if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">"; replacements[i] = replacement; diff --git a/mode/soy/soy.js b/mode/soy/soy.js index cac59bb3df..17bafcd932 100644 --- a/mode/soy/soy.js +++ b/mode/soy/soy.js @@ -498,6 +498,17 @@ } return expression(stream, state); + case "template-call-expression": + if (stream.match(/^([\w-?]+)(?==)/)) { + return "attribute"; + } else if (stream.eat('>')) { + state.soyState.pop(); + return "keyword"; + } else if (stream.eat('/>')) { + state.soyState.pop(); + return "keyword"; + } + return expression(stream, state); case "literal": if (stream.match(/^(?=\{\/literal})/)) { state.soyState.pop(); @@ -563,6 +574,15 @@ state.soyState.push("import"); state.indent += 2 * config.indentUnit; return "keyword"; + } else if (match = stream.match(/^<\{/)) { + state.soyState.push("template-call-expression"); + state.tag = "print"; + state.indent += 2 * config.indentUnit; + state.soyState.push("tag"); + return "keyword"; + } else if (match = stream.match(/^<\/>/)) { + state.indent -= 2 * config.indentUnit; + return "keyword"; } return tokenUntil(stream, state, /\{|\s+\/\/|\/\*/); diff --git a/mode/soy/test.js b/mode/soy/test.js index 8c764c7a2b..ae13158720 100644 --- a/mode/soy/test.js +++ b/mode/soy/test.js @@ -27,8 +27,13 @@ '[string "][tag&bracket />]'); MT('soy-element-composition-test', - '[tag&bracket <][keyword {][callee&variable foo]()[keyword }]', - '[tag&bracket >]'); + '[keyword <{][callee&variable foo]()[keyword }]', + '[keyword >]'); + + MT('soy-element-composition-attribute-test', + '[keyword <{][callee&variable foo]()[keyword }]', + '[attribute class]=[string "Foo"]', + '[keyword >]'); MT('namespace-test', '[keyword {namespace] [variable namespace][keyword }]') From 37f7d7b00b674c4ebf380855d77f822829a8b76b Mon Sep 17 00:00:00 2001 From: Hendrik Erz Date: Sat, 14 Nov 2020 20:23:25 +0100 Subject: [PATCH 1481/1880] [show-hint addon] Document all options --- doc/manual.html | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 1da41d3ccb..2ba7c732f2 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2700,8 +2700,8 @@

    Addons

    Defines editor.showHint, which takes an optional options object, and pops up a widget that allows the user to select a completion. Finding hints is done with a hinting - functions (the hint option), which is a function - that take an editor instance and options object, and return + function (the hint option). This function + takes an editor instance and an options object, and returns a {list, from, to} object, where list is an array of strings or objects (the completions), and from and to give the start and end @@ -2771,9 +2771,22 @@

    Addons

    alignWithWord: boolean
    Whether the pop-up should be horizontally aligned with the start of the word (true, default), or with the cursor (false).
    +
    closeCharacters: RegExp
    +
    A regular expression object used to match characters which + cause the pop up to be closed (default: /[\s()\[\]{};:>,]/). + If the user types one of these characters, the pop up will close, and + the endCompletion event is fired on the editor instance.
    closeOnUnfocus: boolean
    When enabled (which is the default), the pop-up will close when the editor is unfocused.
    +
    completeOnSingleClick: boolean
    +
    Whether a single click on a list item suffices to trigger the + completion (which is the default), or if the user has to use a + doubleclick.
    +
    container: Element|null
    +
    Can be used to define a custom container for the widget. The default + is null, in which case the body-element will + be used.
    customKeys: keymap
    Allows you to provide a custom key map of keys to be active when the pop-up is active. The handlers will be called with an @@ -2809,6 +2822,14 @@

    Addons

    "close" ()
    Fired when the completion is finished.
    + The following events will be fired on the editor instance during + completion: +
    +
    "endCompletion" ()
    +
    Fired when the pop-up is being closed programmatically, e.g., when + the user types a character which matches the + closeCharacters option.
    +
    This addon depends on styles from addon/hint/show-hint.css. Check out the demo for an From 097d7c957c7d4988a942d11c0ac681f004ba0e8a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 16 Nov 2020 21:58:04 +0100 Subject: [PATCH 1482/1880] [html-hint addon] Add dialog tag Closes #6474 --- addon/hint/html-hint.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/hint/html-hint.js b/addon/hint/html-hint.js index d0cca4f6a2..9878eca6ef 100644 --- a/addon/hint/html-hint.js +++ b/addon/hint/html-hint.js @@ -98,6 +98,7 @@ dfn: s, dir: s, div: s, + dialog: { attrs: { open: null } }, dl: s, dt: s, em: s, From 12512d3ed0014696a64fe5d6bee2e0e5259a4861 Mon Sep 17 00:00:00 2001 From: erosman Date: Tue, 17 Nov 2020 14:23:54 +0330 Subject: [PATCH 1483/1880] [javascript-lint addon] Add comment noting dependency Added note on dependency on jshint.js --- addon/lint/javascript-lint.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addon/lint/javascript-lint.js b/addon/lint/javascript-lint.js index cc132d7f82..e5bc752308 100644 --- a/addon/lint/javascript-lint.js +++ b/addon/lint/javascript-lint.js @@ -1,6 +1,8 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/LICENSE +// Depends on jshint.js from https://github.com/jshint/jshint + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); From 0e6548686356d58504638c2bea95d403a9e53cde Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 18 Nov 2020 07:55:38 +0100 Subject: [PATCH 1484/1880] Fix focus state confusion in drag handler Issue #6480 --- mode/clike/clike.js | 8 ++++---- src/edit/mouse_events.js | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 37da2ec964..2154f1d2df 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -82,15 +82,15 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { state.tokenize = tokenString(ch); return state.tokenize(stream, state); } - if (isPunctuationChar.test(ch)) { - curPunc = ch; - return null; - } if (numberStart.test(ch)) { stream.backUp(1) if (stream.match(number)) return "number" stream.next() } + if (isPunctuationChar.test(ch)) { + curPunc = ch; + return null; + } if (ch == "/") { if (stream.eat("*")) { state.tokenize = tokenComment; diff --git a/src/edit/mouse_events.js b/src/edit/mouse_events.js index 401eadf431..b5d0b5a64e 100644 --- a/src/edit/mouse_events.js +++ b/src/edit/mouse_events.js @@ -149,7 +149,10 @@ function leftButtonStartDrag(cm, event, pos, behavior) { let dragEnd = operation(cm, e => { if (webkit) display.scroller.draggable = false cm.state.draggingText = false - if (cm.state.delayingBlurEvent) delayBlurEvent(cm) + if (cm.state.delayingBlurEvent) { + if (cm.hasFocus()) cm.state.delayingBlurEvent = false + else delayBlurEvent(cm) + } off(display.wrapper.ownerDocument, "mouseup", dragEnd) off(display.wrapper.ownerDocument, "mousemove", mouseMove) off(display.scroller, "dragstart", dragStart) From 5d2feacfc89aab7e9b973ec59627b9def1f63d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Esp=C3=ADn?= Date: Wed, 18 Nov 2020 13:27:20 +0100 Subject: [PATCH 1485/1880] [real-world uses] Add Graviton Editor --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index da6182515e..5da12e2c48 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -96,6 +96,7 @@

    CodeMirror real-world uses

  • Go language tour
  • Google Apps Script
  • Graphit (function graphing)
  • +
  • Graviton Editor (Cross-platform and modern-looking code editor)
  • HackMD (Realtime collaborative markdown notes on all platforms)
  • Handcraft (HTML prototyping)
  • Hawkee
  • From 0630b63d94ba1b1f79ae89577ec1985f5e277025 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 19 Nov 2020 09:29:46 +0100 Subject: [PATCH 1486/1880] [placeholder addon] Further fix composition handling Closes #6479 --- addon/display/placeholder.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/addon/display/placeholder.js b/addon/display/placeholder.js index 89bb93f378..cfb8341db2 100644 --- a/addon/display/placeholder.js +++ b/addon/display/placeholder.js @@ -50,11 +50,12 @@ function onComposition(cm) { setTimeout(function() { - var empty = false, input = cm.getInputField() - if (input.nodeName == "TEXTAREA") - empty = !input.value - else if (cm.lineCount() == 1) - empty = !/[^\u200b]/.test(input.querySelector(".CodeMirror-line").textContent) + var empty = false + if (cm.lineCount() == 1) { + var input = cm.getInputField() + empty = input.nodeName == "TEXTAREA" ? !cm.getLine(0).length + : !/[^\u200b]/.test(input.querySelector(".CodeMirror-line").textContent) + } if (empty) setPlaceholder(cm) else clearPlaceholder(cm) }, 20) From a53e86069bc06410ff477a8a5849a5abd26f983a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 19 Nov 2020 09:38:15 +0100 Subject: [PATCH 1487/1880] Mark version 5.58.3 --- AUTHORS | 5 +++++ CHANGELOG.md | 12 ++++++++++++ doc/manual.html | 2 +- doc/releases.html | 9 +++++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 30 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index b8087133a8..33d819ed24 100644 --- a/AUTHORS +++ b/AUTHORS @@ -251,6 +251,7 @@ Eric Allam Eric Bogard Erik Demaine Erik Welander +erosman eustas Evan Minsk Fabien Dubosson @@ -326,6 +327,7 @@ Heanes Hector Oswaldo Caballero Hein Htat Hélio +Hendrik Erz Hendrik Wallbaum Henrik Haugbølle Herculano Campos @@ -353,6 +355,7 @@ Ilya Zverev Ingo Richter Intervue Irakli Gozalishvili +iteriani Ivan Kurnosov Ivoah Jack Douglas @@ -517,6 +520,7 @@ Manuel Rego Casasnovas Marat Dreizin Marcel Gerber Marcelo Camargo +Marc Espín Marco Aurélio Marco Munizaga Marcus Bointon @@ -681,6 +685,7 @@ Peter Flynn peterkroon Peter Kroon Peter László +Phil DeJarnett Philipp A Philipp Markovics Philip Stadermann diff --git a/CHANGELOG.md b/CHANGELOG.md index 80200fc784..2b00dbd80e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## 5.58.3 (2020-11-19) + +### Bug fixes + +Suppress quick-firing of blur-focus events when dragging and clicking on Internet Explorer. + +Fix the `insertAt` option to `addLineWidget` to actually allow the widget to be placed after all widgets for the line. + +[soy mode](https://codemirror.net/mode/soy/): Support `@Attribute` and element composition. + +[shell mode](https://codemirror.net/mode/shell/): Support heredoc quoting. + ## 5.58.2 (2020-10-23) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 2ba7c732f2..89a6328e6d 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

    User manual and reference guide - version 5.58.2 + version 5.58.3

    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index bdf24ed2f7..1b4f9a7976 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,15 @@

    Release notes and version history

    Version 5.x

    +

    19-11-2020: Version 5.58.3:

    + +
      +
    • Suppress quick-firing of blur-focus events when dragging and clicking on Internet Explorer.
    • +
    • Fix the insertAt option to addLineWidget to actually allow the widget to be placed after all widgets for the line.
    • +
    • soy mode: Support @Attribute and element composition.
    • +
    • shell mode: Support heredoc quoting.
    • +
    +

    23-10-2020: Version 5.58.2:

      diff --git a/index.html b/index.html index 6d41dcc79e..7ea8c48961 100644 --- a/index.html +++ b/index.html @@ -99,7 +99,7 @@

      This is CodeMirror

    - Get the current version: 5.58.2.
    + Get the current version: 5.58.3.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index 2103e1c325..a768858ec8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.58.2", + "version": "5.58.3", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 800ee766f2..d51192c6e5 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.58.2" +CodeMirror.version = "5.58.3" From 5bef47a743e8569af3f11fac628501bb3bc10108 Mon Sep 17 00:00:00 2001 From: erosman Date: Thu, 19 Nov 2020 16:19:58 +0330 Subject: [PATCH 1488/1880] Fix white CodeMirror-scrollbar-filler on dark themes background-color: white; remains white on dark themes which doesn't suit dark background pages. Changing it to transparent to match the theme. --- lib/codemirror.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index a64f97c777..5ea2d2be2a 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -19,7 +19,7 @@ } .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { - background-color: white; /* The little square between H and V scrollbars */ + background-color: transparent; /* The little square between H and V scrollbars */ } /* GUTTER */ From a82516d0fab6ce877f2aa699fd0a435e2274c7fd Mon Sep 17 00:00:00 2001 From: Lonnie Abelbeck Date: Fri, 20 Nov 2020 02:23:52 -0600 Subject: [PATCH 1489/1880] [shell mode] Fix Heredoc to allow quotes and not require a space (a space is not required and the DELIMITER may be quoted for special meaning) cat < Date: Sat, 21 Nov 2020 01:34:52 +0330 Subject: [PATCH 1490/1880] [lint addon] Filter out duplicate messages on a single line --- addon/lint/lint.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 963f2cf227..e970a25ade 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -170,6 +170,10 @@ var anns = annotations[line]; if (!anns) continue; + // filter out duplicate messages + var message = []; + anns = anns.filter(item => message.indexOf(item.message) > -1 ? false : message.push(item.message)); + var maxSeverity = null; var tipLabel = state.hasGutter && document.createDocumentFragment(); @@ -187,9 +191,9 @@ __annotation: ann })); } - + // use original annotations[line] to show multiple messages if (state.hasGutter) - cm.setGutterMarker(line, GUTTER_ID, makeMarker(cm, tipLabel, maxSeverity, anns.length > 1, + cm.setGutterMarker(line, GUTTER_ID, makeMarker(cm, tipLabel, maxSeverity, annotations[line].length > 1, state.options.tooltips)); } if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); From 4f37b1e9ca592461473a64bf3ba43543eecdf550 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 21 Nov 2020 11:34:06 +0100 Subject: [PATCH 1491/1880] [lint addon] Remove arrow function Issue #6492 --- addon/lint/lint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/lint/lint.js b/addon/lint/lint.js index e970a25ade..395f0d9314 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -172,7 +172,7 @@ // filter out duplicate messages var message = []; - anns = anns.filter(item => message.indexOf(item.message) > -1 ? false : message.push(item.message)); + anns = anns.filter(function(item) { return message.indexOf(item.message) > -1 ? false : message.push(item.message) }); var maxSeverity = null; var tipLabel = state.hasGutter && document.createDocumentFragment(); From f65b46d154af2ba7e83fb78b449bea41e1c23c43 Mon Sep 17 00:00:00 2001 From: erosman Date: Sun, 22 Nov 2020 19:42:08 +0330 Subject: [PATCH 1492/1880] [seach addon] Add option to configure search, bottom option to put dialog at bottom Closes #6489 --- addon/search/jump-to-line.js | 5 ++++- addon/search/search.js | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/addon/search/jump-to-line.js b/addon/search/jump-to-line.js index 1f3526d247..990c235ef1 100644 --- a/addon/search/jump-to-line.js +++ b/addon/search/jump-to-line.js @@ -13,8 +13,11 @@ })(function(CodeMirror) { "use strict"; + // default search panel location + CodeMirror.defineOption("search", {bottom: false}); + function dialog(cm, text, shortText, deflt, f) { - if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true}); + if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true, bottom: cm.options.search.bottom}); else f(prompt(shortText, deflt)); } diff --git a/addon/search/search.js b/addon/search/search.js index cecdd52ea1..118f1112f1 100644 --- a/addon/search/search.js +++ b/addon/search/search.js @@ -19,6 +19,9 @@ })(function(CodeMirror) { "use strict"; + // default search panel location + CodeMirror.defineOption("search", {bottom: false}); + function searchOverlay(query, caseInsensitive) { if (typeof query == "string") query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g"); @@ -63,12 +66,13 @@ selectValueOnOpen: true, closeOnEnter: false, onClose: function() { clearSearch(cm); }, - onKeyDown: onKeyDown + onKeyDown: onKeyDown, + bottom: cm.options.search.bottom }); } function dialog(cm, text, shortText, deflt, f) { - if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true}); + if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true, bottom: cm.options.search.bottom}); else f(prompt(shortText, deflt)); } From 464a66067b8d984c81b8e61ce048b34d7a1054bb Mon Sep 17 00:00:00 2001 From: quiddity-wp Date: Sun, 22 Nov 2020 13:02:36 -0800 Subject: [PATCH 1493/1880] [real-world uses] Add MediaWiki --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 5da12e2c48..c6e6c80323 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -129,6 +129,7 @@

    CodeMirror real-world uses

  • LiveUML (PlantUML online editor)
  • Markdown Delight Editor (extensible markdown editor polymer component)
  • Marklight editor (lightweight markup editor)
  • +
  • MediaWiki extension (wiki engine)
  • Mergely (interactive diffing)
  • MIHTool (iOS web-app debugging tool)
  • mscgen_js (online sequence chart editor)
  • From f4b04da36d5c88762382db44651b0b5389077bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20=C5=9Alepowro=C5=84ski?= <45392875+slepowronski@users.noreply.github.com> Date: Wed, 25 Nov 2020 09:23:24 +0100 Subject: [PATCH 1494/1880] [show-hint addon] Add additional customizing options Introduces four new options for the show-hint addon: - closeOnCursorActivity - closeOnPick - paddingForScrollbar - moveOnOverlap --- addon/hint/show-hint.js | 50 ++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index cd0d6a7bd5..5ef1bba645 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -1,6 +1,8 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/LICENSE +// declare global: DOMRect + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); @@ -94,8 +96,10 @@ completion.to || data.to, "complete"); CodeMirror.signal(data, "pick", completion); self.cm.scrollIntoView(); - }) - this.close(); + }); + if (this.options.closeOnPick) { + this.close(); + } }, cursorActivity: function() { @@ -113,7 +117,9 @@ if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || pos.ch < identStart.ch || this.cm.somethingSelected() || (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { - this.close(); + if (this.options.closeOnCursorActivity) { + this.close(); + } } else { var self = this; this.debounce = requestAnimationFrame(function() {self.update();}); @@ -259,10 +265,15 @@ var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth); var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight); container.appendChild(hints); - var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; - var scrolls = hints.scrollHeight > hints.clientHeight + 1 - var startScroll = cm.getScrollInfo(); + var box = completion.options.moveOnOverlap ? hints.getBoundingClientRect() : new DOMRect(); + var scrolls = completion.options.paddingForScrollbar ? hints.scrollHeight > hints.clientHeight + 1 : false; + + // Compute in the timeout to avoid reflow on init + var startScroll; + setTimeout(function() { startScroll = cm.getScrollInfo(); }); + + var overlapY = box.bottom - winH; if (overlapY > 0) { var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); if (curTop - height > 0) { // Fits above cursor @@ -332,7 +343,12 @@ CodeMirror.on(hints, "mousedown", function() { setTimeout(function(){cm.focus();}, 20); }); - this.scrollToActive() + + // The first hint doesn't need to be scrolled to on init + var selectedHintRange = this.getSelectedHintRange(); + if (selectedHintRange.from !== 0 || selectedHintRange.to !== 0) { + this.scrollToActive(); + } CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]); return true; @@ -379,9 +395,9 @@ }, scrollToActive: function() { - var margin = this.completion.options.scrollMargin || 0; - var node1 = this.hints.childNodes[Math.max(0, this.selectedHint - margin)]; - var node2 = this.hints.childNodes[Math.min(this.data.list.length - 1, this.selectedHint + margin)]; + var selectedHintRange = this.getSelectedHintRange(); + var node1 = this.hints.childNodes[selectedHintRange.from]; + var node2 = this.hints.childNodes[selectedHintRange.to]; var firstNode = this.hints.firstChild; if (node1.offsetTop < this.hints.scrollTop) this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop; @@ -391,6 +407,14 @@ screenAmount: function() { return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; + }, + + getSelectedHintRange: function() { + var margin = this.completion.options.scrollMargin || 0; + return { + from: Math.max(0, this.selectedHint - margin), + to: Math.min(this.data.list.length - 1, this.selectedHint + margin), + }; } }; @@ -468,11 +492,15 @@ completeSingle: true, alignWithWord: true, closeCharacters: /[\s()\[\]{};:>,]/, + closeOnCursorActivity: true, + closeOnPick: true, closeOnUnfocus: true, completeOnSingleClick: true, container: null, customKeys: null, - extraKeys: null + extraKeys: null, + paddingForScrollbar: true, + moveOnOverlap: true, }; CodeMirror.defineOption("hintOptions", null); From 5e11705588c69925dcd8531bc605854bb379150b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 1 Dec 2020 08:48:39 +0100 Subject: [PATCH 1495/1880] [clojure mode] Fix exponential-complexity regexp --- mode/clojure/clojure.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/clojure/clojure.js b/mode/clojure/clojure.js index 25d308ab4c..0b9d6acc3e 100644 --- a/mode/clojure/clojure.js +++ b/mode/clojure/clojure.js @@ -160,10 +160,10 @@ CodeMirror.defineMode("clojure", function (options) { var numberLiteral = /^(?:[+\-]?\d+(?:(?:N|(?:[eE][+\-]?\d+))|(?:\.?\d*(?:M|(?:[eE][+\-]?\d+))?)|\/\d+|[xX][0-9a-fA-F]+|r[0-9a-zA-Z]+)?(?=[\\\[\]\s"#'(),;@^`{}~]|$))/; var characterLiteral = /^(?:\\(?:backspace|formfeed|newline|return|space|tab|o[0-7]{3}|u[0-9A-Fa-f]{4}|x[0-9A-Fa-f]{4}|.)?(?=[\\\[\]\s"(),;@^`{}~]|$))/; - // simple-namespace := /^[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*/ + // simple-namespace := /^[^\\\/\[\]\d\s"#'(),;@^`{}~.][^\\\[\]\s"(),;@^`{}~.\/]*/ // simple-symbol := /^(?:\/|[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*)/ // qualified-symbol := ((<.>)*)? - var qualifiedSymbol = /^(?:(?:[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*(?:\.[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*)*\/)?(?:\/|[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*)*(?=[\\\[\]\s"(),;@^`{}~]|$))/; + var qualifiedSymbol = /^(?:(?:[^\\\/\[\]\d\s"#'(),;@^`{}~.][^\\\[\]\s"(),;@^`{}~.\/]*(?:\.[^\\\/\[\]\d\s"#'(),;@^`{}~.][^\\\[\]\s"(),;@^`{}~.\/]*)*\/)?(?:\/|[^\\\/\[\]\d\s"#'(),;@^`{}~][^\\\[\]\s"(),;@^`{}~]*)*(?=[\\\[\]\s"(),;@^`{}~]|$))/; function base(stream, state) { if (stream.eatSpace() || stream.eat(",")) return ["space", null]; From 1cec2af7be8a2158ff5bf71ab76c8c62fe669791 Mon Sep 17 00:00:00 2001 From: Ben Hormann Date: Wed, 2 Dec 2020 10:14:35 +0000 Subject: [PATCH 1496/1880] [wast mode] Add link --- mode/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/index.html b/mode/index.html index 858ba127f2..51205ddce9 100644 --- a/mode/index.html +++ b/mode/index.html @@ -153,6 +153,7 @@

    Language modes

  • VHDL
  • Vue.js app
  • Web IDL
  • +
  • WebAssembly Text Format
  • XML/HTML
  • XQuery
  • Yacas
  • From f4fd159353930680dbe617d440e5a4867d8b13a9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 2 Dec 2020 17:20:39 +0100 Subject: [PATCH 1497/1880] [hardwrap addon] Improve start-of-line condition for overlong words Issue #6494 --- addon/wrap/hardwrap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/wrap/hardwrap.js b/addon/wrap/hardwrap.js index f194946c5d..bccdc8d14c 100644 --- a/addon/wrap/hardwrap.js +++ b/addon/wrap/hardwrap.js @@ -35,7 +35,7 @@ for (; at > 0; --at) if (wrapOn.test(text.slice(at - 1, at + 1))) break; - if (at == 0 && !forceBreak) { + if (!forceBreak && at <= text.match(/^[ \t]*/)[0].length) { // didn't find a break point before column, in non-forceBreak mode try to // find one after 'column'. for (at = column + 1; at < text.length - 1; ++at) { From c04867c786c5625f5f221c4162cb54d798dc9a8e Mon Sep 17 00:00:00 2001 From: "Jakub T. Jankiewicz" Date: Thu, 3 Dec 2020 19:15:50 +0100 Subject: [PATCH 1498/1880] [scheme mode] Add more special indentation words and keywords --- mode/scheme/scheme.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/scheme/scheme.js b/mode/scheme/scheme.js index 56e4e332e9..0bbb8c8a41 100644 --- a/mode/scheme/scheme.js +++ b/mode/scheme/scheme.js @@ -26,8 +26,8 @@ CodeMirror.defineMode("scheme", function () { return obj; } - var keywords = makeKeywords("λ case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt #f floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string=? string>? string? substring symbol->string symbol? #t tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?"); - var indentKeys = makeKeywords("define let letrec let* lambda"); + var keywords = makeKeywords("λ case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax define-macro defmacro delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt #f floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string=? string>? string? substring symbol->string symbol? #t tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?"); + var indentKeys = makeKeywords("define let letrec let* lambda define-macro defmacro let-syntax letrec-syntax define-syntax syntax-rules"); function stateStack(indent, type, prev) { // represents a state stack object this.indent = indent; From e410e5c17866308e1aba41f56383a6a2d31f02a9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 3 Dec 2020 19:30:28 +0100 Subject: [PATCH 1499/1880] Add a funding.yml file --- .github/FUNDING.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..d87b38eee6 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +patreon: marijn +custom: ['https://www.paypal.com/paypalme/marijnhaverbeke', 'https://marijnhaverbeke.nl/fund/'] From a966b5d115af09983d37f7c9aa034b78ac954ca4 Mon Sep 17 00:00:00 2001 From: Piyush Date: Fri, 4 Dec 2020 09:50:24 +0530 Subject: [PATCH 1500/1880] fix memory leak with matchbrackets --- addon/edit/matchbrackets.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js index 2c47e07033..0377408802 100644 --- a/addon/edit/matchbrackets.js +++ b/addon/edit/matchbrackets.js @@ -117,25 +117,25 @@ }); } - CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { - function clear(cm) { - if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) { - cm.state.matchBrackets.currentlyHighlighted(); - cm.state.matchBrackets.currentlyHighlighted = null; - } + function clearHighlighted(cm) { + if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) { + cm.state.matchBrackets.currentlyHighlighted(); + cm.state.matchBrackets.currentlyHighlighted = null; } + } + CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { if (old && old != CodeMirror.Init) { cm.off("cursorActivity", doMatchBrackets); cm.off("focus", doMatchBrackets) - cm.off("blur", clear) - clear(cm); + cm.off("blur", clearHighlighted) + clearHighlighted(cm); } if (val) { cm.state.matchBrackets = typeof val == "object" ? val : {}; cm.on("cursorActivity", doMatchBrackets); cm.on("focus", doMatchBrackets) - cm.on("blur", clear) + cm.on("blur", clearHighlighted) } }); From e3fc417882517edaffda6f445c62f8697a0cd495 Mon Sep 17 00:00:00 2001 From: Simon Huber Date: Mon, 7 Dec 2020 10:16:23 +0100 Subject: [PATCH 1501/1880] [solaized theme] Fix typos --- theme/solarized.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/solarized.css b/theme/solarized.css index fcd1d70de6..9c6b1265c1 100644 --- a/theme/solarized.css +++ b/theme/solarized.css @@ -99,7 +99,7 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png .cm-s-solarized.cm-s-light div.CodeMirror-selected { background: #eee8d5; } .cm-s-solarized.cm-s-light .CodeMirror-line::selection, .cm-s-light .CodeMirror-line > span::selection, .cm-s-light .CodeMirror-line > span > span::selection { background: #eee8d5; } -.cm-s-solarized.cm-s-light .CodeMirror-line::-moz-selection, .cm-s-ligh .CodeMirror-line > span::-moz-selection, .cm-s-ligh .CodeMirror-line > span > span::-moz-selection { background: #eee8d5; } +.cm-s-solarized.cm-s-light .CodeMirror-line::-moz-selection, .cm-s-light .CodeMirror-line > span::-moz-selection, .cm-s-light .CodeMirror-line > span > span::-moz-selection { background: #eee8d5; } /* Editor styling */ From 622fcb9b8740ceade71c1f579eaa76c8b82a0c0b Mon Sep 17 00:00:00 2001 From: "Jakub T. Jankiewicz" Date: Mon, 7 Dec 2020 10:19:14 +0100 Subject: [PATCH 1502/1880] [scheme mode] More indent fixes --- mode/scheme/scheme.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/scheme/scheme.js b/mode/scheme/scheme.js index 0bbb8c8a41..efac89078b 100644 --- a/mode/scheme/scheme.js +++ b/mode/scheme/scheme.js @@ -26,8 +26,8 @@ CodeMirror.defineMode("scheme", function () { return obj; } - var keywords = makeKeywords("λ case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax define-macro defmacro delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt #f floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string=? string>? string? substring symbol->string symbol? #t tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?"); - var indentKeys = makeKeywords("define let letrec let* lambda define-macro defmacro let-syntax letrec-syntax define-syntax syntax-rules"); + var keywords = makeKeywords("λ case-lambda call/cc class cond-expand define-class define-values exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax define-macro defmacro delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt #f floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string=? string>? string? substring symbol->string symbol? #t tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?"); + var indentKeys = makeKeywords("define let letrec let* lambda define-macro defmacro let-syntax letrec-syntax let-values let*-values define-syntax syntax-rules define-values when unless"); function stateStack(indent, type, prev) { // represents a state stack object this.indent = indent; From ae4e671eb2d931ce88cf91d6d1f39cdaf7f0654e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 7 Dec 2020 21:45:51 +0100 Subject: [PATCH 1503/1880] [shell mode] Treat <<< as here string operator Issue #6512 --- mode/shell/shell.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/shell/shell.js b/mode/shell/shell.js index 2219e62e19..8271485f5f 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -71,6 +71,7 @@ CodeMirror.defineMode('shell', function() { return 'attribute'; } if (ch == "<") { + if (stream.match("<<")) return "operator" var heredoc = stream.match(/^<-?\s*['"]?([^'"]*)['"]?/) if (heredoc) { state.tokens.unshift(tokenHeredoc(heredoc[1])) From fb4ec129858dc916de86e8dd802e9668ae0049a0 Mon Sep 17 00:00:00 2001 From: mlsad3 Date: Tue, 8 Dec 2020 01:35:04 -0700 Subject: [PATCH 1504/1880] [verilog mode] Improve * Handle `uvm_*_begin/end macros as well as macros in case/switch. * Prevent extern functions and typedef classes from indenting. * Indent lines after assignments, handle corner-case inside parenthesis. * Handle 'disable fork' and 'wait fork'. * Add '<' and '>' to operators. * Add tests for mode/verilog changes. * Verilog mode handles compiler directives and differentiates assignment vs comparison. * Cleanup lint errors. * Add verilog mode support for '@'. Co-authored-by: Matt Diehl --- mode/verilog/test.js | 170 ++++++++++++++++++++++++++++++++++++++++ mode/verilog/verilog.js | 138 ++++++++++++++++++++++++++++---- 2 files changed, 292 insertions(+), 16 deletions(-) diff --git a/mode/verilog/test.js b/mode/verilog/test.js index bafe726db3..38c1cbe457 100644 --- a/mode/verilog/test.js +++ b/mode/verilog/test.js @@ -139,6 +139,32 @@ "" ); + MT("align_assignments", + /** + * always @(posedge clk) begin + * if (rst) + * data_out <= 8'b0 + + * 8'b1; + * else + * data_out = 8'b0 + + * 8'b1; + * data_out = + * 8'b0 + 8'b1; + * end + */ + "[keyword always] [def @][bracket (][keyword posedge] [variable clk][bracket )] [keyword begin]", + " [keyword if] [bracket (][variable rst][bracket )]", + " [variable data_out] [meta <=] [number 8'b0] [meta +]", + " [number 8'b1];", + " [keyword else]", + " [variable data_out] [meta =] [number 8'b0] [meta +]", + " [number 8'b1];", + " [variable data_out] [meta =] [number 8'b0] [meta +]", + " [number 8'b1];", + "[keyword end]", + "" + ); + // Indentation tests MT("indent_single_statement_if", "[keyword if] [bracket (][variable foo][bracket )]", @@ -270,4 +296,148 @@ "" ); + MT("indent_uvm_macros", + /** + * `uvm_object_utils_begin(foo) + * `uvm_field_event(foo, UVM_ALL_ON) + * `uvm_object_utils_end + */ + "[def `uvm_object_utils_begin][bracket (][variable foo][bracket )]", + " [def `uvm_field_event][bracket (][variable foo], [variable UVM_ALL_ON][bracket )]", + "[def `uvm_object_utils_end]", + "" + ); + + MT("indent_uvm_macros2", + /** + * `uvm_do_with(mem_read,{ + * bar_nb == 0; + * }) + */ + "[def `uvm_do_with][bracket (][variable mem_read],[bracket {]", + " [variable bar_nb] [meta ==] [number 0];", + "[bracket })]", + "" + ); + + MT("indent_wait_disable_fork", + /** + * virtual task body(); + * repeat (20) begin + * fork + * `uvm_create_on(t,p_seq) + * join_none + * end + * wait fork; + * disable fork; + * endtask : body + */ + "[keyword virtual] [keyword task] [variable body][bracket ()];", + " [keyword repeat] [bracket (][number 20][bracket )] [keyword begin]", + " [keyword fork]", + " [def `uvm_create_on][bracket (][variable t],[variable p_seq][bracket )]", + " [keyword join_none]", + " [keyword end]", + " [keyword wait] [keyword fork];", + " [keyword disable] [keyword fork];", + "[keyword endtask] : [variable body]", + "" + ); + + MT("indent_typedef_class", + /** + * typedef class asdf; + * typedef p p_t[]; + * typedef enum { + * ASDF + * } t; + */ + "[keyword typedef] [keyword class] [variable asdf];", + "[keyword typedef] [variable p] [variable p_t][bracket [[]]];", + "[keyword typedef] [keyword enum] [bracket {]", + " [variable ASDF]", + "[bracket }] [variable t];", + "" + ); + + MT("indent_case_with_macro", + /** + * // It should be assumed that Macros can have ';' inside, or 'begin'/'end' blocks. + * // As such, 'case' statement should indent correctly with macros inside. + * case(foo) + * ASDF : this.foo = seqNum; + * ABCD : `update(f) + * EFGH : `update(g) + * endcase + */ + "[keyword case][bracket (][variable foo][bracket )]", + " [variable ASDF] : [keyword this].[variable foo] [meta =] [variable seqNum];", + " [variable ABCD] : [def `update][bracket (][variable f][bracket )]", + " [variable EFGH] : [def `update][bracket (][variable g][bracket )]", + "[keyword endcase]", + "" + ); + + MT("indent_extern_function", + /** + * extern virtual function void do(ref packet trans); + * extern virtual function void do2(ref packet trans); + */ + "[keyword extern] [keyword virtual] [keyword function] [keyword void] [variable do1][bracket (][keyword ref] [variable packet] [variable trans][bracket )];", + "[keyword extern] [keyword virtual] [keyword function] [keyword void] [variable do2][bracket (][keyword ref] [variable packet] [variable trans][bracket )];", + "" + ); + + MT("indent_assignment", + /** + * for (int i=1;i < fun;i++) begin + * foo = 2 << asdf || 11'h35 >> abcd + * && 8'h6 | 1'b1; + * end + */ + "[keyword for] [bracket (][keyword int] [variable i][meta =][number 1];[variable i] [meta <] [variable fun];[variable i][meta ++][bracket )] [keyword begin]", + " [variable foo] [meta =] [number 2] [meta <<] [variable asdf] [meta ||] [number 11'h35] [meta >>] [variable abcd]", + " [meta &&] [number 8'h6] [meta |] [number 1'b1];", + "[keyword end]", + "" + ); + + MT("indent_foreach_constraint", + /** + * `uvm_rand_send_with(wrTlp, { + * length ==1; + * foreach (Data[i]) { + * payload[i] == Data[i]; + * } + * }) + */ + "[def `uvm_rand_send_with][bracket (][variable wrTlp], [bracket {]", + " [variable length] [meta ==][number 1];", + " [keyword foreach] [bracket (][variable Data][bracket [[][variable i][bracket ]])] [bracket {]", + " [variable payload][bracket [[][variable i][bracket ]]] [meta ==] [variable Data][bracket [[][variable i][bracket ]]];", + " [bracket }]", + "[bracket })]", + "" + ); + + MT("indent_compiler_directives", + /** + * `ifdef DUT + * `else + * `ifndef FOO + * `define FOO + * `endif + * `endif + * `timescale 1ns/1ns + */ + "[def `ifdef] [variable DUT]", + "[def `else]", + " [def `ifndef] [variable FOO]", + " [def `define] [variable FOO]", + " [def `endif]", + "[def `endif]", + "[def `timescale] [number 1][variable ns][meta /][number 1][variable ns]", + "" + ); + })(); diff --git a/mode/verilog/verilog.js b/mode/verilog/verilog.js index 43990452d3..544045b867 100644 --- a/mode/verilog/verilog.js +++ b/mode/verilog/verilog.js @@ -16,6 +16,12 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { var indentUnit = config.indentUnit, statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, dontAlignCalls = parserConfig.dontAlignCalls, + // compilerDirectivesUseRegularIndentation - If set, Compiler directive + // indentation follows the same rules as everything else. Otherwise if + // false, compiler directives will track their own indentation. + // For example, `ifdef nested inside another `ifndef will be indented, + // but a `ifdef inside a function block may not be indented. + compilerDirectivesUseRegularIndentation = parserConfig.compilerDirectivesUseRegularIndentation, noIndentKeywords = parserConfig.noIndentKeywords || [], multiLineStrings = parserConfig.multiLineStrings, hooks = parserConfig.hooks || {}; @@ -62,7 +68,7 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { binary_module_path_operator ::= == | != | && | || | & | | | ^ | ^~ | ~^ */ - var isOperatorChar = /[\+\-\*\/!~&|^%=?:]/; + var isOperatorChar = /[\+\-\*\/!~&|^%=?:<>]/; var isBracketChar = /[\[\]{}()]/; var unsignedNumber = /\d[0-9_]*/; @@ -72,8 +78,13 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { var hexLiteral = /\d*\s*'s?h\s*[0-9a-fxz?][0-9a-fxz?_]*/i; var realLiteral = /(\d[\d_]*(\.\d[\d_]*)?E-?[\d_]+)|(\d[\d_]*\.\d[\d_]*)/i; - var closingBracketOrWord = /^((\w+)|[)}\]])/; + var closingBracketOrWord = /^((`?\w+)|[)}\]])/; var closingBracket = /[)}\]]/; + var compilerDirectiveRegex = new RegExp( + "^(`(?:ifdef|ifndef|elsif|else|endif|undef|undefineall|define|include|begin_keywords|celldefine|default|" + + "nettype|end_keywords|endcelldefine|line|nounconnected_drive|pragma|resetall|timescale|unconnected_drive))\\b"); + var compilerDirectiveBeginRegex = /^(`(?:ifdef|ifndef|elsif|else))\b/; + var compilerDirectiveEndRegex = /^(`(?:elsif|else|endif))\b/; var curPunc; var curKeyword; @@ -96,6 +107,7 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { openClose["do" ] = "while"; openClose["fork" ] = "join;join_any;join_none"; openClose["covergroup"] = "endgroup"; + openClose["macro_begin"] = "macro_end"; for (var i in noIndentKeywords) { var keyword = noIndentKeywords[i]; @@ -105,7 +117,7 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { } // Keywords which open statements that are ended with a semi-colon - var statementKeywords = words("always always_comb always_ff always_latch assert assign assume else export for foreach forever if import initial repeat while"); + var statementKeywords = words("always always_comb always_ff always_latch assert assign assume else export for foreach forever if import initial repeat while extern typedef"); function tokenBase(stream, state) { var ch = stream.peek(), style; @@ -125,6 +137,24 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { if (ch == '`') { stream.next(); if (stream.eatWhile(/[\w\$_]/)) { + var cur = stream.current(); + curKeyword = cur; + // Macros that end in _begin, are start of block and end with _end + if (cur.startsWith("`uvm_") && cur.endsWith("_begin")) { + var keywordClose = curKeyword.substr(0,curKeyword.length - 5) + "end"; + openClose[cur] = keywordClose; + curPunc = "newblock"; + } else if (cur.startsWith("`uvm_") && cur.endsWith("_end")) { + } else { + stream.eatSpace(); + if (stream.peek() == '(') { + // Check if this is a block + curPunc = "newmacro"; + } + var withSpace = stream.current(); + // Move the stream back before the spaces + stream.backUp(withSpace.length - cur.length); + } return "def"; } else { return null; @@ -145,6 +175,12 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { stream.eatWhile(/[\d_.]/); return "def"; } + // Event + if (ch == '@') { + stream.next(); + stream.eatWhile(/[@]/); + return "def"; + } // Strings if (ch == '"') { stream.next(); @@ -178,6 +214,7 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { // Operators if (stream.eatWhile(isOperatorChar)) { + curPunc = stream.current(); return "meta"; } @@ -187,6 +224,15 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { if (keywords[cur]) { if (openClose[cur]) { curPunc = "newblock"; + if (cur === "fork") { + // Fork can be a statement instead of block in cases of: + // "disable fork;" and "wait fork;" (trailing semicolon) + stream.eatSpace() + if (stream.peek() == ';') { + curPunc = "newstatement"; + } + stream.backUp(stream.current().length - cur.length); + } } if (statementKeywords[cur]) { curPunc = "newstatement"; @@ -226,16 +272,17 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { return "comment"; } - function Context(indented, column, type, align, prev) { + function Context(indented, column, type, scopekind, align, prev) { this.indented = indented; this.column = column; this.type = type; + this.scopekind = scopekind; this.align = align; this.prev = prev; } - function pushContext(state, col, type) { + function pushContext(state, col, type, scopekind) { var indent = state.indented; - var c = new Context(indent, col, type, null, state.context); + var c = new Context(indent, col, type, scopekind ? scopekind : "", null, state.context); return state.context = c; } function popContext(state) { @@ -261,6 +308,16 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { } } + function isInsideScopeKind(ctx, scopekind) { + if (ctx == null) { + return false; + } + if (ctx.scopekind === scopekind) { + return true; + } + return isInsideScopeKind(ctx.prev, scopekind); + } + function buildElectricInputRegEx() { // Reindentation should occur on any bracket char: {}()[] // or on a match of any of the block closing keywords, at @@ -287,8 +344,9 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { startState: function(basecolumn) { var state = { tokenize: null, - context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + context: new Context((basecolumn || 0) - indentUnit, 0, "top", "top", false), indented: 0, + compilerDirectiveIndented: 0, startOfLine: true }; if (hooks.startState) hooks.startState(state); @@ -313,15 +371,42 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { curPunc = null; curKeyword = null; var style = (state.tokenize || tokenBase)(stream, state); - if (style == "comment" || style == "meta" || style == "variable") return style; + if (style == "comment" || style == "meta" || style == "variable") { + if (((curPunc === "=") || (curPunc === "<=")) && !isInsideScopeKind(ctx, "assignment")) { + // '<=' could be nonblocking assignment or lessthan-equals (which shouldn't cause indent) + // Search through the context to see if we are already in an assignment. + // '=' could be inside port declaration with comma or ')' afterward, or inside for(;;) block. + pushContext(state, stream.column() + curPunc.length, "assignment", "assignment"); + if (ctx.align == null) ctx.align = true; + } + return style; + } if (ctx.align == null) ctx.align = true; - if (curPunc == ctx.type) { - popContext(state); - } else if ((curPunc == ";" && ctx.type == "statement") || + var isClosingAssignment = ctx.type == "assignment" && + closingBracket.test(curPunc) && ctx.prev && ctx.prev.type === curPunc; + if (curPunc == ctx.type || isClosingAssignment) { + if (isClosingAssignment) { + ctx = popContext(state); + } + ctx = popContext(state); + if (curPunc == ")") { + // Handle closing macros, assuming they could have a semicolon or begin/end block inside. + if (ctx && (ctx.type === "macro")) { + ctx = popContext(state); + while (ctx && (ctx.type == "statement" || ctx.type == "assignment")) ctx = popContext(state); + } + } else if (curPunc == "}") { + // Handle closing statements like constraint block: "foreach () {}" which + // do not have semicolon at end. + if (ctx && (ctx.type === "statement")) { + while (ctx && (ctx.type == "statement")) ctx = popContext(state); + } + } + } else if (((curPunc == ";" || curPunc == ",") && (ctx.type == "statement" || ctx.type == "assignment")) || (ctx.type && isClosing(curKeyword, ctx.type))) { ctx = popContext(state); - while (ctx && ctx.type == "statement") ctx = popContext(state); + while (ctx && (ctx.type == "statement" || ctx.type == "assignment")) ctx = popContext(state); } else if (curPunc == "{") { pushContext(state, stream.column(), "}"); } else if (curPunc == "[") { @@ -329,9 +414,9 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { } else if (curPunc == "(") { pushContext(state, stream.column(), ")"); } else if (ctx && ctx.type == "endcase" && curPunc == ":") { - pushContext(state, stream.column(), "statement"); + pushContext(state, stream.column(), "statement", "case"); } else if (curPunc == "newstatement") { - pushContext(state, stream.column(), "statement"); + pushContext(state, stream.column(), "statement", curKeyword); } else if (curPunc == "newblock") { if (curKeyword == "function" && ctx && (ctx.type == "statement" || ctx.type == "endgroup")) { // The 'function' keyword can appear in some other contexts where it actually does not @@ -339,9 +424,23 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { // Do nothing in this case } else if (curKeyword == "task" && ctx && ctx.type == "statement") { // Same thing for task + } else if (curKeyword == "class" && ctx && ctx.type == "statement") { + // Same thing for class (e.g. typedef) } else { var close = openClose[curKeyword]; - pushContext(state, stream.column(), close); + pushContext(state, stream.column(), close, curKeyword); + } + } else if (curPunc == "newmacro" || (curKeyword && curKeyword.match(compilerDirectiveRegex))) { + if (curPunc == "newmacro") { + // Macros (especially if they have parenthesis) potentially have a semicolon + // or complete statement/block inside, and should be treated as such. + pushContext(state, stream.column(), "macro", "macro"); + } + if (curKeyword.match(compilerDirectiveEndRegex)) { + state.compilerDirectiveIndented -= statementIndentUnit; + } + if (curKeyword.match(compilerDirectiveBeginRegex)) { + state.compilerDirectiveIndented += statementIndentUnit; } } @@ -361,8 +460,15 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { var possibleClosing = textAfter.match(closingBracketOrWord); if (possibleClosing) closing = isClosing(possibleClosing[0], ctx.type); + if (!compilerDirectivesUseRegularIndentation && textAfter.match(compilerDirectiveRegex)) { + if (textAfter.match(compilerDirectiveEndRegex)) { + return state.compilerDirectiveIndented - statementIndentUnit; + } + return state.compilerDirectiveIndented; + } if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); - else if (closingBracket.test(ctx.type) && ctx.align && !dontAlignCalls) return ctx.column + (closing ? 0 : 1); + else if ((closingBracket.test(ctx.type) || ctx.type == "assignment") + && ctx.align && !dontAlignCalls) return ctx.column + (closing ? 0 : 1); else if (ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit; else return ctx.indented + (closing ? 0 : indentUnit); }, From 348ab5603405d1e396f32a9acfdf81055c91a16f Mon Sep 17 00:00:00 2001 From: iteriani Date: Tue, 8 Dec 2020 00:41:03 -0800 Subject: [PATCH 1505/1880] [soy mode] Update indentation rules for Element Composition * Add support for Soy Element Composition. Add support for Soy Element Composition. It has the syntax in the form of <{foo()}> This adds support to pass through allowEmptyTag and to support this mode in closetag. * Disable allowMissingTagName and handle Soy Element Composition directly. Disable allowMissingTagName and handle Soy Element Composition directly. This also adds a case in closetag.js to handle autocompletes for soy element composition. Right now, if you were to do something like <{foo()}> it would autocomplet with . This change makes it autocomplete with * Update indentation rules for Soy Element Composition Update indentation rules for Soy Element Composition * Update soy.js * Update soy.js --- mode/soy/soy.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/mode/soy/soy.js b/mode/soy/soy.js index 17bafcd932..e3427ebe3c 100644 --- a/mode/soy/soy.js +++ b/mode/soy/soy.js @@ -463,8 +463,15 @@ return null; case "tag": - var endTag = state.tag[0] == "/"; - var tagName = endTag ? state.tag.substring(1) : state.tag; + var endTag; + var tagName; + if (state.tag === undefined) { + endTag = true; + tagName = ''; + } else { + endTag = state.tag[0] == "/"; + tagName = endTag ? state.tag.substring(1) : state.tag; + } var tag = tags[tagName]; if (stream.match(/^\/?}/)) { var selfClosed = stream.current() == "/}"; @@ -576,12 +583,11 @@ return "keyword"; } else if (match = stream.match(/^<\{/)) { state.soyState.push("template-call-expression"); - state.tag = "print"; state.indent += 2 * config.indentUnit; state.soyState.push("tag"); return "keyword"; } else if (match = stream.match(/^<\/>/)) { - state.indent -= 2 * config.indentUnit; + state.indent -= 1 * config.indentUnit; return "keyword"; } From e20f9118534ebbb1249a2316639de5ce675523a8 Mon Sep 17 00:00:00 2001 From: Matt Diehl Date: Tue, 8 Dec 2020 09:50:20 -0700 Subject: [PATCH 1506/1880] Remove unnecessary line. --- mode/verilog/verilog.js | 1 - 1 file changed, 1 deletion(-) diff --git a/mode/verilog/verilog.js b/mode/verilog/verilog.js index 544045b867..89fe9c1ac8 100644 --- a/mode/verilog/verilog.js +++ b/mode/verilog/verilog.js @@ -144,7 +144,6 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { var keywordClose = curKeyword.substr(0,curKeyword.length - 5) + "end"; openClose[cur] = keywordClose; curPunc = "newblock"; - } else if (cur.startsWith("`uvm_") && cur.endsWith("_end")) { } else { stream.eatSpace(); if (stream.peek() == '(') { From d096a604db350e678c53bce0b2081e0817b84056 Mon Sep 17 00:00:00 2001 From: Elmar Peise Date: Thu, 10 Dec 2020 13:44:26 +0100 Subject: [PATCH 1507/1880] [hardwrap addon] Break an inifite loop This breaks an infinite loop triggered by wrapping a text containing a word longer than the targed width (e.g., a long URL). --- addon/wrap/hardwrap.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/wrap/hardwrap.js b/addon/wrap/hardwrap.js index bccdc8d14c..516368c80d 100644 --- a/addon/wrap/hardwrap.js +++ b/addon/wrap/hardwrap.js @@ -91,7 +91,8 @@ } while (curLine.length > column) { var bp = findBreakPoint(curLine, column, wrapOn, killTrailing, forceBreak); - if (bp.from != bp.to || forceBreak) { + if (bp.from != bp.to || + forceBreak && leadingSpace !== curLine.slice(0, bp.to)) { changes.push({text: ["", leadingSpace], from: Pos(curNo, bp.from), to: Pos(curNo, bp.to)}); From 7f3c36619f964d20e20c0ff5bec9cee99dae1549 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 11 Dec 2020 07:48:40 +0100 Subject: [PATCH 1508/1880] Fix platform detection for iPadOS Safari See https://github.com/ProseMirror/prosemirror/issues/1111 --- src/util/browser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/browser.js b/src/util/browser.js index 9fc4602c68..6e3022e765 100644 --- a/src/util/browser.js +++ b/src/util/browser.js @@ -17,7 +17,7 @@ export let safari = /Apple Computer/.test(navigator.vendor) export let mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent) export let phantom = /PhantomJS/.test(userAgent) -export let ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent) +export let ios = !edge && /AppleWebKit/.test(userAgent) && (/Mobile\/\w+/.test(userAgent) || navigator.maxTouchPoints > 2) export let android = /Android/.test(userAgent) // This is woefully incomplete. Suggestions for alternative methods welcome. export let mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent) From e4784f6e9c34f4642791ecf622640c81b91f37fa Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 15 Dec 2020 08:28:52 +0100 Subject: [PATCH 1509/1880] [javascript mode] Allow separator-less object types Issue #6520 --- mode/javascript/javascript.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 63eaa241b7..188dbf217c 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -616,13 +616,18 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (value == "|" || value == "&") return cont(typeexpr) if (type == "string" || type == "number" || type == "atom") return cont(afterType); if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType) - if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType) + if (type == "{") return cont(pushlex("}"), typeprops, poplex, afterType) if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType, afterType) if (type == "<") return cont(commasep(typeexpr, ">"), typeexpr) } function maybeReturnType(type) { if (type == "=>") return cont(typeexpr) } + function typeprops(type) { + if (type == "}") return cont() + if (type == "," || type == ";") return cont(typeprops) + return pass(typeprop, typeprops) + } function typeprop(type, value) { if (type == "variable" || cx.style == "keyword") { cx.marked = "property" From 7faab336a4b644eb4d8ff34d2eb1d96d912f7fa7 Mon Sep 17 00:00:00 2001 From: Kim-Anh Tran Date: Fri, 18 Dec 2020 05:27:35 +0100 Subject: [PATCH 1510/1880] [wast mode] Update to reflect latest reference-types spec --- mode/wast/test.js | 25 ++++++++++++++++++++++--- mode/wast/wast.js | 4 ++-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/mode/wast/test.js b/mode/wast/test.js index 9998cfd965..3e5137c072 100644 --- a/mode/wast/test.js +++ b/mode/wast/test.js @@ -21,7 +21,8 @@ '[string "foo #\\"# bar"]'); MT('atom-test', - '[atom anyfunc]', + '[atom funcref]', + '[atom externref]', '[atom i32]', '[atom i64]', '[atom f32]', @@ -42,9 +43,11 @@ '[keyword br_table] [variable-2 $label0] [variable-2 $label1] [variable-2 $label3]', '[keyword return]', '[keyword call] [variable-2 $func0]', - '[keyword call_indirect] ([keyword param] [atom f32] [atom f64]) ([keyword result] [atom i32] [atom i64])', + '[keyword call_indirect] [variable-2 $table] ([keyword param] [atom f32] [atom f64]) ([keyword result] [atom i32] [atom i64])', '[keyword return_call] [variable-2 $func0]', - '[keyword return_call_indirect] ([keyword param] [atom f32] [atom f64]) ([keyword result] [atom i32] [atom i64])'); + '[keyword return_call_indirect] ([keyword param] [atom f32] [atom f64]) ([keyword result] [atom i32] [atom i64])', + '[keyword select] ([keyword local.get] [number 1]) ([keyword local.get] [number 2]) ([keyword local.get] [number 3])'); + MT('memory-instructions', '[keyword i32.load] [keyword offset]=[number 4] [keyword align]=[number 4]', @@ -318,4 +321,20 @@ '[keyword i32x4.trunc_sat_f32x4_u]', '[keyword f32x4.convert_i32x4_s]', '[keyword f32x4.convert_i32x4_u]'); + + MT('reference-type-instructions', + '[keyword ref.null] [keyword extern]', + '[keyword ref.null] [keyword func]', + '[keyword ref.is_null] ([keyword ref.func] [variable-2 $f])', + '[keyword ref.func] [variable-2 $f]'); + + MT('table-instructions', + '[keyword table.get] [variable-2 $t] ([keyword i32.const] [number 5])', + '[keyword table.set] [variable-2 $t] ([keyword i32.const] [number 5]) ([keyword ref.func] [variable-2 $f])', + '[keyword table.size] [variable-2 $t]', + '[keyword table.grow] [variable-2 $t] ([keyword ref.null] [keyword extern]) ([keyword i32.const] [number 5])', + '[keyword table.fill] [variable-2 $t] ([keyword i32.const] [number 5]) ([keyword param] [variable-2 $r] [atom externref]) ([keyword i32.const] [number 5])', + '[keyword table.init] [variable-2 $t] [number 1] ([keyword i32.const] [number 5]) ([keyword i32.const] [number 10]) ([keyword i32.const] [number 15])', + '[keyword table.copy] [variable-2 $t] [variable-2 $t2] ([keyword i32.const] [number 5]) ([keyword i32.const] [number 10]) ([keyword i32.const] [number 15])' + ); })(); diff --git a/mode/wast/wast.js b/mode/wast/wast.js index 9348ad3e0a..a730d39efc 100644 --- a/mode/wast/wast.js +++ b/mode/wast/wast.js @@ -14,8 +14,8 @@ CodeMirror.defineSimpleMode('wast', { start: [ {regex: /[+\-]?(?:nan(?::0x[0-9a-fA-F]+)?|infinity|inf|0x[0-9a-fA-F]+\.?[0-9a-fA-F]*p[+\/-]?\d+|\d+(?:\.\d*)?[eE][+\-]?\d*|\d+\.\d*|0x[0-9a-fA-F]+|\d+)/, token: "number"}, - {regex: /mut|nop|block|if|then|else|loop|br_if|br_table|br|call(_indirect)?|drop|end|return(_call(_indirect)?)?|local\.(get|set|tee)|global\.(get|set)|i(32|64)\.(store(8|16)|(load(8|16)_[su]))|i64\.(load32_[su]|store32)|[fi](32|64)\.(const|load|store)|f(32|64)\.(abs|add|ceil|copysign|div|eq|floor|[gl][et]|max|min|mul|nearest|neg?|sqrt|sub|trunc)|i(32|64)\.(a[dn]d|c[lt]z|(div|rem)_[su]|eqz?|[gl][te]_[su]|mul|ne|popcnt|rot[lr]|sh(l|r_[su])|sub|x?or)|i64\.extend_[su]_i32|i32\.wrap_i64|i(32|64)\.trunc_f(32|64)_[su]|f(32|64)\.convert_i(32|64)_[su]|f64\.promote_f32|f32\.demote_f64|f32\.reinterpret_i32|i32\.reinterpret_f32|f64\.reinterpret_i64|i64\.reinterpret_f64|select|unreachable|current_memory|memory(\.((atomic\.(notify|wait(32|64)))|grow|size))?|type|func|param|result|local|global|module|table|start|elem|data|align|offset|import|export|i64\.atomic\.(load32_u|store32|rmw32\.(a[dn]d|sub|x?or|(cmp)?xchg)_u)|i(32|64)\.atomic\.(load((8|16)_u)?|store(8|16)?|rmw(\.(a[dn]d|sub|x?or|(cmp)?xchg)|(8|16)\.(a[dn]d|sub|x?or|(cmp)?xchg)_u))|v128\.(load|store|const|not|andnot|and|or|xor|bitselect)|i(8x16|16x8|32x4|64x2)\.(shl|shr_[su])|i(8x16|16x8)\.(extract_lane_[su]|((add|sub)_saturate_[su])|avgr_u)|(i(8x16|16x8|32x4|64x2)|f(32x4|64x2))\.(splat|replace_lane|neg|add|sub)|i(8x16|16x8|32x4)\.(eq|ne|([lg][te]_[su])|abs|any_true|all_true|bitmask|((min|max)_[su]))|f(32x4|64x2)\.(eq|ne|[lg][te]|abs|sqrt|mul|div|min|max)|[fi](32x4|64x2)\.extract_lane|v8x16\.(shuffle|swizzle)|i16x8\.(load8x8_[su]|narrow_i32x4_[su]|widen_(low|high)_i8x16_[su]|mul)|i32x4\.(load16x4_[su]|widen_(low|high)_i16x8_[su]|mul|trunc_sat_f32x4_[su])|i64x2\.(load32x2_[su]|mul)|(v(8x16|16x8|32x4|64x2)\.load_splat)|i8x16\.narrow_i16x8_[su]|f32x4\.convert_i32x4_[su]/, token: "keyword"}, - {regex: /\b(anyfunc|[fi](32|64))\b/, token: "atom"}, + {regex: /mut|nop|block|if|then|else|loop|br_if|br_table|br|call(_indirect)?|drop|end|return(_call(_indirect)?)?|local\.(get|set|tee)|global\.(get|set)|i(32|64)\.(store(8|16)|(load(8|16)_[su]))|i64\.(load32_[su]|store32)|[fi](32|64)\.(const|load|store)|f(32|64)\.(abs|add|ceil|copysign|div|eq|floor|[gl][et]|max|min|mul|nearest|neg?|sqrt|sub|trunc)|i(32|64)\.(a[dn]d|c[lt]z|(div|rem)_[su]|eqz?|[gl][te]_[su]|mul|ne|popcnt|rot[lr]|sh(l|r_[su])|sub|x?or)|i64\.extend_[su]_i32|i32\.wrap_i64|i(32|64)\.trunc_f(32|64)_[su]|f(32|64)\.convert_i(32|64)_[su]|f64\.promote_f32|f32\.demote_f64|f32\.reinterpret_i32|i32\.reinterpret_f32|f64\.reinterpret_i64|i64\.reinterpret_f64|select|unreachable|current_memory|memory(\.((atomic\.(notify|wait(32|64)))|grow|size))?|type|\bfunc\b|param|result|local|global|module|start|elem|data|align|offset|import|export|i64\.atomic\.(load32_u|store32|rmw32\.(a[dn]d|sub|x?or|(cmp)?xchg)_u)|i(32|64)\.atomic\.(load((8|16)_u)?|store(8|16)?|rmw(\.(a[dn]d|sub|x?or|(cmp)?xchg)|(8|16)\.(a[dn]d|sub|x?or|(cmp)?xchg)_u))|v128\.(load|store|const|not|andnot|and|or|xor|bitselect)|i(8x16|16x8|32x4|64x2)\.(shl|shr_[su])|i(8x16|16x8)\.(extract_lane_[su]|((add|sub)_saturate_[su])|avgr_u)|(i(8x16|16x8|32x4|64x2)|f(32x4|64x2))\.(splat|replace_lane|neg|add|sub)|i(8x16|16x8|32x4)\.(eq|ne|([lg][te]_[su])|abs|any_true|all_true|bitmask|((min|max)_[su]))|f(32x4|64x2)\.(eq|ne|[lg][te]|abs|sqrt|mul|div|min|max)|[fi](32x4|64x2)\.extract_lane|v8x16\.(shuffle|swizzle)|i16x8\.(load8x8_[su]|narrow_i32x4_[su]|widen_(low|high)_i8x16_[su]|mul)|i32x4\.(load16x4_[su]|widen_(low|high)_i16x8_[su]|mul|trunc_sat_f32x4_[su])|i64x2\.(load32x2_[su]|mul)|(v(8x16|16x8|32x4|64x2)\.load_splat)|i8x16\.narrow_i16x8_[su]|f32x4\.convert_i32x4_[su]|ref\.(func|(is_)?null)|\bextern\b|table(\.(size|get|set|size|grow|fill|init|copy))?/, token: "keyword"}, + {regex: /\b(funcref|externref|[fi](32|64))\b/, token: "atom"}, {regex: /\$([a-zA-Z0-9_`\+\-\*\/\\\^~=<>!\?@#$%&|:\.]+)/, token: "variable-2"}, {regex: /"(?:[^"\\\x00-\x1f\x7f]|\\[nt\\'"]|\\[0-9a-fA-F][0-9a-fA-F])*"/, token: "string"}, {regex: /\(;.*?/, token: "comment", next: "comment"}, From abc65fe746384652c36c027ff73b95f17d262378 Mon Sep 17 00:00:00 2001 From: nathanlesage Date: Thu, 17 Dec 2020 09:15:10 +0100 Subject: [PATCH 1511/1880] Document singleCursorHeightPerLine option --- doc/manual.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/manual.html b/doc/manual.html index 89a6328e6d..ad5c275d50 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -512,6 +512,15 @@

    Configuration

    which causes the cursor to not reach all the way to the bottom of the line, looks better +
    singleCursorHeightPerLine: boolean
    +
    Determines if CodeMirror can expect all lines to be of the + same height (true, the default) and the cursor-size + can therefore be lazily evaluated. In case your editor contains + multiple line-sizes, for instance, if addLineClass + sets classes which contain line-height-rules, you + should consider setting this to false to prevent + visual artefacts. +
    resetSelectionOnContextMenu: boolean
    Controls whether, when the context menu is opened with a click outside of the current selection, the cursor is moved to From ee414661b9099e9c122f40b8408b841801f37ed9 Mon Sep 17 00:00:00 2001 From: Hendrik Erz Date: Sat, 19 Dec 2020 21:05:56 +0100 Subject: [PATCH 1512/1880] Update description of singleCursorHeightPerLine --- doc/manual.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index ad5c275d50..06ee3dbf18 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -513,13 +513,13 @@

    Configuration

    of the line, looks better
    singleCursorHeightPerLine: boolean
    -
    Determines if CodeMirror can expect all lines to be of the - same height (true, the default) and the cursor-size - can therefore be lazily evaluated. In case your editor contains - multiple line-sizes, for instance, if addLineClass - sets classes which contain line-height-rules, you - should consider setting this to false to prevent - visual artefacts. +
    If set to true (the default), CodeMirror will + calculate the cursor height from the adjacent characters or + text markers. If set to false, the cursor height + will be calculated based off the height of all bounding boxes + on the current (wrapped) line, keeping the height consistent. + This is visible especially if you use text markers that are + bigger than the font-size of the characters on the line.
    resetSelectionOnContextMenu: boolean
    Controls whether, when the context menu is opened with a From a90d0f8e992b6fa9232c8982a970305096a28164 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 20 Dec 2020 11:17:22 +0100 Subject: [PATCH 1513/1880] [manual] Correct documentation for singleCursorHeightPerLine Issue #6524 --- doc/manual.html | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 06ee3dbf18..1086507a91 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -513,13 +513,10 @@

    Configuration

    of the line, looks better
    singleCursorHeightPerLine: boolean
    -
    If set to true (the default), CodeMirror will - calculate the cursor height from the adjacent characters or - text markers. If set to false, the cursor height - will be calculated based off the height of all bounding boxes - on the current (wrapped) line, keeping the height consistent. - This is visible especially if you use text markers that are - bigger than the font-size of the characters on the line. +
    If set to true (the default), will keep the + cursor height constant for an entire line (or wrapped part of a + line). When false, the cursor's height is based on + the height of the adjacent reference character.
    resetSelectionOnContextMenu: boolean
    Controls whether, when the context menu is opened with a From e49f2950e9ca59f437db26a2b43e3cc478fc4761 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 20 Dec 2020 11:48:25 +0100 Subject: [PATCH 1514/1880] Mark release 5.59.0 --- AUTHORS | 10 ++++++++++ CHANGELOG.md | 18 ++++++++++++++++++ doc/manual.html | 2 +- doc/releases.html | 11 +++++++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 43 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 33d819ed24..95134fa2d5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -244,6 +244,7 @@ edoroshenko edsharp ekhaled Elisée +Elmar Peise elpnt Emmanuel Schanzer Enam Mijbah Noor @@ -363,6 +364,7 @@ Jacob Lee Jaimin Jake Peyser Jakob Miland +Jakub T. Jankiewicz Jakub Vrana Jakub Vrána James Campos @@ -466,6 +468,7 @@ Kevin Muret Kevin Sawicki Kevin Ushey Kier Darby +Kim-Anh Tran Klaus Silveira Koh Zi Han, Cliff komakino @@ -547,6 +550,7 @@ Mason Malone Mateusz Paprocki Mathias Bynens mats cronqvist +Matt Diehl Matt Gaide Matthew Bauer Matthew Beale @@ -604,6 +608,7 @@ Miraculix87 misfo mkaminsky11 mloginov +mlsad3 Moritz Schubotz (physikerwelt) Moritz Schwörer Moshe Wajnberg @@ -614,6 +619,7 @@ Mu-An ✌️ Chiou Mu-An Chiou mzabuawala Narciso Jaramillo +nathanlesage Nathan Williams ndr Neil Anderson @@ -692,6 +698,7 @@ Philip Stadermann Pi Delport Pierre Gerold Pieter Ouwerkerk +Piyush Pontus Melke prasanthj Prasanth J @@ -699,6 +706,7 @@ Prayag Verma prendota Prendota Qiang Li +quiddity-wp Radek Piórkowski Rahul Rahul Anand @@ -759,6 +767,7 @@ Scott Aikin Scott Feeney Scott Goodhew Seb35 +Sebastian Ślepowroński Sebastian Wilzbach Sebastian Zaha Seren D @@ -779,6 +788,7 @@ Siamak Mokhtari Siddhartha Gunti silverwind Simon Edwards +Simon Huber sinkuu snasa soliton4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b00dbd80e..9276146f78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## 5.59.0 (2020-12-20) + +### Bug fixes + +Fix platform detection on recent iPadOS. + +[lint addon](https://codemirror.net/doc/manual.html#addon_lint): Don't show duplicate messages for a given line. + +[clojure mode](https://codemirror.net/mode/clojure/index.html): Fix regexp that matched in exponential time for some inputs. + +[hardwrap addon](https://codemirror.net/doc/manual.html#addon_hardwrap): Improve handling of words that are longer than the line length. + +[matchbrackets addon](https://codemirror.net/doc/manual.html#addon_matchbrackets): Fix leaked event handler on disabling the addon. + +### New features + +[search addon](https://codemirror.net/demo/search/): Make it possible to configure the search addon to show the dialog at the bottom of the editor. + ## 5.58.3 (2020-11-19) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 1086507a91..b7ca9a6972 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

    User manual and reference guide - version 5.58.3 + version 5.59.0

    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 1b4f9a7976..18987f5ea2 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,17 @@

    Release notes and version history

    Version 5.x

    +

    20-12-2020: Version 5.59.0:

    + +
      +
    • Fix platform detection on recent iPadOS.
    • +
    • lint addon: Don't show duplicate messages for a given line.
    • +
    • clojure mode: Fix regexp that matched in exponential time for some inputs.
    • +
    • hardwrap addon: Improve handling of words that are longer than the line length.
    • +
    • matchbrackets addon: Fix leaked event handler on disabling the addon.
    • +
    • search addon: Make it possible to configure the search addon to show the dialog at the bottom of the editor.
    • +
    +

    19-11-2020: Version 5.58.3:

      diff --git a/index.html b/index.html index 7ea8c48961..849447a578 100644 --- a/index.html +++ b/index.html @@ -99,7 +99,7 @@

      This is CodeMirror

    - Get the current version: 5.58.3.
    + Get the current version: 5.59.0.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index a768858ec8..321a46c1d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.58.3", + "version": "5.59.0", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index d51192c6e5..6550214906 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.58.3" +CodeMirror.version = "5.59.0" From ffa872e4d5a7b01cc148099322ef376bd6ada5a3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Dec 2020 08:57:43 +0100 Subject: [PATCH 1515/1880] [closebrackets addon] Fix left-to-right assumption Closes #6527 --- addon/edit/closebrackets.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 4415c39381..f2239fdd12 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -87,7 +87,7 @@ cm.operation(function() { var linesep = cm.lineSeparator() || "\n"; cm.replaceSelection(linesep + linesep, null); - cm.execCommand("goCharLeft"); + moveSel(cm, -1) ranges = cm.listSelections(); for (var i = 0; i < ranges.length; i++) { var line = ranges[i].head.line; @@ -97,6 +97,17 @@ }); } + function moveSel(cm, dir) { + let newRanges = [], ranges = cm.listSelections(), primary = 0 + for (let i = 0; i < ranges.length; i++) { + let range = ranges[i] + if (range.head == cm.getCursor()) primary = i + let pos = {line: range.head.line, ch: range.head.ch + dir} + newRanges.push({anchor: pos, head: pos}) + } + cm.setSelections(newRanges, primary) + } + function contractSelection(sel) { var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0; return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)), @@ -153,10 +164,9 @@ var right = pos % 2 ? ch : pairs.charAt(pos + 1); cm.operation(function() { if (type == "skip") { - cm.execCommand("goCharRight"); + moveSel(cm, 1) } else if (type == "skipThree") { - for (var i = 0; i < 3; i++) - cm.execCommand("goCharRight"); + moveSel(cm, 3) } else if (type == "surround") { var sels = cm.getSelections(); for (var i = 0; i < sels.length; i++) @@ -169,10 +179,10 @@ } else if (type == "both") { cm.replaceSelection(left + right, null); cm.triggerElectric(left + right); - cm.execCommand("goCharLeft"); + moveSel(cm, -1) } else if (type == "addFour") { cm.replaceSelection(left + left + left + left, "before"); - cm.execCommand("goCharRight"); + moveSel(cm, 1) } }); } From ff70b4e2d1139b052064ec73e4d1ad86cf56d36c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20dBruxelles?= <18559798+jdbruxelles@users.noreply.github.com> Date: Mon, 21 Dec 2020 08:58:32 +0100 Subject: [PATCH 1516/1880] [release notes] Fix the search addon page link Simply add the .html extension to the link. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9276146f78..c1ffa87816 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ Fix platform detection on recent iPadOS. ### New features -[search addon](https://codemirror.net/demo/search/): Make it possible to configure the search addon to show the dialog at the bottom of the editor. +[search addon](https://codemirror.net/demo/search.html): Make it possible to configure the search addon to show the dialog at the bottom of the editor. ## 5.58.3 (2020-11-19) From 885daa14aad5dd35a537cdadea7e01300374aeea Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Mon, 21 Dec 2020 00:04:40 -0800 Subject: [PATCH 1517/1880] Defined the webmanifest MIME (#6529) --- mode/javascript/javascript.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 188dbf217c..cfcd6cb6ed 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -930,9 +930,10 @@ CodeMirror.defineMIME("text/ecmascript", "javascript"); CodeMirror.defineMIME("application/javascript", "javascript"); CodeMirror.defineMIME("application/x-javascript", "javascript"); CodeMirror.defineMIME("application/ecmascript", "javascript"); -CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); -CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true}); -CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true}); +CodeMirror.defineMIME("application/json", { name: "javascript", json: true }); +CodeMirror.defineMIME("application/x-json", { name: "javascript", json: true }); +CodeMirror.defineMIME("application/manifest+json", { name: "javascript", json: true }) +CodeMirror.defineMIME("application/ld+json", { name: "javascript", jsonld: true }); CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); From c58ccada2ddfb064149237cb7f59ce73176b376a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Dec 2020 09:07:47 +0100 Subject: [PATCH 1518/1880] Fix ES6 use in addon --- addon/edit/closebrackets.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index f2239fdd12..19a3c53c1f 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -98,11 +98,11 @@ } function moveSel(cm, dir) { - let newRanges = [], ranges = cm.listSelections(), primary = 0 + var newRanges = [], ranges = cm.listSelections(), primary = 0 for (let i = 0; i < ranges.length; i++) { - let range = ranges[i] + var range = ranges[i] if (range.head == cm.getCursor()) primary = i - let pos = {line: range.head.line, ch: range.head.ch + dir} + var pos = {line: range.head.line, ch: range.head.ch + dir} newRanges.push({anchor: pos, head: pos}) } cm.setSelections(newRanges, primary) From f18854ef817b831419b5b3353197b403b7a9b8b8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Dec 2020 12:44:06 +0100 Subject: [PATCH 1519/1880] Remove another let in an addon --- addon/edit/closebrackets.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 19a3c53c1f..5c1aeab3c5 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -99,7 +99,7 @@ function moveSel(cm, dir) { var newRanges = [], ranges = cm.listSelections(), primary = 0 - for (let i = 0; i < ranges.length; i++) { + for (var i = 0; i < ranges.length; i++) { var range = ranges[i] if (range.head == cm.getCursor()) primary = i var pos = {line: range.head.line, ch: range.head.ch + dir} From c88d09d0ca8b6c2f88b4432094d72e4be757b4a3 Mon Sep 17 00:00:00 2001 From: Masahiro MATAYOSHI Date: Tue, 22 Dec 2020 16:52:16 +0900 Subject: [PATCH 1520/1880] [perl mode] Don't treat <<1 as here document start --- mode/perl/perl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/perl/perl.js b/mode/perl/perl.js index a3101a7c5b..f620b41e27 100644 --- a/mode/perl/perl.js +++ b/mode/perl/perl.js @@ -516,7 +516,7 @@ CodeMirror.defineMode("perl",function(){ if(stream.match(/^\-?[\d\.]/,false)) if(stream.match(/^(\-?(\d*\.\d+(e[+-]?\d+)?|\d+\.\d*)|0x[\da-fA-F]+|0b[01]+|\d+(e[+-]?\d+)?)/)) return 'number'; - if(stream.match(/^<<(?=\w)/)){ // NOTE: < Date: Wed, 23 Dec 2020 08:22:14 +0100 Subject: [PATCH 1521/1880] Try to refine iPadOS/iOS detection Issue #6532 --- src/util/browser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/browser.js b/src/util/browser.js index 6e3022e765..ae9d6af706 100644 --- a/src/util/browser.js +++ b/src/util/browser.js @@ -17,7 +17,7 @@ export let safari = /Apple Computer/.test(navigator.vendor) export let mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent) export let phantom = /PhantomJS/.test(userAgent) -export let ios = !edge && /AppleWebKit/.test(userAgent) && (/Mobile\/\w+/.test(userAgent) || navigator.maxTouchPoints > 2) +export let ios = safari && (/Mobile\/\w+/.test(userAgent) || navigator.maxTouchPoints > 2) export let android = /Android/.test(userAgent) // This is woefully incomplete. Suggestions for alternative methods welcome. export let mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent) From d8d78f5e7aa07e682bf51ad94a75ba6bb2484794 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 23 Dec 2020 08:29:43 +0100 Subject: [PATCH 1522/1880] [panel addon] Preserve scroll post when initializing/removing panel wrapper Closes #6533 --- addon/display/panel.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/addon/display/panel.js b/addon/display/panel.js index 4c9f2c0fca..29f7e0bebb 100644 --- a/addon/display/panel.js +++ b/addon/display/panel.js @@ -76,7 +76,7 @@ }; function initPanels(cm) { - var wrap = cm.getWrapperElement(); + var wrap = cm.getWrapperElement() var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle; var height = parseInt(style.height); var info = cm.state.panels = { @@ -84,9 +84,10 @@ panels: [], wrapper: document.createElement("div") }; + var hasFocus = cm.hasFocus(), scrollPos = cm.getScrollInfo() wrap.parentNode.insertBefore(info.wrapper, wrap); - var hasFocus = cm.hasFocus(); info.wrapper.appendChild(wrap); + cm.scrollTo(scrollPos.left, scrollPos.top) if (hasFocus) cm.focus(); cm._setSize = cm.setSize; @@ -114,8 +115,11 @@ var info = cm.state.panels; cm.state.panels = null; - var wrap = cm.getWrapperElement(); + var wrap = cm.getWrapperElement() + var hasFocus = cm.hasFocus(), scrollPos = cm.getScrollInfo() info.wrapper.parentNode.replaceChild(wrap, info.wrapper); + cm.scrollTo(scrollPos.left, scrollPos.top) + if (hasFocus) cm.focus(); wrap.style.height = info.setHeight; cm.setSize = cm._setSize; cm.setSize(); From 3ce2ef56989085002e6ac4078b0f580ab5fcc4ad Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 23 Dec 2020 16:46:53 +0100 Subject: [PATCH 1523/1880] [perl mode] Don't include brackets in variable names Closes #6534 --- mode/perl/perl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/perl/perl.js b/mode/perl/perl.js index f620b41e27..220b0a6994 100644 --- a/mode/perl/perl.js +++ b/mode/perl/perl.js @@ -697,7 +697,7 @@ CodeMirror.defineMode("perl",function(){ return "variable-2";} stream.pos=p;} if(/[$@%&]/.test(ch)){ - if(stream.eatWhile(/[\w$\[\]]/)||stream.eat("{")&&stream.eatWhile(/[\w$\[\]]/)&&stream.eat("}")){ + if(stream.eatWhile(/[\w$]/)||stream.eat("{")&&stream.eatWhile(/[\w$]/)&&stream.eat("}")){ var c=stream.current(); if(PERL[c]) return "variable-2"; From d4a1a1a5d8648508c314ffb20fc700333f9ab5de Mon Sep 17 00:00:00 2001 From: "Dinindu D. Wanniarachchi" Date: Sat, 26 Dec 2020 19:15:17 +0530 Subject: [PATCH 1524/1880] [real-world uses] Changed SASS2CSS url --- doc/realworld.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/realworld.html b/doc/realworld.html index c6e6c80323..487208b286 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -157,7 +157,7 @@

    CodeMirror real-world uses

  • RealTime.io (Internet-of-Things infrastructure)
  • Refork (animation demo gallery and sharing)
  • SageMathCell (interactive mathematical software)
  • -
  • SASS2CSS (SASS, SCSS or LESS to CSS converter and CSS beautifier)
  • +
  • SASS2CSS (SASS, SCSS or LESS to CSS converter and CSS beautifier)
  • SageMathCloud (interactive mathematical software environment)
  • salvare (real-time collaborative code editor)
  • ServePHP (PHP code testing in Chrome dev tools)
  • From 90e1c26104b2b98aa803b2b98d917b19a32c8720 Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Tue, 29 Dec 2020 00:05:24 -0800 Subject: [PATCH 1525/1880] [javascript mode] Mention more MIME types in demo page --- mode/javascript/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/javascript/index.html b/mode/javascript/index.html index d1f7f68e8a..3023835727 100644 --- a/mode/javascript/index.html +++ b/mode/javascript/index.html @@ -110,5 +110,5 @@

    JavaScript mode

    -

    MIME types defined: text/javascript, application/json, application/ld+json, text/typescript, application/typescript.

    +

    MIME types defined: text/javascript, application/javascript, application/x-javascript, text/ecmascript, application/ecmascript, application/json, application/x-json, application/manifest+json, application/ld+json, text/typescript, application/typescript.

    From d2728850abe64849ddd2730dc22536ef1361a90a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 29 Dec 2020 09:04:32 +0100 Subject: [PATCH 1526/1880] [javascript mode] Fix infinite loop on some invalid syntax Closes #6542 --- mode/javascript/javascript.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index cfcd6cb6ed..8191c4d925 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -640,6 +640,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return cont(expect("variable"), maybetypeOrIn, expect("]"), typeprop) } else if (type == "(") { return pass(functiondecl, typeprop) + } else { + return cont() } } function typearg(type, value) { From 4d5da83c1493cf5dec219ecb637adc69e468ea5d Mon Sep 17 00:00:00 2001 From: Yash-Singh1 Date: Mon, 28 Dec 2020 11:28:36 -0800 Subject: [PATCH 1527/1880] Prefer dot syntax in test --- test/test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test.js b/test/test.js index 2a5101f4e1..07fa67858f 100644 --- a/test/test.js +++ b/test/test.js @@ -1807,8 +1807,8 @@ testCM("atomicMarker", function(cm) { inclusiveRight: ri }; - if (ls === true || ls === false) options["selectLeft"] = ls; - if (rs === true || rs === false) options["selectRight"] = rs; + if (ls === true || ls === false) options.selectLeft = ls; + if (rs === true || rs === false) options.selectRight = rs; return cm.markText(Pos(ll, cl), Pos(lr, cr), options); } From 863c18904febf364876494ee650ced49c3b08bd9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 29 Dec 2020 09:27:13 +0100 Subject: [PATCH 1528/1880] [javascript mode] Make sure type props don't consume closing braces --- mode/javascript/javascript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 8191c4d925..966ffef063 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -640,7 +640,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return cont(expect("variable"), maybetypeOrIn, expect("]"), typeprop) } else if (type == "(") { return pass(functiondecl, typeprop) - } else { + } else if (!type.match(/[;\}\)\],]/)) { return cont() } } From 37d7b2efceb192c94811a13b2b7b3eec4b786608 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 29 Dec 2020 18:10:02 +0100 Subject: [PATCH 1529/1880] Fix moving backwards across astral chars Closes #6544 --- src/edit/methods.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/edit/methods.js b/src/edit/methods.js index a5e2afc39f..eb8f8d28dc 100644 --- a/src/edit/methods.js +++ b/src/edit/methods.js @@ -480,9 +480,12 @@ function findPosH(doc, pos, dir, unit, visually) { let next if (unit == "codepoint") { let ch = lineObj.text.charCodeAt(pos.ch + (unit > 0 ? 0 : -1)) - if (isNaN(ch)) next = null - else next = new Pos(pos.line, Math.max(0, Math.min(lineObj.text.length, pos.ch + dir * (ch >= 0xD800 && ch < 0xDC00 ? 2 : 1))), - -dir) + if (isNaN(ch)) { + next = null + } else { + let astral = dir > 0 ? ch >= 0xD800 && ch < 0xDC00 : ch >= 0xDC00 && ch < 0xDFFF + next = new Pos(pos.line, Math.max(0, Math.min(lineObj.text.length, pos.ch + dir * (astral ? 2 : 1))), -dir) + } } else if (visually) { next = moveVisually(doc.cm, lineObj, pos, dir) } else { From 5e25c3ce3026d7be3e98b8653f1aa171333d43ca Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 30 Dec 2020 09:21:06 +0100 Subject: [PATCH 1530/1880] [sponsors] Add Execute Program logo --- index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/index.html b/index.html index 849447a578..9631b88366 100644 --- a/index.html +++ b/index.html @@ -203,6 +203,7 @@

    Sponsors

  • CodePen
  • JetBrains
  • desmos
  • +
  • Execute Program
  • From 1698f003a5cfabfbabad106c69cd214ec4ed996a Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Thu, 31 Dec 2020 02:09:33 -0800 Subject: [PATCH 1531/1880] [manual] Add link to demo for jump-to-line Closes #6539 --- doc/manual.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index b7ca9a6972..00472c5236 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2405,7 +2405,7 @@

    Addons

    Accepts linenumber, +/-linenumber, line:char, scroll% and :linenumber formats. This will make use of openDialog - when available to make prompting for line number neater. + when available to make prompting for line number neater. Demo avaliable here.
    search/matchesonscrollbar.js
    Adds a showMatchesOnScrollbar method to editor From bd37a96d362b8d92895d3960d569168ec39e4165 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 31 Dec 2020 13:02:29 +0100 Subject: [PATCH 1532/1880] Mark version 5.59.1 --- AUTHORS | 4 ++++ CHANGELOG.md | 6 ++++++ doc/manual.html | 2 +- doc/releases.html | 6 ++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 20 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 95134fa2d5..4ea87576d3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -432,6 +432,7 @@ Jon Malmaud Jon Sangster Joo Joost-Wim Boekesteijn +José dBruxelles Joseph Pecoraro Josh Barnes Josh Cohen @@ -546,6 +547,7 @@ Martin Hasoň Martin Hunt Martin Laine Martin Zagora +Masahiro MATAYOSHI Mason Malone Mateusz Paprocki Mathias Bynens @@ -894,6 +896,8 @@ wonderboyjon Wu Cheng-Han Xavier Mendez Yang Guo +Yash Singh +Yash-Singh1 Yassin N. Hassan YNH Webdev yoongu diff --git a/CHANGELOG.md b/CHANGELOG.md index c1ffa87816..5a9baf4df1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 5.59.1 (2020-12-31) + +### Bug fixes + +Fix an issue where some Chrome browsers were detected as iOS. + ## 5.59.0 (2020-12-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 00472c5236..285d420d9a 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

    User manual and reference guide - version 5.59.0 + version 5.59.1

    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 18987f5ea2..f6628b6548 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -30,6 +30,12 @@

    Release notes and version history

    Version 5.x

    +

    31-12-2020: Version 5.59.1:

    + +
      +
    • Fix an issue where some Chrome browsers were detected as iOS.
    • +
    +

    20-12-2020: Version 5.59.0:

      diff --git a/index.html b/index.html index 9631b88366..a89b1de5d3 100644 --- a/index.html +++ b/index.html @@ -99,7 +99,7 @@

      This is CodeMirror

    - Get the current version: 5.59.0.
    + Get the current version: 5.59.1.
    You can see the code,
    read the release notes,
    or study the user manual. diff --git a/package.json b/package.json index 321a46c1d6..7ab19be203 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.59.0", + "version": "5.59.1", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 6550214906..cb8c8cac5b 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.59.0" +CodeMirror.version = "5.59.1" From 9749ba3ce08154510e631217e21532987415d9b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Wielgus?= <61328879+encap@users.noreply.github.com> Date: Sun, 3 Jan 2021 19:58:51 +0100 Subject: [PATCH 1533/1880] [real world uses] Add coderush.xyz (typing speed test) Uses CodeMirror with dynamic mode switching --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 487208b286..698b0c3a80 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -58,6 +58,7 @@

    CodeMirror real-world uses

  • Codepen (gallery of animations)
  • Coderba Google Web Toolkit (GWT) wrapper
  • Coderpad (interviewing tool)
  • +
  • CodeRush typing speed test for programmers
  • Code School (online tech learning environment)
  • Code Snippets (WordPress snippet management plugin)
  • Code together (collaborative editing)
  • From c8059735fc9ef79a1b8176d776cb81a03771a28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Wielgus?= <61328879+encap@users.noreply.github.com> Date: Sun, 3 Jan 2021 20:11:00 +0100 Subject: [PATCH 1534/1880] [real world uses] Update "clone-it" url Previous url (clone-it.github.io) returns 404 because I changed github account. --- doc/realworld.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/realworld.html b/doc/realworld.html index 698b0c3a80..a7402551f7 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -41,7 +41,7 @@

    CodeMirror real-world uses

  • Cargo Collective (creative publishing platform)
  • Chrome DevTools
  • ClickHelp (technical writing tool)
  • -
  • Clone-It (HTML & CSS learning game)
  • +
  • Clone-It (HTML & CSS learning game)
  • Colon (A flexible text editor or IDE)
  • CodeWorld (Haskell playground)
  • Complete.ly playground
  • From a46e33049de2c6f4550b77cad743d293039f2e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20=C5=9Alepowro=C5=84ski?= <45392875+slepowronski@users.noreply.github.com> Date: Mon, 4 Jan 2021 13:28:25 +0100 Subject: [PATCH 1535/1880] [show-hint addon] Changed closeOnCursorActivity to updateOnCursorActivity --- addon/hint/show-hint.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 5ef1bba645..a9f2ded18c 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -61,8 +61,10 @@ this.startPos = this.cm.getCursor("start"); this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length; - var self = this; - cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); }); + if (this.options.updateOnCursorActivity) { + var self = this; + cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); }); + } } var requestAnimationFrame = window.requestAnimationFrame || function(fn) { @@ -75,7 +77,9 @@ if (!this.active()) return; this.cm.state.completionActive = null; this.tick = null; - this.cm.off("cursorActivity", this.activityFunc); + if (this.options.updateOnCursorActivity) { + this.cm.off("cursorActivity", this.activityFunc); + } if (this.widget && this.data) CodeMirror.signal(this.data, "close"); if (this.widget) this.widget.close(); @@ -117,9 +121,7 @@ if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || pos.ch < identStart.ch || this.cm.somethingSelected() || (!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { - if (this.options.closeOnCursorActivity) { - this.close(); - } + this.close(); } else { var self = this; this.debounce = requestAnimationFrame(function() {self.update();}); @@ -492,9 +494,9 @@ completeSingle: true, alignWithWord: true, closeCharacters: /[\s()\[\]{};:>,]/, - closeOnCursorActivity: true, closeOnPick: true, closeOnUnfocus: true, + updateOnCursorActivity: true, completeOnSingleClick: true, container: null, customKeys: null, From 36c786bcca35c0650e78ab65ac8afb9d71abb89c Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Tue, 5 Jan 2021 02:42:31 -0800 Subject: [PATCH 1536/1880] [closetag demo] Add description --- demo/closetag.html | 1 + 1 file changed, 1 insertion(+) diff --git a/demo/closetag.html b/demo/closetag.html index 4f857fa4bb..1f86114a9f 100644 --- a/demo/closetag.html +++ b/demo/closetag.html @@ -38,4 +38,5 @@

    Close-Tag Demo

    autoCloseTags: true }); +

    Uses the closetag addon to auto-close tags.

    From d19a746e51e041dd9aa1c9b79386b29cb1bcb3f1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Jan 2021 18:23:19 +0100 Subject: [PATCH 1537/1880] Fix bug in findPosH Closes #6554 --- src/edit/methods.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edit/methods.js b/src/edit/methods.js index eb8f8d28dc..c33a859865 100644 --- a/src/edit/methods.js +++ b/src/edit/methods.js @@ -479,7 +479,7 @@ function findPosH(doc, pos, dir, unit, visually) { function moveOnce(boundToLine) { let next if (unit == "codepoint") { - let ch = lineObj.text.charCodeAt(pos.ch + (unit > 0 ? 0 : -1)) + let ch = lineObj.text.charCodeAt(pos.ch + (dir > 0 ? 0 : -1)) if (isNaN(ch)) { next = null } else { From 498e7c0c0a762c2ad5b8bc8b455ef1f12db1e5bd Mon Sep 17 00:00:00 2001 From: Josh Soref Date: Fri, 8 Jan 2021 08:32:22 -0500 Subject: [PATCH 1538/1880] Fix various spelling mistakes * spelling: across Signed-off-by: Josh Soref * spelling: advise Signed-off-by: Josh Soref * spelling: aframework Signed-off-by: Josh Soref * spelling: after Signed-off-by: Josh Soref * spelling: alphanumeric Signed-off-by: Josh Soref * spelling: anyway Signed-off-by: Josh Soref * spelling: async Signed-off-by: Josh Soref * spelling: available Signed-off-by: Josh Soref * spelling: backticks Signed-off-by: Josh Soref * spelling: behavior Signed-off-by: Josh Soref * spelling: bracket Signed-off-by: Josh Soref * spelling: cacheable Signed-off-by: Josh Soref * spelling: characters Signed-off-by: Josh Soref * spelling: completeable Signed-off-by: Josh Soref * spelling: data Signed-off-by: Josh Soref * spelling: definition Signed-off-by: Josh Soref * spelling: different Signed-off-by: Josh Soref * spelling: do not Signed-off-by: Josh Soref * spelling: duplicate Signed-off-by: Josh Soref * spelling: e.g. Signed-off-by: Josh Soref * spelling: entities Signed-off-by: Josh Soref * spelling: expression-in Signed-off-by: Josh Soref * spelling: extract Signed-off-by: Josh Soref * spelling: feedback Signed-off-by: Josh Soref * spelling: filesystem Signed-off-by: Josh Soref * spelling: function Signed-off-by: Josh Soref * spelling: github Signed-off-by: Josh Soref * spelling: height Signed-off-by: Josh Soref * spelling: highlighted Signed-off-by: Josh Soref * spelling: i'm Signed-off-by: Josh Soref * spelling: identifier Signed-off-by: Josh Soref * spelling: immediately Signed-off-by: Josh Soref * spelling: in case Signed-off-by: Josh Soref * spelling: indentation Signed-off-by: Josh Soref * spelling: independent Signed-off-by: Josh Soref * spelling: initial Signed-off-by: Josh Soref * spelling: interchangeable Signed-off-by: Josh Soref * spelling: interruptible Signed-off-by: Josh Soref * spelling: interviews Signed-off-by: Josh Soref * spelling: intrinsic Signed-off-by: Josh Soref * spelling: javascript Signed-off-by: Josh Soref * spelling: label Signed-off-by: Josh Soref * spelling: matching Signed-off-by: Josh Soref * spelling: misbehavior Signed-off-by: Josh Soref * spelling: number Signed-off-by: Josh Soref * spelling: numbered Signed-off-by: Josh Soref * spelling: occurrences Signed-off-by: Josh Soref * spelling: repeatedly Signed-off-by: Josh Soref * spelling: separator Signed-off-by: Josh Soref * spelling: string Signed-off-by: Josh Soref * spelling: styleable Signed-off-by: Josh Soref * spelling: textarea Signed-off-by: Josh Soref * spelling: texture Signed-off-by: Josh Soref * spelling: useful Signed-off-by: Josh Soref * spelling: whenever Signed-off-by: Josh Soref * spelling: wikipedia Signed-off-by: Josh Soref --- CHANGELOG.md | 14 +++++++------- addon/edit/continuelist.js | 2 +- addon/edit/matchbrackets.js | 2 +- addon/hint/javascript-hint.js | 2 +- addon/hint/sql-hint.js | 4 ++-- addon/search/match-highlighter.js | 2 +- demo/complete.html | 4 ++-- demo/matchhighlighter.html | 2 +- demo/simplemode.html | 2 +- doc/internals.html | 2 +- doc/manual.html | 8 ++++---- doc/realworld.html | 4 ++-- doc/releases.html | 14 +++++++------- doc/upgrade_v2.2.html | 2 +- index.html | 2 +- keymap/vim.js | 6 +++--- mode/asn.1/asn.1.js | 2 +- mode/clike/clike.js | 2 +- mode/clike/index.html | 2 +- mode/dtd/dtd.js | 2 +- mode/factor/factor.js | 2 +- mode/factor/index.html | 2 +- mode/fcl/index.html | 10 +++++----- mode/forth/index.html | 2 +- mode/gas/gas.js | 4 ++-- mode/gfm/test.js | 2 +- mode/haml/haml.js | 2 +- mode/htmlembedded/index.html | 2 +- mode/idl/idl.js | 2 +- mode/javascript/test.js | 2 +- mode/markdown/index.html | 10 +++++----- mode/markdown/markdown.js | 2 +- mode/markdown/test.js | 4 ++-- mode/meta.js | 2 +- mode/modelica/modelica.js | 6 +++--- mode/mumps/mumps.js | 2 +- mode/nginx/index.html | 4 ++-- mode/ntriples/index.html | 2 +- mode/oz/oz.js | 2 +- mode/perl/perl.js | 4 ++-- mode/python/index.html | 2 +- mode/python/test.js | 2 +- mode/rpm/rpm.js | 4 ++-- mode/ruby/index.html | 2 +- mode/scheme/scheme.js | 2 +- mode/sieve/sieve.js | 2 +- mode/sql/sql.js | 4 ++-- mode/vbscript/vbscript.js | 4 ++-- mode/velocity/velocity.js | 2 +- mode/verilog/verilog.js | 4 ++-- mode/vue/index.html | 2 +- mode/yaml/yaml.js | 4 ++-- 52 files changed, 91 insertions(+), 91 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a9baf4df1..3a3ee68cef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -234,7 +234,7 @@ Make Shift-Delete to cut work on Firefox. [handlebars mode](https://codemirror.net/mode/handlebars/): Fix triple-brace support. -[searchcursor addon](https://codemirror.net/doc/manual.html#addon_searchcursor): Support mathing `$` in reverse regexp search. +[searchcursor addon](https://codemirror.net/doc/manual.html#addon_searchcursor): Support matching `$` in reverse regexp search. [panel addon](https://codemirror.net/doc/manual.html#addon_panel): Don't get confused by changing panel sizes. @@ -490,7 +490,7 @@ Add `hintWords` (basic completion) helper to [clojure](https://codemirror.net/mo [panel addon](https://codemirror.net/doc/manual.html#addon_panel): Fix problem where replacing the last remaining panel dropped the newly added panel. -[hardwrap addon](https://codemirror.net/doc/manual.html#addon_hardwrap): Fix an infinite loop when the indention is greater than the target column. +[hardwrap addon](https://codemirror.net/doc/manual.html#addon_hardwrap): Fix an infinite loop when the indentation is greater than the target column. [jinja2](https://codemirror.net/mode/jinja2/) and [markdown](https://codemirror.net/mode/markdown/) modes: Add comment metadata. @@ -878,7 +878,7 @@ Add `role=presentation` to more DOM elements to improve screen reader support. [merge addon](https://codemirror.net/doc/manual.html#addon_merge): Make aligning of unchanged chunks more robust. -[comment addon](https://codemirror.net/doc/manual.html#addon_comment): Fix comment-toggling on a block of text that starts and ends in a (differnet) block comment. +[comment addon](https://codemirror.net/doc/manual.html#addon_comment): Fix comment-toggling on a block of text that starts and ends in a (different) block comment. [javascript mode](https://codemirror.net/mode/javascript/): Improve support for TypeScript syntax. @@ -996,7 +996,7 @@ New event: [`optionChange`](https://codemirror.net/doc/manual.html#event_optionC Tapping/clicking the editor in [contentEditable mode](https://codemirror.net/doc/manual.html#option_inputStyle) on Chrome now puts the cursor at the tapped position. -Fix various crashes and misbehaviors when reading composition events in [contentEditable mode](https://codemirror.net/doc/manual.html#option_inputStyle). +Fix various crashes and misbehavior when reading composition events in [contentEditable mode](https://codemirror.net/doc/manual.html#option_inputStyle). Catches and ignores an IE 'Unspecified Error' when creating an editor in an iframe before there is a ``. @@ -1331,7 +1331,7 @@ Fix a [bug](https://github.com/codemirror/CodeMirror/issues/3834) that caused ph * New modes: [Vue](https://codemirror.net/mode/vue/index.html), [Oz](https://codemirror.net/mode/oz/index.html), [MscGen](https://codemirror.net/mode/mscgen/index.html) (and dialects), [Closure Stylesheets](https://codemirror.net/mode/css/gss.html) * Implement [CommonMark](http://commonmark.org)-style flexible list indent and cross-line code spans in [Markdown](https://codemirror.net/mode/markdown/index.html) mode * Add a replace-all button to the [search addon](https://codemirror.net/doc/manual.html#addon_search), and make the persistent search dialog transparent when it obscures the match -* Handle `acync`/`await` and ocal and binary numbers in [JavaScript mode](https://codemirror.net/mode/javascript/index.html) +* Handle `async`/`await` and ocal and binary numbers in [JavaScript mode](https://codemirror.net/mode/javascript/index.html) * Fix various issues with the [Haxe mode](https://codemirror.net/mode/haxe/index.html) * Make the [closebrackets addon](https://codemirror.net/doc/manual.html#addon_closebrackets) select only the wrapped text when wrapping selection in brackets * Tokenize properties as properties in the [CoffeeScript mode](https://codemirror.net/mode/coffeescript/index.html) @@ -1818,7 +1818,7 @@ Emergency fix for a bug where an editor with line wrapping on IE will break when * Slightly incompatible API changes. Read [this](https://codemirror.net/doc/upgrade_v2.2.html). * New approach to [binding](https://codemirror.net/doc/manual.html#option_extraKeys) keys, support for [custom bindings](https://codemirror.net/doc/manual.html#option_keyMap). * Support for overwrite (insert). -* [Custom-width](https://codemirror.net/doc/manual.html#option_tabSize) and [stylable](https://codemirror.net/demo/visibletabs.html) tabs. +* [Custom-width](https://codemirror.net/doc/manual.html#option_tabSize) and [styleable](https://codemirror.net/demo/visibletabs.html) tabs. * Moved more code into [add-on scripts](https://codemirror.net/doc/manual.html#addons). * Support for sane vertical cursor movement in wrapped lines. * More reliable handling of editing [marked text](https://codemirror.net/doc/manual.html#markText). @@ -1832,7 +1832,7 @@ Fixes `TextMarker.clear`, which is broken in 2.17. ## 2.17.0 (2011-11-21) * Add support for [line wrapping](https://codemirror.net/doc/manual.html#option_lineWrapping) and [code folding](https://codemirror.net/doc/manual.html#hideLine). -* Add [Github-style Markdown](https://codemirror.net/mode/gfm/index.html) mode. +* Add [GitHub-style Markdown](https://codemirror.net/mode/gfm/index.html) mode. * Add [Monokai](https://codemirror.net/theme/monokai.css) and [Rubyblue](https://codemirror.net/theme/rubyblue.css) themes. * Add [`setBookmark`](https://codemirror.net/doc/manual.html#setBookmark) method. * Move some of the demo code into reusable components under [`lib/util`](https://codemirror.net/addon/). diff --git a/addon/edit/continuelist.js b/addon/edit/continuelist.js index 2e5625adc4..6ec65010d2 100644 --- a/addon/edit/continuelist.js +++ b/addon/edit/continuelist.js @@ -90,7 +90,7 @@ }); } else { if (startIndent.length > nextIndent.length) return; - // This doesn't run if the next line immediatley indents, as it is + // This doesn't run if the next line immediately indents, as it is // not clear of the users intention (new indented item or same level) if ((startIndent.length < nextIndent.length) && (lookAhead === 1)) return; skipCount += 1; diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js index 0377408802..692e09e0cc 100644 --- a/addon/edit/matchbrackets.js +++ b/addon/edit/matchbrackets.js @@ -94,7 +94,7 @@ if (marks.length) { // Kludge to work around the IE bug from issue #1193, where text - // input stops going to the textare whever this fires. + // input stops going to the textarea whenever this fires. if (ie_lt8 && cm.state.focused) cm.focus(); var clear = function() { diff --git a/addon/hint/javascript-hint.js b/addon/hint/javascript-hint.js index 6d09e6b44e..9f06b1b546 100644 --- a/addon/hint/javascript-hint.js +++ b/addon/hint/javascript-hint.js @@ -69,7 +69,7 @@ function getCoffeeScriptToken(editor, cur) { // This getToken, it is for coffeescript, imitates the behavior of // getTokenAt method in javascript.js, that is, returning "property" - // type and treat "." as indepenent token. + // type and treat "." as independent token. var token = editor.getTokenAt(cur); if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { token.end = token.start; diff --git a/addon/hint/sql-hint.js b/addon/hint/sql-hint.js index 5b65e29105..efdce813cf 100644 --- a/addon/hint/sql-hint.js +++ b/addon/hint/sql-hint.js @@ -97,7 +97,7 @@ if (name.charAt(0) == ".") { name = name.substr(1); } - // replace doublicated identifierQuotes with single identifierQuotes + // replace duplicated identifierQuotes with single identifierQuotes // and remove single identifierQuotes var nameParts = name.split(identifierQuote+identifierQuote); for (var i = 0; i < nameParts.length; i++) @@ -109,7 +109,7 @@ var nameParts = getText(name).split("."); for (var i = 0; i < nameParts.length; i++) nameParts[i] = identifierQuote + - // doublicate identifierQuotes + // duplicate identifierQuotes nameParts[i].replace(new RegExp(identifierQuote,"g"), identifierQuote+identifierQuote) + identifierQuote; var escaped = nameParts.join("."); diff --git a/addon/search/match-highlighter.js b/addon/search/match-highlighter.js index 3a4a7dedc1..9b181ebc01 100644 --- a/addon/search/match-highlighter.js +++ b/addon/search/match-highlighter.js @@ -16,7 +16,7 @@ // highlighted only if the selected text is a word. showToken, when enabled, // will cause the current token to be highlighted when nothing is selected. // delay is used to specify how much time to wait, in milliseconds, before -// highlighting the matches. If annotateScrollbar is enabled, the occurences +// highlighting the matches. If annotateScrollbar is enabled, the occurrences // will be highlighted on the scrollbar via the matchesonscrollbar addon. (function(mod) { diff --git a/demo/complete.html b/demo/complete.html index 2fef796401..3e7bd5ff56 100644 --- a/demo/complete.html +++ b/demo/complete.html @@ -71,7 +71,7 @@

    Autocomplete Demo

    addons.

    @@ -88,7 +88,7 @@

    Autocomplete Demo

    ["here", "hither"], ["asynchronous", "nonsynchronous"], ["completion", "achievement", "conclusion", "culmination", "expirations"], - ["hinting", "advive", "broach", "imply"], + ["hinting", "advise", "broach", "imply"], ["function","action"], ["provide", "add", "bring", "give"], ["synonyms", "equivalents"], diff --git a/demo/matchhighlighter.html b/demo/matchhighlighter.html index 6aa937782d..8e0ff25b89 100644 --- a/demo/matchhighlighter.html +++ b/demo/matchhighlighter.html @@ -98,6 +98,6 @@

    Match Highlighter Demo

    }); -

    Search and highlight occurences of the selected text.

    +

    Search and highlight occurrences of the selected text.

    diff --git a/demo/simplemode.html b/demo/simplemode.html index d7b0cface4..b03335fb87 100644 --- a/demo/simplemode.html +++ b/demo/simplemode.html @@ -129,7 +129,7 @@

    Simple Mode Demo

    */ CodeMirror.defineSimpleMode("simplemode", { - // The start state contains the rules that are intially used + // The start state contains the rules that are initially used start: [ // The regex matches the token, the token property contains the type {regex: /"(?:[^\\]|\\.)*?(?:"|$)/, token: "string"}, diff --git a/doc/internals.html b/doc/internals.html index 2137c937f2..893604e936 100644 --- a/doc/internals.html +++ b/doc/internals.html @@ -293,7 +293,7 @@

    Intelligent Updating

    Parsers can be Simple

    When I wrote CodeMirror 1, I -thought interruptable +thought interruptible parsers were a hugely scary and complicated thing, and I used a bunch of heavyweight abstractions to keep this supposed complexity under control: parsers diff --git a/doc/manual.html b/doc/manual.html index 285d420d9a..7aade3df15 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2405,7 +2405,7 @@

    Addons

    Accepts linenumber, +/-linenumber, line:char, scroll% and :linenumber formats. This will make use of openDialog - when available to make prompting for line number neater. Demo avaliable here. + when available to make prompting for line number neater. Demo available here.
    search/matchesonscrollbar.js
    Adds a showMatchesOnScrollbar method to editor @@ -2721,7 +2721,7 @@

    Addons

    the "hint" type to find applicable hinting functions, and tries them one by one. If that fails, it looks for a "hintWords" helper to fetch a list of - completable words for the mode, and + completeable words for the mode, and uses CodeMirror.hint.fromList to complete from those.
    When completions aren't simple strings, they should be @@ -3683,13 +3683,13 @@

    Extending VIM

    getRegisterController()
    Returns the RegisterController that manages the state of registers used by vim mode. For the RegisterController api see its - defintion here. + definition here.
    buildKeyMap()
    Not currently implemented. If you would like to contribute this please open - a pull request on Github. + a pull request on GitHub.
    defineRegister()
    diff --git a/doc/realworld.html b/doc/realworld.html index a7402551f7..e5f8aef6f9 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -81,7 +81,7 @@

    CodeMirror real-world uses

  • Eloquent JavaScript (book)
  • Emmet (fast XML editing)
  • Espruino Web IDE (Chrome App for writing code on Espruino devices)
  • -
  • EXLskills Live Interivews
  • +
  • EXLskills Live Interviews
  • Fastfig (online computation/math tool)
  • Farabi (modern Perl IDE)
  • FathomJS integration (slides with editors, again)
  • @@ -92,7 +92,7 @@

    CodeMirror real-world uses

  • Gerrit's diff view and inline editor
  • Git Crx (Chrome App for browsing local git repos)
  • GitHub's Android app
  • -
  • Github's in-browser edit feature
  • +
  • GitHub's in-browser edit feature
  • Glitch (community-driven app building)
  • Go language tour
  • Google Apps Script
  • diff --git a/doc/releases.html b/doc/releases.html index f6628b6548..feeb8088d5 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -193,7 +193,7 @@

    Version 5.x

  • Make Shift-Delete to cut work on Firefox.
  • closetag addon: Properly handle self-closing tags.
  • handlebars mode: Fix triple-brace support.
  • -
  • searchcursor addon: Support mathing $ in reverse regexp search.
  • +
  • searchcursor addon: Support matching $ in reverse regexp search.
  • panel addon: Don’t get confused by changing panel sizes.
  • javascript-hint addon: Complete variables defined in outer scopes.
  • sublime bindings: Make by-subword motion more consistent with Sublime Text.
  • @@ -354,7 +354,7 @@

    Version 5.x

  • New method phrase and option phrases to make translating UI text in addons easier.
  • closebrackets addon: Fix issue where bracket-closing wouldn't work before punctuation.
  • panel addon: Fix problem where replacing the last remaining panel dropped the newly added panel.
  • -
  • hardwrap addon: Fix an infinite loop when the indention is greater than the target column.
  • +
  • hardwrap addon: Fix an infinite loop when the indentation is greater than the target column.
  • jinja2 and markdown modes: Add comment metadata.
  • @@ -588,7 +588,7 @@

    Version 5.x

  • Fix handling of shadow DOM roots when finding the active element.
  • Add role=presentation to more DOM elements to improve screen reader support.
  • merge addon: Make aligning of unchanged chunks more robust.
  • -
  • comment addon: Fix comment-toggling on a block of text that starts and ends in a (differnet) block comment.
  • +
  • comment addon: Fix comment-toggling on a block of text that starts and ends in a (different) block comment.
  • javascript mode: Improve support for TypeScript syntax.
  • r mode: Fix indentation after semicolon-less statements.
  • shell mode: Properly handle escaped parentheses in parenthesized expressions.
  • @@ -653,7 +653,7 @@

    Version 5.x

    • Tapping/clicking the editor in contentEditable mode on Chrome now puts the cursor at the tapped position.
    • -
    • Fix various crashes and misbehaviors when reading composition events in contentEditable mode.
    • +
    • Fix various crashes and misbehavior when reading composition events in contentEditable mode.
    • Catches and ignores an IE 'Unspecified Error' when creating an editor in an iframe before there is a <body>.
    • merge addon: Fix several issues in the chunk-aligning feature.
    • verilog mode: Rewritten to address various issues.
    • @@ -876,7 +876,7 @@

      Version 5.x

    • New modes: Vue, Oz, MscGen (and dialects), Closure Stylesheets
    • Implement CommonMark-style flexible list indent and cross-line code spans in Markdown mode
    • Add a replace-all button to the search addon, and make the persistent search dialog transparent when it obscures the match
    • -
    • Handle acync/await and ocal and binary numbers in JavaScript mode
    • +
    • Handle async/await and ocal and binary numbers in JavaScript mode
    • Fix various issues with the Haxe mode
    • Make the closebrackets addon select only the wrapped text when wrapping selection in brackets
    • Tokenize properties as properties in the CoffeeScript mode
    • @@ -1683,7 +1683,7 @@

      Version 2.x

      bindings.
    • Support for overwrite (insert).
    • Custom-width - and stylable tabs.
    • + and styleable tabs.
    • Moved more code into add-on scripts.
    • Support for sane vertical cursor movement in wrapped lines.
    • More reliable handling of @@ -1704,7 +1704,7 @@

      Version 2.x

    • Add support for line wrapping and code folding.
    • -
    • Add Github-style Markdown mode.
    • +
    • Add GitHub-style Markdown mode.
    • Add Monokai and Rubyblue themes.
    • Add setBookmark method.
    • diff --git a/doc/upgrade_v2.2.html b/doc/upgrade_v2.2.html index 5709e652bf..dabe974cfa 100644 --- a/doc/upgrade_v2.2.html +++ b/doc/upgrade_v2.2.html @@ -79,7 +79,7 @@

      Different key customization

      and indent it less when shift is held ("indentLess"). There are also "indentAuto" (smart indent) and "insertTab" commands provided for alternate -behaviors. Or you can write your own handler function to do something +behavior. Or you can write your own handler function to do something different altogether.

      Tabs

      diff --git a/index.html b/index.html index a89b1de5d3..3934c309d9 100644 --- a/index.html +++ b/index.html @@ -100,7 +100,7 @@

      This is CodeMirror

    Get the current version: 5.59.1.
    - You can see the code,
    + You can see the code,
    read the release notes,
    or study the user manual.
    diff --git a/keymap/vim.js b/keymap/vim.js index 789e1e55b3..dba9d7c1e0 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -737,7 +737,7 @@ // TODO: Convert keymap into dictionary format for fast lookup. }, // Testing hook, though it might be useful to expose the register - // controller anyways. + // controller anyway. getRegisterController: function() { return vimGlobalState.registerController; }, @@ -4322,7 +4322,7 @@ raw += ' ' + desc + ''; return raw; } - var searchPromptDesc = '(Javascript regexp)'; + var searchPromptDesc = '(JavaScript regexp)'; function showPrompt(cm, options) { var shortText = (options.prefix || '') + ' ' + (options.desc || ''); var prompt = makePrompt(options.prefix, options.desc); @@ -5234,7 +5234,7 @@ * @param {Cursor} lineEnd Line to stop replacing at. * @param {RegExp} query Query for performing matches with. * @param {string} replaceWith Text to replace matches with. May contain $1, - * $2, etc for replacing captured groups using Javascript replace. + * $2, etc for replacing captured groups using JavaScript replace. * @param {function()} callback A callback for when the replace is done. */ function doReplace(cm, confirm, global, lineStart, lineEnd, searchCursor, query, diff --git a/mode/asn.1/asn.1.js b/mode/asn.1/asn.1.js index d3ecb08781..df1330b686 100644 --- a/mode/asn.1/asn.1.js +++ b/mode/asn.1/asn.1.js @@ -190,7 +190,7 @@ " NetworkAddress BITS BMPString TimeStamp TimeTicks" + " TruthValue RowStatus DisplayString GeneralString" + " GraphicString IA5String NumericString" + - " PrintableString SnmpAdminAtring TeletexString" + + " PrintableString SnmpAdminString TeletexString" + " UTF8String VideotexString VisibleString StringStore" + " ISO646String T61String UniversalString Unsigned32" + " Integer32 Gauge Gauge32 Counter Counter32 Counter64"), diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 2154f1d2df..5d01e1cd4c 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -749,7 +749,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { "gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " + "gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " + "gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " + - "gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " + + "gl_TextureMatrixTranspose gl_ModelViewMatrixInverseTranspose " + "gl_ProjectionMatrixInverseTranspose " + "gl_ModelViewProjectionMatrixInverseTranspose " + "gl_TextureMatrixInverseTranspose " + diff --git a/mode/clike/index.html b/mode/clike/index.html index 0cfae2149e..b1c881904f 100644 --- a/mode/clike/index.html +++ b/mode/clike/index.html @@ -148,7 +148,7 @@

    Objective-C example

    */ #import "MyClass.h" -#import +#import @import BFrameworkModule; NS_ENUM(SomeValues) { diff --git a/mode/dtd/dtd.js b/mode/dtd/dtd.js index 74b8c6bded..40370a393d 100644 --- a/mode/dtd/dtd.js +++ b/mode/dtd/dtd.js @@ -34,7 +34,7 @@ CodeMirror.defineMode("dtd", function(config) { state.tokenize = inBlock("meta", "?>"); return ret("meta", ch); } else if (ch == "#" && stream.eatWhile(/[\w]/)) return ret("atom", "tag"); - else if (ch == "|") return ret("keyword", "seperator"); + else if (ch == "|") return ret("keyword", "separator"); else if (ch.match(/[\(\)\[\]\-\.,\+\?>]/)) return ret(null, ch);//if(ch === ">") return ret(null, "endtag"); else else if (ch.match(/[\[\]]/)) return ret("rule", ch); else if (ch == "\"" || ch == "'") { diff --git a/mode/factor/factor.js b/mode/factor/factor.js index 7108278cca..4c876d4d29 100644 --- a/mode/factor/factor.js +++ b/mode/factor/factor.js @@ -16,7 +16,7 @@ "use strict"; CodeMirror.defineSimpleMode("factor", { - // The start state contains the rules that are intially used + // The start state contains the rules that are initially used start: [ // comments {regex: /#?!.*/, token: "comment"}, diff --git a/mode/factor/index.html b/mode/factor/index.html index 574d402dda..6a77230d40 100644 --- a/mode/factor/index.html +++ b/mode/factor/index.html @@ -70,7 +70,7 @@

    Factor mode

    });

    -

    Simple mode that handles Factor Syntax (Factor on WikiPedia).

    +

    Simple mode that handles Factor Syntax (Factor on Wikipedia).

    MIME types defined: text/x-factor.

    diff --git a/mode/fcl/index.html b/mode/fcl/index.html index e51fa166b9..9194dfddaf 100644 --- a/mode/fcl/index.html +++ b/mode/fcl/index.html @@ -61,7 +61,7 @@

    FCL mode

    END_FUZZIFY DEFUZZIFY ProbabilityAccess - TERM hight := 1; + TERM height := 1; TERM medium := 0.5; TERM low := 0; ACCU: MAX; @@ -70,7 +70,7 @@

    FCL mode

    END_DEFUZZIFY DEFUZZIFY ProbabilityDistribution - TERM hight := 1; + TERM height := 1; TERM medium := 0.5; TERM low := 0; ACCU: MAX; @@ -80,14 +80,14 @@

    FCL mode

    RULEBLOCK No1 AND : MIN; - RULE 1 : IF TimeDay IS outside AND ApplicateHost IS few THEN ProbabilityAccess IS hight; - RULE 2 : IF ApplicateHost IS many THEN ProbabilityAccess IS hight; + RULE 1 : IF TimeDay IS outside AND ApplicateHost IS few THEN ProbabilityAccess IS height; + RULE 2 : IF ApplicateHost IS many THEN ProbabilityAccess IS height; RULE 3 : IF TimeDay IS inside AND ApplicateHost IS few THEN ProbabilityAccess IS low; END_RULEBLOCK RULEBLOCK No2 AND : MIN; - RULE 1 : IF ApplicateHost IS many THEN ProbabilityDistribution IS hight; + RULE 1 : IF ApplicateHost IS many THEN ProbabilityDistribution IS height; END_RULEBLOCK END_FUNCTION_BLOCK diff --git a/mode/forth/index.html b/mode/forth/index.html index c6f0b5c5c8..6b6477cae7 100644 --- a/mode/forth/index.html +++ b/mode/forth/index.html @@ -68,7 +68,7 @@

    Forth mode

    }); -

    Simple mode that handle Forth-Syntax (Forth on WikiPedia).

    +

    Simple mode that handle Forth-Syntax (Forth on Wikipedia).

    MIME types defined: text/x-forth.

    diff --git a/mode/gas/gas.js b/mode/gas/gas.js index e34d7a7b61..b3515abe77 100644 --- a/mode/gas/gas.js +++ b/mode/gas/gas.js @@ -302,11 +302,11 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) { } if (ch === '{') { - return "braket"; + return "bracket"; } if (ch === '}') { - return "braket"; + return "bracket"; } if (/\d/.test(ch)) { diff --git a/mode/gfm/test.js b/mode/gfm/test.js index d933896aa5..e2002879cb 100644 --- a/mode/gfm/test.js +++ b/mode/gfm/test.js @@ -92,7 +92,7 @@ "[em *foo ][em&link bar/hello@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2][em *]"); MT("wordSHA", - "ask for feedbac") + "ask for feedback") MT("num", "foo [link #1] bar"); diff --git a/mode/haml/haml.js b/mode/haml/haml.js index 3c8f505eb5..d941d97433 100644 --- a/mode/haml/haml.js +++ b/mode/haml/haml.js @@ -72,7 +72,7 @@ } } - // donot handle --> as valid ruby, make it HTML close comment instead + // do not handle --> as valid ruby, make it HTML close comment instead if (state.startOfLine && !stream.match("-->", false) && (ch == "=" || ch == "-" )) { state.tokenize = ruby; return state.tokenize(stream, state); diff --git a/mode/htmlembedded/index.html b/mode/htmlembedded/index.html index b1cafde973..d17afec8b1 100644 --- a/mode/htmlembedded/index.html +++ b/mode/htmlembedded/index.html @@ -55,6 +55,6 @@

    Html Embedded Scripts mode

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

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

    diff --git a/mode/idl/idl.js b/mode/idl/idl.js index 168761cd88..37302bb90f 100644 --- a/mode/idl/idl.js +++ b/mode/idl/idl.js @@ -62,7 +62,7 @@ 'empty', 'enable_sysrtn', 'eof', 'eos', 'erase', 'erf', 'erfc', 'erfcx', 'erode', 'errorplot', 'errplot', 'estimator_filter', 'execute', 'exit', 'exp', - 'expand', 'expand_path', 'expint', 'extrac', 'extract_slice', + 'expand', 'expand_path', 'expint', 'extract', 'extract_slice', 'f_cvf', 'f_pdf', 'factorial', 'fft', 'file_basename', 'file_chmod', 'file_copy', 'file_delete', 'file_dirname', 'file_expand_path', 'file_gunzip', 'file_gzip', 'file_info', diff --git a/mode/javascript/test.js b/mode/javascript/test.js index ffff05f513..26a81ffc8d 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -252,7 +252,7 @@ MT("async_object", "[keyword let] [def obj] [operator =] { [property async]: [atom false] };"); - // async be highlighet as keyword and foo as def, but it requires potentially expensive look-ahead. See #4173 + // async be highlighted as keyword and foo as def, but it requires potentially expensive look-ahead. See #4173 MT("async_object_function", "[keyword let] [def obj] [operator =] { [property async] [property foo]([def args]) { [keyword return] [atom true]; } };"); diff --git a/mode/markdown/index.html b/mode/markdown/index.html index da3fe61b98..4984c04b2c 100644 --- a/mode/markdown/index.html +++ b/mode/markdown/index.html @@ -159,7 +159,7 @@

    Markdown mode

    Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`, `+`, and `-`) as list markers. These three markers are -interchangable; this: +interchangeable; this: * Candy. * Gum. @@ -306,7 +306,7 @@

    Markdown mode

    I strongly recommend against using any `<blink>` tags. I wish SmartyPants used named entities like `&mdash;` - instead of decimal-encoded entites like `&#8212;`. + instead of decimal-encoded entities like `&#8212;`. Output: @@ -315,7 +315,7 @@

    Markdown mode

    <p>I wish SmartyPants used named entities like <code>&amp;mdash;</code> instead of decimal-encoded - entites like <code>&amp;#8212;</code>.</p> + entities like <code>&amp;#8212;</code>.</p> To specify an entire block of pre-formatted code, indent every line of @@ -360,7 +360,7 @@

    Markdown mode

    }); -

    If you also want support strikethrough, emoji and few other goodies, check out Github-Flavored Markdown mode.

    +

    If you also want support strikethrough, emoji and few other goodies, check out GitHub-Flavored Markdown mode.

    Optionally depends on other modes for properly highlighted code blocks, and XML mode for properly highlighted inline XML blocks.

    @@ -370,7 +370,7 @@

    Markdown mode

  • highlightFormatting: boolean
    -
    Whether to separately highlight markdown meta characterts (*[]()etc.) (default: false).
    +
    Whether to separately highlight markdown meta characters (*[]()etc.) (default: false).
  • diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 287f39b55d..aee76c43ac 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -223,7 +223,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { // Add this list item's content's indentation to the stack state.listStack.push(state.indentation); - // Reset inline styles which shouldn't propagate aross list items + // Reset inline styles which shouldn't propagate across list items state.em = false; state.strong = false; state.code = false; diff --git a/mode/markdown/test.js b/mode/markdown/test.js index 929e7bba19..fd5a1fb4d5 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -315,7 +315,7 @@ "[header&header-2 bar]", "[header&header-2 ---]"); - MT("setextAferATX", + MT("setextAfterATX", "[header&header-1 # foo]", "[header&header-2 bar]", "[header&header-2 ---]"); @@ -659,7 +659,7 @@ " [variable-2 text after fenced code]"); // should correctly parse numbered list content indentation - MT("listCommonMark_NumeberedListIndent", + MT("listCommonMark_NumberedListIndent", "[variable-2 1000. list with base indent of 6]", "", " [variable-2 text must be indented 6 spaces at minimum]", diff --git a/mode/meta.js b/mode/meta.js index c7738a514c..92b68074ca 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -44,7 +44,7 @@ {name: "edn", mime: "application/edn", mode: "clojure", ext: ["edn"]}, {name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]}, {name: "Elm", mime: "text/x-elm", mode: "elm", ext: ["elm"]}, - {name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]}, + {name: "Embedded JavaScript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]}, {name: "Embedded Ruby", mime: "application/x-erb", mode: "htmlembedded", ext: ["erb"]}, {name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]}, {name: "Esper", mime: "text/x-esper", mode: "sql"}, diff --git a/mode/modelica/modelica.js b/mode/modelica/modelica.js index a83a4135d0..2e9622f03f 100644 --- a/mode/modelica/modelica.js +++ b/mode/modelica/modelica.js @@ -90,7 +90,7 @@ return "error"; } - function tokenUnsignedNuber(stream, state) { + function tokenUnsignedNumber(stream, state) { stream.eatWhile(isDigit); if (stream.eat('.')) { stream.eatWhile(isDigit); @@ -164,9 +164,9 @@ else if(ch == '"') { state.tokenize = tokenString; } - // UNSIGNED_NUBER + // UNSIGNED_NUMBER else if(isDigit.test(ch)) { - state.tokenize = tokenUnsignedNuber; + state.tokenize = tokenUnsignedNumber; } // ERROR else { diff --git a/mode/mumps/mumps.js b/mode/mumps/mumps.js index 3671c9cb36..c53b4bf3a2 100644 --- a/mode/mumps/mumps.js +++ b/mode/mumps/mumps.js @@ -26,7 +26,7 @@ var brackets = new RegExp("[()]"); var identifiers = new RegExp("^[%A-Za-z][A-Za-z0-9]*"); var commandKeywords = ["break","close","do","else","for","goto", "halt", "hang", "if", "job","kill","lock","merge","new","open", "quit", "read", "set", "tcommit", "trollback", "tstart", "use", "view", "write", "xecute", "b","c","d","e","f","g", "h", "i", "j","k","l","m","n","o", "q", "r", "s", "tc", "tro", "ts", "u", "v", "w", "x"]; - // The following list includes instrinsic functions _and_ special variables + // The following list includes intrinsic functions _and_ special variables var intrinsicFuncsWords = ["\\$ascii", "\\$char", "\\$data", "\\$ecode", "\\$estack", "\\$etrap", "\\$extract", "\\$find", "\\$fnumber", "\\$get", "\\$horolog", "\\$io", "\\$increment", "\\$job", "\\$justify", "\\$length", "\\$name", "\\$next", "\\$order", "\\$piece", "\\$qlength", "\\$qsubscript", "\\$query", "\\$quit", "\\$random", "\\$reverse", "\\$select", "\\$stack", "\\$test", "\\$text", "\\$translate", "\\$view", "\\$x", "\\$y", "\\$a", "\\$c", "\\$d", "\\$e", "\\$ec", "\\$es", "\\$et", "\\$f", "\\$fn", "\\$g", "\\$h", "\\$i", "\\$j", "\\$l", "\\$n", "\\$na", "\\$o", "\\$p", "\\$q", "\\$ql", "\\$qs", "\\$r", "\\$re", "\\$s", "\\$st", "\\$t", "\\$tr", "\\$v", "\\$z"]; var intrinsicFuncs = wordRegexp(intrinsicFuncsWords); var command = wordRegexp(commandKeywords); diff --git a/mode/nginx/index.html b/mode/nginx/index.html index 5c2bc6e2cf..1aa690a6d4 100644 --- a/mode/nginx/index.html +++ b/mode/nginx/index.html @@ -62,7 +62,7 @@

    NGINX mode

    location / { index index.html index.php; ## Allow a static html file to be shown first try_files $uri $uri/ @handler; ## If missing pass the URI to Magento's front handler - expires 30d; ## Assume all files are cachable + expires 30d; ## Assume all files are cacheable } ## These locations would be hidden by .htaccess normally @@ -128,7 +128,7 @@

    NGINX mode

    location / { index index.html index.php; ## Allow a static html file to be shown first try_files $uri $uri/ @handler; ## If missing pass the URI to Magento's front handler - expires 30d; ## Assume all files are cachable + expires 30d; ## Assume all files are cacheable } ## These locations would be hidden by .htaccess normally diff --git a/mode/ntriples/index.html b/mode/ntriples/index.html index 5473dbffc0..275cf08b49 100644 --- a/mode/ntriples/index.html +++ b/mode/ntriples/index.html @@ -58,7 +58,7 @@

    N-Triples mode

    "literal 1" . _:bnode3 . _:bnode4 "literal 2"@lang . - # if a graph labe + # if a graph label _:bnode5 "literal 3"^^ . diff --git a/mode/oz/oz.js b/mode/oz/oz.js index a9738495b6..63ad806abc 100644 --- a/mode/oz/oz.js +++ b/mode/oz/oz.js @@ -130,7 +130,7 @@ CodeMirror.defineMode("oz", function (conf) { return "operator"; } - // If nothing match, we skip the entire alphanumerical block + // If nothing match, we skip the entire alphanumeric block stream.eatWhile(/\w/); return "variable"; diff --git a/mode/perl/perl.js b/mode/perl/perl.js index 220b0a6994..ffe7877af1 100644 --- a/mode/perl/perl.js +++ b/mode/perl/perl.js @@ -347,7 +347,7 @@ CodeMirror.defineMode("perl",function(){ lc :1, // - return lower-case version of a string lcfirst :1, // - return a string with just the next letter in lower case length :1, // - return the number of bytes in a string - 'link' :1, // - create a hard link in the filesytem + 'link' :1, // - create a hard link in the filesystem listen :1, // - register your socket as a server local : 2, // - create a temporary value for a global variable (dynamic scoping) localtime :1, // - convert UNIX time into record or string using local time @@ -441,7 +441,7 @@ CodeMirror.defineMode("perl",function(){ state :1, // - declare and assign a state variable (persistent lexical scoping) study :1, // - optimize input data for repeated searches 'sub' :1, // - declare a subroutine, possibly anonymously - 'substr' :1, // - get or alter a portion of a stirng + 'substr' :1, // - get or alter a portion of a string symlink :1, // - create a symbolic link to a file syscall :1, // - execute an arbitrary system call sysopen :1, // - open a file, pipe, or descriptor diff --git a/mode/python/index.html b/mode/python/index.html index bdfc8f574c..78a3a14641 100644 --- a/mode/python/index.html +++ b/mode/python/index.html @@ -190,7 +190,7 @@

    Configuration Options for Python mode:

  • hangingIndent - int - If you want to write long arguments to a function starting on a new line, how much that line should be indented. Defaults to one normal indentation unit.
  • Advanced Configuration Options:

    -

    Usefull for superset of python syntax like Enthought enaml, IPython magics and questionmark help

    +

    Useful for superset of python syntax like Enthought enaml, IPython magics and questionmark help

    • singleOperators - RegEx - Regular Expression for single operator matching, default :
      ^[\\+\\-\\*/%&|\\^~<>!]
      including
      @
      on Python 3
    • singleDelimiters - RegEx - Regular Expression for single delimiter matching, default :
      ^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]
    • diff --git a/mode/python/test.js b/mode/python/test.js index 2b605b8e62..39b80cf70a 100644 --- a/mode/python/test.js +++ b/mode/python/test.js @@ -31,7 +31,7 @@ } MT("fValidStringPrefix", "[string f'this is a]{[variable formatted]}[string string']"); - MT("fValidExpressioninFString", "[string f'expression ]{[number 100][operator *][number 5]}[string string']"); + MT("fValidExpressionInFString", "[string f'expression ]{[number 100][operator *][number 5]}[string string']"); MT("fInvalidFString", "[error f'this is wrong}]"); MT("fNestedFString", "[string f'expression ]{[number 100] [operator +] [string f'inner]{[number 5]}[string ']}[string string']"); MT("uValidStringPrefix", "[string u'this is an unicode string']"); diff --git a/mode/rpm/rpm.js b/mode/rpm/rpm.js index 2dece2eabd..88a7e889ed 100644 --- a/mode/rpm/rpm.js +++ b/mode/rpm/rpm.js @@ -12,14 +12,14 @@ "use strict"; CodeMirror.defineMode("rpm-changes", function() { - var headerSeperator = /^-+$/; + var headerSeparator = /^-+$/; var headerLine = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ?\d{1,2} \d{2}:\d{2}(:\d{2})? [A-Z]{3,4} \d{4} - /; var simpleEmail = /^[\w+.-]+@[\w.-]+/; return { token: function(stream) { if (stream.sol()) { - if (stream.match(headerSeperator)) { return 'tag'; } + if (stream.match(headerSeparator)) { return 'tag'; } if (stream.match(headerLine)) { return 'tag'; } } if (stream.match(simpleEmail)) { return 'string'; } diff --git a/mode/ruby/index.html b/mode/ruby/index.html index 55fe6c5892..daebdca291 100644 --- a/mode/ruby/index.html +++ b/mode/ruby/index.html @@ -34,7 +34,7 @@

      Ruby mode

      # This program evaluates polynomials. It first asks for the coefficients # of a polynomial, which must be entered on one line, highest-order first. # It then requests values of x and will compute the value of the poly for -# each x. It will repeatly ask for x values, unless you the user enters +# each x. It will repeatedly ask for x values, unless you the user enters # a blank line. It that case, it will ask for another polynomial. If the # user types quit for either input, the program immediately exits. # diff --git a/mode/scheme/scheme.js b/mode/scheme/scheme.js index efac89078b..370250d856 100644 --- a/mode/scheme/scheme.js +++ b/mode/scheme/scheme.js @@ -170,7 +170,7 @@ CodeMirror.defineMode("scheme", function () { } else if (stream.match(/^[-+0-9.]/, false)) { hasRadix = false; numTest = isDecimalNumber; - // re-consume the intial # if all matches failed + // re-consume the initial # if all matches failed } else if (!hasExactness) { stream.eat('#'); } diff --git a/mode/sieve/sieve.js b/mode/sieve/sieve.js index f02a867e7a..b7236401a7 100644 --- a/mode/sieve/sieve.js +++ b/mode/sieve/sieve.js @@ -43,7 +43,7 @@ CodeMirror.defineMode("sieve", function(config) { if (ch == "(") { state._indent.push("("); // add virtual angel wings so that editor behaves... - // ...more sane incase of broken brackets + // ...more sane in case of broken brackets state._indent.push("{"); return null; } diff --git a/mode/sql/sql.js b/mode/sql/sql.js index 4127cd9a05..dcde1a771c 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -370,7 +370,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { "$": hookVar, // The preferred way to escape Identifiers is using double quotes, ref: http://sqlite.org/lang_keywords.html "\"": hookIdentifierDoublequote, - // there is also support for backtics, ref: http://sqlite.org/lang_keywords.html + // there is also support for backticks, ref: http://sqlite.org/lang_keywords.html "`": hookIdentifier } }); @@ -451,7 +451,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { // Spark SQL CodeMirror.defineMIME("text/x-sparksql", { name: "sql", - keywords: set("add after all alter analyze and anti archive array as asc at between bucket buckets by cache cascade case cast change clear cluster clustered codegen collection column columns comment commit compact compactions compute concatenate cost create cross cube current current_date current_timestamp database databases datata dbproperties defined delete delimited deny desc describe dfs directories distinct distribute drop else end escaped except exchange exists explain export extended external false fields fileformat first following for format formatted from full function functions global grant group grouping having if ignore import in index indexes inner inpath inputformat insert intersect interval into is items join keys last lateral lazy left like limit lines list load local location lock locks logical macro map minus msck natural no not null nulls of on optimize option options or order out outer outputformat over overwrite partition partitioned partitions percent preceding principals purge range recordreader recordwriter recover reduce refresh regexp rename repair replace reset restrict revoke right rlike role roles rollback rollup row rows schema schemas select semi separated serde serdeproperties set sets show skewed sort sorted start statistics stored stratify struct table tables tablesample tblproperties temp temporary terminated then to touch transaction transactions transform true truncate unarchive unbounded uncache union unlock unset use using values view when where window with"), + keywords: set("add after all alter analyze and anti archive array as asc at between bucket buckets by cache cascade case cast change clear cluster clustered codegen collection column columns comment commit compact compactions compute concatenate cost create cross cube current current_date current_timestamp database databases data dbproperties defined delete delimited deny desc describe dfs directories distinct distribute drop else end escaped except exchange exists explain export extended external false fields fileformat first following for format formatted from full function functions global grant group grouping having if ignore import in index indexes inner inpath inputformat insert intersect interval into is items join keys last lateral lazy left like limit lines list load local location lock locks logical macro map minus msck natural no not null nulls of on optimize option options or order out outer outputformat over overwrite partition partitioned partitions percent preceding principals purge range recordreader recordwriter recover reduce refresh regexp rename repair replace reset restrict revoke right rlike role roles rollback rollup row rows schema schemas select semi separated serde serdeproperties set sets show skewed sort sorted start statistics stored stratify struct table tables tablesample tblproperties temp temporary terminated then to touch transaction transactions transform true truncate unarchive unbounded uncache union unlock unset use using values view when where window with"), builtin: set("tinyint smallint int bigint boolean float double string binary timestamp decimal array map struct uniontype delimited serde sequencefile textfile rcfile inputformat outputformat"), atoms: set("false true null"), operatorChars: /^[*\/+\-%<>!=~&|^]/, diff --git a/mode/vbscript/vbscript.js b/mode/vbscript/vbscript.js index 0670c0ceef..4033948133 100644 --- a/mode/vbscript/vbscript.js +++ b/mode/vbscript/vbscript.js @@ -32,7 +32,7 @@ CodeMirror.defineMode("vbscript", function(conf, parserConf) { var singleOperators = new RegExp("^[\\+\\-\\*/&\\\\\\^<>=]"); var doubleOperators = new RegExp("^((<>)|(<=)|(>=))"); var singleDelimiters = new RegExp('^[\\.,]'); - var brakets = new RegExp('^[\\(\\)]'); + var brackets = new RegExp('^[\\(\\)]'); var identifiers = new RegExp("^[A-Za-z][_A-Za-z0-9]*"); var openingKeywords = ['class','sub','select','while','if','function', 'property', 'with', 'for']; @@ -183,7 +183,7 @@ CodeMirror.defineMode("vbscript", function(conf, parserConf) { return null; } - if (stream.match(brakets)) { + if (stream.match(brackets)) { return "bracket"; } diff --git a/mode/velocity/velocity.js b/mode/velocity/velocity.js index 56caa671b3..1d17c84ebe 100644 --- a/mode/velocity/velocity.js +++ b/mode/velocity/velocity.js @@ -48,7 +48,7 @@ CodeMirror.defineMode("velocity", function() { else if (state.inParams) return chain(stream, state, tokenString(ch)); } - // is it one of the special signs []{}().,;? Seperator? + // is it one of the special signs []{}().,;? Separator? else if (/[\[\]{}\(\),;\.]/.test(ch)) { if (ch == "(" && beforeParams) state.inParams = true; diff --git a/mode/verilog/verilog.js b/mode/verilog/verilog.js index 89fe9c1ac8..6c799f298b 100644 --- a/mode/verilog/verilog.js +++ b/mode/verilog/verilog.js @@ -542,7 +542,7 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { }; var tlvIndentUnit = 3; var tlvTrackStatements = false; - var tlvIdentMatch = /^([~!@#\$%\^&\*-\+=\?\/\\\|'"<>]+)([\d\w_]*)/; // Matches an identifiere. + var tlvIdentMatch = /^([~!@#\$%\^&\*-\+=\?\/\\\|'"<>]+)([\d\w_]*)/; // Matches an identifier. // Note that ':' is excluded, because of it's use in [:]. var tlvFirstLevelIndentMatch = /^[! ] /; var tlvLineIndentationMatch = /^[! ] */; @@ -719,7 +719,7 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { } else { // Just swallow one character and try again. // This enables subsequent identifier match with preceding symbol character, which - // is legal within a statement. (Eg, !$reset). It also enables detection of + // is legal within a statement. (E.g., !$reset). It also enables detection of // comment start with preceding symbols. stream.backUp(stream.current().length - 1); style = "tlv-default"; diff --git a/mode/vue/index.html b/mode/vue/index.html index df519a5cb7..78b4784840 100644 --- a/mode/vue/index.html +++ b/mode/vue/index.html @@ -38,7 +38,7 @@

      Vue.js mode

      - Get the current version: 5.65.8.
      + Get the current version: 5.65.9.
      You can see the code,
      read the release notes,
      or study the user manual. diff --git a/package.json b/package.json index e1388a4b0c..4647fb121f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.65.8", + "version": "5.65.9", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 5b222fe15e..85841e7279 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.65.8" +CodeMirror.version = "5.65.9" From e1fe2100d0fdc7c34d47993f6514bdd2213c0015 Mon Sep 17 00:00:00 2001 From: Mark Boyes Date: Thu, 6 Oct 2022 12:52:06 +0100 Subject: [PATCH 1815/1880] [sparql mode] Identify all characters in prefixes --- mode/sparql/sparql.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/mode/sparql/sparql.js b/mode/sparql/sparql.js index 5e68f5670d..6d928b5cde 100644 --- a/mode/sparql/sparql.js +++ b/mode/sparql/sparql.js @@ -33,6 +33,9 @@ CodeMirror.defineMode("sparql", function(config) { "true", "false", "with", "data", "copy", "to", "move", "add", "create", "drop", "clear", "load", "into"]); var operatorChars = /[*+\-<>=&|\^\/!\?]/; + var PN_CHARS = "[A-Za-z_\\-0-9]"; + var PREFIX_START = new RegExp("[A-Za-z]"); + var PREFIX_REMAINDER = new RegExp("((" + PN_CHARS + "|\\.)*(" + PN_CHARS + "))?:"); function tokenBase(stream, state) { var ch = stream.next(); @@ -71,20 +74,18 @@ CodeMirror.defineMode("sparql", function(config) { stream.eatWhile(/[a-z\d\-]/i); return "meta"; } - else { - stream.eatWhile(/[_\w\d]/); - if (stream.eat(":")) { + else if (PREFIX_START.test(ch) && stream.match(PREFIX_REMAINDER)) { eatPnLocal(stream); return "atom"; - } - var word = stream.current(); - if (ops.test(word)) - return "builtin"; - else if (keywords.test(word)) - return "keyword"; - else - return "variable"; } + stream.eatWhile(/[_\w\d]/); + var word = stream.current(); + if (ops.test(word)) + return "builtin"; + else if (keywords.test(word)) + return "keyword"; + else + return "variable"; } function eatPnLocal(stream) { From 9296326b0a9e37489e00d4d7bfabd4725f6bfb7b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 26 Oct 2022 14:23:29 +0200 Subject: [PATCH 1816/1880] [javascript mode] Fix recognition of class property keywords before private names Closes https://github.com/codemirror/codemirror5/issues/6996 --- mode/javascript/javascript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 48a46d65d0..bb735ebc96 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -779,7 +779,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "async" || (type == "variable" && (value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) && - cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) { + cx.stream.match(/^\s+#?[\w$\xa1-\uffff]/, false))) { cx.marked = "keyword"; return cont(classBody); } From 2e3df70d4cfa5db5a9218893f2366fba7e59b928 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 15 Nov 2022 01:32:23 +0100 Subject: [PATCH 1817/1880] [pegjs mode] Remove useless lines --- mode/pegjs/pegjs.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/mode/pegjs/pegjs.js b/mode/pegjs/pegjs.js index c0ed2fcc06..c0012c5cf2 100644 --- a/mode/pegjs/pegjs.js +++ b/mode/pegjs/pegjs.js @@ -31,8 +31,6 @@ CodeMirror.defineMode("pegjs", function (config) { }; }, token: function (stream, state) { - if (stream) - //check for state changes if (!state.inString && !state.inComment && ((stream.peek() == '"') || (stream.peek() == "'"))) { state.stringType = stream.peek(); @@ -43,7 +41,6 @@ CodeMirror.defineMode("pegjs", function (config) { state.inComment = true; } - //return state if (state.inString) { while (state.inString && !stream.eol()) { if (stream.peek() === state.stringType) { From 407d1f1c896dd507095559466fedb3335b8e182f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 15 Nov 2022 01:33:47 +0100 Subject: [PATCH 1818/1880] [sql-hint addon] Make completion work when SQL isn't the outermost mode Closes https://github.com/codemirror/codemirror5/issues/5249 --- addon/hint/sql-hint.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/addon/hint/sql-hint.js b/addon/hint/sql-hint.js index 57c3b64f26..e01f502635 100644 --- a/addon/hint/sql-hint.js +++ b/addon/hint/sql-hint.js @@ -24,15 +24,13 @@ function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" } function getKeywords(editor) { - var mode = editor.doc.modeOption; - if (mode === "sql") mode = "text/x-sql"; - return CodeMirror.resolveMode(mode).keywords; + return editor.getModeAt(editor.getCursor()).keywords || CodeMirror.resolveMode("text/x-sql").keywords; } function getIdentifierQuote(editor) { - var mode = editor.doc.modeOption; - if (mode === "sql") mode = "text/x-sql"; - return CodeMirror.resolveMode(mode).identifierQuote || "`"; + return editor.getModeAt(editor.getCursor()).identifierQuote || + CodeMirror.resolveMode("text/x-sql").identifierQuote || + "`"; } function getText(item) { From 742627abcab8314dcabed2ce8ae6d347eaaf5512 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 15 Nov 2022 09:36:27 +0100 Subject: [PATCH 1819/1880] [sql-hint addon] Fix retrieving of parser config --- addon/hint/sql-hint.js | 10 ++++++---- mode/sql/sql.js | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/addon/hint/sql-hint.js b/addon/hint/sql-hint.js index e01f502635..61faec0bc0 100644 --- a/addon/hint/sql-hint.js +++ b/addon/hint/sql-hint.js @@ -23,14 +23,16 @@ function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" } + function getModeConf(editor) { + return editor.getModeAt(editor.getCursor()).config || CodeMirror.resolveMode("text/x-sql") + } + function getKeywords(editor) { - return editor.getModeAt(editor.getCursor()).keywords || CodeMirror.resolveMode("text/x-sql").keywords; + return getModeConf(editor).keywords || [] } function getIdentifierQuote(editor) { - return editor.getModeAt(editor.getCursor()).identifierQuote || - CodeMirror.resolveMode("text/x-sql").identifierQuote || - "`"; + return getModeConf(editor).identifierQuote || "`"; } function getText(item) { diff --git a/mode/sql/sql.js b/mode/sql/sql.js index 105b22ffb9..fedf6cd77c 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -207,7 +207,8 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { blockCommentStart: "/*", blockCommentEnd: "*/", lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : "--", - closeBrackets: "()[]{}''\"\"``" + closeBrackets: "()[]{}''\"\"``", + config: parserConfig }; }); From fe0bc6d5d5967ad4073805022b4e01e96a21bc1f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 20 Nov 2022 16:35:33 +0100 Subject: [PATCH 1820/1880] Mark version 5.65.10 --- CHANGELOG.md | 8 ++++++++ doc/manual.html | 2 +- doc/releases.html | 7 +++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8e118d258..41d7f0815d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 5.65.10 (2022-11-20) + +### Bug fixes + +[sql-hint addon](https://codemirror.net/5/doc/manual.html#addon_sql-hint): Fix completion when the SQL mode is wrapped by some outer mode. + +[javascript mode](https://codemirror.net/5/mode/javascript/index.html): Fix parsing of property keywords before private property names. + ## 5.65.9 (2022-09-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 9be3471a1c..19b21d8c1c 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

      User manual and reference guide - version 5.65.9 + version 5.65.10

      CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 9a8f368bc6..a20dfa0312 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -34,6 +34,13 @@

      Version 6.x

      Version 5.x

      +

      20-11-2022: Version 5.65.10:

      + +
        +
      • sql mode: Fix completion when the SQL mode is wrapped by some outer mode.
      • +
      • javascript mode: Fix parsing of property keywords before private property names.
      • +
      +

      20-09-2022: Version 5.65.9:

        diff --git a/index.html b/index.html index 33dd81f12d..75c53a2de0 100644 --- a/index.html +++ b/index.html @@ -92,7 +92,7 @@

        This is CodeMirror

        - Get the current version: 5.65.9.
        + Get the current version: 5.65.10.
        You can see the code,
        read the release notes,
        or study the user manual. diff --git a/package.json b/package.json index 4647fb121f..b6cde62684 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.65.9", + "version": "5.65.10", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 85841e7279..6d436dfbeb 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.65.9" +CodeMirror.version = "5.65.10" From 349c8a6c7adbb1a0d31b205260807f4f5847b1a6 Mon Sep 17 00:00:00 2001 From: DoctorKrolic <70431552+DoctorKrolic@users.noreply.github.com> Date: Tue, 29 Nov 2022 18:58:47 +0300 Subject: [PATCH 1821/1880] [clike mode] Add new C# keywords --- mode/clike/clike.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 748909efeb..8075edb8a1 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -512,8 +512,8 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { name: "clike", keywords: words("abstract as async await base break case catch checked class const continue" + " default delegate do else enum event explicit extern finally fixed for" + - " foreach goto if implicit in interface internal is lock namespace new" + - " operator out override params private protected public readonly ref return sealed" + + " foreach goto if implicit in init interface internal is lock namespace new" + + " operator out override params private protected public readonly record ref required return sealed" + " sizeof stackalloc static struct switch this throw try typeof unchecked" + " unsafe using virtual void volatile while add alias ascending descending dynamic from get" + " global group into join let orderby partial remove select set value var yield"), @@ -522,7 +522,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { " UInt64 bool byte char decimal double short int long object" + " sbyte float string ushort uint ulong"), blockKeywords: words("catch class do else finally for foreach if struct switch try while"), - defKeywords: words("class interface namespace struct var"), + defKeywords: words("class interface namespace record struct var"), typeFirstDefinitions: true, atoms: words("true false null"), hooks: { From 7814ddf4011a9ec479d378fe7f3623bea0b17faf Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 8 Dec 2022 08:21:15 +0100 Subject: [PATCH 1822/1880] [sql-hint addon] Reindent --- addon/hint/sql-hint.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/addon/hint/sql-hint.js b/addon/hint/sql-hint.js index 61faec0bc0..b4a919518e 100644 --- a/addon/hint/sql-hint.js +++ b/addon/hint/sql-hint.js @@ -109,9 +109,9 @@ var nameParts = getText(name).split("."); for (var i = 0; i < nameParts.length; i++) nameParts[i] = identifierQuote + - // duplicate identifierQuotes - nameParts[i].replace(new RegExp(identifierQuote,"g"), identifierQuote+identifierQuote) + - identifierQuote; + // duplicate identifierQuotes + nameParts[i].replace(new RegExp(identifierQuote,"g"), identifierQuote+identifierQuote) + + identifierQuote; var escaped = nameParts.join("."); if (typeof name == "string") return escaped; name = shallowClone(name); @@ -283,21 +283,21 @@ } return w; }; - addMatches(result, search, defaultTable, function(w) { + addMatches(result, search, defaultTable, function(w) { return objectOrClass(w, "CodeMirror-hint-table CodeMirror-hint-default-table"); - }); - addMatches( + }); + addMatches( result, search, tables, function(w) { return objectOrClass(w, "CodeMirror-hint-table"); } - ); - if (!disableKeywords) - addMatches(result, search, keywords, function(w) { + ); + if (!disableKeywords) + addMatches(result, search, keywords, function(w) { return objectOrClass(w.toUpperCase(), "CodeMirror-hint-keyword"); - }); - } + }); + } return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)}; }); From fbe612a66ab2a8063b6309c24d5cc613d8b80a50 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 8 Dec 2022 08:27:56 +0100 Subject: [PATCH 1823/1880] [sql-hint addon] Fix getting keywords from plain sql mode --- addon/hint/sql-hint.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addon/hint/sql-hint.js b/addon/hint/sql-hint.js index b4a919518e..5c9810537a 100644 --- a/addon/hint/sql-hint.js +++ b/addon/hint/sql-hint.js @@ -23,16 +23,16 @@ function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" } - function getModeConf(editor) { - return editor.getModeAt(editor.getCursor()).config || CodeMirror.resolveMode("text/x-sql") + function getModeConf(editor, field) { + return editor.getModeAt(editor.getCursor()).config[field] || CodeMirror.resolveMode("text/x-sql")[field] } function getKeywords(editor) { - return getModeConf(editor).keywords || [] + return getModeConf(editor, "keywords") || [] } function getIdentifierQuote(editor) { - return getModeConf(editor).identifierQuote || "`"; + return getModeConf(editor, "identifierQuote") || "`"; } function getText(item) { From d122e55c4818ef72e45939c4c06301bc36cb4a53 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 8 Dec 2022 08:35:20 +0100 Subject: [PATCH 1824/1880] [sql mode] Always enable tokenizing of dot-prefixed names --- mode/sql/sql.js | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/mode/sql/sql.js b/mode/sql/sql.js index fedf6cd77c..7b9dec7de1 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -94,9 +94,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { return "number"; if (stream.match(/^\.+/)) return null - // .table_name (ODBC) - // // ref: https://dev.mysql.com/doc/refman/8.0/en/identifier-qualifiers.html - if (support.ODBCdotTable && stream.match(/^[\w\d_$#]+/)) + if (stream.match(/^[\w\d_$#]+/)) return "variable-2"; } else if (operatorChars.test(ch)) { // operators @@ -295,7 +293,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { builtin: set(defaultBuiltin), atoms: set("false true null unknown"), dateSQL: set("date time timestamp"), - support: set("ODBCdotTable doubleQuote binaryNumber hexNumber") + support: set("doubleQuote binaryNumber hexNumber") }); CodeMirror.defineMIME("text/x-mssql", { @@ -322,7 +320,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { atoms: set("false true null unknown"), operatorChars: /^[*+\-%<>!=&|^]/, dateSQL: set("date time timestamp"), - support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"), + support: set("decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"), hooks: { "@": hookVar, "`": hookIdentifier, @@ -338,7 +336,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { atoms: set("false true null unknown"), operatorChars: /^[*+\-%<>!=&|^]/, dateSQL: set("date time timestamp"), - support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"), + support: set("decimallessFloat zerolessFloat binaryNumber hexNumber doubleQuote nCharCast charsetCast commentHash commentSpaceRequired"), hooks: { "@": hookVar, "`": hookIdentifier, @@ -409,7 +407,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { atoms: set("false true null unknown"), operatorChars: /^[*+\-%<>!=]/, dateSQL: set("date timestamp"), - support: set("ODBCdotTable doubleQuote binaryNumber hexNumber") + support: set("doubleQuote binaryNumber hexNumber") }); CodeMirror.defineMIME("text/x-pgsql", { @@ -424,7 +422,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { operatorChars: /^[*\/+\-%<>!=&|^\/#@?~]/, backslashStringEscapes: false, dateSQL: set("date time timestamp"), - support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast escapeConstant") + support: set("decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast escapeConstant") }); // Google's SQL-like query language, GQL @@ -446,7 +444,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { atoms: set("false true null unknown"), operatorChars: /^[*+\-%<>!=&|^\/#@?~]/, dateSQL: set("date time timestamp"), - support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast") + support: set("decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast") }); // Spark SQL @@ -457,7 +455,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { atoms: set("false true null"), operatorChars: /^[*\/+\-%<>!=~&|^]/, dateSQL: set("date time timestamp"), - support: set("ODBCdotTable doubleQuote zerolessFloat") + support: set("doubleQuote zerolessFloat") }); // Esper @@ -490,7 +488,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { dateSQL: set("date time timestamp zone"), // hexNumber is necessary for VARBINARY literals, e.g. X'65683F' // but it also enables 0xFF hex numbers, which Trino doesn't support. - support: set("ODBCdotTable decimallessFloat zerolessFloat hexNumber") + support: set("decimallessFloat zerolessFloat hexNumber") }); }); @@ -508,7 +506,6 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { Commands parsed and executed by the client (not the server). support: A list of supported syntaxes which are not common, but are supported by more than 1 DBMS. - * ODBCdotTable: .tableName * zerolessFloat: .1 * decimallessFloat: 1. * hexNumber: X'01AF' X'01af' x'01AF' x'01af' 0x01AF 0x01af From dd931d8f896de393b959f7519ff401071c09135b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 9 Dec 2022 10:47:14 +0100 Subject: [PATCH 1825/1880] Respect spellcheck/autocorrect/autocapitalize options in textarea input style Issue https://github.com/codemirror/codemirror5/issues/7009 --- src/input/ContentEditableInput.js | 1 + src/input/TextareaInput.js | 4 +++- src/input/input.js | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index ef2e41f51e..f789af74ee 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -94,6 +94,7 @@ export default class ContentEditableInput { } // Old-fashioned briefly-focus-a-textarea hack let kludge = hiddenTextarea(), te = kludge.firstChild + disableBrowserMagic(te) cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild) te.value = lastCopied.text.join("\n") let hadFocus = activeElt(div.ownerDocument) diff --git a/src/input/TextareaInput.js b/src/input/TextareaInput.js index 3db3f5f0f3..0aac125b11 100644 --- a/src/input/TextareaInput.js +++ b/src/input/TextareaInput.js @@ -1,6 +1,6 @@ import { operation, runInOp } from "../display/operations.js" import { prepareSelection } from "../display/selection.js" -import { applyTextInput, copyableRanges, handlePaste, hiddenTextarea, setLastCopied } from "./input.js" +import { applyTextInput, copyableRanges, handlePaste, hiddenTextarea, disableBrowserMagic, setLastCopied } from "./input.js" import { cursorCoords, posFromMouse } from "../measurement/position_measurement.js" import { eventInWidget } from "../measurement/widgets.js" import { simpleSelection } from "../model/selection.js" @@ -117,6 +117,8 @@ export default class TextareaInput { // The semihidden textarea that is focused when the editor is // focused, and receives input. this.textarea = this.wrapper.firstChild + let opts = this.cm.options + disableBrowserMagic(this.textarea, opts.spellcheck, opts.autocorrect, opts.autocapitalize) } screenReaderLabelChanged(label) { diff --git a/src/input/input.js b/src/input/input.js index e740106298..8b15639cfd 100644 --- a/src/input/input.js +++ b/src/input/input.js @@ -130,6 +130,5 @@ export function hiddenTextarea() { else te.setAttribute("wrap", "off") // If border: 0; -- iOS fails to open keyboard (issue #1287) if (ios) te.style.border = "1px solid black" - disableBrowserMagic(te) return div } From d4d7d3c4e18cc6bfff7136abc4cbd31bad194b6e Mon Sep 17 00:00:00 2001 From: "Joseph D. Purcell" Date: Wed, 7 Dec 2022 18:20:31 -0500 Subject: [PATCH 1826/1880] Use autocorrect and autocapitalize value of on instead of empty string --- src/input/input.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/input/input.js b/src/input/input.js index 8b15639cfd..b766d415db 100644 --- a/src/input/input.js +++ b/src/input/input.js @@ -114,8 +114,8 @@ export function copyableRanges(cm) { } export function disableBrowserMagic(field, spellcheck, autocorrect, autocapitalize) { - field.setAttribute("autocorrect", autocorrect ? "" : "off") - field.setAttribute("autocapitalize", autocapitalize ? "" : "off") + field.setAttribute("autocorrect", autocorrect ? "on" : "off") + field.setAttribute("autocapitalize", autocapitalize ? "on" : "off") field.setAttribute("spellcheck", !!spellcheck) } From f006b571d20b3b3e932b1d9013d73d0ada2c22bd Mon Sep 17 00:00:00 2001 From: "sahil.mahna" Date: Tue, 13 Dec 2022 17:46:27 +0530 Subject: [PATCH 1827/1880] Add keyboard spacebar interactive for merge editor buttons --- addon/merge/merge.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index d61051cf32..14362fa6e9 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -610,7 +610,7 @@ lock.setAttribute("tabindex", "0"); var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap"); CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); }); - CodeMirror.on(lock, "keyup", function(e) { e.key === "Enter" && setScrollLock(dv, !dv.lockScroll); }); + CodeMirror.on(lock, "keyup", function(e) { (e.key === "Enter" || e.code === "Space") && setScrollLock(dv, !dv.lockScroll); }); var gapElts = [lockWrap]; if (dv.mv.options.revertButtons !== false) { dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type); @@ -624,7 +624,7 @@ copyChunk(dv, dv.edit, dv.orig, node.chunk); } CodeMirror.on(dv.copyButtons, "click", copyButtons); - CodeMirror.on(dv.copyButtons, "keyup", function(e) { e.key === "Enter" && copyButtons(e); }); + CodeMirror.on(dv.copyButtons, "keyup", function(e) { (e.key === "Enter" || e.code === "Space") && copyButtons(e); }); gapElts.unshift(dv.copyButtons); } if (dv.mv.options.connect != "align") { From f124e299238f2b622a96761886d0d930b11d55d9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Dec 2022 11:11:01 +0100 Subject: [PATCH 1828/1880] Mark version 5.65.11 --- AUTHORS | 2 ++ CHANGELOG.md | 8 ++++++++ doc/manual.html | 2 +- doc/releases.html | 7 +++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 21 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 3d19b21470..72c1eaa757 100644 --- a/AUTHORS +++ b/AUTHORS @@ -238,6 +238,7 @@ Dimitri Mitropoulos Dinindu D. Wanniarachchi dmaclach Dmitry Kiselyov +DoctorKrolic domagoj412 Dominator008 Domizio Demichelis @@ -460,6 +461,7 @@ Jon Sangster Joo Joost-Wim Boekesteijn José dBruxelles +Joseph D. Purcell Joseph Pecoraro Josh Barnes Josh Cohen diff --git a/CHANGELOG.md b/CHANGELOG.md index 41d7f0815d..a4f6c93166 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 5.65.11 (2022-12-20) + +### Bug fixes + +Also respect autocapitalize/autocorrect/spellcheck options in textarea mode. + +[sql-hint addon](https://codemirror.net/5/doc/manual.html#addon_sql-hint): Fix keyword completion in generic SQL mode. + ## 5.65.10 (2022-11-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 19b21d8c1c..6598c9f52d 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

        User manual and reference guide - version 5.65.10 + version 5.65.11

        CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index a20dfa0312..20948676a4 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -34,6 +34,13 @@

        Version 6.x

        Version 5.x

        +

        20-12-2022: Version 5.65.11:

        + +
          +
        • Also respect autocapitalize/autocorrect/spellcheck options in textarea mode.
        • +
        • sql-hint addon: Fix keyword completion in generic SQL mode.
        • +
        +

        20-11-2022: Version 5.65.10:

          diff --git a/index.html b/index.html index 75c53a2de0..022d6d39c3 100644 --- a/index.html +++ b/index.html @@ -92,7 +92,7 @@

          This is CodeMirror

          - Get the current version: 5.65.10.
          + Get the current version: 5.65.11.
          You can see the code,
          read the release notes,
          or study the user manual. diff --git a/package.json b/package.json index b6cde62684..c845e8fbca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.65.10", + "version": "5.65.11", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 6d436dfbeb..7cbb5330b4 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.65.10" +CodeMirror.version = "5.65.11" From d4a6699187bb34ebf82321c227c0118f4c28f564 Mon Sep 17 00:00:00 2001 From: yoyoyodog123 <104166150+CommanderQuack@users.noreply.github.com> Date: Fri, 23 Dec 2022 03:07:17 -0600 Subject: [PATCH 1829/1880] [python mode] Add match/case to py3 keywords --- mode/python/python.js | 6 +++--- mode/python/test.js | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/mode/python/python.js b/mode/python/python.js index d75b021e2c..cbf12ad4b1 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -20,7 +20,7 @@ "def", "del", "elif", "else", "except", "finally", "for", "from", "global", "if", "import", "lambda", "pass", "raise", "return", - "try", "while", "with", "yield", "in"]; + "try", "while", "with", "yield", "in", "False", "True"]; var commonBuiltins = ["abs", "all", "any", "bin", "bool", "bytearray", "callable", "chr", "classmethod", "compile", "complex", "delattr", "dict", "dir", "divmod", "enumerate", "eval", "filter", "float", "format", "frozenset", @@ -60,7 +60,7 @@ if (py3) { // since http://legacy.python.org/dev/peps/pep-0465/ @ is also an operator var identifiers = parserConf.identifiers|| /^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*/; - myKeywords = myKeywords.concat(["nonlocal", "False", "True", "None", "async", "await"]); + myKeywords = myKeywords.concat(["nonlocal", "None", "async", "await", "match", "case"]); myBuiltins = myBuiltins.concat(["ascii", "bytes", "exec", "print"]); var stringPrefixes = new RegExp("^(([rbuf]|(br)|(rb)|(fr)|(rf))?('{3}|\"{3}|['\"]))", "i"); } else { @@ -68,7 +68,7 @@ myKeywords = myKeywords.concat(["exec", "print"]); myBuiltins = myBuiltins.concat(["apply", "basestring", "buffer", "cmp", "coerce", "execfile", "file", "intern", "long", "raw_input", "reduce", "reload", - "unichr", "unicode", "xrange", "False", "True", "None"]); + "unichr", "unicode", "xrange", "None"]); var stringPrefixes = new RegExp("^(([rubf]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i"); } var keywords = wordRegexp(myKeywords); diff --git a/mode/python/test.js b/mode/python/test.js index ca5da153dd..9fe1439f3f 100644 --- a/mode/python/test.js +++ b/mode/python/test.js @@ -71,4 +71,19 @@ " [keyword pass]", " [keyword else]:", " [variable baz]()") + + MT("dedentCase", + "[keyword match] [variable x]:", + " [keyword case] [variable y]:", + " [variable foo]()") + MT("dedentCasePass", + "[keyword match] [variable x]:", + " [keyword case] [variable y]:", + " [keyword pass]") + + MT("dedentCaseInFunction", + "[keyword def] [def foo]():", + " [keyword match] [variable x]:", + " [keyword case] [variable y]:", + " [variable foo]()") })(); From 9e864a1bb7c4c452f462d7f8d8be111c8bb8ad6f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 23 Dec 2022 10:17:29 +0100 Subject: [PATCH 1830/1880] Remove trailing whitespace --- mode/python/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/python/test.js b/mode/python/test.js index 9fe1439f3f..ade5498166 100644 --- a/mode/python/test.js +++ b/mode/python/test.js @@ -71,7 +71,7 @@ " [keyword pass]", " [keyword else]:", " [variable baz]()") - + MT("dedentCase", "[keyword match] [variable x]:", " [keyword case] [variable y]:", From 34b84359c4ce289086c82c203f66ef74614d8a0d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 24 Jan 2023 08:25:56 +0100 Subject: [PATCH 1831/1880] Update maintainer email --- LICENSE | 2 +- index.html | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index ff7db4b99f..9018d33e8f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (C) 2017 by Marijn Haverbeke and others +Copyright (C) 2017 by Marijn Haverbeke and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/index.html b/index.html index 022d6d39c3..bd697e9c72 100644 --- a/index.html +++ b/index.html @@ -152,7 +152,7 @@

          Community

          posted in the forum's "announce" category. If needed, you can - contact the maintainer + contact the maintainer directly. We aim to be an inclusive, welcoming community. To make that explicit, we have a code of diff --git a/package.json b/package.json index c845e8fbca..b2082c799d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "style": "lib/codemirror.css", "author": { "name": "Marijn Haverbeke", - "email": "marijnh@gmail.com", + "email": "marijn@haverbeke.berlin", "url": "http://marijnhaverbeke.nl" }, "description": "Full-featured in-browser code editor", From 58f592582f114919e980a8035a46327471c01527 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 2 Feb 2023 09:57:06 +0100 Subject: [PATCH 1832/1880] [bespin theme] Increase selection contrast Closes https://github.com/codemirror/codemirror5/issues/7018 --- theme/bespin.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/bespin.css b/theme/bespin.css index 60913ba938..3fd3d93a5a 100644 --- a/theme/bespin.css +++ b/theme/bespin.css @@ -9,7 +9,7 @@ */ .cm-s-bespin.CodeMirror {background: #28211c; color: #9d9b97;} -.cm-s-bespin div.CodeMirror-selected {background: #36312e !important;} +.cm-s-bespin div.CodeMirror-selected {background: #59554f !important;} .cm-s-bespin .CodeMirror-gutters {background: #28211c; border-right: 0px;} .cm-s-bespin .CodeMirror-linenumber {color: #666666;} .cm-s-bespin .CodeMirror-cursor {border-left: 1px solid #797977 !important;} From 659df46b1f53cd94952058e23687f9e58e1b997e Mon Sep 17 00:00:00 2001 From: yoyoyodog123 <104166150+Captain-Quack@users.noreply.github.com> Date: Tue, 14 Feb 2023 11:44:36 -0600 Subject: [PATCH 1833/1880] [python mode] Add new built-in functions - Aiter (added in 3.10) - Anext (added in 3.10) - Breakpoint (added in 3.7) --- mode/python/python.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/python/python.js b/mode/python/python.js index cbf12ad4b1..3946ceeeb0 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -60,7 +60,7 @@ if (py3) { // since http://legacy.python.org/dev/peps/pep-0465/ @ is also an operator var identifiers = parserConf.identifiers|| /^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*/; - myKeywords = myKeywords.concat(["nonlocal", "None", "async", "await", "match", "case"]); + myKeywords = myKeywords.concat(["nonlocal", "None", "aiter", "anext", "async", "await", "breakpoint", "match", "case"]); myBuiltins = myBuiltins.concat(["ascii", "bytes", "exec", "print"]); var stringPrefixes = new RegExp("^(([rbuf]|(br)|(rb)|(fr)|(rf))?('{3}|\"{3}|['\"]))", "i"); } else { From 6fc81b126fabd791a31d9c9d146f2aff32953d5b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 20 Feb 2023 11:55:39 +0100 Subject: [PATCH 1834/1880] Mark version 5.65.12 --- AUTHORS | 2 ++ CHANGELOG.md | 6 ++++++ doc/manual.html | 2 +- doc/releases.html | 6 ++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 18 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 72c1eaa757..13e0c7f48a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -799,6 +799,7 @@ ryu-sato sabaca sach.gupta Sachin Gupta +sahil.mahna Sam Lee Sam Rawlins Samuel Ainsworth @@ -964,6 +965,7 @@ Yash-Singh1 Yassin N. Hassan YNH Webdev yoongu +yoyoyodog123 Yunchi Luo Yuvi Panda Yvonnick Esnault diff --git a/CHANGELOG.md b/CHANGELOG.md index a4f6c93166..ab3ca34ee5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 5.65.12 (2023-02-20) + +### Bug fixes + +[python mode](https://codemirror.net/5/mode/python/): Add new built-ins and keywords. + ## 5.65.11 (2022-12-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 6598c9f52d..20ff731d01 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

          User manual and reference guide - version 5.65.11 + version 5.65.12

          CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 20948676a4..3e86d6e9eb 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -34,6 +34,12 @@

          Version 6.x

          Version 5.x

          +

          20-12-2022: Version 5.65.12:

          + + +

          20-12-2022: Version 5.65.11:

            diff --git a/index.html b/index.html index bd697e9c72..ea7dc4ffb8 100644 --- a/index.html +++ b/index.html @@ -92,7 +92,7 @@

            This is CodeMirror

            - Get the current version: 5.65.11.
            + Get the current version: 5.65.12.
            You can see the code,
            read the release notes,
            or study the user manual. diff --git a/package.json b/package.json index b2082c799d..6bdd100884 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.65.11", + "version": "5.65.12", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 7cbb5330b4..2becd5c766 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.65.11" +CodeMirror.version = "5.65.12" From 658bff7c56b7829aeabb8a914be5ca728d8aba0b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 24 Feb 2023 08:40:47 +0100 Subject: [PATCH 1835/1880] [sql mode] Make sure 'with' is highlighted as a keyword for PostgreSQL Closes https://github.com/codemirror/codemirror5/issues/7022 --- mode/sql/sql.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/sql/sql.js b/mode/sql/sql.js index 7b9dec7de1..d3983889f7 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -417,7 +417,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { // For pl/pgsql lang - https://github.com/postgres/postgres/blob/REL_11_2/src/pl/plpgsql/src/pl_scanner.c keywords: set(sqlKeywords + "a abort abs absent absolute access according action ada add admin after aggregate alias all allocate also alter always analyse analyze and any are array array_agg array_max_cardinality as asc asensitive assert assertion assignment asymmetric at atomic attach attribute attributes authorization avg backward base64 before begin begin_frame begin_partition bernoulli between bigint binary bit bit_length blob blocked bom boolean both breadth by c cache call called cardinality cascade cascaded case cast catalog catalog_name ceil ceiling chain char char_length character character_length character_set_catalog character_set_name character_set_schema characteristics characters check checkpoint class class_origin clob close cluster coalesce cobol collate collation collation_catalog collation_name collation_schema collect column column_name columns command_function command_function_code comment comments commit committed concurrently condition condition_number configuration conflict connect connection connection_name constant constraint constraint_catalog constraint_name constraint_schema constraints constructor contains content continue control conversion convert copy corr corresponding cost count covar_pop covar_samp create cross csv cube cume_dist current current_catalog current_date current_default_transform_group current_path current_role current_row current_schema current_time current_timestamp current_transform_group_for_type current_user cursor cursor_name cycle data database datalink datatype date datetime_interval_code datetime_interval_precision day db deallocate debug dec decimal declare default defaults deferrable deferred defined definer degree delete delimiter delimiters dense_rank depends depth deref derived desc describe descriptor detach detail deterministic diagnostics dictionary disable discard disconnect dispatch distinct dlnewcopy dlpreviouscopy dlurlcomplete dlurlcompleteonly dlurlcompletewrite dlurlpath dlurlpathonly dlurlpathwrite dlurlscheme dlurlserver dlvalue do document domain double drop dump dynamic dynamic_function dynamic_function_code each element else elseif elsif empty enable encoding encrypted end end_frame end_partition endexec enforced enum equals errcode error escape event every except exception exclude excluding exclusive exec execute exists exit exp explain expression extension external extract false family fetch file filter final first first_value flag float floor following for force foreach foreign fortran forward found frame_row free freeze from fs full function functions fusion g general generated get global go goto grant granted greatest group grouping groups handler having header hex hierarchy hint hold hour id identity if ignore ilike immediate immediately immutable implementation implicit import in include including increment indent index indexes indicator info inherit inherits initially inline inner inout input insensitive insert instance instantiable instead int integer integrity intersect intersection interval into invoker is isnull isolation join k key key_member key_type label lag language large last last_value lateral lead leading leakproof least left length level library like like_regex limit link listen ln load local localtime localtimestamp location locator lock locked log logged loop lower m map mapping match matched materialized max max_cardinality maxvalue member merge message message_length message_octet_length message_text method min minute minvalue mod mode modifies module month more move multiset mumps name names namespace national natural nchar nclob nesting new next nfc nfd nfkc nfkd nil no none normalize normalized not nothing notice notify notnull nowait nth_value ntile null nullable nullif nulls number numeric object occurrences_regex octet_length octets of off offset oids old on only open operator option options or order ordering ordinality others out outer output over overlaps overlay overriding owned owner p pad parallel parameter parameter_mode parameter_name parameter_ordinal_position parameter_specific_catalog parameter_specific_name parameter_specific_schema parser partial partition pascal passing passthrough password path percent percent_rank percentile_cont percentile_disc perform period permission pg_context pg_datatype_name pg_exception_context pg_exception_detail pg_exception_hint placing plans pli policy portion position position_regex power precedes preceding precision prepare prepared preserve primary print_strict_params prior privileges procedural procedure procedures program public publication query quote raise range rank read reads real reassign recheck recovery recursive ref references referencing refresh regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy regr_syy reindex relative release rename repeatable replace replica requiring reset respect restart restore restrict result result_oid return returned_cardinality returned_length returned_octet_length returned_sqlstate returning returns reverse revoke right role rollback rollup routine routine_catalog routine_name routine_schema routines row row_count row_number rows rowtype rule savepoint scale schema schema_name schemas scope scope_catalog scope_name scope_schema scroll search second section security select selective self sensitive sequence sequences serializable server server_name session session_user set setof sets share show similar simple size skip slice smallint snapshot some source space specific specific_name specifictype sql sqlcode sqlerror sqlexception sqlstate sqlwarning sqrt stable stacked standalone start state statement static statistics stddev_pop stddev_samp stdin stdout storage strict strip structure style subclass_origin submultiset subscription substring substring_regex succeeds sum symmetric sysid system system_time system_user t table table_name tables tablesample tablespace temp template temporary text then ties time timestamp timezone_hour timezone_minute to token top_level_count trailing transaction transaction_active transactions_committed transactions_rolled_back transform transforms translate translate_regex translation treat trigger trigger_catalog trigger_name trigger_schema trim trim_array true truncate trusted type types uescape unbounded uncommitted under unencrypted union unique unknown unlink unlisten unlogged unnamed unnest until untyped update upper uri usage use_column use_variable user user_defined_type_catalog user_defined_type_code user_defined_type_name user_defined_type_schema using vacuum valid validate validator value value_of values var_pop var_samp varbinary varchar variable_conflict variadic varying verbose version versioning view views volatile warning when whenever where while whitespace width_bucket window with within without work wrapper write xml xmlagg xmlattributes xmlbinary xmlcast xmlcomment xmlconcat xmldeclaration xmldocument xmlelement xmlexists xmlforest xmliterate xmlnamespaces xmlparse xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltext xmlvalidate year yes zone"), // https://www.postgresql.org/docs/11/datatype.html - builtin: set("bigint int8 bigserial serial8 bit varying varbit boolean bool box bytea character char varchar cidr circle date double precision float8 inet integer int int4 interval json jsonb line lseg macaddr macaddr8 money numeric decimal path pg_lsn point polygon real float4 smallint int2 smallserial serial2 serial serial4 text time without zone with timetz timestamp timestamptz tsquery tsvector txid_snapshot uuid xml"), + builtin: set("bigint int8 bigserial serial8 bit varying varbit boolean bool box bytea character char varchar cidr circle date double precision float8 inet integer int int4 interval json jsonb line lseg macaddr macaddr8 money numeric decimal path pg_lsn point polygon real float4 smallint int2 smallserial serial2 serial serial4 text time zone timetz timestamp timestamptz tsquery tsvector txid_snapshot uuid xml"), atoms: set("false true null unknown"), operatorChars: /^[*\/+\-%<>!=&|^\/#@?~]/, backslashStringEscapes: false, From 6a705898e74e223b74e02fe59f60af83074205a0 Mon Sep 17 00:00:00 2001 From: Brett Morgan Date: Fri, 3 Mar 2023 10:10:22 +1100 Subject: [PATCH 1836/1880] [dart mode] Add keywords --- mode/dart/dart.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/dart/dart.js b/mode/dart/dart.js index 340076712c..54aedf3297 100644 --- a/mode/dart/dart.js +++ b/mode/dart/dart.js @@ -15,7 +15,7 @@ "implements mixin get native set typedef with enum throw rethrow " + "assert break case continue default in return new deferred async await covariant " + "try catch finally do else for if switch while import library export " + - "part of show hide is as extension on yield late required").split(" "); + "part of show hide is as extension on yield late required sealed base interface when").split(" "); var blockKeywords = "try catch finally do else for if switch while".split(" "); var atoms = "true false null".split(" "); var builtins = "void bool num int double dynamic var String Null Never".split(" "); From c17c5f0abe0147151d834e8eec9c400ec327120a Mon Sep 17 00:00:00 2001 From: Brett Morgan Date: Wed, 8 Mar 2023 21:26:18 +1100 Subject: [PATCH 1837/1880] [dart mode] Add `inline` keyword for inline classes Context: https://github.com/dart-lang/language/blob/master/accepted/future-releases/inline-classes/feature-specification.md Related: https://github.com/dart-lang/sdk/issues/49734 --- mode/dart/dart.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mode/dart/dart.js b/mode/dart/dart.js index 54aedf3297..f81e4f91a4 100644 --- a/mode/dart/dart.js +++ b/mode/dart/dart.js @@ -12,10 +12,10 @@ "use strict"; var keywords = ("this super static final const abstract class extends external factory " + - "implements mixin get native set typedef with enum throw rethrow " + - "assert break case continue default in return new deferred async await covariant " + - "try catch finally do else for if switch while import library export " + - "part of show hide is as extension on yield late required sealed base interface when").split(" "); + "implements mixin get native set typedef with enum throw rethrow assert break case " + + "continue default in return new deferred async await covariant try catch finally " + + "do else for if switch while import library export part of show hide is as extension " + + "on yield late required sealed base interface when inline").split(" "); var blockKeywords = "try catch finally do else for if switch while".split(" "); var atoms = "true false null".split(" "); var builtins = "void bool num int double dynamic var String Null Never".split(" "); From 9974ded36bf01746eb2a00926916fef834d3d0d0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 16 Mar 2023 17:45:22 +0100 Subject: [PATCH 1838/1880] [clike mode] Properly match character literals in Scala mode --- mode/clike/clike.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 8075edb8a1..fcfc7c45cc 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -613,6 +613,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { return state.tokenize(stream, state); }, "'": function(stream) { + if (stream.match(/^(\\[^'\s]+|[^\\'])'/)) return "string-2" stream.eatWhile(/[\w\$_\xa1-\uffff]/); return "atom"; }, From 330a06dd6ece17833f0127093d44ae18a1a5c451 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 27 Apr 2023 10:23:26 +0200 Subject: [PATCH 1839/1880] Mark version 5.65.13 --- AUTHORS | 1 + CHANGELOG.md | 8 ++++++++ doc/manual.html | 2 +- doc/releases.html | 7 +++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 20 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 13e0c7f48a..3dd26e0fbb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -139,6 +139,7 @@ Brad Metcalf Brandon Frohs Brandon Wamboldt Bret Little +Brett Morgan Brett Zamir Brian Grinstead BrianHung diff --git a/CHANGELOG.md b/CHANGELOG.md index ab3ca34ee5..3daac7a9ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 5.65.13 (2023-04-27) + +### Bug fixes + +[dart mode](https://codemirror.net/5/mode/dart/index.html): Add some new keywords. + +[clike mode](https://codemirror.net/5/mode/clike/): Tokenize Scala character literals. + ## 5.65.12 (2023-02-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 20ff731d01..7d3667f90d 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

            User manual and reference guide - version 5.65.12 + version 5.65.13

            CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 3e86d6e9eb..40f7e16031 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -34,6 +34,13 @@

            Version 6.x

            Version 5.x

            +

            20-12-2022: Version 5.65.13:

            + + +

            20-12-2022: Version 5.65.12:

              diff --git a/index.html b/index.html index ea7dc4ffb8..2adb14b3ed 100644 --- a/index.html +++ b/index.html @@ -92,7 +92,7 @@

              This is CodeMirror

              - Get the current version: 5.65.12.
              + Get the current version: 5.65.13.
              You can see the code,
              read the release notes,
              or study the user manual. diff --git a/package.json b/package.json index 6bdd100884..3af57c7282 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.65.12", + "version": "5.65.13", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 2becd5c766..d41a4e45c0 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.65.12" +CodeMirror.version = "5.65.13" From 480a35d793745572de439a5aaa44fd4fe74a2bb3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 27 Apr 2023 10:39:13 +0200 Subject: [PATCH 1840/1880] Fix error output in release upload script --- bin/upload-release.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/upload-release.js b/bin/upload-release.js index 59ed6f5a8f..336a37ecd0 100644 --- a/bin/upload-release.js +++ b/bin/upload-release.js @@ -24,7 +24,7 @@ function post(host, path, body) { } else if (res.statusCode >= 400) { console.error(res.statusCode, res.statusMessage) res.on("data", d => console.log(d.toString())) - res.on("end", process.exit(1)) + res.on("end", () => process.exit(1)) } }) req.write(body) From 1e58b28781af0d2a9fc426c744dcdc22c6216dd6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 29 Jun 2023 17:15:39 +0200 Subject: [PATCH 1841/1880] [lint addon] Remove confused annotation filtering --- addon/lint/lint.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 7b40e10e91..052313dc5c 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -199,10 +199,6 @@ var anns = annotations[line]; if (!anns) continue; - // filter out duplicate messages - var message = []; - anns = anns.filter(function(item) { return message.indexOf(item.message) > -1 ? false : message.push(item.message) }); - var maxSeverity = null; var tipLabel = state.hasGutter && document.createDocumentFragment(); @@ -220,9 +216,8 @@ __annotation: ann })); } - // use original annotations[line] to show multiple messages if (state.hasGutter) - cm.setGutterMarker(line, GUTTER_ID, makeMarker(cm, tipLabel, maxSeverity, annotations[line].length > 1, + cm.setGutterMarker(line, GUTTER_ID, makeMarker(cm, tipLabel, maxSeverity, anns.length > 1, options.tooltips)); if (options.highlightLines) From a0854c752a76e4ba9512a9beedb9076f36e4f8f9 Mon Sep 17 00:00:00 2001 From: "Jan T. Sott" Date: Mon, 3 Jul 2023 09:54:01 +0200 Subject: [PATCH 1842/1880] [nsis mode] Add !assert command --- mode/nsis/nsis.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/nsis/nsis.js b/mode/nsis/nsis.js index 2173916bb2..de18871251 100644 --- a/mode/nsis/nsis.js +++ b/mode/nsis/nsis.js @@ -24,7 +24,7 @@ CodeMirror.defineSimpleMode("nsis",{ { regex: /`(?:[^\\`]|\\.)*`?/, token: "string" }, // Compile Time Commands - {regex: /^\s*(?:\!(addincludedir|addplugindir|appendfile|cd|define|delfile|echo|error|execute|finalize|getdllversion|gettlbversion|include|insertmacro|macro|macroend|makensis|packhdr|pragma|searchparse|searchreplace|system|tempfile|undef|uninstfinalize|verbose|warning))\b/i, token: "keyword"}, + {regex: /^\s*(?:\!(addincludedir|addplugindir|appendfile|assert|cd|define|delfile|echo|error|execute|finalize|getdllversion|gettlbversion|include|insertmacro|macro|macroend|makensis|packhdr|pragma|searchparse|searchreplace|system|tempfile|undef|uninstfinalize|verbose|warning))\b/i, token: "keyword"}, // Conditional Compilation {regex: /^\s*(?:\!(if(?:n?def)?|ifmacron?def|macro))\b/i, token: "keyword", indent: true}, From 69e38f574c03bc2d46c806ffc5f652d31d071c21 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 15 Jul 2023 08:59:15 +0200 Subject: [PATCH 1843/1880] [java mode] Fix indentation after class extends clause Closes https://github.com/codemirror/codemirror5/issues/7049 --- mode/clike/clike.js | 3 ++- mode/clike/test.js | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index fcfc7c45cc..e9f441fc0a 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -218,7 +218,8 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { }, indent: function(state, textAfter) { - if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass; + if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine && isTopScope(state.context)) + return CodeMirror.Pass; var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); var closing = firstChar == ctx.type; if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; diff --git a/mode/clike/test.js b/mode/clike/test.js index 80d8ea4548..2933a00277 100644 --- a/mode/clike/test.js +++ b/mode/clike/test.js @@ -162,4 +162,9 @@ "[type StringBuffer];", "[type StringBuilder];", "[type Void];"); + + MTJAVA("indent", + "[keyword public] [keyword class] [def A] [keyword extends] [variable B]", + "{", + " [variable c]()") })(); From 82ce3d2f64b18e86306a9d9da85beeba4e17834e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 17 Jul 2023 09:35:44 +0200 Subject: [PATCH 1844/1880] Mark version 5.65.14 --- CHANGELOG.md | 10 ++++++++++ doc/manual.html | 2 +- doc/releases.html | 12 ++++++++++-- index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3daac7a9ac..4ef2a2cc79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 5.65.14 (2023-07-17) + +### Bug fixes + +[clike mode](https://codemirror.net/5/mode/clike/): Fix poor indentation in some Java code. + +[nsis mode](https://codemirror.net/5/mode/nsis/index.html): Recognize `!assert` command. + +[lint addon](https://codemirror.net/5/doc/manual.html#addon_lint): Remove broken annotation deduplication. + ## 5.65.13 (2023-04-27) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 7d3667f90d..873bd4a6a9 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

              User manual and reference guide - version 5.65.13 + version 5.65.14

              CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 40f7e16031..e8b6ccae7c 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -34,14 +34,22 @@

              Version 6.x

              Version 5.x

              -

              20-12-2022: Version 5.65.13:

              +

              17-07-2023: Version 5.65.14:

              + +
                +
              • clike mode: Fix poor indentation in some Java code.
              • +
              • nsis mode: Recognize !assert command.
              • +
              • lint addon: Remove broken annotation deduplication.
              • +
              + +

              27-04-2023: Version 5.65.13:

              -

              20-12-2022: Version 5.65.12:

              +

              20-02-2023: Version 5.65.12:

              • python mode: Add new built-ins and keywords.
              • diff --git a/index.html b/index.html index 2adb14b3ed..728b0bfb62 100644 --- a/index.html +++ b/index.html @@ -92,7 +92,7 @@

                This is CodeMirror

                - Get the current version: 5.65.13.
                + Get the current version: 5.65.14.
                You can see the code,
                read the release notes,
                or study the user manual. diff --git a/package.json b/package.json index 3af57c7282..a9c6f80eb6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.65.13", + "version": "5.65.14", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index d41a4e45c0..834e27eb45 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.65.13" +CodeMirror.version = "5.65.14" From 370f7c4a7222211987a826b0e9f43d8980229c64 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 21 Jul 2023 21:23:28 +0200 Subject: [PATCH 1845/1880] [lint addon] Make sure tooltips don't stick out of the window width Issue https://github.com/codemirror/codemirror5/pull/7044 --- addon/lint/lint.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 052313dc5c..21631b9d24 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -24,8 +24,10 @@ function position(e) { if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); - tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; - tt.style.left = (e.clientX + 5) + "px"; + var top = Math.max(0, e.clientY - tt.offsetHeight - 5); + var left = Math.max(0, Math.min(e.clientX + 5, tt.ownerDocument.defaultView.innerWidth - tt.offsetWidth)); + tt.style.top = top + "px" + tt.style.left = left + "px"; } CodeMirror.on(document, "mousemove", position); position(e); From 817ea7be474c3452a78864c05aa7f38ec8f2ff85 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 31 Jul 2023 21:21:56 +0200 Subject: [PATCH 1846/1880] Fix install example in readme Closes https://github.com/codemirror/codemirror5/issues/7051 --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 578a5a9730..e021f2bf7a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # CodeMirror [![Build Status](https://github.com/codemirror/codemirror5/workflows/main/badge.svg)](https://github.com/codemirror/codemirror5/actions) -[![NPM version](https://img.shields.io/npm/v/codemirror.svg)](https://www.npmjs.org/package/codemirror) CodeMirror is a versatile text editor implemented in JavaScript for the browser. It is specialized for editing code, and comes with over @@ -33,7 +32,7 @@ Either get the [zip file](https://codemirror.net/5/codemirror.zip) with the latest version, or make sure you have [Node](https://nodejs.org/) installed and run: - npm install codemirror + npm install codemirror@5 **NOTE**: This is the source repository for the library, and not the distribution channel. Cloning it is not the recommended way to install From 4ea5f465587e1624b668ae98738ffafc1bef71de Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 9 Aug 2023 22:54:39 +0200 Subject: [PATCH 1847/1880] [yaml mode] Fix exponential regexp Closes https://github.com/codemirror/codemirror5/issues/7053 --- mode/yaml/yaml.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/yaml/yaml.js b/mode/yaml/yaml.js index 298db55f6f..895d1330a2 100644 --- a/mode/yaml/yaml.js +++ b/mode/yaml/yaml.js @@ -85,7 +85,7 @@ CodeMirror.defineMode("yaml", function() { } /* pairs (associative arrays) -> key */ - if (!state.pair && stream.match(/^\s*(?:[,\[\]{}&*!|>'"%@`][^\s'":]|[^,\[\]{}#&*!|>'"%@`])[^#]*?(?=\s*:($|\s))/)) { + if (!state.pair && stream.match(/^\s*(?:[,\[\]{}&*!|>'"%@`][^\s'":]|[^\s,\[\]{}#&*!|>'"%@`])[^#:]*(?=:($|\s))/)) { state.pair = true; state.keyCol = stream.indentation(); return "atom"; From 854ee51ef20434eae043d64f92e6f8548d569030 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 29 Aug 2023 08:59:28 +0200 Subject: [PATCH 1848/1880] Mark version 5.65.15 --- CHANGELOG.md | 8 ++++++++ doc/manual.html | 2 +- doc/releases.html | 7 +++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 6 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ef2a2cc79..31c9043708 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 5.65.15 (2023-08-29) + +### Bug fixes + +[lint addon](https://codemirror.net/5/doc/manual.html#addon_lint): Prevent tooltips from sticking out of the viewport. + +[yaml mode](https://codemirror.net/5/mode/yaml/): Fix an exponential-complexity regular expression. + ## 5.65.14 (2023-07-17) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 873bd4a6a9..7496ff277a 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

                User manual and reference guide - version 5.65.14 + version 5.65.15

                CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index e8b6ccae7c..5d94bad1fb 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -34,6 +34,13 @@

                Version 6.x

                Version 5.x

                +

                29-08-2023: Version 5.65.15:

                + +
                  +
                • lint addon: Prevent tooltips from sticking out of the viewport.
                • +
                • yaml mode: Fix an exponential-complexity regular expression.
                • +
                +

                17-07-2023: Version 5.65.14:

                  diff --git a/index.html b/index.html index 728b0bfb62..319adcbaa9 100644 --- a/index.html +++ b/index.html @@ -92,7 +92,7 @@

                  This is CodeMirror

                  - Get the current version: 5.65.14.
                  + Get the current version: 5.65.15.
                  You can see the code,
                  read the release notes,
                  or study the user manual. diff --git a/package.json b/package.json index a9c6f80eb6..eb0c44cf09 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.65.14", + "version": "5.65.15", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 834e27eb45..f69663b6fe 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.65.14" +CodeMirror.version = "5.65.15" From 638abda97cf458d9243804b75de53714209e8632 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 1 Sep 2023 08:56:11 +0200 Subject: [PATCH 1849/1880] [go mode] Allow underscore separators in numbers Closes https://github.com/codemirror/codemirror5/issues/7059 --- mode/go/go.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mode/go/go.js b/mode/go/go.js index 8dbdc65d1c..bd54f1ab03 100644 --- a/mode/go/go.js +++ b/mode/go/go.js @@ -46,11 +46,11 @@ CodeMirror.defineMode("go", function(config) { } if (/[\d\.]/.test(ch)) { if (ch == ".") { - stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/); + stream.match(/^[0-9_]+([eE][\-+]?[0-9_]+)?/); } else if (ch == "0") { - stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/); + stream.match(/^[xX][0-9a-fA-F_]+/) || stream.match(/^[0-7_]+/); } else { - stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/); + stream.match(/^[0-9_]*\.?[0-9_]*([eE][\-+]?[0-9_]+)?/); } return "number"; } From ee6a1d201f748fa6b777513e4998eb652df896ed Mon Sep 17 00:00:00 2001 From: Parker Lougheed Date: Sun, 10 Sep 2023 10:35:37 -0500 Subject: [PATCH 1850/1880] [dart mode] Remove support for inline keyword --- mode/dart/dart.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/dart/dart.js b/mode/dart/dart.js index f81e4f91a4..ba9ff3dd2c 100644 --- a/mode/dart/dart.js +++ b/mode/dart/dart.js @@ -15,7 +15,7 @@ "implements mixin get native set typedef with enum throw rethrow assert break case " + "continue default in return new deferred async await covariant try catch finally " + "do else for if switch while import library export part of show hide is as extension " + - "on yield late required sealed base interface when inline").split(" "); + "on yield late required sealed base interface when").split(" "); var blockKeywords = "try catch finally do else for if switch while".split(" "); var atoms = "true false null".split(" "); var builtins = "void bool num int double dynamic var String Null Never".split(" "); From 53faa33ac69598b7495e160824b58ebb8d70fe97 Mon Sep 17 00:00:00 2001 From: Parker Lougheed Date: Sun, 10 Sep 2023 10:36:12 -0500 Subject: [PATCH 1851/1880] [dart mdoe] Fix code example to compile and run with modern Dart versions --- mode/dart/index.html | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mode/dart/index.html b/mode/dart/index.html index 88b8936dec..ee6128c1f7 100644 --- a/mode/dart/index.html +++ b/mode/dart/index.html @@ -29,33 +29,33 @@

                  Dart mode

                  import 'dart:math' show Random; void main() { - print(new Die(n: 12).roll()); + print(Die(n: 12).roll()); } // Define a class. class Die { // Define a class variable. - static Random shaker = new Random(); + static final Random shaker = Random(); // Define instance variables. - int sides, value; - - // Define a method using shorthand syntax. - String toString() => '$value'; + final int sides; + int? lastRoll; // Define a constructor. - Die({int n: 6}) { - if (4 <= n && n <= 20) { - sides = n; - } else { + Die({int n = 6}) : sides = n { + if (4 > n || n > 20) { // Support for errors and exceptions. - throw new ArgumentError(/* */); + throw ArgumentError(/* */); } } + // Define a method using shorthand syntax. + @override + String toString() => '$lastRoll'; + // Define an instance method. int roll() { - return value = shaker.nextInt(sides) + 1; + return lastRoll = shaker.nextInt(sides) + 1; } } From 3bb9e7a38a9b95c66538676100fcced9cfe264ef Mon Sep 17 00:00:00 2001 From: Gabriela Gutierrez Date: Thu, 21 Sep 2023 11:27:55 -0300 Subject: [PATCH 1852/1880] Ref actions by commit SHA in ci.yml It's important to make sure the SHA's are from the original repositories and not forks. For reference: https://github.com/actions/checkout/releases/tag/v4.0.0 https://github.com/actions/checkout/commit/3df4ab11eba7bda6032a0b82a6bb43b11571feac https://github.com/actions/cache/releases/tag/v3.3.2 https://github.com/actions/cache/commit/704facf57e6136b1bc63b828d79edcd491f0ee84 Signed-off-by: Gabriela Gutierrez --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82d6354155..d0a07b4e07 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,9 +5,9 @@ jobs: runs-on: ubuntu-latest name: Build and test steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0 - - uses: actions/cache@v2 + - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2 with: path: '/home/runner/work/codemirror/codemirror5/node_modules' key: ${{ runner.os }}-modules From 2329ebb19b9846d1306c2379a5c85858df85e71f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 18 Oct 2023 17:54:08 +0200 Subject: [PATCH 1853/1880] Link to CM6 in readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e021f2bf7a..6f42e99c50 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# CodeMirror +# CodeMirror 5 + +**NOTE:** [CodeMirror 6](https://codemirror.net/) exists, and is more mobile-friendly, more accessible, better designed, and much more actively maintained. [![Build Status](https://github.com/codemirror/codemirror5/workflows/main/badge.svg)](https://github.com/codemirror/codemirror5/actions) From bcb86262e8a2a606bfa13ed47f8c6171b4d37ac9 Mon Sep 17 00:00:00 2001 From: Luke Haas Date: Wed, 25 Oct 2023 17:13:13 +0100 Subject: [PATCH 1854/1880] [jsx mode] Support trailing-comma generics syntax in JSX with TS Issue https://github.com/codemirror/codemirror5/pull/7073 --- mode/jsx/jsx.js | 2 +- mode/jsx/test.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mode/jsx/jsx.js b/mode/jsx/jsx.js index 1406ef195d..83141c0567 100644 --- a/mode/jsx/jsx.js +++ b/mode/jsx/jsx.js @@ -103,7 +103,7 @@ } function jsToken(stream, state, cx) { - if (stream.peek() == "<" && jsMode.expressionAllowed(stream, cx.state)) { + if (stream.peek() == "<" && !/,\s*>/.test(stream.string) && jsMode.expressionAllowed(stream, cx.state)) { state.context = new Context(CodeMirror.startState(xmlMode, jsMode.indent(cx.state, "", "")), xmlMode, 0, state.context) jsMode.skipExpression(cx.state) diff --git a/mode/jsx/test.js b/mode/jsx/test.js index 08a0d47c3e..606557363a 100644 --- a/mode/jsx/test.js +++ b/mode/jsx/test.js @@ -95,4 +95,6 @@ "[bracket&tag <][tag MyComponent] [attribute foo]=[string \"bar\"] [bracket&tag />]; [comment //ok]", "[bracket&tag <][tag MyComponent] [attribute foo]={[number 0]} [bracket&tag />]; [comment //error]") + TS("tsx_react_generics", + "[variable x] [operator =] [operator <] [variable T],[operator >] ([def v]: [type T]) [operator =>] [variable-2 v];") })() From adc4282471ee15e2c91b7da7d5398cd1b8eee978 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 27 Oct 2023 10:34:12 +0200 Subject: [PATCH 1855/1880] [jsx mode] Narrow test for trailing-comma generic Issue https://github.com/codemirror/codemirror5/pull/7073 --- mode/jsx/jsx.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mode/jsx/jsx.js b/mode/jsx/jsx.js index 83141c0567..35ac608e16 100644 --- a/mode/jsx/jsx.js +++ b/mode/jsx/jsx.js @@ -103,7 +103,8 @@ } function jsToken(stream, state, cx) { - if (stream.peek() == "<" && !/,\s*>/.test(stream.string) && jsMode.expressionAllowed(stream, cx.state)) { + if (stream.peek() == "<" && !stream.match(/^<([^<>]|<[^>]*>)+,\s*>/, false) && + jsMode.expressionAllowed(stream, cx.state)) { state.context = new Context(CodeMirror.startState(xmlMode, jsMode.indent(cx.state, "", "")), xmlMode, 0, state.context) jsMode.skipExpression(cx.state) From 676fc52bf13e8788636af2cd4519e6b50c1f5adc Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Fri, 10 Nov 2023 23:42:44 -0800 Subject: [PATCH 1856/1880] Make active element tracking work inside closed shadow roots --- src/display/operations.js | 4 ++-- src/display/update_display.js | 6 +++--- src/edit/fromTextArea.js | 4 ++-- src/edit/key_events.js | 4 ++-- src/edit/methods.js | 4 ++-- src/edit/mouse_events.js | 6 +++--- src/input/ContentEditableInput.js | 8 ++++---- src/input/TextareaInput.js | 4 ++-- src/util/dom.js | 14 ++++++++++++-- 9 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/display/operations.js b/src/display/operations.js index b004575bb9..a7e8039e89 100644 --- a/src/display/operations.js +++ b/src/display/operations.js @@ -2,7 +2,7 @@ import { clipPos } from "../line/pos.js" import { findMaxLine } from "../line/spans.js" import { displayWidth, measureChar, scrollGap } from "../measurement/position_measurement.js" import { signal } from "../util/event.js" -import { activeElt, doc } from "../util/dom.js" +import { activeElt, root } from "../util/dom.js" import { finishOperation, pushOperation } from "../util/operation_group.js" import { ensureFocus } from "./focus.js" @@ -116,7 +116,7 @@ function endOperation_W2(op) { cm.display.maxLineChanged = false } - let takeFocus = op.focus && op.focus == activeElt(doc(cm)) + let takeFocus = op.focus && op.focus == activeElt(root(cm)) if (op.preparedSelection) cm.display.input.showSelection(op.preparedSelection, takeFocus) if (op.updatedDisplay || op.startHeight != cm.doc.height) diff --git a/src/display/update_display.js b/src/display/update_display.js index 63529d5188..665dc8c91a 100644 --- a/src/display/update_display.js +++ b/src/display/update_display.js @@ -3,7 +3,7 @@ import { heightAtLine, visualLineEndNo, visualLineNo } from "../line/spans.js" import { getLine, lineNumberFor } from "../line/utils_line.js" import { displayHeight, displayWidth, getDimensions, paddingVert, scrollGap } from "../measurement/position_measurement.js" import { mac, webkit } from "../util/browser.js" -import { activeElt, removeChildren, contains, win, doc } from "../util/dom.js" +import { activeElt, removeChildren, contains, win, root, rootNode } from "../util/dom.js" import { hasHandler, signal } from "../util/event.js" import { signalLater } from "../util/operation_group.js" import { indexOf } from "../util/misc.js" @@ -57,7 +57,7 @@ export function maybeClipScrollbars(cm) { function selectionSnapshot(cm) { if (cm.hasFocus()) return null - let active = activeElt(doc(cm)) + let active = activeElt(root(cm)) if (!active || !contains(cm.display.lineDiv, active)) return null let result = {activeElt: active} if (window.getSelection) { @@ -73,7 +73,7 @@ function selectionSnapshot(cm) { } function restoreSelection(snapshot) { - if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt(snapshot.activeElt.ownerDocument)) return + if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt(rootNode(snapshot.activeElt))) return snapshot.activeElt.focus() if (!/^(INPUT|TEXTAREA)$/.test(snapshot.activeElt.nodeName) && snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) { diff --git a/src/edit/fromTextArea.js b/src/edit/fromTextArea.js index cdd10d74a0..cbad7f6eb4 100644 --- a/src/edit/fromTextArea.js +++ b/src/edit/fromTextArea.js @@ -1,5 +1,5 @@ import { CodeMirror } from "./CodeMirror.js" -import { activeElt } from "../util/dom.js" +import { activeElt, rootNode } from "../util/dom.js" import { off, on } from "../util/event.js" import { copyObj } from "../util/misc.js" @@ -13,7 +13,7 @@ export function fromTextArea(textarea, options) { // Set autofocus to true if this textarea is focused, or if it has // autofocus and no other element is focused. if (options.autofocus == null) { - let hasFocus = activeElt(textarea.ownerDocument) + let hasFocus = activeElt(rootNode(textarea)) options.autofocus = hasFocus == textarea || textarea.getAttribute("autofocus") != null && hasFocus == document.body } diff --git a/src/edit/key_events.js b/src/edit/key_events.js index 1d3c9f908c..737d11d89b 100644 --- a/src/edit/key_events.js +++ b/src/edit/key_events.js @@ -3,7 +3,7 @@ import { restartBlink } from "../display/selection.js" import { isModifierKey, keyName, lookupKey } from "../input/keymap.js" import { eventInWidget } from "../measurement/widgets.js" import { ie, ie_version, mac, presto, gecko } from "../util/browser.js" -import { activeElt, addClass, rmClass, doc } from "../util/dom.js" +import { activeElt, addClass, rmClass, root } from "../util/dom.js" import { e_preventDefault, off, on, signalDOMEvent } from "../util/event.js" import { hasCopyEvent } from "../util/feature_detection.js" import { Delayed, Pass } from "../util/misc.js" @@ -107,7 +107,7 @@ let lastStoppedKey = null export function onKeyDown(e) { let cm = this if (e.target && e.target != cm.display.input.getField()) return - cm.curOp.focus = activeElt(doc(cm)) + cm.curOp.focus = activeElt(root(cm)) if (signalDOMEvent(cm, e)) return // IE does strange things with escape. if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false diff --git a/src/edit/methods.js b/src/edit/methods.js index b1cbcc9e2e..9fb8787522 100644 --- a/src/edit/methods.js +++ b/src/edit/methods.js @@ -1,7 +1,7 @@ import { deleteNearSelection } from "./deleteNearSelection.js" import { commands } from "./commands.js" import { attachDoc } from "../model/document_data.js" -import { activeElt, addClass, rmClass, doc, win } from "../util/dom.js" +import { activeElt, addClass, rmClass, root, win } from "../util/dom.js" import { eventMixin, signal } from "../util/event.js" import { getLineStyles, getContextBefore, takeToken } from "../line/highlight.js" import { indentLine } from "../input/indent.js" @@ -358,7 +358,7 @@ export default function(CodeMirror) { signal(this, "overwriteToggle", this, this.state.overwrite) }, - hasFocus: function() { return this.display.input.getField() == activeElt(doc(this)) }, + hasFocus: function() { return this.display.input.getField() == activeElt(root(this)) }, isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) }, scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y) }), diff --git a/src/edit/mouse_events.js b/src/edit/mouse_events.js index e854d64791..421e70b2a7 100644 --- a/src/edit/mouse_events.js +++ b/src/edit/mouse_events.js @@ -9,7 +9,7 @@ import { normalizeSelection, Range, Selection } from "../model/selection.js" import { extendRange, extendSelection, replaceOneSelection, setSelection } from "../model/selection_updates.js" import { captureRightClick, chromeOS, ie, ie_version, mac, webkit, safari } from "../util/browser.js" import { getOrder, getBidiPartAt } from "../util/bidi.js" -import { activeElt, doc as getDoc, win } from "../util/dom.js" +import { activeElt, root, win } from "../util/dom.js" import { e_button, e_defaultPrevented, e_preventDefault, e_target, hasHandler, off, on, signal, signalDOMEvent } from "../util/event.js" import { dragAndDrop } from "../util/feature_detection.js" import { bind, countColumn, findColumn, sel_mouse } from "../util/misc.js" @@ -128,7 +128,7 @@ function configureMouse(cm, repeat, event) { function leftButtonDown(cm, pos, repeat, event) { if (ie) setTimeout(bind(ensureFocus, cm), 0) - else cm.curOp.focus = activeElt(getDoc(cm)) + else cm.curOp.focus = activeElt(root(cm)) let behavior = configureMouse(cm, repeat, event) @@ -292,7 +292,7 @@ function leftButtonSelect(cm, event, start, behavior) { let cur = posFromMouse(cm, e, true, behavior.unit == "rectangle") if (!cur) return if (cmp(cur, lastPos) != 0) { - cm.curOp.focus = activeElt(getDoc(cm)) + cm.curOp.focus = activeElt(root(cm)) extendTo(cur) let visible = visibleLines(display, doc) if (cur.line >= visible.to || cur.line < visible.from) diff --git a/src/input/ContentEditableInput.js b/src/input/ContentEditableInput.js index f789af74ee..158ff24749 100644 --- a/src/input/ContentEditableInput.js +++ b/src/input/ContentEditableInput.js @@ -10,7 +10,7 @@ import { simpleSelection } from "../model/selection.js" import { setSelection } from "../model/selection_updates.js" import { getBidiPartAt, getOrder } from "../util/bidi.js" import { android, chrome, gecko, ie_version } from "../util/browser.js" -import { activeElt, contains, range, removeChildrenAndAdd, selectInput } from "../util/dom.js" +import { activeElt, contains, range, removeChildrenAndAdd, selectInput, rootNode } from "../util/dom.js" import { on, signalDOMEvent } from "../util/event.js" import { Delayed, lst, sel_dontScroll } from "../util/misc.js" @@ -97,7 +97,7 @@ export default class ContentEditableInput { disableBrowserMagic(te) cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild) te.value = lastCopied.text.join("\n") - let hadFocus = activeElt(div.ownerDocument) + let hadFocus = activeElt(rootNode(div)) selectInput(te) setTimeout(() => { cm.display.lineSpace.removeChild(kludge) @@ -120,7 +120,7 @@ export default class ContentEditableInput { prepareSelection() { let result = prepareSelection(this.cm, false) - result.focus = activeElt(this.div.ownerDocument) == this.div + result.focus = activeElt(rootNode(this.div)) == this.div return result } @@ -214,7 +214,7 @@ export default class ContentEditableInput { focus() { if (this.cm.options.readOnly != "nocursor") { - if (!this.selectionInEditor() || activeElt(this.div.ownerDocument) != this.div) + if (!this.selectionInEditor() || activeElt(rootNode(this.div)) != this.div) this.showSelection(this.prepareSelection(), true) this.div.focus() } diff --git a/src/input/TextareaInput.js b/src/input/TextareaInput.js index 0aac125b11..26a17281c4 100644 --- a/src/input/TextareaInput.js +++ b/src/input/TextareaInput.js @@ -6,7 +6,7 @@ import { eventInWidget } from "../measurement/widgets.js" import { simpleSelection } from "../model/selection.js" import { selectAll, setSelection } from "../model/selection_updates.js" import { captureRightClick, ie, ie_version, ios, mac, mobile, presto, webkit } from "../util/browser.js" -import { activeElt, removeChildrenAndAdd, selectInput } from "../util/dom.js" +import { activeElt, removeChildrenAndAdd, selectInput, rootNode } from "../util/dom.js" import { e_preventDefault, e_stop, off, on, signalDOMEvent } from "../util/event.js" import { hasSelection } from "../util/feature_detection.js" import { Delayed, sel_dontScroll } from "../util/misc.js" @@ -182,7 +182,7 @@ export default class TextareaInput { supportsTouch() { return false } focus() { - if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt(this.textarea.ownerDocument) != this.textarea)) { + if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt(rootNode(this.textarea)) != this.textarea)) { try { this.textarea.focus() } catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM } diff --git a/src/util/dom.js b/src/util/dom.js index 6672645a8d..52fc9495ce 100644 --- a/src/util/dom.js +++ b/src/util/dom.js @@ -64,13 +64,14 @@ export function contains(parent, child) { } while (child = child.parentNode) } -export function activeElt(doc) { +export function activeElt(rootNode) { // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement. // IE < 10 will throw when accessed while the page is loading or in an iframe. // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable. + let doc = rootNode.ownerDocument || rootNode let activeElement try { - activeElement = doc.activeElement + activeElement = rootNode.activeElement } catch(e) { activeElement = doc.body || null } @@ -98,4 +99,13 @@ else if (ie) // Suppress mysterious IE10 errors export function doc(cm) { return cm.display.wrapper.ownerDocument } +export function root(cm) { + return rootNode(cm.display.wrapper) +} + +export function rootNode(element) { + // Detect modern browsers (2017+). + return element.getRootNode ? element.getRootNode() : element.ownerDocument +} + export function win(cm) { return doc(cm).defaultView } From e84384b4210bc35300994de07c6333666f2a5c9e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 20 Nov 2023 10:57:37 +0100 Subject: [PATCH 1857/1880] Mark version 5.65.16 --- AUTHORS | 2 ++ CHANGELOG.md | 10 ++++++++++ doc/manual.html | 2 +- doc/releases.html | 8 ++++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 24 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 3dd26e0fbb..c38f088f68 100644 --- a/AUTHORS +++ b/AUTHORS @@ -301,6 +301,7 @@ fraxx001 Fredrik Borg FUJI Goro (gfx) fzipp +Gabriela Gutierrez Gabriel Gheorghian Gabriel Horner Gabriel Nahmias @@ -718,6 +719,7 @@ Panupong Pasupat paris Paris Paris Kasidiaris +Parker Lougheed Patil Arpith Patrick Kettner Patrick Stoica diff --git a/CHANGELOG.md b/CHANGELOG.md index 31c9043708..6ba18d2cd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 5.65.16 (2023-11-20) + +### Bug fixes + +Fix focus tracking in shadow DOM. + +[go mode](https://codemirror.net/5/mode/go/): Allow underscores in numbers. + +[jsx mode](https://codemirror.net/5/mode/jsx/index.html): Support TS generics marked by trailing comma. + ## 5.65.15 (2023-08-29) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 7496ff277a..2a915729e3 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

                  User manual and reference guide - version 5.65.15 + version 5.65.16

                  CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 5d94bad1fb..9777ec70ea 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -34,6 +34,14 @@

                  Version 6.x

                  Version 5.x

                  +

                  20-11-2023: Version 5.65.16:

                  + +
                    +
                  • Fix focus tracking in shadow DOM.
                  • +
                  • go mode: Allow underscores in numbers.
                  • +
                  • jsx mode: Support TS generics marked by trailing comma.
                  • +
                  +

                  29-08-2023: Version 5.65.15:

                    diff --git a/index.html b/index.html index 319adcbaa9..28c0918d63 100644 --- a/index.html +++ b/index.html @@ -92,7 +92,7 @@

                    This is CodeMirror

                    - Get the current version: 5.65.15.
                    + Get the current version: 5.65.16.
                    You can see the code,
                    read the release notes,
                    or study the user manual. diff --git a/package.json b/package.json index eb0c44cf09..2c618b4db0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.65.15", + "version": "5.65.16", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index f69663b6fe..650d09bd95 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.65.15" +CodeMirror.version = "5.65.16" From 0c8456c3bc92fb3085ac636f5ed117df24e22ca7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 29 Feb 2024 07:17:45 +0100 Subject: [PATCH 1858/1880] [duotone theme] Improve contrast on comment tokens Closes https://github.com/codemirror/codemirror5/issues/7087 --- theme/duotone-dark.css | 2 +- theme/duotone-light.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/theme/duotone-dark.css b/theme/duotone-dark.css index 88fdc76c8e..5373178e8d 100644 --- a/theme/duotone-dark.css +++ b/theme/duotone-dark.css @@ -26,7 +26,7 @@ CodeMirror template by Jan T. Sott (https://github.com/idleberg), adapted by Bra .cm-s-duotone-dark span.cm-variable-2, .cm-s-duotone-dark span.cm-variable-3, .cm-s-duotone-dark span.cm-type, .cm-s-duotone-dark span.cm-string-2, .cm-s-duotone-dark span.cm-url { color: #7a63ee; } .cm-s-duotone-dark span.cm-def, .cm-s-duotone-dark span.cm-tag, .cm-s-duotone-dark span.cm-builtin, .cm-s-duotone-dark span.cm-qualifier, .cm-s-duotone-dark span.cm-header, .cm-s-duotone-dark span.cm-em { color: #eeebff; } -.cm-s-duotone-dark span.cm-bracket, .cm-s-duotone-dark span.cm-comment { color: #6c6783; } +.cm-s-duotone-dark span.cm-bracket, .cm-s-duotone-dark span.cm-comment { color: #a7a5b2; } /* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */ .cm-s-duotone-dark span.cm-error, .cm-s-duotone-dark span.cm-invalidchar { color: #f00; } diff --git a/theme/duotone-light.css b/theme/duotone-light.css index d99480f7c4..a0a0b8336e 100644 --- a/theme/duotone-light.css +++ b/theme/duotone-light.css @@ -25,7 +25,7 @@ CodeMirror template by Jan T. Sott (https://github.com/idleberg), adapted by Bra .cm-s-duotone-light span.cm-variable-2, .cm-s-duotone-light span.cm-variable-3, .cm-s-duotone-light span.cm-type, .cm-s-duotone-light span.cm-string-2, .cm-s-duotone-light span.cm-url { color: #896724; } .cm-s-duotone-light span.cm-def, .cm-s-duotone-light span.cm-tag, .cm-s-duotone-light span.cm-builtin, .cm-s-duotone-light span.cm-qualifier, .cm-s-duotone-light span.cm-header, .cm-s-duotone-light span.cm-em { color: #2d2006; } -.cm-s-duotone-light span.cm-bracket, .cm-s-duotone-light span.cm-comment { color: #b6ad9a; } +.cm-s-duotone-light span.cm-bracket, .cm-s-duotone-light span.cm-comment { color: #6f6e6a; } /* using #f00 red for errors, don't think any of the colorscheme variables will stand out enough, ... maybe by giving it a background-color ... */ /* .cm-s-duotone-light span.cm-error { background: #896724; color: #728fcb; } */ From b7b1bbcb9668032f6ab16766e19572745c6326b9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Apr 2024 14:56:27 +0200 Subject: [PATCH 1859/1880] [crystal mode] Fix an infinite loop in tokenizing of heredoc strings Closes https://github.com/codemirror/codemirror5/issues/7092 --- mode/crystal/crystal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/crystal/crystal.js b/mode/crystal/crystal.js index 73b0dbe13c..b22c5dbe41 100644 --- a/mode/crystal/crystal.js +++ b/mode/crystal/crystal.js @@ -379,7 +379,7 @@ return "string"; } - escaped = embed && stream.next() == "\\"; + escaped = stream.next() == "\\" && embed; } else { stream.next(); escaped = false; From 5a966343ec7c7f740f0dc01e4a8e7d0bd288c1ef Mon Sep 17 00:00:00 2001 From: David Foster Date: Fri, 19 Apr 2024 09:48:36 -0700 Subject: [PATCH 1860/1880] Add regression test for issue #4641 --- test/comment_test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/comment_test.js b/test/comment_test.js index 7deda79138..2210667163 100644 --- a/test/comment_test.js +++ b/test/comment_test.js @@ -115,4 +115,9 @@ namespace = "comment_"; cm.setCursor(1, 0) cm.execCommand("toggleComment") }, "", "") + + test("toggleWithMultipleInnerComments", "javascript", function(cm) { + cm.execCommand("selectAll") + cm.execCommand("toggleComment") + }, "/* foo */\na\n/* bar */\nb", "// /* foo */\n// a\n// /* bar */\n// b") })(); From fec380ddc125419ab2ba47765442ea557a88d611 Mon Sep 17 00:00:00 2001 From: David Foster Date: Mon, 22 Apr 2024 12:46:40 -0700 Subject: [PATCH 1861/1880] Add regression test for issue #1975 --- test/comment_test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/comment_test.js b/test/comment_test.js index 2210667163..7612f47e37 100644 --- a/test/comment_test.js +++ b/test/comment_test.js @@ -120,4 +120,16 @@ namespace = "comment_"; cm.execCommand("selectAll") cm.execCommand("toggleComment") }, "/* foo */\na\n/* bar */\nb", "// /* foo */\n// a\n// /* bar */\n// b") + + var before = 'console.log("//string gets corrupted.");'; + var after = '// console.log("//string gets corrupted.");'; + test("toggleWithStringContainingComment1", "javascript", function(cm) { + cm.setCursor({line: 0, ch: 16 /* after // inside string */}); + cm.execCommand("toggleComment"); + }, before, after) + test("toggleWithStringContainingComment2", "javascript", function(cm) { + cm.setCursor({line: 0, ch: 16 /* after // inside string */}); + cm.execCommand("toggleComment"); + cm.execCommand("toggleComment"); + }, before, before) })(); From 064c9a880750a492c598433e6ddd155f836caaac Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 20 Jul 2024 16:24:23 +0200 Subject: [PATCH 1862/1880] Mark version 5.65.17 --- AUTHORS | 1 + CHANGELOG.md | 6 ++++++ doc/manual.html | 2 +- doc/releases.html | 6 ++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 17 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index c38f088f68..5bc0ef4f48 100644 --- a/AUTHORS +++ b/AUTHORS @@ -218,6 +218,7 @@ Dave Brondsema Dave MacLachlan Dave Myers David Barnett +David Foster David H. Bronke David Mignot David Pathakjee diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ba18d2cd7..81107b20dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 5.65.17 (2024-07-20) + +### Bug fixes + +[crystal mode](https://codemirror.net/5/mode/crystal/index.html): Fix an infinite loop bug when tokenizing heredoc strings. + ## 5.65.16 (2023-11-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 2a915729e3..9951e08cca 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

                    User manual and reference guide - version 5.65.16 + version 5.65.17

                    CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 9777ec70ea..da9acb17aa 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -34,6 +34,12 @@

                    Version 6.x

                    Version 5.x

                    +

                    20-07-2024: Version 5.65.17:

                    + +
                      +
                    • crystal mode: Fix an infinite loop bug when tokenizing heredoc strings.
                    • +
                    +

                    20-11-2023: Version 5.65.16:

                      diff --git a/index.html b/index.html index 28c0918d63..0a61fa7693 100644 --- a/index.html +++ b/index.html @@ -92,7 +92,7 @@

                      This is CodeMirror

                      - Get the current version: 5.65.16.
                      + Get the current version: 5.65.17.
                      You can see the code,
                      read the release notes,
                      or study the user manual. diff --git a/package.json b/package.json index 2c618b4db0..37c4c86670 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.65.16", + "version": "5.65.17", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index 650d09bd95..ad89b5a760 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.65.16" +CodeMirror.version = "5.65.17" From 13eeec1ec2fe12571cd0b2feb57a1d575fc14355 Mon Sep 17 00:00:00 2001 From: "Allef Santana (garug)" Date: Thu, 1 Aug 2024 12:18:54 -0300 Subject: [PATCH 1863/1880] [clojure mode] Enable brace folding --- mode/clojure/clojure.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/clojure/clojure.js b/mode/clojure/clojure.js index 3305165808..78bf286606 100644 --- a/mode/clojure/clojure.js +++ b/mode/clojure/clojure.js @@ -281,6 +281,7 @@ CodeMirror.defineMode("clojure", function (options) { }, closeBrackets: {pairs: "()[]{}\"\""}, + fold: "brace", lineComment: ";;" }; }); From 48d159a49b1db89523df7834cb18b46ac142764b Mon Sep 17 00:00:00 2001 From: pkucode Date: Thu, 15 Aug 2024 23:46:23 +0800 Subject: [PATCH 1864/1880] Remove repeated words in comments Signed-off-by: pkucode --- addon/edit/matchbrackets.js | 2 +- doc/manual.html | 2 +- src/display/update_lines.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js index c342910ed5..0d1bcb662e 100644 --- a/addon/edit/matchbrackets.js +++ b/addon/edit/matchbrackets.js @@ -27,7 +27,7 @@ afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className) var re = bracketRegex(config) - // A cursor is defined as between two characters, but in in vim command mode + // A cursor is defined as between two characters, but in vim command mode // (i.e. not insert mode), the cursor is visually represented as a // highlighted box on top of the 2nd character. Otherwise, we allow matches // from before or after the cursor. diff --git a/doc/manual.html b/doc/manual.html index 9951e08cca..553ac6c731 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -3733,7 +3733,7 @@

                      Extending VIM

                      been mapped to their Vim equivalents. Finds a command based on the key (and cached keys if there is a multi-key sequence). Returns undefined if no key is matched, a noop function if a partial match is found (multi-key), - and a function to execute the bound command if a a key is matched. The + and a function to execute the bound command if a key is matched. The function always returns true. diff --git a/src/display/update_lines.js b/src/display/update_lines.js index f09524b605..efb68f4479 100644 --- a/src/display/update_lines.js +++ b/src/display/update_lines.js @@ -58,7 +58,7 @@ function updateWidgetHeight(line) { } // Compute the lines that are visible in a given viewport (defaults -// the the current scroll position). viewport may contain top, +// the current scroll position). viewport may contain top, // height, and ensure (see op.scrollToPos) properties. export function visibleLines(display, doc, viewport) { let top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop From dd44c943cc25109d73041abb9f859581c4dec07a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 28 Aug 2024 10:21:47 +0200 Subject: [PATCH 1865/1880] [groovy mode] Stop parsing interpolated variable names when hitting whitespace Closes https://github.com/codemirror/codemirror5/issues/7103 --- mode/groovy/groovy.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mode/groovy/groovy.js b/mode/groovy/groovy.js index 89d0fe0854..24d886ebb1 100644 --- a/mode/groovy/groovy.js +++ b/mode/groovy/groovy.js @@ -129,10 +129,8 @@ CodeMirror.defineMode("groovy", function(config) { function tokenVariableDeref(stream, state) { var next = stream.match(/^(\.|[\w\$_]+)/) - if (!next) { - state.tokenize.pop() - return state.tokenize[state.tokenize.length-1](stream, state) - } + if (!next || !stream.match(next[0] == "." ? /^[\w$_]/ : /^\./)) state.tokenize.pop() + if (!next) return state.tokenize[state.tokenize.length-1](stream, state) return next[0] == "." ? null : "variable" } From e1b414d88d515b895add96df9d689fc9d0098fa0 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Thu, 5 Sep 2024 07:45:25 -0700 Subject: [PATCH 1866/1880] [dart mode] Support digit separators --- mode/dart/dart.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mode/dart/dart.js b/mode/dart/dart.js index ba9ff3dd2c..cbbf391cc5 100644 --- a/mode/dart/dart.js +++ b/mode/dart/dart.js @@ -44,6 +44,8 @@ blockKeywords: set(blockKeywords), builtin: set(builtins), atoms: set(atoms), + // clike numbers without the suffixes, and with '_' separators. + number: /^(?:0x[a-f\d_]+|(?:[\d_]+\.?[\d_]*|\.[\d_]+)(?:e[-+]?[\d_]+)?)/i, hooks: { "@": function(stream) { stream.eatWhile(/[\w\$_\.]/); From 81d004923d399fdb3af447fee63c5255e255d6f3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 18 Sep 2024 09:29:02 +0200 Subject: [PATCH 1867/1880] Drop realworld.html page --- doc/realworld.html | 209 --------------------------------------------- index.html | 9 +- 2 files changed, 1 insertion(+), 217 deletions(-) delete mode 100644 doc/realworld.html diff --git a/doc/realworld.html b/doc/realworld.html deleted file mode 100644 index 4d822b36ab..0000000000 --- a/doc/realworld.html +++ /dev/null @@ -1,209 +0,0 @@ - - -CodeMirror: Real-world Uses - - - - - -
                      - -

                      CodeMirror real-world uses

                      - -

                      Create a pull - request if you'd like your project to be added to this list.

                      - - - -
                      - diff --git a/index.html b/index.html index 0a61fa7693..2bc4b9c083 100644 --- a/index.html +++ b/index.html @@ -128,14 +128,7 @@

                      Features

                      Community

                      CodeMirror is an open-source project shared under - an MIT license. It is the editor used in the - dev tools for - Firefox, - Chrome, - and Safari, in Light - Table, Adobe - Brackets, Bitbucket, - and many other projects.

                      + an MIT license.

                      Development and bug tracking happens on github From 998f328b6b01217f6ef9e958ce3a128daddc592e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 20 Sep 2024 13:18:09 +0200 Subject: [PATCH 1868/1880] Mark version 5.65.18 --- AUTHORS | 2 ++ CHANGELOG.md | 8 ++++++++ doc/manual.html | 2 +- doc/releases.html | 7 +++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 21 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 5bc0ef4f48..db9c367183 100644 --- a/AUTHORS +++ b/AUTHORS @@ -41,6 +41,7 @@ alexey-k Alex Piggott Alf Eaton Aliaksei Chapyzhenka +Allef Santana (garug) Allen Sarkisyan Ami Fischman Amin Shali @@ -748,6 +749,7 @@ Pi Delport Pierre Gerold Pieter Ouwerkerk Piyush +pkucode Pontus Granström Pontus Melke prasanthj diff --git a/CHANGELOG.md b/CHANGELOG.md index 81107b20dc..665ec14023 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 5.65.18 (2024-09-20) + +### Bug fixes + +[dart mode](https://codemirror.net/5/mode/dart/index.html): Handle numeric separators. + +[groovy mode](https://codemirror.net/5/mode/groovy/index.html): Fix a bug in highlighting interpolated variable names. + ## 5.65.17 (2024-07-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 553ac6c731..ae992b3e6d 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

                      User manual and reference guide - version 5.65.17 + version 5.65.18

                      CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index da9acb17aa..de5d6f0b82 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -34,6 +34,13 @@

                      Version 6.x

                      Version 5.x

                      +

                      20-09-2024: Version 5.65.18:

                      + +
                        +
                      • dart mode: Handle numeric separators.
                      • +
                      • groovy mode: Fix a bug in highlighting interpolated variable names.
                      • +
                      +

                      20-07-2024: Version 5.65.17:

                        diff --git a/index.html b/index.html index 2bc4b9c083..0d823ad2cb 100644 --- a/index.html +++ b/index.html @@ -92,7 +92,7 @@

                        This is CodeMirror

                        - Get the current version: 5.65.17.
                        + Get the current version: 5.65.18.
                        You can see the code,
                        read the release notes,
                        or study the user manual. diff --git a/package.json b/package.json index 37c4c86670..2b4a0f237a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.65.17", + "version": "5.65.18", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index ad89b5a760..d136287d12 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.65.17" +CodeMirror.version = "5.65.18" From deee5c01586a7630fb0c1b32d4635fd4bb5fa545 Mon Sep 17 00:00:00 2001 From: "noor.masarwa" <62531656+Noormasarwa@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:21:57 +0300 Subject: [PATCH 1869/1880] [gherkin mode]: Add support for Rule Example keywords Co-authored-by: Noor-Masarwe --- mode/gherkin/gherkin.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mode/gherkin/gherkin.js b/mode/gherkin/gherkin.js index 196543e505..b6464310c9 100644 --- a/mode/gherkin/gherkin.js +++ b/mode/gherkin/gherkin.js @@ -155,6 +155,22 @@ CodeMirror.defineMode("gherkin", function () { state.inKeywordLine = true; return "keyword"; + // RULE + } else if (state.allowScenario && stream.match(/(規則|ルール|قانون|قواعد|חוק|قاعدة|Правило|Правила|Reegel|Regel|Règle|Regola|Regla|Regulă|Regul|Regula|Regel|Regel|Regula|Правило|Правила|Regel|Regola|Regul|Reeglid|Rule):/)) { + state.allowPlaceholders = false; + state.allowSteps = true; + state.allowBackground = false; + state.allowMultilineArgument = true; + return "keyword"; + + // EXAMPLE + } else if (state.allowScenario && stream.match(/(例子|例|サンプル|예|דוגמה|مثال|Үрнәк|Пример|Παράδειγμα|Exemplo|Exemple|Beispiel|Ejemplo|Example|Esempio|Örnek|Példa|Pavyzdys|Paraugs|Voorbeeld|Příklad|Príklad|Exemplu|Esempi):/)) { + state.allowPlaceholders = false; + state.allowSteps = true; + state.allowBackground = false; + state.allowMultilineArgument = true; + return "keyword"; + // INLINE STRING } else if (stream.match(/"[^"]*"?/)) { return "string"; From b60e456801640147f47609c141105d5d58fcb1e8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 5 Dec 2024 10:33:40 +0100 Subject: [PATCH 1870/1880] [pascal mode] Make keywords case-insensitive Closes https://github.com/codemirror/codemirror5/pull/7113 --- mode/pascal/pascal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/pascal/pascal.js b/mode/pascal/pascal.js index 062ea1189e..502f2c886b 100644 --- a/mode/pascal/pascal.js +++ b/mode/pascal/pascal.js @@ -72,7 +72,7 @@ CodeMirror.defineMode("pascal", function() { return "operator"; } stream.eatWhile(/[\w\$_]/); - var cur = stream.current(); + var cur = stream.current().toLowerCase(); if (keywords.propertyIsEnumerable(cur)) return "keyword"; if (atoms.propertyIsEnumerable(cur)) return "atom"; return "variable"; From 064ea16b7d1c0724ed1f63b2d6187435c9497a1e Mon Sep 17 00:00:00 2001 From: Beni Cherniavsky-Paskin Date: Mon, 11 Mar 2019 20:02:26 +0200 Subject: [PATCH 1871/1880] [theme demo] Fix dropdown losing choice on solarized light / dark Choosing "solarized dark" correctly sets .cm-s-solarized .cm-s-dark (as documented https://codemirror.net/doc/manual.html#option_theme). It then sets URL fragment to #solarized%20dark, which was looking for `solarized%20dark` in dropdown and failing. This commit makes both setting and getting URL fragment reliable. --- demo/theme.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/demo/theme.html b/demo/theme.html index e394aa266b..5fe7a57547 100644 --- a/demo/theme.html +++ b/demo/theme.html @@ -183,9 +183,10 @@

                        Theme Demo

                        function selectTheme() { var theme = input.options[input.selectedIndex].textContent; editor.setOption("theme", theme); - location.hash = "#" + theme; + location.hash = "#" + encodeURIComponent(theme); } - var choice = (location.hash && location.hash.slice(1)) || + var choice = (location.hash && + decodeURIComponent(location.hash.slice(1))) || (document.location.search && decodeURIComponent(document.location.search.slice(1))); if (choice) { @@ -193,7 +194,7 @@

                        Theme Demo

                        editor.setOption("theme", choice); } CodeMirror.on(window, "hashchange", function() { - var theme = location.hash.slice(1); + var theme = decodeURIComponent(location.hash.slice(1)); if (theme) { input.value = theme; selectTheme(); } }); From 187450ac140094ae30630bc209c88c9f1b278e67 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 11 Mar 2025 15:39:10 +0100 Subject: [PATCH 1872/1880] Upgrade actions/cache to v4 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0a07b4e07..723792ec31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: steps: - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac #v4.0.0 - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 #v3.3.2 + - uses: actions/cache@v4 with: path: '/home/runner/work/codemirror/codemirror5/node_modules' key: ${{ runner.os }}-modules From eed51d071bce00302f209d66b8d2cf908b2cb733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Vr=C3=A1na?= Date: Sun, 16 Mar 2025 20:27:59 +0100 Subject: [PATCH 1873/1880] [sql mode] Support quoted identifier for PostgreSQL --- mode/sql/sql.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mode/sql/sql.js b/mode/sql/sql.js index d3983889f7..a386f5c6c3 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -421,6 +421,10 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { atoms: set("false true null unknown"), operatorChars: /^[*\/+\-%<>!=&|^\/#@?~]/, backslashStringEscapes: false, + identifierQuote: "\"", // https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS + hooks: { + "\"": hookIdentifierDoublequote + }, dateSQL: set("date time timestamp"), support: set("decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast escapeConstant") }); From 8a5dcbb838e06fa01cba4d0b74d988ab66821c33 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Mar 2025 17:27:04 +0100 Subject: [PATCH 1874/1880] Mark version 5.65.19 --- AUTHORS | 1 + CHANGELOG.md | 10 ++++++++++ doc/manual.html | 2 +- doc/releases.html | 8 ++++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 23 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index db9c367183..b263596758 100644 --- a/AUTHORS +++ b/AUTHORS @@ -697,6 +697,7 @@ Nils Knappmeier Nina Pypchenko Nisarg Jhaveri nlwillia +noor.masarwa noragrossman Norman Rzepka Nouzbe diff --git a/CHANGELOG.md b/CHANGELOG.md index 665ec14023..ee12d024db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 5.65.19 (2025-03-20) + +### Bug fixes + +[gherkin mode](https://codemirror.net/5/mode/gherkin/index.html): Add support for Rule Example keywords + +[pascal mode](https://codemirror.net/5/mode/pascal/index.html) Make keywords case-insensitive + +[sql mode](https://codemirror.net/5/mode/sql/) Support quoted identifier for PostgreSQL + ## 5.65.18 (2024-09-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index ae992b3e6d..957a8f2fd1 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

                        User manual and reference guide - version 5.65.18 + version 5.65.19

                        CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index de5d6f0b82..4229243846 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -34,6 +34,14 @@

                        Version 6.x

                        Version 5.x

                        +

                        20-03-2025: Version 5.65.19:

                        + + +

                        20-09-2024: Version 5.65.18:

                          diff --git a/index.html b/index.html index 0d823ad2cb..9190bf20f2 100644 --- a/index.html +++ b/index.html @@ -92,7 +92,7 @@

                          This is CodeMirror

                          - Get the current version: 5.65.18.
                          + Get the current version: 5.65.19.
                          You can see the code,
                          read the release notes,
                          or study the user manual. diff --git a/package.json b/package.json index 2b4a0f237a..6273631203 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.65.18", + "version": "5.65.19", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index d136287d12..a27507456b 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.65.18" +CodeMirror.version = "5.65.19" From 1df33b7ac759488da69d8d83a792636e7c08c2e2 Mon Sep 17 00:00:00 2001 From: Zaid Daba'een Date: Mon, 31 Mar 2025 13:50:52 +0300 Subject: [PATCH 1875/1880] clip-path issue fixed in Chrome 106 In Chrome 105, `clip-path` needed to be set as pointer events were ineffective outside CodeMirror editor instance but within paddings and margins of its elements. This has been resolved in Chrome 106 as seen [here](https://issues.chromium.org/issues/40863245#comment21). --- src/display/Display.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display/Display.js b/src/display/Display.js index 28d8dbb013..201e81c1cc 100644 --- a/src/display/Display.js +++ b/src/display/Display.js @@ -49,7 +49,7 @@ export function Display(place, doc, input, options) { // The element in which the editor lives. d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror") // See #6982. FIXME remove when this has been fixed for a while in Chrome - if (chrome && chrome_version >= 105) d.wrapper.style.clipPath = "inset(0px)" + if (chrome && chrome_version === 105) d.wrapper.style.clipPath = "inset(0px)" // This attribute is respected by automatic translation systems such as Google Translate, // and may also be respected by tools used by human translators. From 98e86d1ae3fc8b6353e511bf25cf7adac7b03482 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 18 Jul 2025 07:55:08 +0200 Subject: [PATCH 1876/1880] [gas mode] Define text/x-gas mime type Closes https://github.com/codemirror/codemirror5/issues/7134 --- mode/gas/gas.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mode/gas/gas.js b/mode/gas/gas.js index db09a8af08..cbf08586fc 100644 --- a/mode/gas/gas.js +++ b/mode/gas/gas.js @@ -350,4 +350,6 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) { }; }); +CodeMirror.defineMIME("text/x-gas", "gas"); + }); From 9f1450da47dd6ce43bb54491415364782970fe98 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 10 Aug 2025 10:22:41 +0200 Subject: [PATCH 1877/1880] [show-hint addon] Fix incorrectly applied offset Closes https://github.com/codemirror/codemirror5/pull/7129 --- addon/hint/show-hint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index aaf1f643f4..eb448db7af 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -290,7 +290,7 @@ var height = box.bottom - box.top, spaceAbove = box.top - (pos.bottom - pos.top) - 2 if (winH - box.top < spaceAbove) { // More room at the top if (height > spaceAbove) hints.style.height = (height = spaceAbove) + "px"; - hints.style.top = ((top = pos.top - height) + offsetTop) + "px"; + hints.style.top = ((top = pos.top - height) - offsetTop) + "px"; below = false; } else { hints.style.height = (winH - box.top - 2) + "px"; From b0c45cf0fbd3dc7cb2016a79fb81c723827f4e31 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 10 Aug 2025 10:30:49 +0200 Subject: [PATCH 1878/1880] Mark version 5.65.20 --- AUTHORS | 1 + CHANGELOG.md | 8 ++++++++ doc/manual.html | 2 +- doc/releases.html | 7 +++++++ index.html | 2 +- package.json | 2 +- src/edit/main.js | 2 +- 7 files changed, 20 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index b263596758..c800afe9d5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -978,6 +978,7 @@ Yuvi Panda Yvonnick Esnault Zac Anger Zachary Dremann +Zaid Daba'een ZeeshanNoor Zeno Rocha Zhang Hao diff --git a/CHANGELOG.md b/CHANGELOG.md index ee12d024db..8a7064be6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +## 5.65.20 (2025-08-10) + +### Bug fixes + +[show-hint addon](https://codemirror.net/5/doc/manual.html#addon_show-hint): Fix a positioning issue when the tooltip is at the bottom of the screen. + +[gas mode](https://codemirror.net/5/mode/gas/index.html): Properly define the MIME type the mode's demo page mentions. + ## 5.65.19 (2025-03-20) ### Bug fixes diff --git a/doc/manual.html b/doc/manual.html index 957a8f2fd1..3ea659e970 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -70,7 +70,7 @@

                          User manual and reference guide - version 5.65.19 + version 5.65.20

                          CodeMirror is a code-editor component that can be embedded in diff --git a/doc/releases.html b/doc/releases.html index 4229243846..42227c7316 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -34,6 +34,13 @@

                          Version 6.x

                          Version 5.x

                          +

                          10-08-2025: Version 5.65.20:

                          + +
                            +
                          • show-hint addon: Fix a positioning issue when the tooltip is at the bottom of the screen. +
                          • gas mode: Properly define the MIME type the mode's demo page mentions. +
                          +

                          20-03-2025: Version 5.65.19:

                            diff --git a/index.html b/index.html index 9190bf20f2..7cc603ccbc 100644 --- a/index.html +++ b/index.html @@ -92,7 +92,7 @@

                            This is CodeMirror

                            - Get the current version: 5.65.19.
                            + Get the current version: 5.65.20.
                            You can see the code,
                            read the release notes,
                            or study the user manual. diff --git a/package.json b/package.json index 6273631203..330bfeb30a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version": "5.65.19", + "version": "5.65.20", "main": "lib/codemirror.js", "style": "lib/codemirror.css", "author": { diff --git a/src/edit/main.js b/src/edit/main.js index a27507456b..949d9d4031 100644 --- a/src/edit/main.js +++ b/src/edit/main.js @@ -66,4 +66,4 @@ import { addLegacyProps } from "./legacy.js" addLegacyProps(CodeMirror) -CodeMirror.version = "5.65.19" +CodeMirror.version = "5.65.20" From 876911012efc844bcbc8e6e764399cf28916d7a7 Mon Sep 17 00:00:00 2001 From: flofriday Date: Thu, 21 Aug 2025 14:47:06 +0200 Subject: [PATCH 1879/1880] [kotlin mode]: Fix unsigned long literal token --- mode/clike/clike.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index e9f441fc0a..f783dfc8f2 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -680,7 +680,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { intendSwitch: false, indentStatements: false, multiLineStrings: true, - number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i, + number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(ul?|l|f)?/i, blockKeywords: words("catch class do else finally for if where try while enum"), defKeywords: words("class val var object interface fun"), atoms: words("true false null this"), From be271d3b04487edeece41c27f7a2e2ac98faccc9 Mon Sep 17 00:00:00 2001 From: Hicham Omari Date: Tue, 16 Sep 2025 16:09:16 +0200 Subject: [PATCH 1880/1880] [clike mode] Correct a typo --- mode/clike/clike.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index f783dfc8f2..30c8f6e3aa 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -677,7 +677,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { "ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy " + "LazyThreadSafetyMode LongArray Nothing ShortArray Unit" ), - intendSwitch: false, + indentSwitch: false, indentStatements: false, multiLineStrings: true, number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(ul?|l|f)?/i,