From aa29a981282a46105930194a2852365c1994c509 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 22 Nov 2014 09:59:37 +0100 Subject: [PATCH 01/97] Bump version number post-4.8 --- bower.json | 2 +- doc/manual.html | 2 +- lib/codemirror.js | 2 +- package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bower.json b/bower.json index bf28a95f87..5c1642313b 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version":"4.8.0", + "version":"4.8.1", "main": ["lib/codemirror.js", "lib/codemirror.css"], "ignore": [ "**/.*", diff --git a/doc/manual.html b/doc/manual.html index 34b7e6102a..bf2536da34 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -63,7 +63,7 @@

User manual and reference guide - version 4.8.0 + version 4.8.1

CodeMirror is a code-editor component that can be embedded in diff --git a/lib/codemirror.js b/lib/codemirror.js index e6011f7e66..493d6ae225 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -7916,7 +7916,7 @@ // THE END - CodeMirror.version = "4.8.0"; + CodeMirror.version = "4.8.1"; return CodeMirror; }); diff --git a/package.json b/package.json index fe52bcfe8b..380be98384 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version":"4.8.0", + "version":"4.8.1", "main": "lib/codemirror.js", "description": "In-browser code editing made bearable", "licenses": [{"type": "MIT", From f689a9e9d680a26f7680022c5f70a8d1197cd53b Mon Sep 17 00:00:00 2001 From: Jason Barnabe Date: Sat, 22 Nov 2014 15:04:25 -0600 Subject: [PATCH 02/97] [search addon] Do a string search if a bad regexp is entered --- addon/search/search.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/addon/search/search.js b/addon/search/search.js index c25aeda8b2..9596f6941e 100644 --- a/addon/search/search.js +++ b/addon/search/search.js @@ -63,7 +63,12 @@ function parseQuery(query) { var isRE = query.match(/^\/(.*)\/([a-z]*)$/); if (isRE) { - query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); + try { + query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); + } catch (ex) { + // Not a regular expression after all, do a string search + return query; + } if (query.test("")) query = /x^/; } else if (query == "") { query = /x^/; From 8acbea70088dfa938a46e964608a0457029290a1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 22 Nov 2014 22:27:23 +0100 Subject: [PATCH 03/97] [search addon] Simplify control flow --- addon/search/search.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/addon/search/search.js b/addon/search/search.js index 9596f6941e..5e7a05e3f3 100644 --- a/addon/search/search.js +++ b/addon/search/search.js @@ -63,16 +63,11 @@ function parseQuery(query) { var isRE = query.match(/^\/(.*)\/([a-z]*)$/); if (isRE) { - try { - query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); - } catch (ex) { - // Not a regular expression after all, do a string search - return query; - } - if (query.test("")) query = /x^/; - } else if (query == "") { - query = /x^/; + try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); } + catch(e) {} // Not a regular expression after all, do a string search } + if (typeof query == "string" ? query == "" : query.test("")) + query = /x^/; return query; } var queryDialog = From dd2b9d86ac30feb74c0bf0b999893382cd9f1e07 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 22 Nov 2014 22:30:21 +0100 Subject: [PATCH 04/97] Pass a context (the editor) to keymaps with a call method Issue #2915 --- lib/codemirror.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 493d6ae225..304ff434fd 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3173,11 +3173,11 @@ function lookupKeyForEditor(cm, name, handle) { for (var i = 0; i < cm.state.keyMaps.length; i++) { - var result = lookupKey(name, cm.state.keyMaps[i], handle); + var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); if (result) return result; } - return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle)) - || lookupKey(name, cm.options.keyMap, handle); + return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) + || lookupKey(name, cm.options.keyMap, handle, cm); } var stopSeq = new Delayed; @@ -4954,18 +4954,18 @@ return keymap; }; - var lookupKey = CodeMirror.lookupKey = function(key, map, handle) { + var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) { map = getKeyMap(map); - var found = map.call ? map.call(key) : map[key]; + 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); + return lookupKey(key, map.fallthrough, handle, context); for (var i = 0; i < map.fallthrough.length; i++) { - var result = lookupKey(key, map.fallthrough[i], handle); + var result = lookupKey(key, map.fallthrough[i], handle, context); if (result) return result; } } From c9b932bd27af998f4309768e55230ceab79e330b Mon Sep 17 00:00:00 2001 From: Daniele Di Sarli Date: Wed, 19 Nov 2014 10:41:32 +0100 Subject: [PATCH 05/97] [shell mode] Add folding helper reference --- mode/shell/shell.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mode/shell/shell.js b/mode/shell/shell.js index 8e31f6f30b..a684e8c233 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -129,7 +129,8 @@ CodeMirror.defineMode('shell', function() { token: function(stream, state) { return tokenize(stream, state); }, - lineComment: '#' + lineComment: '#', + fold: "brace" }; }); From 184b5f1d19e65eb0fe4bd620458ca116c1965af0 Mon Sep 17 00:00:00 2001 From: Scott Goodhew Date: Thu, 13 Nov 2014 11:13:07 +1100 Subject: [PATCH 06/97] [dialog addon] Ensure that enter presses can be preventDefault-ed When closeOnEnter is disabled the enter event never gets default prevented this causes issues for IE9/10, this way implementors can optionally preventDefault if they want --- addon/dialog/dialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/dialog/dialog.js b/addon/dialog/dialog.js index 5a88d99e64..e0e8ad4eb7 100644 --- a/addon/dialog/dialog.js +++ b/addon/dialog/dialog.js @@ -73,7 +73,7 @@ CodeMirror.e_stop(e); close(); } - if (e.keyCode == 13) callback(inp.value); + if (e.keyCode == 13) callback(inp.value, e); }); if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close); From 6ef6ef99a78f5f4678024c86e80ab9bed801cc8d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 25 Nov 2014 10:47:25 +0100 Subject: [PATCH 07/97] Make sure scrollPosIntoView always returns a coords object --- lib/codemirror.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 304ff434fd..b398518c80 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3750,8 +3750,9 @@ setScrollLeft(cm, scrollPos.scrollLeft); if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; } - if (!changed) return coords; + if (!changed) break; } + return coords; } // Scroll a given set of coordinates into view (immediately). From 8b24724babfaaeda851205f4b02da32cfc1bbf56 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 25 Nov 2014 10:48:02 +0100 Subject: [PATCH 08/97] Never render tokens larger than 50k chararcters Webkit can't deal with them. Issue #2945 --- lib/codemirror.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index b398518c80..a1470ac5c2 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -5897,8 +5897,11 @@ if (mName) style = "m-" + (style ? mName + " " + style : mName); } if (!flattenSpans || curStyle != style) { - if (curStart < stream.start) f(stream.start, curStyle); - curStart = stream.start; curStyle = style; + while (curStart < stream.start) { + curStart = Math.min(stream.start, curStart + 50000); + f(curStart, curStyle); + } + curStyle = style; } stream.start = stream.pos; } From 6b7bc72b11ebcae061dc400093567708fbc59edb Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Mon, 24 Nov 2014 16:12:46 -0800 Subject: [PATCH 09/97] [meta addon] Add Embedded Ruby (erb) as a htmlembedded mode The mime type is currently accounted for in the htmlembedded definition, but erb is not listed in the `mode/meta.js` index. --- mode/meta.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/meta.js b/mode/meta.js index 945b9b565b..d9e63d55e2 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -34,6 +34,7 @@ {name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]}, {name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]}, {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: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90"]}, {name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]}, From 4f6ffd6d3991d8c250cf250885180ab1b6bccdfa Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 26 Nov 2014 23:10:58 +0100 Subject: [PATCH 10/97] [real-world uses] Add JSER --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 8a87a0485b..39c8e7e03d 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -96,6 +96,7 @@

  • Joomla plugin
  • jQuery fundamentals (interactive tutorial)
  • jsbin.com (JS playground)
  • +
  • JSER preprocessor
  • jscpd (code duplication detector)
  • jsfiddle.com (another JS playground)
  • JSHint (JS linter)
  • From 4d8c0cb5d2a95fb7a03fdc93b54aef8c78b15549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Gait=C3=A1n?= Date: Wed, 26 Nov 2014 16:22:39 -0300 Subject: [PATCH 11/97] [real-world uses] Added Waliki a wiki engine --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 39c8e7e03d..a9fc3b884c 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -151,6 +151,7 @@
  • uiCod (animation demo gallery and sharing)
  • UmpleOnline (model-oriented programming tool)
  • Upsource (code viewer)
  • +
  • Waliki (wiki engine)
  • Wamer (web application builder)
  • webappfind (windows file bindings for webapps)
  • WebGL academy (learning WebGL)
  • From e0326500f0e90f481d998632b7ec25268cf04a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Schw=C3=B6rer?= Date: Wed, 26 Nov 2014 14:01:43 +0100 Subject: [PATCH 12/97] [markdown mode] Fix bad require call --- 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 7c87984e2b..8c85b9f20d 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -3,7 +3,7 @@ (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror", require("../xml/xml"), require("../meta"))); + mod(require("../../lib/codemirror"), require("../xml/xml"), require("../meta")); else if (typeof define == "function" && define.amd) // AMD define(["../../lib/codemirror", "../xml/xml", "../meta"], mod); else // Plain browser env From b9c4feb11da1b5c1f2550ffee6c31c5bf43e6048 Mon Sep 17 00:00:00 2001 From: Lanfei Date: Thu, 27 Nov 2014 16:50:56 +0800 Subject: [PATCH 13/97] [continuelist addon] Fix a bug in matching ordered list --- addon/edit/continuelist.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addon/edit/continuelist.js b/addon/edit/continuelist.js index 9ad0a98fa0..ca8d26751a 100644 --- a/addon/edit/continuelist.js +++ b/addon/edit/continuelist.js @@ -11,9 +11,9 @@ })(function(CodeMirror) { "use strict"; - var listRE = /^(\s*)([> ]+|[*+-]|(\d+)\.)(\s+)/, - emptyListRE = /^(\s*)([> ]+|[*+-]|(\d+)\.)(\s*)$/, - unorderedBullets = "*+-"; + var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)\.)(\s*)/, + emptyListRE = /^(\s*)(>[> ]*|[*+-]|(\d+)\.)(\s*)$/, + unorderedListRE = /[*+-]\s/; CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { if (cm.getOption("disableInput")) return CodeMirror.Pass; @@ -38,7 +38,7 @@ } else { var indent = match[1], after = match[4]; - var bullet = unorderedBullets.indexOf(match[2]) >= 0 || match[2].indexOf(">") >= 0 + var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0 ? match[2] : (parseInt(match[3], 10) + 1) + "."; From a69661a4d1ce475e77fe6477cddc25307ffb1220 Mon Sep 17 00:00:00 2001 From: darealshinji Date: Thu, 27 Nov 2014 19:15:44 +0100 Subject: [PATCH 14/97] [html-hint addon] Remove executable bit --- addon/hint/html-hint.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 addon/hint/html-hint.js diff --git a/addon/hint/html-hint.js b/addon/hint/html-hint.js old mode 100755 new mode 100644 From 4b6d57ea50c67c537e2ad5e455d3cdc9b5c27716 Mon Sep 17 00:00:00 2001 From: nightwing Date: Tue, 25 Nov 2014 16:47:51 +0400 Subject: [PATCH 15/97] [vim] add support for paragraph text object --- keymap/vim.js | 66 ++++++++++++++++++++++++++++++++++++++++++++------------ test/vim_test.js | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+), 14 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index c5b945cd67..a9e81d874f 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1610,20 +1610,8 @@ return cm.findPosV(curStart, (motionArgs.forward ? repeat : -repeat), 'page'); }, moveByParagraph: function(cm, head, motionArgs) { - var line = head.line; - var repeat = motionArgs.repeat; - var inc = motionArgs.forward ? 1 : -1; - for (var i = 0; i < repeat; i++) { - if ((!motionArgs.forward && line === cm.firstLine() ) || - (motionArgs.forward && line == cm.lastLine())) { - break; - } - line += inc; - while (line !== cm.firstLine() && line != cm.lastLine() && cm.getLine(line)) { - line += inc; - } - } - return Pos(line, 0); + var dir = motionArgs.forward ? 1 : -1; + return findParagraph(cm, head, motionArgs.repeat, dir); }, moveByScroll: function(cm, head, motionArgs, vim) { var scrollbox = cm.getScrollInfo(); @@ -1761,6 +1749,8 @@ } else if (character === 'w') { tmp = expandWordUnderCursor(cm, inclusive, true /** forward */, false /** bigWord */); + } else if (character === 'p') { + tmp = findParagraph(cm, head, motionArgs.repeat, 0, inclusive); } else { // No text object defined for this, don't move. return null; @@ -3268,6 +3258,54 @@ return idx; } + function findParagraph(cm, head, repeat, dir, inclusive) { + var line = head.line; + var min = cm.firstLine(); + var max = cm.lastLine(); + var start, end, i = line; + function isEmpty(i) { return !cm.getLine(i); } + function isBoundary(i, dir, any) { + if (any) { return isEmpty(i) != isEmpty(i + dir); } + return !isEmpty(i) && isEmpty(i + dir); + } + if (dir) { + while (min <= i && i <= max && repeat > 0) { + if (isBoundary(i, dir)) { repeat--; } + i += dir; + } + return new Pos(i, 0); + } + + var vim = cm.state.vim; + if (vim.visualMode && isBoundary(line, 1, true)) { + var anchor = vim.sel.anchor; + if (isBoundary(anchor.line, -1, true)) { + if (!inclusive || anchor.line != line) { + line += 1; + } + } + } + var startState = isEmpty(line); + for (i = line; i <= max && repeat; i++) { + if (isBoundary(i, 1, true)) { + if (!inclusive || isEmpty(i) != startState) { + repeat--; + } + } + } + end = new Pos(i, 0); + // select boundary before paragraph for the last one + if (i > max && !startState) { startState = true; } + else { inclusive = false; } + for (i = line; i > min; i--) { + if (!inclusive || isEmpty(i) == startState || i == line) { + if (isBoundary(i, -1, true)) { break; } + } + } + start = new Pos(i, 0); + return { start: start, end: end }; + } + // TODO: perhaps this finagling of start and end positions belonds // in codmirror/replaceRange? function selectCompanionObject(cm, head, symb, inclusive) { diff --git a/test/vim_test.js b/test/vim_test.js index 7eb8f6d8f7..2373c0afac 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -502,6 +502,70 @@ testVim('{', function(cm, vim, helpers) { helpers.doKeys('6', '{'); helpers.assertCursorAt(0, 0); }, { value: 'a\n\nb\nc\n\nd' }); +testVim('paragraph motions', function(cm, vim, helpers) { + cm.setCursor(10, 0); + helpers.doKeys('{'); + helpers.assertCursorAt(4, 0); + helpers.doKeys('{'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('2', '}'); + helpers.assertCursorAt(7, 0); + helpers.doKeys('2', '}'); + helpers.assertCursorAt(16, 0); + + cm.setCursor(9, 0); + helpers.doKeys('}'); + helpers.assertCursorAt(14, 0); + + cm.setCursor(6, 0); + helpers.doKeys('}'); + helpers.assertCursorAt(7, 0); + + // ip inside empty space + cm.setCursor(10, 0); + helpers.doKeys('v', 'i', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(12, 0), cm.getCursor('head')); + helpers.doKeys('i', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(13, 1), cm.getCursor('head')); + helpers.doKeys('2', 'i', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(16, 1), cm.getCursor('head')); + + // TODO: this should switch to visual mode + // cm.setCursor(14, 0); + // helpers.doKeys('', 'v', 'i', 'p'); + // helpers.assertCursorAt(14, 0); + + cm.setCursor(14, 0); + helpers.doKeys('', 'V', 'i', 'p'); + eqPos(Pos(16, 1), cm.getCursor('head')); + + // ap inside empty space + cm.setCursor(10, 0); + helpers.doKeys('', 'v', 'a', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(13, 1), cm.getCursor('head')); + helpers.doKeys('a', 'p'); + eqPos(Pos(7, 0), cm.getCursor('anchor')); + eqPos(Pos(16, 1), cm.getCursor('head')); + + cm.setCursor(13, 0); + helpers.doKeys('v', 'a', 'p'); + eqPos(Pos(13, 0), cm.getCursor('anchor')); + eqPos(Pos(14, 0), cm.getCursor('head')); + + cm.setCursor(16, 0); + helpers.doKeys('v', 'a', 'p'); + eqPos(Pos(14, 0), cm.getCursor('anchor')); + eqPos(Pos(16, 1), cm.getCursor('head')); + + cm.setCursor(0, 0); + helpers.doKeys('v', 'a', 'p'); + eqPos(Pos(0, 0), cm.getCursor('anchor')); + eqPos(Pos(4, 0), cm.getCursor('head')); +}, { value: 'a\na\n\n\n\nb\nc\n\n\n\n\n\n\nd\n\ne\nf' }); // Operator tests testVim('dl', function(cm, vim, helpers) { From b8ea5a73c1410d41c7c51a8dab3bfb2ce11cb669 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 24 Nov 2014 17:52:01 +0100 Subject: [PATCH 16/97] Make default scroll style for CodeMirror-scroller 'scroll' And manually compensate for our own scrollbar sizes. This way, we're no longer dependent on the size of our scrollbars being the same as the size of native scrollbars, and can start to think about custom scrollbars. --- demo/resize.html | 11 +----- doc/manual.html | 16 +++----- lib/codemirror.css | 9 +---- lib/codemirror.js | 112 ++++++++++++++++++++++++++++------------------------- 4 files changed, 70 insertions(+), 78 deletions(-) diff --git a/demo/resize.html b/demo/resize.html index 69eae2c39b..1c1ef390ab 100644 --- a/demo/resize.html +++ b/demo/resize.html @@ -12,10 +12,6 @@ border: 1px solid #eee; height: auto; } - .CodeMirror-scroll { - overflow-y: hidden; - overflow-x: auto; - }