From 182c6f55d598890d1ee9ccc75ed674947db149fb Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Dec 2012 10:10:04 +0100 Subject: [PATCH 0001/5273] Add Toolsverse Data Explorer to real-world uses --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index ad50c10a89..80bfe58255 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -69,6 +69,7 @@

{ } CodeMi
  • SolidShops (hosted e-commerce platform)
  • SQLFiddle (SQL playground)
  • The File Tree (collab editor)
  • +
  • Toolsverse Data Explorer (database management)
  • Tributary (augmented editing)
  • TurboPY (web publishing framework)
  • WebGL playground
  • From 6902d1ea615470963ff097377ee2da3f9f3d1959 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Dec 2012 11:26:43 +0100 Subject: [PATCH 0002/5273] [clike mode] Support a dontAlignCalls configuration option Issue #1053 --- mode/clike/clike.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 4d1484a708..1b350aeb8c 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -1,6 +1,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { var indentUnit = config.indentUnit, statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, + dontAlignCalls = parserConfig.dontAlignCalls, keywords = parserConfig.keywords || {}, builtin = parserConfig.builtin || {}, blockKeywords = parserConfig.blockKeywords || {}, @@ -149,6 +150,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; var closing = firstChar == ctx.type; if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); + else if (dontAlignCalls && ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit; else if (ctx.align) return ctx.column + (closing ? 0 : 1); else return ctx.indented + (closing ? 0 : indentUnit); }, From 47988c08ca03e3146418b66b4ccda4eafcf83d75 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Dec 2012 13:04:04 +0100 Subject: [PATCH 0003/5273] Mention release 2.37 on project page --- doc/compress.html | 1 + doc/oldrelease.html | 23 +++++++++++++++++++++++ index.html | 32 +++++++++----------------------- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 19796d0bca..94df0c595e 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -35,6 +35,7 @@

    { } CodeMi + diff --git a/doc/oldrelease.html b/doc/oldrelease.html index 702e75d2e7..dafe738652 100644 --- a/doc/oldrelease.html +++ b/doc/oldrelease.html @@ -19,6 +19,29 @@

    { } CodeMi +

    22-06-2012: Version 2.3:

    + +
      +
    • New scrollbar implementation. Should flicker less. Changes DOM structure of the editor.
    • +
    • New theme: vibrant-ink.
    • +
    • Many extensions to the VIM keymap (including text objects).
    • +
    • Add mode-multiplexing utility script.
    • +
    • Fix bug where right-click paste works in read-only mode.
    • +
    • Add a getScrollInfo method.
    • +
    • Lots of other fixes.
    • +
    + +

    23-05-2012: Version 2.25:

    + +
      +
    • New mode: Erlang.
    • +
    • Remove xmlpure mode (use xml.js).
    • +
    • Fix line-wrapping in Opera.
    • +
    • Fix X Windows middle-click paste in Chrome.
    • +
    • Fix bug that broke pasting of huge documents.
    • +
    • Fix backspace and tab key repeat in Opera.
    • +
    +

    23-04-2012: Version 2.24:

      diff --git a/index.html b/index.html index f576de2e64..3347d21949 100644 --- a/index.html +++ b/index.html @@ -291,6 +291,15 @@

      Reading material

      Releases

      +

      20-12-2012: Version 2.37:

      + +
        +
      • New mode: SQL (will replace plsql and mysql modes).
      • +
      • Further work on the new VIM mode.
      • +
      • Fix Cmd/Ctrl keys on recent Operas on OS X.
      • +
      • Full list of patches.
      • +
      +

      10-12-2012: Version 3.0:

      New major version. Only @@ -431,29 +440,6 @@

      Releases

    • And more... (all patches)
    -

    22-06-2012: Version 2.3:

    - -
      -
    • New scrollbar implementation. Should flicker less. Changes DOM structure of the editor.
    • -
    • New theme: vibrant-ink.
    • -
    • Many extensions to the VIM keymap (including text objects).
    • -
    • Add mode-multiplexing utility script.
    • -
    • Fix bug where right-click paste works in read-only mode.
    • -
    • Add a getScrollInfo method.
    • -
    • Lots of other fixes.
    • -
    - -

    23-05-2012: Version 2.25:

    - -
      -
    • New mode: Erlang.
    • -
    • Remove xmlpure mode (use xml.js).
    • -
    • Fix line-wrapping in Opera.
    • -
    • Fix X Windows middle-click paste in Chrome.
    • -
    • Fix bug that broke pasting of huge documents.
    • -
    • Fix backspace and tab key repeat in Opera.
    • -
    -

    Older releases...

    From 88852e7b811994650e73762cb2798329ac362ff9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 30 Dec 2012 12:51:10 +0100 Subject: [PATCH 0004/5273] Add my2ndgeneration to real-world uses --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 80bfe58255..efb10420ec 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -56,6 +56,7 @@

    { } CodeMi
  • kl1p (paste service)
  • Light Table (experimental IDE)
  • Mergely (interactive diffing)
  • +
  • My2ndGeneration (social coding)
  • NoTex (rST authoring)
  • ORG (z80 assembly IDE)
  • Orion-CodeMirror integration (running CodeMirror modes in Orion)
  • From 1fc80e4ef6dce8dca96bbbd670a1ba0e955408cd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 30 Dec 2012 13:07:06 +0100 Subject: [PATCH 0005/5273] Make cursor elements div instead of pre elements There is no reason for styling intended for lines to affect the cursor. --- lib/codemirror.css | 16 ++++++++-------- lib/codemirror.js | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index f9ff050d3d..923c3024ff 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -39,14 +39,14 @@ /* CURSOR */ -.CodeMirror pre.CodeMirror-cursor { +.CodeMirror div.CodeMirror-cursor { border-left: 1px solid black; } /* Shown when moving in bi-directional text */ -.CodeMirror pre.CodeMirror-secondarycursor { +.CodeMirror div.CodeMirror-secondarycursor { border-left: 1px solid silver; } -.cm-keymap-fat-cursor pre.CodeMirror-cursor { +.cm-keymap-fat-cursor div.CodeMirror-cursor { width: auto; border: 0; background: transparent; @@ -54,11 +54,11 @@ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800); } /* Kludge to turn off filter in ie9+, which also accepts rgba */ -.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) { +.cm-keymap-fat-cursor div.CodeMirror-cursor:not(#nonsense_id) { filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } /* Can style cursor different in overwrite (non-insert) mode */ -.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {} +.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {} /* DEFAULT THEME */ @@ -210,13 +210,13 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} } .CodeMirror-measure pre { position: static; } -.CodeMirror pre.CodeMirror-cursor { +.CodeMirror div.CodeMirror-cursor { position: absolute; visibility: hidden; border-right: none; width: 0; } -.CodeMirror-focused pre.CodeMirror-cursor { +.CodeMirror-focused div.CodeMirror-cursor { visibility: visible; } @@ -233,7 +233,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} @media print { /* Hide the cursor when printing */ - .CodeMirror pre.CodeMirror-cursor { + .CodeMirror div.CodeMirror-cursor { visibility: hidden; } } diff --git a/lib/codemirror.js b/lib/codemirror.js index fd16ccece5..5af01f3aee 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -96,9 +96,9 @@ window.CodeMirror = (function() { d.lineDiv = elt("div"); d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); // Blinky cursor, and element used to ensure cursor fits at the end of a line - d.cursor = elt("pre", "\u00a0", "CodeMirror-cursor"); + d.cursor = elt("div", "\u00a0", "CodeMirror-cursor"); // Secondary cursor, shown when on a 'jump' in bi-directional text - d.otherCursor = elt("pre", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"); + d.otherCursor = elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"); // Used to measure text size d.measure = elt("div", null, "CodeMirror-measure"); // Wraps everything that needs to exist inside the vertically-padded coordinate system From 4d9c8881efc2cb96a1429b2f51f0a0c3e31e7a07 Mon Sep 17 00:00:00 2001 From: Peter Kroon Date: Fri, 21 Dec 2012 17:16:11 +0100 Subject: [PATCH 0006/5273] update test for iPAD 4 closes #993 --- test/test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test.js b/test/test.js index 841a984fab..810e50f553 100644 --- a/test/test.js +++ b/test/test.js @@ -487,6 +487,7 @@ testCM("doubleScrollbar", function(cm) { dummy.style.cssText = "height: 50px; overflow: scroll; width: 50px"; var scrollbarWidth = dummy.offsetWidth + 1 - dummy.clientWidth; document.body.removeChild(dummy); + if (scrollbarWidth < 2) return; cm.setSize(null, 100); addDoc(cm, 1, 300); var wrap = cm.getWrapperElement(); From c46ffbea705196904b49afaa1aa6ebdfba13cde8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 30 Dec 2012 14:48:21 +0100 Subject: [PATCH 0007/5273] Update xml completion demo to new interface for closetag add-on Closes #1106 --- demo/xmlcomplete.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/demo/xmlcomplete.html b/demo/xmlcomplete.html index f7cca8a352..142d52b477 100644 --- a/demo/xmlcomplete.html +++ b/demo/xmlcomplete.html @@ -62,12 +62,11 @@

    CodeMirror: XML Autocomplete demo

    mode: 'text/html', lineNumbers: true, extraKeys: { - "'>'": function(cm) { cm.closeTag(cm, '>'); }, - "'/'": function(cm) { cm.closeTag(cm, '/'); }, "' '": function(cm) { CodeMirror.xmlHint(cm, ' '); }, "'<'": function(cm) { CodeMirror.xmlHint(cm, '<'); }, "Ctrl-Space": function(cm) { CodeMirror.xmlHint(cm, ''); } - } + }, + autoCloseTags: true }); From e778265f9745b0e770fc73cafade146f289ab32b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 30 Dec 2012 14:57:39 +0100 Subject: [PATCH 0008/5273] Mention in manual that replacedWith expects an inline elt Issue #1109 --- doc/manual.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index e7568a1ed5..24a5b3eea2 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -835,7 +835,8 @@

    Programming API

    happens.
    replacedWith (dom node)
    Use a given node to display this range. Implies both - collapsed and atomic.
    + collapsed and atomic. The given DOM node must be an + inline element (as opposed to a block element).
    readOnly
    A read-only span can, as long as it is not cleared, not be modified except by From 0296db854ec6554604fc73425ae882ad5e5d7b6b Mon Sep 17 00:00:00 2001 From: Thomas Schmid Date: Sun, 23 Dec 2012 15:11:30 +0100 Subject: [PATCH 0009/5273] [sieve mode] Better indentation --- mode/sieve/sieve.js | 47 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/mode/sieve/sieve.js b/mode/sieve/sieve.js index 291c9c8c25..b1bba53e05 100644 --- a/mode/sieve/sieve.js +++ b/mode/sieve/sieve.js @@ -31,19 +31,37 @@ CodeMirror.defineMode("sieve", function(config) { state.tokenize = tokenString(ch); return state.tokenize(stream, state); } - - if (ch === "{") - { - state._indent++; + + if (ch == "(") { + state._indent.push("("); + // add virtual angel wings so that editor behaves... + // ...more sane incase of broken brackets + state._indent.push("{"); return null; } - if (ch === "}") - { - state._indent--; + if (ch === "{") { + state._indent.push("{"); return null; } + + if (ch == ")") { + state._indent.pop(); + state._indent.pop(); + } + if (ch === "}") { + state._indent.pop(); + return null; + } + + if (ch == ",") + return null; + + if (ch == ";") + return null; + + if (/[{}\(\),;]/.test(ch)) return null; @@ -62,7 +80,7 @@ CodeMirror.defineMode("sieve", function(config) { return "operator"; } - stream.eatWhile(/[\w\$_]/); + stream.eatWhile(/\w/); var cur = stream.current(); // "text:" *(SP / HTAB) (hash-comment / CRLF) @@ -79,6 +97,8 @@ CodeMirror.defineMode("sieve", function(config) { if (atoms.propertyIsEnumerable(cur)) return "atom"; + + return null; } function tokenMultiLineString(stream, state) @@ -135,7 +155,7 @@ CodeMirror.defineMode("sieve", function(config) { startState: function(base) { return {tokenize: tokenBase, baseIndent: base || 0, - _indent: 0}; + _indent: []}; }, token: function(stream, state) { @@ -146,7 +166,14 @@ CodeMirror.defineMode("sieve", function(config) { }, indent: function(state, _textAfter) { - return state.baseIndent + state._indent * indentUnit; + var length = state._indent.length; + if (_textAfter && (_textAfter[0] == "}")) + length--; + + if (length <0) + length = 0; + + return length * indentUnit; }, electricChars: "}" From 5490e6dd84d1f2950ae3f85993d6c97795160b8d Mon Sep 17 00:00:00 2001 From: nerbert Date: Sun, 30 Dec 2012 15:16:22 +0100 Subject: [PATCH 0010/5273] Add util/collapserange and demo Collapsing code by selecting a range to collapse in the gutter. --- demo/collapserange.html | 122 ++++++++++++++++++++++++++++++++++++++ lib/util/collapserange.js | 89 +++++++++++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 demo/collapserange.html create mode 100644 lib/util/collapserange.js diff --git a/demo/collapserange.html b/demo/collapserange.html new file mode 100644 index 0000000000..95c74ab07f --- /dev/null +++ b/demo/collapserange.html @@ -0,0 +1,122 @@ + + + + + CodeMirror: Range Collapsing Demo + + + + + + + + + +

    CodeMirror: Range Collapsing Demo

    + +
    + + + +

    Click on the gutter, then click again below, the code between will collapse. Click on either arrow to expand. + To use, simply include the collapsecode.js file and set collapseCode : true in options.

    + + + diff --git a/lib/util/collapserange.js b/lib/util/collapserange.js new file mode 100644 index 0000000000..0eed5b90be --- /dev/null +++ b/lib/util/collapserange.js @@ -0,0 +1,89 @@ +(function() { + CodeMirror.defaults.collapseCode = false; + CodeMirror.defineInitHook(function(cm) { + if(cm.getOption("collapseCode")) cm.initCollapseCode(cm); + }); + + CodeMirror.defineExtension("initCollapseCode", function(cm) { + cm.n = -1; + cm.col = []; + cm.oldmarker = ""; + if(typeof cm.guttters == 'undefined') cm.gutters = cm.getOption("gutters"); + var gutters = cm.gutters; + for(var i = 0; i < gutters.length; i++) { + if(gutters[i] == "CodeMirror-linenumbers") break; + } + gutters.splice(i + 1, 0, "collapse"); + // Why this is necessary I shall NEVER know! + gutters = gutters.toString().split(","); + cm.setOption("gutters", gutters); + cm.on("gutterClick", function(cm, line) { + cm.setGutterMarker(line, "collapse", cm.makeMarker(cm, line)); + }); + // No CSS class "collapse" is provided, so set styling here and refresh. + var g = cm.getGutterElement().childNodes; + for(i = 0; i < g.length; i++) { + if(/CodeMirror-linenumbers/.test(g[i].getAttribute("class"))) var linenumbers = g[i]; + if(/collapse/.test(g[i].getAttribute("class"))) var collapse = g[i]; + } + var gutterBorder = getStyle(linenumbers, "borderRight", "border-right"); + linenumbers.style.borderRight = "none"; + collapse.style.width = "0.4em"; + collapse.style.color = getStyle(linenumbers, "color", "color"); + collapse.style.borderRight = gutterBorder || "1px solid black"; + cm.refresh(); + }); + + CodeMirror.defineExtension("makeMarker", function(cm, line) { + var dn = ""; + var up = ""; + var info = cm.lineInfo(line); + var mark = info.gutterMarkers; + if(line <= cm.n) { + cm.setGutterMarker(cm.n, "collapse", null); + var nn = cm.n; + cm.n = -1; + if(line == nn) return; + } + if(typeof mark == "undefined" || mark == null) { + if(typeof cm.oldmarker.style != "undefined") cm.oldmarker.style.color = ""; + var marker = document.createElement("div"); + marker.style.marginLeft = "-2px"; + if(cm.n == -1) marker.style.color = "red"; + if(cm.n >= 0) { + marker.innerHTML = up; + var c = cm.markText({line:cm.n}, {line:line-1}, {collapsed:true}); + c.begin = cm.n; + c.end = line; + cm.col.push(c); + c = null; + cm.n = -1; + cm.scrollIntoView({line:line - 1, ch:0}); + } else { + marker.innerHTML = dn; + cm.n = line; + } + cm.oldmarker = marker; + } else { + for(i = 0; i < cm.col.length; i++) { + if(cm.col[i].begin == line ||cm.col[i].end == line) { + cm.col[i].clear(); + cm.setGutterMarker(cm.col[i].begin, "collapse", null); + cm.setGutterMarker(cm.col[i].end, "collapse", null); + cm.col.splice(i, 1); + break; + } + } + } + return marker; + }); + + function getStyle(elt, camelCase, hyphenated){ + if (elt.currentStyle) + return elt.currentStyle[camelCase]; + else if (document.defaultView && document.defaultView.getComputedStyle) + return document.defaultView.getComputedStyle(elt, null).getPropertyValue(hyphenated); + else + return null; + } +})(); \ No newline at end of file From a71d2bbf647a3ee9867960cbcdf50a5a9daaf22a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 30 Dec 2012 15:57:53 +0100 Subject: [PATCH 0011/5273] [util/collapserange] Document and rewrite --- demo/collapserange.html | 164 +++++++++++++++++--------------------- doc/manual.html | 5 ++ lib/codemirror.js | 4 +- lib/util/collapserange.js | 145 ++++++++++++++------------------- 4 files changed, 143 insertions(+), 175 deletions(-) diff --git a/demo/collapserange.html b/demo/collapserange.html index 95c74ab07f..87aad82307 100644 --- a/demo/collapserange.html +++ b/demo/collapserange.html @@ -11,112 +11,94 @@

    CodeMirror: Range Collapsing Demo

    +})(); + -

    Click on the gutter, then click again below, the code between will collapse. Click on either arrow to expand. - To use, simply include the collapsecode.js file and set collapseCode : true in options.

    +

    Click on the right side of the gutter, then click again below, + the code between will collapse. Click on either arrow to expand. + To use, simply include the collapserange.js file and + set collapseRange: true in options.

    diff --git a/doc/manual.html b/doc/manual.html index 24a5b3eea2..26797f16c9 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1164,6 +1164,11 @@

    Add-ons

    where indentation determines block structure (Python, Haskell), and CodeMirror.tagRangeFinder, for XML-style languages.
    +
    collapserange.js
    +
    Another approach to + folding. See demo. + Allows the user to select a range to fold by clicking in the + gutter.
    runmode.js
    Can be used to run a CodeMirror mode over text without actually opening an editor instance. diff --git a/lib/codemirror.js b/lib/codemirror.js index 5af01f3aee..257d267617 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1342,9 +1342,11 @@ window.CodeMirror = (function() { } function eventInWidget(display, e) { - for (var n = e_target(e); n != display.wrapper; n = n.parentNode) + for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { + if (!n) return true; if (/\bCodeMirror-(?:line)?widget\b/.test(n.className) || n.parentNode == display.sizer && n != display.mover) return true; + } } function posFromMouse(cm, e, liberal) { diff --git a/lib/util/collapserange.js b/lib/util/collapserange.js index 0eed5b90be..27dcbdde0b 100644 --- a/lib/util/collapserange.js +++ b/lib/util/collapserange.js @@ -1,89 +1,68 @@ (function() { - CodeMirror.defaults.collapseCode = false; - CodeMirror.defineInitHook(function(cm) { - if(cm.getOption("collapseCode")) cm.initCollapseCode(cm); + CodeMirror.defineOption("collapseRange", false, function(cm, val, old) { + var wasOn = old && old != CodeMirror.Init; + if (val && !wasOn) + enableRangeCollapsing(cm); + else if (!val && wasOn) + disableRangeCollapsing(cm); }); - - CodeMirror.defineExtension("initCollapseCode", function(cm) { - cm.n = -1; - cm.col = []; - cm.oldmarker = ""; - if(typeof cm.guttters == 'undefined') cm.gutters = cm.getOption("gutters"); - var gutters = cm.gutters; - for(var i = 0; i < gutters.length; i++) { - if(gutters[i] == "CodeMirror-linenumbers") break; - } - gutters.splice(i + 1, 0, "collapse"); - // Why this is necessary I shall NEVER know! - gutters = gutters.toString().split(","); - cm.setOption("gutters", gutters); - cm.on("gutterClick", function(cm, line) { - cm.setGutterMarker(line, "collapse", cm.makeMarker(cm, line)); - }); - // No CSS class "collapse" is provided, so set styling here and refresh. - var g = cm.getGutterElement().childNodes; - for(i = 0; i < g.length; i++) { - if(/CodeMirror-linenumbers/.test(g[i].getAttribute("class"))) var linenumbers = g[i]; - if(/collapse/.test(g[i].getAttribute("class"))) var collapse = g[i]; - } - var gutterBorder = getStyle(linenumbers, "borderRight", "border-right"); - linenumbers.style.borderRight = "none"; - collapse.style.width = "0.4em"; - collapse.style.color = getStyle(linenumbers, "color", "color"); - collapse.style.borderRight = gutterBorder || "1px solid black"; - cm.refresh(); - }); - - CodeMirror.defineExtension("makeMarker", function(cm, line) { - var dn = ""; - var up = ""; - var info = cm.lineInfo(line); - var mark = info.gutterMarkers; - if(line <= cm.n) { - cm.setGutterMarker(cm.n, "collapse", null); - var nn = cm.n; - cm.n = -1; - if(line == nn) return; - } - if(typeof mark == "undefined" || mark == null) { - if(typeof cm.oldmarker.style != "undefined") cm.oldmarker.style.color = ""; - var marker = document.createElement("div"); - marker.style.marginLeft = "-2px"; - if(cm.n == -1) marker.style.color = "red"; - if(cm.n >= 0) { - marker.innerHTML = up; - var c = cm.markText({line:cm.n}, {line:line-1}, {collapsed:true}); - c.begin = cm.n; - c.end = line; - cm.col.push(c); - c = null; - cm.n = -1; - cm.scrollIntoView({line:line - 1, ch:0}); - } else { - marker.innerHTML = dn; - cm.n = line; - } - cm.oldmarker = marker; - } else { - for(i = 0; i < cm.col.length; i++) { - if(cm.col[i].begin == line ||cm.col[i].end == line) { - cm.col[i].clear(); - cm.setGutterMarker(cm.col[i].begin, "collapse", null); - cm.setGutterMarker(cm.col[i].end, "collapse", null); - cm.col.splice(i, 1); - break; + + var gutterClass = "CodeMirror-collapserange"; + + function enableRangeCollapsing(cm) { + cm.on("gutterClick", gutterClick); + cm.setOption("gutters", (cm.getOption("gutters") || []).concat([gutterClass])); + } + + function disableRangeCollapsing(cm) { + cm.rangeCollapseStart = null; + cm.off("gutterClick", gutterClick); + var gutters = cm.getOption("gutters"); + for (var i = 0; i < gutters.length && gutters[i] != gutterClass; ++i) {} + cm.setOption("gutters", gutters.slice(0, i).concat(gutters.slice(i + 1))); + } + + function gutterClick(cm, line, gutter) { + if (gutter != gutterClass) return; + + var start = cm.rangeCollapseStart; + if (start) { + var old = cm.getLineNumber(start); + cm.setGutterMarker(start, gutterClass, null); + cm.rangeCollapseStart = null; + var from = Math.min(old, line), to = Math.max(old, line); + if (from != to) { + // Finish this fold + var fold = cm.markText({line: from + 1, ch: 0}, {line: to - 1}, { + collapsed: true, + inclusiveLeft: true, + inclusiveRight: true, + clearOnEnter: true + }); + var topLine = cm.setGutterMarker(from, gutterClass, makeMarker(true, true, clear)); + var botLine = cm.setGutterMarker(to, gutterClass, makeMarker(false, true, clear)); + CodeMirror.on(fold, "clear", clear); + + function clear() { + cm.setGutterMarker(topLine, gutterClass, null); + cm.setGutterMarker(botLine, gutterClass, null); + fold.clear(); } + return; } } - return marker; - }); - - function getStyle(elt, camelCase, hyphenated){ - if (elt.currentStyle) - return elt.currentStyle[camelCase]; - else if (document.defaultView && document.defaultView.getComputedStyle) - return document.defaultView.getComputedStyle(elt, null).getPropertyValue(hyphenated); - else - return null; + + // Start a new fold + cm.rangeCollapseStart = cm.setGutterMarker(line, gutterClass, makeMarker(true, false)); + } + + function makeMarker(isTop, isFinished, handler) { + var node = document.createElement("div"); + node.innerHTML = isTop ? "\u25bc" : "\u25b2"; + if (!isFinished) node.style.color = "red"; + node.style.fontSize = "85%"; + node.style.cursor = "pointer"; + if (handler) CodeMirror.on(node, "mousedown", handler); + return node; } -})(); \ No newline at end of file +})(); From 88579793750ef10d7c5326b704e9d7156462ed8a Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Thu, 27 Dec 2012 15:17:22 -0500 Subject: [PATCH 0012/5273] [vim keymap] Fix :map --- keymap/vim.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 6095a33749..bd4c6aceef 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2146,7 +2146,7 @@ params.argString = inputStream.match(/.*/)[0]; // Parse command-line arguments var delim = command.argDelimiter || /\s+/; - var args = params.argString.split(delim); + var args = trim(params.argString).split(delim); if (args.length && args[0]) { params.args = args; } @@ -2253,7 +2253,7 @@ var exCommands = { map: function(cm, params) { - var mapArgs = params.commandArgs; + var mapArgs = params.args; if (!mapArgs || mapArgs.length < 2) { if (cm) { showConfirm(cm, 'Invalid mapping: ' + params.input); From b06009d6058f1b2087454628aab4628dddc328ca Mon Sep 17 00:00:00 2001 From: think Date: Thu, 27 Dec 2012 20:53:24 +0100 Subject: [PATCH 0013/5273] added support for D programming language (visit: http://www.dlang.org) --- mode/d/d.js | 205 ++++++++++++++++++++++++++++++++++++ mode/d/index.html | 261 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 466 insertions(+) create mode 100755 mode/d/d.js create mode 100755 mode/d/index.html diff --git a/mode/d/d.js b/mode/d/d.js new file mode 100755 index 0000000000..ab345f1a0d --- /dev/null +++ b/mode/d/d.js @@ -0,0 +1,205 @@ +CodeMirror.defineMode("d", function(config, parserConfig) { + var indentUnit = config.indentUnit, + statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, + keywords = parserConfig.keywords || {}, + builtin = parserConfig.builtin || {}, + blockKeywords = parserConfig.blockKeywords || {}, + atoms = parserConfig.atoms || {}, + hooks = parserConfig.hooks || {}, + multiLineStrings = parserConfig.multiLineStrings; + var isOperatorChar = /[+\-*&%=<>!?|\/]/; + + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (hooks[ch]) { + var result = hooks[ch](stream, state); + if (result !== false) return result; + } + if (ch == '"' || ch == "'" || ch == "`") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + curPunc = ch; + return null; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (ch == "/") { + if (stream.eat("+")) { + state.tokenize = tokenComment; + return tokenNestedComment(stream, state); + } + if (stream.eat("*")) { + state.tokenize = tokenComment; + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + var cur = stream.current(); + if (keywords.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "keyword"; + } + if (builtin.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "builtin"; + } + if (atoms.propertyIsEnumerable(cur)) return "atom"; + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) {end = true; break;} + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = null; + return "string"; + }; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenNestedComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch == "+"); + } + return "comment"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + function pushContext(state, col, type) { + var indent = state.indented; + if (state.context && state.context.type == "statement") + indent = state.context.indented; + return state.context = new Context(indent, col, type, null, state.context); + } + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + // Interface + + return { + startState: function(basecolumn) { + return { + tokenize: null, + context: new Context((basecolumn || 0) - indentUnit, 0, "top", false), + indented: 0, + startOfLine: true + }; + }, + + token: function(stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + if (ctx.align == null) ctx.align = true; + + if ((curPunc == ";" || curPunc == ":" || curPunc == ",") && ctx.type == "statement") popContext(state); + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (((ctx.type == "}" || ctx.type == "top") && curPunc != ';') || (ctx.type == "statement" && curPunc == "newstatement")) + pushContext(state, stream.column(), "statement"); + state.startOfLine = false; + return style; + }, + + indent: function(state, textAfter) { + if (state.tokenize != tokenBase && state.tokenize != null) return CodeMirror.Pass; + var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); + if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; + var closing = firstChar == ctx.type; + if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); + else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indented + (closing ? 0 : indentUnit); + }, + + electricChars: "{}" + }; +}); + +(function() { + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var blockKeywords = "body catch class do else enum for foreach foreach_reverse if in interface mixin " + + "out scope struct switch try union unittest version while with"; + + CodeMirror.defineMIME("text/x-d", { + name: "d", + keywords: words("abstract alias align asm assert auto break case cast cdouble cent cfloat const continue " + + "debug default delegate delete deprecated export extern final finally function goto immutable " + + "import inout invariant is lazy macro module new nothrow override package pragma private " + + "protected public pure ref return shared short static super synchronized template this " + + "throw typedef typeid typeof volatile __FILE__ __LINE__ __gshared __traits __vector __parameters " + + blockKeywords), + blockKeywords: words(blockKeywords), + builtin: words("bool byte char creal dchar double float idouble ifloat int ireal long real short ubyte " + + "ucent uint ulong ushort wchar wstring void size_t sizediff_t"), + atoms: words("exit failure success true false null"), + hooks: { + "@": function(stream, _state) { + stream.eatWhile(/[\w\$_]/); + return "meta"; + } + } + }); +}()); diff --git a/mode/d/index.html b/mode/d/index.html new file mode 100755 index 0000000000..130ba5adac --- /dev/null +++ b/mode/d/index.html @@ -0,0 +1,261 @@ + + + + + CodeMirror: D mode + + + + + + + + +

    CodeMirror: D mode

    + +
    + + + +

    Simple mode that handle D-Syntax (DLang Homepage).

    + +

    MIME types defined: text/x-d + .

    + + From 1082693f6ac1abca368a2af73d46baf19f2e8f15 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 30 Dec 2012 16:16:19 +0100 Subject: [PATCH 0014/5273] Integrate D mode --- doc/compress.html | 1 + index.html | 1 + mode/d/index.html | 1 + 3 files changed, 3 insertions(+) diff --git a/doc/compress.html b/doc/compress.html index 94df0c595e..636a22a956 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -73,6 +73,7 @@

    { } CodeMi + diff --git a/index.html b/index.html index 3347d21949..aaa07cf49f 100644 --- a/index.html +++ b/index.html @@ -40,6 +40,7 @@

    Supported modes:

  • CoffeeScript
  • Common Lisp
  • CSS
  • +
  • D
  • diff
  • ECL
  • Erlang
  • diff --git a/mode/d/index.html b/mode/d/index.html index 130ba5adac..89a849895c 100755 --- a/mode/d/index.html +++ b/mode/d/index.html @@ -249,6 +249,7 @@

    CodeMirror: D mode

    var editor = CodeMirror.fromTextArea(document.getElementById("code"), { lineNumbers: true, matchBrackets: true, + indentUnit: 4, mode: "text/x-d" }); From 1dad2c920299db582b29fa0048e4089342a05817 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 30 Dec 2012 16:25:57 +0100 Subject: [PATCH 0015/5273] [util/foldcode] Fix bug in indentRangeFinder Closes #1121 --- lib/util/foldcode.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/util/foldcode.js b/lib/util/foldcode.js index 407bac2a5e..7425b7dc81 100644 --- a/lib/util/foldcode.js +++ b/lib/util/foldcode.js @@ -142,7 +142,8 @@ CodeMirror.indentRangeFinder = function(cm, start) { var myIndent = CodeMirror.countColumn(firstLine, null, tabSize); for (var i = start.line + 1, end = cm.lineCount(); i < end; ++i) { var curLine = cm.getLine(i); - if (CodeMirror.countColumn(curLine, null, tabSize) < myIndent) + if (CodeMirror.countColumn(curLine, null, tabSize) < myIndent && + CodeMirror.countColumn(cm.getLine(i-1), null, tabSize) > myIndent) return {from: {line: start.line, ch: firstLine.length}, to: {line: i, ch: curLine.length}}; } From f88f3e9d4186e7c4f3529aef4ae536e3f69aed48 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 30 Dec 2012 16:29:57 +0100 Subject: [PATCH 0016/5273] [util/formatting] Don't add a trailing newline unless the formatter wants one Issue #1120 --- lib/util/formatting.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util/formatting.js b/lib/util/formatting.js index ccf2a9a6bb..25ee1531a8 100644 --- a/lib/util/formatting.js +++ b/lib/util/formatting.js @@ -95,7 +95,7 @@ newline(); } if (!stream.pos && outer.blankLine) outer.blankLine(state); - if (!atSol) newline(); + if (!atSol && i < text.length - 1) newline(); } cm.operation(function () { From 2dff7cb41e7f6cf6f0b63f86433cb55a5d3184b7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 30 Dec 2012 16:46:25 +0100 Subject: [PATCH 0017/5273] Fix bug in code that compensates for strange browser line wrapping Closes #1123 --- demo/folding.html | 2 +- lib/codemirror.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/folding.html b/demo/folding.html index 89120cb63f..f9873d9b45 100644 --- a/demo/folding.html +++ b/demo/folding.html @@ -36,7 +36,7 @@

    CodeMirror: Code Folding Demo

    window.onload = function() { var te = document.getElementById("code"); var sc = document.getElementById("script"); - te.value = (sc.textContent || sc.innerText || sc.innerHTML).replace(/^\s*/, ""); + te.value = "window.onload = function(){ $\\displaystyle \\lim_{x\\to0}\\frac{\\int_0^{\\sin x}e^tdt}{x}\\lim_{x\\to0}\\frac{\\int_0^{\\sin x}e^tdt}{x}$\n" + (sc.textContent || sc.innerText || sc.innerHTML).replace(/^\s*/, ""); sc.innerHTML = ""; var te_html = document.getElementById("code-html"); te_html.value = "\n " + document.documentElement.innerHTML + "\n"; diff --git a/lib/codemirror.js b/lib/codemirror.js index 257d267617..fd1817e6af 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3745,7 +3745,7 @@ window.CodeMirror = (function() { function buildTokenMeasure(builder, text, style, startStyle, endStyle) { for (var i = 0; i < text.length; ++i) { - if (i && i < text.length - 1 && + if (i && i < text.length && builder.cm.options.lineWrapping && spanAffectsWrapping.test(text.slice(i - 1, i + 1))) builder.pre.appendChild(elt("wbr")); From 634acc1a5e8e6d01adfa10a6f4654e54c696a431 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 30 Dec 2012 16:53:08 +0100 Subject: [PATCH 0018/5273] Revert debugging change --- demo/folding.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/folding.html b/demo/folding.html index f9873d9b45..89120cb63f 100644 --- a/demo/folding.html +++ b/demo/folding.html @@ -36,7 +36,7 @@

    CodeMirror: Code Folding Demo

    window.onload = function() { var te = document.getElementById("code"); var sc = document.getElementById("script"); - te.value = "window.onload = function(){ $\\displaystyle \\lim_{x\\to0}\\frac{\\int_0^{\\sin x}e^tdt}{x}\\lim_{x\\to0}\\frac{\\int_0^{\\sin x}e^tdt}{x}$\n" + (sc.textContent || sc.innerText || sc.innerHTML).replace(/^\s*/, ""); + te.value = (sc.textContent || sc.innerText || sc.innerHTML).replace(/^\s*/, ""); sc.innerHTML = ""; var te_html = document.getElementById("code-html"); te_html.value = "\n " + document.documentElement.innerHTML + "\n"; From 3e8821c693a40fd84ea6a01d4c1407cb8ef57f3f Mon Sep 17 00:00:00 2001 From: Eric Allam Date: Wed, 2 Jan 2013 09:45:18 +0100 Subject: [PATCH 0019/5273] Add a Sass mode --- mode/sass/sass.js | 360 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 mode/sass/sass.js diff --git a/mode/sass/sass.js b/mode/sass/sass.js new file mode 100644 index 0000000000..d9e83df826 --- /dev/null +++ b/mode/sass/sass.js @@ -0,0 +1,360 @@ +CodeMirror.defineMode("sass", function(config) { + indentUnit = config.indentUnit; + + var tokenRegexp = function(words){ + return new RegExp("^" + words.join("|")); + } + + var controlDirectives = ["@for", "@while", "@if", + "@each", "@mixin", "@function", + "@else", "@else if"]; + + var controlRegexp = new RegExp(controlDirectives.join("|")); + + var tags = ["&", "a","abbr","acronym","address","applet","area","article","aside","audio","b","base","basefont","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","command","datalist","dd","del","details","dfn","dir","div","dl","dt","em","embed","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","keygen","kbd","label","legend","li","link","map","mark","menu","meta","meter","nav","noframes","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strike","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","tt","u","ul","var","video","wbr"]; + var keywords = ["true", "false", "null", "auto"]; + var keywordsRegexp = new RegExp("^" + keywords.join("|")) + + var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-", "\\!=", "/", "\\*", "%", "and", "or", "not"] + var opRegexp = tokenRegexp(operators); + + function htmlTag(val){ + for(var i=0; i Date: Wed, 2 Jan 2013 09:58:12 +0100 Subject: [PATCH 0020/5273] [sass mode] Integrate new mode --- doc/compress.html | 2 ++ doc/realworld.html | 2 +- index.html | 1 + mode/sass/index.html | 54 ++++++++++++++++++++++++++++++++++++++++++++ mode/sass/sass.js | 2 ++ 5 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 mode/sass/index.html diff --git a/doc/compress.html b/doc/compress.html index 636a22a956..3bfec8df41 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -106,6 +106,8 @@

    { } CodeMi + + diff --git a/doc/realworld.html b/doc/realworld.html index efb10420ec..9c3076bb99 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -28,7 +28,7 @@

    { } CodeMi
  • Codebug (PHP Xdebug front-end)
  • CodeMirror2-GWT (Google Web Toolkit wrapper)
  • Codepen (gallery of animations)
  • -
  • Code School (online tech learning environment)
  • +
  • Code School (online tech learning environment)
  • Codev (collaborative IDE)
  • Collaborative CodeMirror demo (CodeMirror + operational transforms)
  • CKWNC (UML editor)
  • diff --git a/index.html b/index.html index aaa07cf49f..1fc56855fa 100644 --- a/index.html +++ b/index.html @@ -70,6 +70,7 @@

    Supported modes:

  • reStructuredText
  • Ruby
  • Rust
  • +
  • Sass
  • Scala
  • Scheme
  • Shell
  • diff --git a/mode/sass/index.html b/mode/sass/index.html new file mode 100644 index 0000000000..71c05e0c30 --- /dev/null +++ b/mode/sass/index.html @@ -0,0 +1,54 @@ + + + + + CodeMirror: Sass mode + + + + + + + + +

    CodeMirror: Sass mode

    +
    + + +

    MIME types defined: text/x-sass.

    + + diff --git a/mode/sass/sass.js b/mode/sass/sass.js index d9e83df826..45466a10ab 100644 --- a/mode/sass/sass.js +++ b/mode/sass/sass.js @@ -358,3 +358,5 @@ CodeMirror.defineMode("sass", function(config) { } }; }); + +CodeMirror.defineMIME("text/x-sass", "sass"); From 7f87babf2aad43a4c50172a265637a4508321dfd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 2 Jan 2013 10:05:12 +0100 Subject: [PATCH 0021/5273] [sass mode] Clean up missing semicolons, unused vars, and trailing space --- mode/sass/sass.js | 225 ++++++++++++++++++++++------------------------ 1 file changed, 106 insertions(+), 119 deletions(-) diff --git a/mode/sass/sass.js b/mode/sass/sass.js index 45466a10ab..8f17cf1692 100644 --- a/mode/sass/sass.js +++ b/mode/sass/sass.js @@ -1,23 +1,15 @@ CodeMirror.defineMode("sass", function(config) { - indentUnit = config.indentUnit; - var tokenRegexp = function(words){ return new RegExp("^" + words.join("|")); - } - - var controlDirectives = ["@for", "@while", "@if", - "@each", "@mixin", "@function", - "@else", "@else if"]; - - var controlRegexp = new RegExp(controlDirectives.join("|")); - + }; + var tags = ["&", "a","abbr","acronym","address","applet","area","article","aside","audio","b","base","basefont","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","command","datalist","dd","del","details","dfn","dir","div","dl","dt","em","embed","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","keygen","kbd","label","legend","li","link","map","mark","menu","meta","meter","nav","noframes","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strike","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","tt","u","ul","var","video","wbr"]; var keywords = ["true", "false", "null", "auto"]; - var keywordsRegexp = new RegExp("^" + keywords.join("|")) - - var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-", "\\!=", "/", "\\*", "%", "and", "or", "not"] + var keywordsRegexp = new RegExp("^" + keywords.join("|")); + + var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-", "\\!=", "/", "\\*", "%", "and", "or", "not"]; var opRegexp = tokenRegexp(operators); - + function htmlTag(val){ for(var i=0; i Date: Wed, 2 Jan 2013 10:43:18 +0100 Subject: [PATCH 0022/5273] Expose TextMarker constructor, add getOptions method to it Issue #1111 --- doc/manual.html | 20 ++++++++++++++------ lib/codemirror.js | 13 +++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 26797f16c9..5f7c080c89 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -852,12 +852,20 @@

    Programming API

    endStyle
    Equivalent to startStyle, but for the rightmost span.
    - The method will return an object with two methods, - clear(), which removes the mark, - and find(), which returns a {from, to} - (both document positions), indicating the current position of - the marked range, or undefined if the marker is no - longer in the document. + The method will return an object that represents the marker + (with constuctor CodeMirror.TextMarker), which + exposes three methods: + clear(), to remove the mark, + find(), which returns a {from, to} + object (both holding document positions), indicating the current + position of the marked range, or undefined if the + marker is no longer in the document, and + finally getOptions(copyWidget), which returns an + object representing the options for the marker. + If copyWidget is given an true, it will clone the + value of + the replacedWith + option, if any.
    setBookmark(pos, widget) → object
    Inserts a bookmark, a handle that follows the text around it diff --git a/lib/codemirror.js b/lib/codemirror.js index fd1817e6af..c637977b30 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3264,6 +3264,7 @@ window.CodeMirror = (function() { this.type = type; this.cm = cm; } + CodeMirror.TextMarker = TextMarker; TextMarker.prototype.clear = function() { if (this.explicitlyCleared) return; @@ -3305,6 +3306,18 @@ window.CodeMirror = (function() { return from && {from: from, to: to}; }; + TextMarker.prototype.getOptions = function(copyWidget) { + var repl = this.replacedWith; + return {className: this.className, + inclusiveLeft: this.inclusiveLeft, inclusiveRight: this.inclusiveRight, + atomic: this.atomic, + collapsed: this.collapsed, + clearOnEnter: this.clearOnEnter, + replacedWith: copyWidget ? repl && repl.cloneNode(true) : repl, + readOnly: this.readOnly, + startStyle: this.startStyle, endStyle: this.endStyle}; + }; + function markText(cm, from, to, options, type) { var doc = cm.view.doc; var marker = new TextMarker(cm, type); From 42ab2479c4efe546524cca00710d0badeebd55cc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 2 Jan 2013 11:22:04 +0100 Subject: [PATCH 0023/5273] Add overflow: auto to line widget wrapper to prevent margin leaking (If the widget had a margin, that margin would end up outside the wrapper, throwing off line height measurement.) Might be related to issue #925 --- lib/codemirror.css | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codemirror.css b/lib/codemirror.css index 923c3024ff..2afcbb1556 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -196,6 +196,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} .CodeMirror-linewidget { position: relative; z-index: 2; + overflow: auto; } .CodeMirror-wrap .CodeMirror-scroll { From 47239048037dcfff0c4d34f2734d170f8330b13d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 2 Jan 2013 11:50:50 +0100 Subject: [PATCH 0024/5273] Support showIfHidden option in line widgets Issue #1109 --- doc/manual.html | 3 +++ lib/codemirror.js | 64 +++++++++++++++++++++++++++++------------------ 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 5f7c080c89..23894b0941 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -970,6 +970,9 @@

    Programming API

    above (boolean)
    Causes the widget to be placed above instead of below the text of the line.
    +
    showIfHidden (boolean)
    +
    When true, will cause the widget to be rendered even if + the line it is associated with is hidden.
    Note that the widget node will become a descendant of nodes with CodeMirror-specific CSS classes, and those classes might in some diff --git a/lib/codemirror.js b/lib/codemirror.js index c637977b30..0913c4b7c2 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -560,6 +560,17 @@ window.CodeMirror = (function() { if (nextIntact && nextIntact.to == lineNo) nextIntact = intact.shift(); if (lineIsHidden(line)) { if (line.height != 0) updateLineHeight(line, 0); + if (line.widgets && cur.previousSibling) for (var i = 0; i < line.widgets.length; ++i) + if (line.widgets[i].showIfHidden) { + var prev = cur.previousSibling; + if (prev.nodeType == "pre") { + var wrap = elt("div", null, null, "position: relative"); + prev.parentNode.replaceChild(wrap, prev); + wrap.appendChild(prev); + prev = wrap; + } + prev.appendChild(buildLineWidget(line.widgets[i], dims)); + } } else if (nextIntact && nextIntact.from <= lineNo && nextIntact.to > lineNo) { // This line is intact. Skip to the actual node. Update its // line number if needed. @@ -612,35 +623,38 @@ window.CodeMirror = (function() { if (line.bgClass) wrap.appendChild(elt("div", "\u00a0", line.bgClass + " CodeMirror-linebackground")); wrap.appendChild(lineElement); - if (line.widgets) - for (var i = 0, ws = line.widgets; i < ws.length; ++i) { - var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); - node.widget = widget; - if (widget.noHScroll) { - (wrap.alignable || (wrap.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"; - } - 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"; - } - if (widget.above) - wrap.insertBefore(node, cm.options.lineNumbers && line.height != 0 ? gutterWrap : lineElement); - else - wrap.appendChild(node); - } - + if (line.widgets) for (var i = 0, ws = line.widgets; i < ws.length; ++i) { + var widget = ws[i], node = buildLineWidget(widget, dims); + if (widget.above) + wrap.insertBefore(node, cm.options.lineNumbers && line.height != 0 ? gutterWrap : lineElement); + else + wrap.appendChild(node); + } if (ie_lt8) wrap.style.zIndex = 2; return wrap; } + function buildLineWidget(widget, dims) { + var node = elt("div", [widget.node], "CodeMirror-linewidget"); + node.widget = widget; + if (widget.noHScroll) { + (wrap.alignable || (wrap.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"; + } + 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"; + } + return node; + } + // SELECTION / CURSOR function updateSelection(cm) { From 043a6f36103297f64ab624dce3c8f375e34c96dc Mon Sep 17 00:00:00 2001 From: Peter Kroon Date: Sun, 30 Dec 2012 20:40:56 +0100 Subject: [PATCH 0025/5273] Link collapserange demo from folding demo. --- demo/folding.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/folding.html b/demo/folding.html index 89120cb63f..e6180fe888 100644 --- a/demo/folding.html +++ b/demo/folding.html @@ -27,7 +27,7 @@

    CodeMirror: Code Folding Demo

    Demonstration of code folding using the code in foldcode.js. Press ctrl-q or click on the gutter to fold a block, again - to unfold.

    + to unfold.
    Try the Range Colapse demo as well.

    JavaScript:
    HTML:
    From 392c6bba989301000af2789384c547c22cf29368 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sun, 30 Dec 2012 23:26:54 +0100 Subject: [PATCH 0026/5273] Enable JS autocomplete on other variable types. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mode-javascript sets "variable-2" or "variable-3" types, too. They should trigger autocompletion, too. Test case: function(obj. --- lib/util/javascript-hint.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/util/javascript-hint.js b/lib/util/javascript-hint.js index be6098e6e6..d44ff2968d 100644 --- a/lib/util/javascript-hint.js +++ b/lib/util/javascript-hint.js @@ -40,8 +40,8 @@ } } while (level > 0); tprop = getToken(editor, {line: cur.line, ch: tprop.start}); - if (tprop.type == 'variable') - tprop.type = 'function'; + if (tprop.type.indexOf("variable") === 0) + tprop.type = "function"; else return; // no clue } if (!context) var context = []; @@ -106,7 +106,7 @@ // If this is a property, see if it belongs to some object we can // find in the current environment. var obj = context.pop(), base; - if (obj.type == "variable") { + if (obj.type.indexOf("variable") === 0) { if (options && options.additionalContext) base = options.additionalContext[obj.string]; base = base || window[obj.string]; From be495eb996a4ca79d119e36f434ad52183cdd4c0 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Mon, 31 Dec 2012 18:51:19 -0500 Subject: [PATCH 0027/5273] Fix fat cursor --- lib/codemirror.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index 2afcbb1556..1ceb0800dc 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -46,7 +46,7 @@ .CodeMirror div.CodeMirror-secondarycursor { border-left: 1px solid silver; } -.cm-keymap-fat-cursor div.CodeMirror-cursor { +.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor { width: auto; border: 0; background: transparent; @@ -54,7 +54,7 @@ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800); } /* Kludge to turn off filter in ie9+, which also accepts rgba */ -.cm-keymap-fat-cursor div.CodeMirror-cursor:not(#nonsense_id) { +.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor:not(#nonsense_id) { filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } /* Can style cursor different in overwrite (non-insert) mode */ From 3163310e222b94bed4320dc429045f511cadfd95 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Mon, 31 Dec 2012 18:30:51 -0500 Subject: [PATCH 0028/5273] [vim keymap] Catch up on unit tests --- keymap/vim.js | 18 ++-- test/vim_test.js | 238 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 202 insertions(+), 54 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index bd4c6aceef..d72123f10e 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1129,17 +1129,21 @@ cm.setSelection(curStart, curEnd); } } else { + curStart = cm.getCursor('anchor'); + curEnd = cm.getCursor('head'); if (!vim.visualLine && actionArgs.linewise) { // Shift-V pressed in characterwise visual mode. Switch to linewise // visual mode instead of exiting visual mode. vim.visualLine = true; - curStart = cm.getCursor('anchor'); - curEnd = cm.getCursor('head'); curStart.ch = cursorIsBefore(curStart, curEnd) ? 0 : lineLength(cm, curStart.line); curEnd.ch = cursorIsBefore(curStart, curEnd) ? lineLength(cm, curEnd.line) : 0; cm.setSelection(curStart, curEnd); + } else if (vim.visualLine && !actionArgs.linewise) { + // v pressed in linewise visual mode. Switch to characterwise visual + // mode instead of exiting visual mode. + vim.visualLine = false; } else { exitVisualMode(cm, vim); } @@ -2049,10 +2053,10 @@ { name: 'redo', shortName: 'red', type: 'builtIn' }, { name: 'substitute', shortName: 's', type: 'builtIn'} ]; - var ExCommandDispatcher = function() { + Vim.ExCommandDispatcher = function() { this.buildCommandMap_(); }; - ExCommandDispatcher.prototype = { + Vim.ExCommandDispatcher.prototype = { processCommand: function(cm, input) { var inputStream = new CodeMirror.StringStream(input); var params = {}; @@ -2101,7 +2105,7 @@ result.lineEnd = cm.lineCount() - 1; } else { result.line = this.parseLineSpec_(cm, inputStream); - if (result.line && inputStream.eat(',')) { + if (result.line !== undefined && inputStream.eat(',')) { result.lineEnd = this.parseLineSpec_(cm, inputStream); } } @@ -2176,7 +2180,7 @@ } }, map: function(lhs, rhs) { - if (lhs.charAt(0) == ':') { + if (lhs != ':' && lhs.charAt(0) == ':') { var commandName = lhs.substring(1); if (rhs != ':' && rhs.charAt(0) == ':') { // Ex to Ex mapping @@ -2329,7 +2333,7 @@ } }; - var exCommandDispatcher = new ExCommandDispatcher(); + var exCommandDispatcher = new Vim.ExCommandDispatcher(); // Register Vim with CodeMirror function buildVimKeyMap() { diff --git a/test/vim_test.js b/test/vim_test.js index a4531d3bdf..bf3ad4e071 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -113,6 +113,12 @@ function testVim(name, run, opts, expectedFail) { } } } + function doExFn(cm) { + return function(command) { + cm.openDialog = helpers.fakeOpenDialog(command); + helpers.doKeys(':'); + } + } function assertCursorAtFn(cm) { return function(line, ch) { var pos; @@ -131,6 +137,7 @@ function testVim(name, run, opts, expectedFail) { } var helpers = { doKeys: doKeysFn(cm), + doEx: doExFn(cm), assertCursorAt: assertCursorAtFn(cm), fakeOpenDialog: fakeOpenDialog, getRegisterController: function() { @@ -279,7 +286,7 @@ testVim('dl_eol', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq(' ', register.text); is(!register.linewise); - helpers.assertCursorAt(makeCursor(0, 6)); + helpers.assertCursorAt(0, 6); }, { value: ' word1 ' }); testVim('dl_repeat', function(cm, vim, helpers) { var curStart = makeCursor(0, 0); @@ -309,7 +316,7 @@ testVim('dj', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq(' word1\nword2\n', register.text); is(register.linewise); - eqPos(makeCursor(0, 1), cm.getCursor()); + helpers.assertCursorAt(0, 1); }, { value: ' word1\nword2\n word3' }); testVim('dj_end_of_document', function(cm, vim, helpers) { var curStart = makeCursor(0, 3); @@ -329,7 +336,7 @@ testVim('dk', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq(' word1\nword2\n', register.text); is(register.linewise); - eqPos(makeCursor(0, 1), cm.getCursor()); + helpers.assertCursorAt(0, 1); }, { value: ' word1\nword2\n word3' }); testVim('dk_start_of_document', function(cm, vim, helpers) { var curStart = makeCursor(0, 3); @@ -417,7 +424,7 @@ testVim('d_reverse', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq('word1\n', register.text); is(!register.linewise); - eqPos(makeCursor(0, 1), cm.getCursor()); + helpers.assertCursorAt(0, 1); }, { value: ' word1\nword2 ' }); testVim('dd', function(cm, vim, helpers) { cm.setCursor(0, 3); @@ -429,7 +436,7 @@ testVim('dd', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq(expectedBuffer, register.text); is(register.linewise); - eqPos(makeCursor(0, lines[1].textStart), cm.getCursor()); + helpers.assertCursorAt(0, lines[1].textStart); }); testVim('dd_prefix_repeat', function(cm, vim, helpers) { cm.setCursor(0, 3); @@ -441,7 +448,7 @@ testVim('dd_prefix_repeat', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq(expectedBuffer, register.text); is(register.linewise); - eqPos(makeCursor(0, lines[2].textStart), cm.getCursor()); + helpers.assertCursorAt(0, lines[2].textStart); }); testVim('dd_motion_repeat', function(cm, vim, helpers) { cm.setCursor(0, 3); @@ -453,7 +460,7 @@ testVim('dd_motion_repeat', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq(expectedBuffer, register.text); is(register.linewise); - eqPos(makeCursor(0, lines[2].textStart), cm.getCursor()); + helpers.assertCursorAt(0, lines[2].textStart); }); testVim('dd_multiply_repeat', function(cm, vim, helpers) { cm.setCursor(0, 3); @@ -465,7 +472,7 @@ testVim('dd_multiply_repeat', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq(expectedBuffer, register.text); is(register.linewise); - eqPos(makeCursor(0, lines[6].textStart), cm.getCursor()); + helpers.assertCursorAt(0, lines[6].textStart); }); // Yank commands should behave the exact same as d commands, expect that nothing // gets deleted. @@ -520,7 +527,7 @@ testVim('cc_multiply_repeat', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq(expectedBuffer, register.text); is(register.linewise); - eqPos(makeCursor(0, lines[0].textStart), cm.getCursor()); + helpers.assertCursorAt(0, lines[0].textStart); eq('vim-insert', cm.getOption('keyMap')); }); // Swapcase commands edit in place and do not modify registers. @@ -557,7 +564,7 @@ testVim('>{motion}', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq('', register.text); is(!register.linewise); - eqPos(makeCursor(0, 3), cm.getCursor()); + helpers.assertCursorAt(0, 3); }, { value: ' word1\nword2\nword3 ', indentUnit: 2 }); testVim('>>', function(cm, vim, helpers) { cm.setCursor(0, 3); @@ -568,7 +575,7 @@ testVim('>>', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq('', register.text); is(!register.linewise); - eqPos(makeCursor(0, 3), cm.getCursor()); + helpers.assertCursorAt(0, 3); }, { value: ' word1\nword2\nword3 ', indentUnit: 2 }); testVim('<{motion}', function(cm, vim, helpers) { cm.setCursor(1, 3); @@ -579,7 +586,7 @@ testVim('<{motion}', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq('', register.text); is(!register.linewise); - eqPos(makeCursor(0, 1), cm.getCursor()); + helpers.assertCursorAt(0, 1); }, { value: ' word1\n word2\nword3 ', indentUnit: 2 }); testVim('<<', function(cm, vim, helpers) { cm.setCursor(0, 3); @@ -590,7 +597,7 @@ testVim('<<', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq('', register.text); is(!register.linewise); - eqPos(makeCursor(0, 1), cm.getCursor()); + helpers.assertCursorAt(0, 1); }, { value: ' word1\n word2\nword3 ', indentUnit: 2 }); // Operator-motion tests @@ -602,7 +609,7 @@ testVim('D', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq('rd1', register.text); is(!register.linewise); - eqPos(makeCursor(0, 3), cm.getCursor()); + helpers.assertCursorAt(0, 3); }, { value: ' word1\nword2\n word3' }); testVim('C', function(cm, vim, helpers) { var curStart = makeCursor(0, 3); @@ -612,7 +619,7 @@ testVim('C', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq('rd1', register.text); is(!register.linewise); - eqPos(makeCursor(0, 3), cm.getCursor()); + helpers.assertCursorAt(0, 3); eq('vim-insert', cm.getOption('keyMap')); }, { value: ' word1\nword2\n word3' }); testVim('Y', function(cm, vim, helpers) { @@ -623,52 +630,52 @@ testVim('Y', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq('rd1', register.text); is(!register.linewise); - eqPos(makeCursor(0, 3), cm.getCursor()); + helpers.assertCursorAt(0, 3); }, { value: ' word1\nword2\n word3' }); // Action tests testVim('a', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('a'); - eqPos(makeCursor(0, 2), cm.getCursor()); + helpers.assertCursorAt(0, 2); eq('vim-insert', cm.getOption('keyMap')); }); testVim('a_eol', function(cm, vim, helpers) { cm.setCursor(0, lines[0].length - 1); helpers.doKeys('a'); - helpers.assertCursorAt(makeCursor(0, lines[0].length)); + helpers.assertCursorAt(0, lines[0].length); eq('vim-insert', cm.getOption('keyMap')); }); testVim('i', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('i'); - eqPos(makeCursor(0, 1), cm.getCursor()); + helpers.assertCursorAt(0, 1); eq('vim-insert', cm.getOption('keyMap')); }); testVim('A', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('A'); - eqPos(makeCursor(0, lines[0].length), cm.getCursor()); + helpers.assertCursorAt(0, lines[0].length); eq('vim-insert', cm.getOption('keyMap')); }); testVim('I', function(cm, vim, helpers) { cm.setCursor(0, 4); helpers.doKeys('I'); - eqPos(makeCursor(0, lines[0].textStart), cm.getCursor()); + helpers.assertCursorAt(0, lines[0].textStart); eq('vim-insert', cm.getOption('keyMap')); }); testVim('o', function(cm, vim, helpers) { cm.setCursor(0, 4); helpers.doKeys('o'); eq('word1\n\nword2', cm.getValue()); - eqPos(makeCursor(1, 0), cm.getCursor()); + helpers.assertCursorAt(1, 0); eq('vim-insert', cm.getOption('keyMap')); }, { value: 'word1\nword2' }); testVim('O', function(cm, vim, helpers) { cm.setCursor(0, 4); helpers.doKeys('O'); eq('\nword1\nword2', cm.getValue()); - eqPos(makeCursor(0, 0), cm.getCursor()); + helpers.assertCursorAt(0, 0); eq('vim-insert', cm.getOption('keyMap')); }, { value: 'word1\nword2' }); testVim('J', function(cm, vim, helpers) { @@ -676,93 +683,127 @@ testVim('J', function(cm, vim, helpers) { helpers.doKeys('J'); var expectedValue = 'word1 word2\nword3\n word4'; eq(expectedValue, cm.getValue()); - eqPos(makeCursor(0, expectedValue.indexOf('word2') - 1), cm.getCursor()); + helpers.assertCursorAt(0, expectedValue.indexOf('word2') - 1); }, { value: 'word1 \n word2\nword3\n word4' }); testVim('J_repeat', function(cm, vim, helpers) { cm.setCursor(0, 4); helpers.doKeys('3', 'J'); var expectedValue = 'word1 word2 word3\n word4'; eq(expectedValue, cm.getValue()); - eqPos(makeCursor(0, expectedValue.indexOf('word3') - 1), cm.getCursor()); + helpers.assertCursorAt(0, expectedValue.indexOf('word3') - 1); }, { value: 'word1 \n word2\nword3\n word4' }); testVim('p', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false); helpers.doKeys('p'); eq('__abc\ndef_', cm.getValue()); - eqPos(makeCursor(1, 2), cm.getCursor()); + helpers.assertCursorAt(1, 2); }, { value: '___' }); testVim('p_register', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.getRegisterController().getRegister('a').set('abc\ndef', false); helpers.doKeys('"', 'a', 'p'); eq('__abc\ndef_', cm.getValue()); - eqPos(makeCursor(1, 2), cm.getCursor()); + helpers.assertCursorAt(1, 2); }, { value: '___' }); testVim('p_wrong_register', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.getRegisterController().getRegister('a').set('abc\ndef', false); helpers.doKeys('p'); eq('___', cm.getValue()); - eqPos(makeCursor(0, 1), cm.getCursor()); + helpers.assertCursorAt(0, 1); }, { value: '___' }); testVim('p_line', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.getRegisterController().pushText('"', 'yank', ' a\nd\n', true); helpers.doKeys('2', 'p'); eq('___\n a\nd\n a\nd', cm.getValue()); - eqPos(makeCursor(1, 2), cm.getCursor()); + helpers.assertCursorAt(1, 2); }, { value: '___' }); testVim('P', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.getRegisterController().pushText('"', 'yank', 'abc\ndef', false); helpers.doKeys('P'); eq('_abc\ndef__', cm.getValue()); - eqPos(makeCursor(1, 3), cm.getCursor()); + helpers.assertCursorAt(1, 3); }, { value: '___' }); testVim('P_line', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.getRegisterController().pushText('"', 'yank', ' a\nd\n', true); helpers.doKeys('2', 'P'); eq(' a\nd\n a\nd\n___', cm.getValue()); - eqPos(makeCursor(0, 2), cm.getCursor()); + helpers.assertCursorAt(0, 2); }, { value: '___' }); testVim('r', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('3', 'r', 'u'); eq('wuuuet', cm.getValue()); - eqPos(makeCursor(0, 3), cm.getCursor()); + helpers.assertCursorAt(0, 3); }, { value: 'wordet' }); +testVim('mark', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 't'); + cm.setCursor(0, 0); + helpers.doKeys('\'', 't'); + helpers.assertCursorAt(2, 2); + cm.setCursor(0, 0); + helpers.doKeys('`', 't'); + helpers.assertCursorAt(2, 2); +}); +testVim('visual', function(cm, vim, helpers) { + helpers.doKeys('l', 'v', 'l', 'l'); + helpers.assertCursorAt(0, 3); + eqPos(makeCursor(0, 1), cm.getCursor('anchor')); + helpers.doKeys('d'); + eq('15', cm.getValue()); +}, { value: '12345' }); +testVim('visual_line', function(cm, vim, helpers) { + helpers.doKeys('l', 'V', 'l', 'j', 'j', 'd'); + eq(' 4\n 5', cm.getValue()); +}, { value: ' 1\n 2\n 3\n 4\n 5' }); +testVim('visual_marks', function(cm, vim, helpers) { + helpers.doKeys('l', 'v', 'l', 'l', 'v'); + // Test visual mode marks + cm.setCursor(0, 0); + helpers.doKeys('\'', '<'); + helpers.assertCursorAt(0, 1); + helpers.doKeys('\'', '>'); + helpers.assertCursorAt(0, 3); +}); +testVim('visual_join', function(cm, vim, helpers) { + helpers.doKeys('l', 'V', 'l', 'j', 'j', 'J'); + eq(' 1 2 3\n 4\n 5', cm.getValue()); +}, { value: ' 1\n 2\n 3\n 4\n 5' }); testVim('/ and n/N', function(cm, vim, helpers) { cm.openDialog = helpers.fakeOpenDialog('match'); helpers.doKeys('/'); - helpers.assertCursorAt(makeCursor(0, 11)); + helpers.assertCursorAt(0, 11); helpers.doKeys('n'); - helpers.assertCursorAt(makeCursor(1, 6)); + helpers.assertCursorAt(1, 6); helpers.doKeys('N'); - helpers.assertCursorAt(makeCursor(0, 11)); + helpers.assertCursorAt(0, 11); cm.setCursor(0, 0); helpers.doKeys('2', '/'); - helpers.assertCursorAt(makeCursor(1, 6)); + helpers.assertCursorAt(1, 6); }, { value: 'match nope match \n nope Match' }); testVim('/_case', function(cm, vim, helpers) { cm.openDialog = helpers.fakeOpenDialog('Match'); helpers.doKeys('/'); - helpers.assertCursorAt(makeCursor(1, 6)); + helpers.assertCursorAt(1, 6); }, { value: 'match nope match \n nope Match' }); testVim('? and n/N', function(cm, vim, helpers) { cm.openDialog = helpers.fakeOpenDialog('match'); helpers.doKeys('?'); - helpers.assertCursorAt(makeCursor(1, 6)); + helpers.assertCursorAt(1, 6); helpers.doKeys('n'); - helpers.assertCursorAt(makeCursor(0, 11)); + helpers.assertCursorAt(0, 11); helpers.doKeys('N'); - helpers.assertCursorAt(makeCursor(1, 6)); + helpers.assertCursorAt(1, 6); cm.setCursor(0, 0); helpers.doKeys('2', '?'); - helpers.assertCursorAt(makeCursor(0, 11)); + helpers.assertCursorAt(0, 11); }, { value: 'match nope match \n nope Match' }); testVim(',/ clearSearchHighlight', function(cm, vim, helpers) { cm.openDialog = helpers.fakeOpenDialog('match'); @@ -773,11 +814,11 @@ testVim(',/ clearSearchHighlight', function(cm, vim, helpers) { testVim('*', function(cm, vim, helpers) { cm.setCursor(0, 9); helpers.doKeys('*'); - helpers.assertCursorAt(makeCursor(0, 22)); + helpers.assertCursorAt(0, 22); cm.setCursor(0, 9); helpers.doKeys('2', '*'); - helpers.assertCursorAt(makeCursor(1, 8)); + helpers.assertCursorAt(1, 8); }, { value: 'nomatch match nomatch match \nnomatch Match' }); testVim('*_no_word', function(cm, vim, helpers) { cm.setCursor(0, 0); @@ -792,21 +833,124 @@ testVim('*_symbol', function(cm, vim, helpers) { testVim('#', function(cm, vim, helpers) { cm.setCursor(0, 9); helpers.doKeys('#'); - helpers.assertCursorAt(makeCursor(1, 8)); + helpers.assertCursorAt(1, 8); cm.setCursor(0, 9); helpers.doKeys('2', '#'); - helpers.assertCursorAt(makeCursor(0, 22)); + helpers.assertCursorAt(0, 22); }, { value: 'nomatch match nomatch match \nnomatch Match' }); testVim('*_seek', function(cm, vim, helpers) { // Should skip over space and symbols. cm.setCursor(0, 3); helpers.doKeys('*'); - helpers.assertCursorAt(makeCursor(0, 22)); + helpers.assertCursorAt(0, 22); }, { value: ' := match nomatch match \nnomatch Match' }); testVim('#', function(cm, vim, helpers) { // Should skip over space and symbols. cm.setCursor(0, 3); helpers.doKeys('#'); - helpers.assertCursorAt(makeCursor(1, 8)); + helpers.assertCursorAt(1, 8); }, { value: ' := match nomatch match \nnomatch Match' }); +testVim('ex_write', function(cm, vim, helpers) { + var tmp = CodeMirror.commands.save; + var written; + var actualCm; + CodeMirror.commands.save = function(cm) { + written = true; + actualCm = cm; + }; + // Test that w, wr, wri ... write all trigger :write. + var command = 'write'; + for (var i = 1; i < command.length; i++) { + written = false; + actualCm = null; + helpers.doEx(command.substring(0, i)); + eq(written, true); + eq(actualCm, cm); + } + CodeMirror.commands.save = tmp; +}); +testVim('ex_substitute_same_line', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doEx('s/one/two'); + eq('one one\n two two', cm.getValue()); +}, { value: 'one one\n one one'}); +testVim('ex_substitute_global', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doEx('%s/one/two'); + eq('two two\n two two', cm.getValue()); +}, { value: 'one one\n one one'}); +testVim('ex_substitute_input_range', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doEx('1,3s/\\d/0'); + eq('0\n0\n0\n4', cm.getValue()); +}, { value: '1\n2\n3\n4' }); +testVim('ex_substitute_visual_range', function(cm, vim, helpers) { + cm.setCursor(1, 0); + // Set last visual mode selection marks '< and '> at lines 2 and 4 + helpers.doKeys('V', '2', 'j', 'v'); + helpers.doEx('\'<,\'>s/\\d/0'); + eq('1\n0\n0\n0\n5', cm.getValue()); +}, { value: '1\n2\n3\n4\n5' }); +testVim('ex_substitute_capture', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doEx('s/(\\d+)/$1$1/') + eq('a1111 a1212 a1313', cm.getValue()); +}, { value: 'a11 a12 a13' }); +// TODO: Reset key maps after each test. +testVim('ex_map_key2key', function(cm, vim, helpers) { + helpers.doEx('map a x'); + helpers.doKeys('a'); + helpers.assertCursorAt(0, 0); + eq('bc', cm.getValue()); +}, { value: 'abc' }); +testVim('ex_map_key2key_to_colon', function(cm, vim, helpers) { + helpers.doEx('map ; :'); + var dialogOpened = false; + cm.openDialog = function() { + dialogOpened = true; + } + helpers.doKeys(';'); + eq(dialogOpened, true); +}); +testVim('ex_map_ex2key:', function(cm, vim, helpers) { + helpers.doEx('map :del x'); + helpers.doEx('del'); + helpers.assertCursorAt(0, 0); + eq('bc', cm.getValue()); +}, { value: 'abc' }); +testVim('ex_map_ex2ex', function(cm, vim, helpers) { + helpers.doEx('map :del :w'); + var tmp = CodeMirror.commands.save; + var written = false; + var actualCm; + CodeMirror.commands.save = function(cm) { + written = true; + actualCm = cm; + }; + helpers.doEx('del'); + CodeMirror.commands.save = tmp; + eq(written, true); + eq(actualCm, cm); +}); +testVim('ex_map_key2ex', function(cm, vim, helpers) { + helpers.doEx('map a :w'); + var tmp = CodeMirror.commands.save; + var written = false; + var actualCm; + CodeMirror.commands.save = function(cm) { + written = true; + actualCm = cm; + }; + helpers.doKeys('a'); + CodeMirror.commands.save = tmp; + eq(written, true); + eq(actualCm, cm); +}); +// For now, this test needs to be last because it messes up : for future tests. +testVim('ex_map_key2key_from_colon', function(cm, vim, helpers) { + helpers.doEx('map : x'); + helpers.doKeys(':'); + helpers.assertCursorAt(0, 0); + eq('bc', cm.getValue()); +}, { value: 'abc' }); From 8a1df14de5d2f7ec25bde010228b0163bbb91563 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Mon, 31 Dec 2012 19:57:40 -0500 Subject: [PATCH 0029/5273] [vim keymap] Search highlighting using overlay mode --- keymap/vim.js | 94 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 23 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index d72123f10e..ec8f2b9635 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1826,6 +1826,12 @@ setMarked: function(marked) { this.marked = marked; }, + getOverlay: function() { + return this.searchOverlay; + }, + setOverlay: function(overlay) { + this.searchOverlay = overlay; + }, isReversed: function() { return getVimGlobalState().isReversed; }, @@ -1957,17 +1963,53 @@ state.setQuery(query); }); } + function searchOverlay(query) { + return { + token: function(stream) { + var match = stream.match(query, false); + if (match) { + if (!stream.sol()) { + // Backtrack 1 to match \b + stream.backUp(1); + if (!query.exec(stream.next() + match[0])) { + stream.next(); + return null; + } + } + stream.match(query); + return "searching"; + } + while (!stream.eol()) { + stream.next(); + if (stream.match(query, false)) break; + } + }, + query: query + }; + } function highlightSearchMatches(cm, query) { - // TODO: Highlight only text inside the viewport. Highlighting everything - // is inefficient and expensive. - if (cm.lineCount() < 2000) { // This is too expensive on big documents. - var marked = []; - for (var cursor = cm.getSearchCursor(query); - cursor.findNext();) { - marked.push(cm.markText(cursor.from(), cursor.to(), - { className: 'cm-searching' })); + if (cm.addOverlay) { + var overlay = getSearchState(cm).getOverlay(); + if (!overlay || query != overlay.query) { + if (overlay) { + cm.removeOverlay(overlay); + } + overlay = searchOverlay(query); + cm.addOverlay(overlay); + getSearchState(cm).setOverlay(overlay); + } + } else { + // TODO: Highlight only text inside the viewport. Highlighting everything + // is inefficient and expensive. + if (cm.lineCount() < 2000) { // This is too expensive on big documents. + var marked = []; + for (var cursor = cm.getSearchCursor(query); + cursor.findNext();) { + marked.push(cm.markText(cursor.from(), cursor.to(), + { className: 'cm-searching' })); + } + getSearchState(cm).setMarked(marked); } - getSearchState(cm).setMarked(marked); } } function findNext(cm, prev, repeat) { @@ -2001,20 +2043,26 @@ return cursor.from(); });} function clearSearchHighlight(cm) { - cm.operation(function() { - var state = getSearchState(cm); - if (!state.getQuery()) { - return; - } - var marked = state.getMarked(); - if (!marked) { - return; - } - for (var i = 0; i < marked.length; ++i) { - marked[i].clear(); - } - state.setMarked(null); - });} + if (cm.addOverlay) { + cm.removeOverlay(getSearchState(cm).getOverlay()); + getSearchState(cm).setOverlay(null); + } else { + cm.operation(function() { + var state = getSearchState(cm); + if (!state.getQuery()) { + return; + } + var marked = state.getMarked(); + if (!marked) { + return; + } + for (var i = 0; i < marked.length; ++i) { + marked[i].clear(); + } + state.setMarked(null); + }); + } + } /** * Check if pos is in the specified range, INCLUSIVE. * Range can be specified with 1 or 2 arguments. From 55d4f13cbd669cf4aaf5ef9b50044941bcfa1c61 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 2 Jan 2013 17:01:40 +0100 Subject: [PATCH 0030/5273] Fix bug introduced in 47239048037dcfff0c4d34f2734d170f8330b13d --- lib/codemirror.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 0913c4b7c2..0a2fbfdce8 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -569,7 +569,7 @@ window.CodeMirror = (function() { wrap.appendChild(prev); prev = wrap; } - prev.appendChild(buildLineWidget(line.widgets[i], dims)); + prev.appendChild(buildLineWidget(line.widgets[i], prev, dims)); } } else if (nextIntact && nextIntact.from <= lineNo && nextIntact.to > lineNo) { // This line is intact. Skip to the actual node. Update its @@ -624,7 +624,7 @@ window.CodeMirror = (function() { wrap.appendChild(elt("div", "\u00a0", line.bgClass + " CodeMirror-linebackground")); wrap.appendChild(lineElement); if (line.widgets) for (var i = 0, ws = line.widgets; i < ws.length; ++i) { - var widget = ws[i], node = buildLineWidget(widget, dims); + var widget = ws[i], node = buildLineWidget(widget, wrap, dims); if (widget.above) wrap.insertBefore(node, cm.options.lineNumbers && line.height != 0 ? gutterWrap : lineElement); else @@ -634,7 +634,7 @@ window.CodeMirror = (function() { return wrap; } - function buildLineWidget(widget, dims) { + function buildLineWidget(widget, wrap, dims) { var node = elt("div", [widget.node], "CodeMirror-linewidget"); node.widget = widget; if (widget.noHScroll) { From 949764753a29f2d5ca0310c20225750601459408 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 2 Jan 2013 17:26:08 +0100 Subject: [PATCH 0031/5273] [util/collapserange] Don't depend on function definition order inside block Closes #1128 --- lib/util/collapserange.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/util/collapserange.js b/lib/util/collapserange.js index 27dcbdde0b..ebcdda2755 100644 --- a/lib/util/collapserange.js +++ b/lib/util/collapserange.js @@ -39,15 +39,15 @@ inclusiveRight: true, clearOnEnter: true }); + var clear = function() { + cm.setGutterMarker(topLine, gutterClass, null); + cm.setGutterMarker(botLine, gutterClass, null); + fold.clear(); + }; var topLine = cm.setGutterMarker(from, gutterClass, makeMarker(true, true, clear)); var botLine = cm.setGutterMarker(to, gutterClass, makeMarker(false, true, clear)); CodeMirror.on(fold, "clear", clear); - function clear() { - cm.setGutterMarker(topLine, gutterClass, null); - cm.setGutterMarker(botLine, gutterClass, null); - fold.clear(); - } return; } } From 5e3fe8c56a3979c529e000c24008259a2a0cf721 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 4 Jan 2013 09:42:33 +0100 Subject: [PATCH 0032/5273] Two more real-world uses --- doc/realworld.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/realworld.html b/doc/realworld.html index 9c3076bb99..7d9bce0c6f 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -65,6 +65,7 @@

    { } CodeMi
  • ql.io (http API query helper)
  • QiYun web app platform
  • Qt+Webkit integration (building a desktop CodeMirror app)
  • +
  • Rascal (tiny computer)
  • sketchPatch Livecodelab
  • Skulpt (in-browser Python environment)
  • SolidShops (hosted e-commerce platform)
  • @@ -72,6 +73,7 @@

    { } CodeMi
  • The File Tree (collab editor)
  • Toolsverse Data Explorer (database management)
  • Tributary (augmented editing)
  • +
  • Tumblr code highlighting shim
  • TurboPY (web publishing framework)
  • WebGL playground
  • WeScheme (learning tool)
  • From 18d9c452a07a4f434ade27999a75dada1282d0fa Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Thu, 3 Jan 2013 22:13:30 -0500 Subject: [PATCH 0033/5273] [vim keymap] Add count and empty query support for :s --- keymap/vim.js | 28 ++++++++++++++++++++-------- test/vim_test.js | 18 ++++++++++++++++++ 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index ec8f2b9635..54370e0660 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2331,27 +2331,39 @@ var regexPart = argString.substring(slashes[0] + 1, slashes[1]); var replacePart = ''; var flagsPart; + var count; if (slashes[1]) { replacePart = argString.substring(slashes[1] + 1, slashes[2]); } if (slashes[2]) { - flagsPart = argString.substring(slashes[2] + 1); + // After the 3rd slash, we can have flags followed by a space followed + // by count. + var trailing = argString.substring(slashes[2] + 1).split(' '); + flagsPart = trailing[0]; + count = parseInt(trailing[1]); } if (flagsPart) { regexPart = regexPart + '/' + flagsPart; } - updateSearchQuery(cm, regexPart, true /** ignoreCase */, + if (regexPart) { + // If regex part is empty, then use the previous query. Otherwise use + // the regex part as the new query. + updateSearchQuery(cm, regexPart, true /** ignoreCase */, true /** smartCase */); + } var state = getSearchState(cm); var query = state.getQuery(); - var startPos = clipCursorToContent(cm, { line: params.line || 0, - ch: 0 }); + var lineStart = params.line || 0; + var lineEnd = params.lineEnd || lineStart; + if (count) { + lineStart = lineEnd; + lineEnd = lineStart + count - 1; + } + var startPos = clipCursorToContent(cm, { line: lineStart, ch: 0 }); function doReplace() { for (var cursor = cm.getSearchCursor(query, startPos); - cursor.findNext();) { - if (!isInRange(cursor.from(), params.line, params.lineEnd)) { - break; - } + cursor.findNext() && + isInRange(cursor.from(), lineStart, lineEnd);) { var text = cm.getRange(cursor.from(), cursor.to()); var newText = text.replace(query, replacePart); cursor.replace(newText); diff --git a/test/vim_test.js b/test/vim_test.js index bf3ad4e071..dddca2bb84 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -897,6 +897,24 @@ testVim('ex_substitute_capture', function(cm, vim, helpers) { helpers.doEx('s/(\\d+)/$1$1/') eq('a1111 a1212 a1313', cm.getValue()); }, { value: 'a11 a12 a13' }); +testVim('ex_substitute_empty_query', function(cm, vim, helpers) { + // If the query is empty, use last query. + cm.setCursor(1, 0); + cm.openDialog = helpers.fakeOpenDialog('1'); + helpers.doKeys('/'); + helpers.doEx('s//b'); + eq('abb ab2 ab3', cm.getValue()); +}, { value: 'a11 a12 a13' }); +testVim('ex_substitute_count', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doEx('s/\\d/0/i 2'); + eq('1\n0\n0\n4', cm.getValue()); +}, { value: '1\n2\n3\n4' }); +testVim('ex_substitute_count_with_range', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doEx('1,3s/\\d/0/ 3'); + eq('1\n2\n0\n0', cm.getValue()); +}, { value: '1\n2\n3\n4' }); // TODO: Reset key maps after each test. testVim('ex_map_key2key', function(cm, vim, helpers) { helpers.doEx('map a x'); From 9190a49ace2a625f9606057c366c052ddf18b1d8 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Thu, 3 Jan 2013 23:05:22 -0500 Subject: [PATCH 0034/5273] [vim keymap] Add {,} motions --- keymap/vim.js | 20 ++++++++++++++++++++ test/vim_test.js | 22 ++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/keymap/vim.js b/keymap/vim.js index 54370e0660..ec85c28228 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -115,6 +115,10 @@ motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, bigWord: true, inclusive: true }}, + { keys: ['{'], type: 'motion', motion: 'moveByParagraph', + motionArgs: { forward: false }}, + { keys: ['}'], type: 'motion', motion: 'moveByParagraph', + motionArgs: { forward: true }}, { keys: ['Ctrl-f'], type: 'motion', motion: 'moveByPage', motionArgs: { forward: true }}, { keys: ['Ctrl-b'], type: 'motion', @@ -933,6 +937,22 @@ cm.setCursor(curStart); return curEnd; }, + moveByParagraph: function(cm, motionArgs) { + var line = cm.getCursor().line; + var repeat = motionArgs.repeat; + var inc = motionArgs.forward ? 1 : -1; + for (var i = 0; i < repeat; i++) { + if ((!motionArgs.forward && line === 0) || + (motionArgs.forward && line == cm.lineCount() - 1)) { + break; + } + line += inc; + while (line !== 0 && line != cm.lineCount - 1 && cm.getLine(line)) { + line += inc; + } + } + return { line: line, ch: 0 }; + }, moveByWords: function(cm, motionArgs) { return moveToWord(cm, motionArgs.repeat, !!motionArgs.forward, !!motionArgs.wordEnd, !!motionArgs.bigWord); diff --git a/test/vim_test.js b/test/vim_test.js index dddca2bb84..d91abe5ad0 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -266,6 +266,28 @@ testVim('Changing lines after Eol operation', function(cm, vim, helpers) { // same place we were at on line 1 helpers.assertCursorAt({ line: 5, ch: lines[2].length - 2 }); }); +testVim('}', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('}'); + helpers.assertCursorAt(1, 0); + cm.setCursor(0, 0); + helpers.doKeys('2', '}'); + helpers.assertCursorAt(4, 0); + cm.setCursor(0, 0); + helpers.doKeys('6', '}'); + helpers.assertCursorAt(5, 0); +}, { value: 'a\n\nb\nc\n\nd' }); +testVim('{', function(cm, vim, helpers) { + cm.setCursor(5, 0); + helpers.doKeys('{'); + helpers.assertCursorAt(4, 0); + cm.setCursor(5, 0); + helpers.doKeys('2', '{'); + helpers.assertCursorAt(1, 0); + cm.setCursor(5, 0); + helpers.doKeys('6', '{'); + helpers.assertCursorAt(0, 0); +}, { value: 'a\n\nb\nc\n\nd' }); // Operator tests testVim('dl', function(cm, vim, helpers) { From 023f240ac56e93c775ef590c90c3191e51395412 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 7 Jan 2013 11:05:34 +0100 Subject: [PATCH 0035/5273] [test suite] Turn on rtlMoveVisually explicitly in rtl movement test --- test/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.js b/test/test.js index 810e50f553..6eea43b5ac 100644 --- a/test/test.js +++ b/test/test.js @@ -906,7 +906,7 @@ testCM("rtlMovement", function(cm) { prevX = cursor.offsetLeft; } }); -}); +}, {rtlMoveVisually: true}); // Verify that updating a line clears its bidi ordering testCM("bidiUpdate", function(cm) { From 51696b48af0a2baf19934fba68377d82449dc92b Mon Sep 17 00:00:00 2001 From: robertop23 Date: Fri, 4 Jan 2013 00:39:36 -0800 Subject: [PATCH 0036/5273] Create python-hint.js --- lib/util/python-hint.js | 93 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 lib/util/python-hint.js diff --git a/lib/util/python-hint.js b/lib/util/python-hint.js new file mode 100644 index 0000000000..c1d0db2c40 --- /dev/null +++ b/lib/util/python-hint.js @@ -0,0 +1,93 @@ +(function () { + function forEach(arr, f) { + for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); + } + + function arrayContains(arr, item) { + if (!Array.prototype.indexOf) { + var i = arr.length; + while (i--) { + if (arr[i] === item) { + return true; + } + } + return false; + } + return arr.indexOf(item) != -1; + } + + function scriptHint(editor, _keywords, getToken) { + // Find the token at the cursor + var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token; + // If it's not a 'word-style' token, ignore the token. + + if (!/^[\w$_]*$/.test(token.string)) { + token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state, + className: token.string == ":" ? "python-type" : null}; + } + + if (!context) var context = []; + context.push(tprop); + + var completionList = getCompletions(token, context); + completionList = completionList.sort(); + //prevent autocomplete for last word, instead show dropdown with one word + if(completionList.length == 1) { + completionList.push(" "); + } + + return {list: completionList, + from: {line: cur.line, ch: token.start}, + to: {line: cur.line, ch: token.end}}; + } + + CodeMirror.pythonHint = function(editor) { + return scriptHint(editor, pythonKeywordsU, function (e, cur) {return e.getTokenAt(cur);}); + }; + + var pythonKeywords = "and del from not while as elif global or with assert else if pass yield" ++ "break except import print class exec in raise continue finally is return def for lambda try"; + var pythonKeywordsL = pythonKeywords.split(" "); + var pythonKeywordsU = pythonKeywords.toUpperCase().split(" "); + + var pythonBuiltins = "abs divmod input open staticmethod all enumerate int ord str " ++ "any eval isinstance pow sum basestring execfile issubclass print super" ++ "bin file iter property tuple bool filter len range type" ++ "bytearray float list raw_input unichr callable format locals reduce unicode" ++ "chr frozenset long reload vars classmethod getattr map repr xrange" ++ "cmp globals max reversed zip compile hasattr memoryview round __import__" ++ "complex hash min set apply delattr help next setattr buffer" ++ "dict hex object slice coerce dir id oct sorted intern "; + var pythonBuiltinsL = pythonBuiltins.split(" ").join("() ").split(" "); + var pythonBuiltinsU = pythonBuiltins.toUpperCase().split(" ").join("() ").split(" "); + + function getCompletions(token, context) { + var found = [], start = token.string; + function maybeAdd(str) { + if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str); + } + + function gatherCompletions(obj) { + forEach(pythonBuiltinsL, maybeAdd); + forEach(pythonBuiltinsU, maybeAdd); + forEach(pythonKeywordsL, maybeAdd); + forEach(pythonKeywordsU, maybeAdd); + } + + if (context) { + // If this is a property, see if it belongs to some object we can + // find in the current environment. + var obj = context.pop(), base; + + if (obj.type == "variable") + base = obj.string; + else if(obj.type == "variable-3") + base = ":" + obj.string; + + while (base != null && context.length) + base = base[context.pop().string]; + if (base != null) gatherCompletions(base); + } + return found; + } +})(); From bd0955443c05fdb3798cba5083744821928494e1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 7 Jan 2013 11:18:24 +0100 Subject: [PATCH 0037/5273] Integrate python-hint.js --- doc/compress.html | 1 + doc/manual.html | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/doc/compress.html b/doc/compress.html index 3bfec8df41..74e68d0559 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -134,6 +134,7 @@

    { } CodeMi + diff --git a/doc/manual.html b/doc/manual.html index 23894b0941..7bb525a46f 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1228,6 +1228,11 @@

    Add-ons

    and CodeMirror.coffeescriptHint, which are simple hinting functions for the JavaScript and CoffeeScript modes. +
    xml-hint.js
    +
    Defines CodeMirror.xmlHint, a hinting function + for XML (which requires a schema to be defined).
    +
    python-hint.js
    +
    Defines CodeMirror.pythonHint, a hinter for Python code.
    match-highlighter.js
    Adds a matchHighlight method to CodeMirror instances that can be called (typically from From e4f4e14703dea89d388729c3ef5fdb90e9fca207 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 7 Jan 2013 11:19:38 +0100 Subject: [PATCH 0038/5273] [util/python-hint] Clean up to pass linter --- lib/util/python-hint.js | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/util/python-hint.js b/lib/util/python-hint.js index c1d0db2c40..56b077b3fb 100644 --- a/lib/util/python-hint.js +++ b/lib/util/python-hint.js @@ -2,7 +2,7 @@ function forEach(arr, f) { for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); } - + function arrayContains(arr, item) { if (!Array.prototype.indexOf) { var i = arr.length; @@ -25,11 +25,11 @@ token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state, className: token.string == ":" ? "python-type" : null}; } - + if (!context) var context = []; context.push(tprop); - - var completionList = getCompletions(token, context); + + var completionList = getCompletions(token, context); completionList = completionList.sort(); //prevent autocomplete for last word, instead show dropdown with one word if(completionList.length == 1) { @@ -40,34 +40,34 @@ from: {line: cur.line, ch: token.start}, to: {line: cur.line, ch: token.end}}; } - + CodeMirror.pythonHint = function(editor) { return scriptHint(editor, pythonKeywordsU, function (e, cur) {return e.getTokenAt(cur);}); }; - + var pythonKeywords = "and del from not while as elif global or with assert else if pass yield" + "break except import print class exec in raise continue finally is return def for lambda try"; var pythonKeywordsL = pythonKeywords.split(" "); var pythonKeywordsU = pythonKeywords.toUpperCase().split(" "); - + var pythonBuiltins = "abs divmod input open staticmethod all enumerate int ord str " -+ "any eval isinstance pow sum basestring execfile issubclass print super" -+ "bin file iter property tuple bool filter len range type" -+ "bytearray float list raw_input unichr callable format locals reduce unicode" ++ "any eval isinstance pow sum basestring execfile issubclass print super" ++ "bin file iter property tuple bool filter len range type" ++ "bytearray float list raw_input unichr callable format locals reduce unicode" + "chr frozenset long reload vars classmethod getattr map repr xrange" -+ "cmp globals max reversed zip compile hasattr memoryview round __import__" -+ "complex hash min set apply delattr help next setattr buffer" -+ "dict hex object slice coerce dir id oct sorted intern "; - var pythonBuiltinsL = pythonBuiltins.split(" ").join("() ").split(" "); - var pythonBuiltinsU = pythonBuiltins.toUpperCase().split(" ").join("() ").split(" "); - ++ "cmp globals max reversed zip compile hasattr memoryview round __import__" ++ "complex hash min set apply delattr help next setattr buffer" ++ "dict hex object slice coerce dir id oct sorted intern "; + var pythonBuiltinsL = pythonBuiltins.split(" ").join("() ").split(" "); + var pythonBuiltinsU = pythonBuiltins.toUpperCase().split(" ").join("() ").split(" "); + function getCompletions(token, context) { var found = [], start = token.string; function maybeAdd(str) { if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str); } - - function gatherCompletions(obj) { + + function gatherCompletions(_obj) { forEach(pythonBuiltinsL, maybeAdd); forEach(pythonBuiltinsU, maybeAdd); forEach(pythonKeywordsL, maybeAdd); @@ -79,11 +79,11 @@ // find in the current environment. var obj = context.pop(), base; - if (obj.type == "variable") + if (obj.type == "variable") base = obj.string; else if(obj.type == "variable-3") base = ":" + obj.string; - + while (base != null && context.length) base = base[context.pop().string]; if (base != null) gatherCompletions(base); From d81ace3e4f22f932671223ee2c391777c5e4c8c1 Mon Sep 17 00:00:00 2001 From: benbro Date: Sat, 5 Jan 2013 16:08:43 +0200 Subject: [PATCH 0039/5273] Add missing argument in event listener --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 0a2fbfdce8..7d73776b7f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1327,7 +1327,7 @@ window.CodeMirror = (function() { on(d.scroller, "dragover", drag_); on(d.scroller, "drop", operation(cm, onDrop)); } - on(d.scroller, "paste", function(){ + on(d.scroller, "paste", function(e){ if (eventInWidget(d, e)) return; focusInput(cm); fastPoll(cm); From 546c34685149f13019550119f8ab523b4dd6f4f1 Mon Sep 17 00:00:00 2001 From: Jan Jongboom Date: Sat, 5 Jan 2013 15:33:02 +0100 Subject: [PATCH 0040/5273] application/javascript is also a valid mime for JS According to [RFC 4329](http://www.rfc-editor.org/rfc/rfc4329.txt) the MIME type for javascript files should be either application/javascript or application/ecmascript. --- mode/javascript/javascript.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index b66d223617..565513fa01 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -414,6 +414,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { }); CodeMirror.defineMIME("text/javascript", "javascript"); +CodeMirror.defineMIME("text/ecmascript", "javascript"); +CodeMirror.defineMIME("application/javascript", "javascript"); +CodeMirror.defineMIME("application/ecmascript", "javascript"); CodeMirror.defineMIME("application/json", {name: "javascript", json: true}); CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true }); CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true }); From 21e22c642ac9f47c26aca882d2075a6b4a3f7460 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 7 Jan 2013 11:31:50 +0100 Subject: [PATCH 0041/5273] Make sure loadMode triggers a redraw Closes #1137 --- lib/codemirror.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 7d73776b7f..3a20b39891 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -201,10 +201,14 @@ window.CodeMirror = (function() { function loadMode(cm) { var doc = cm.view.doc; cm.view.mode = CodeMirror.getMode(cm.options, cm.options.mode); - doc.iter(0, doc.size, function(line) { if (line.stateAfter) line.stateAfter = null; }); + doc.iter(0, doc.size, function(line) { + if (line.stateAfter) line.stateAfter = null; + if (line.styles) line.styles = null; + }); cm.view.frontier = 0; startWorker(cm, 100); cm.view.modeGen++; + if (cm.curOp) regChange(cm, 0, doc.size); } function wrappingChanged(cm) { From 8f52a02189791f45dd5aa20137627ebe65ca9e0e Mon Sep 17 00:00:00 2001 From: santec Date: Sun, 6 Jan 2013 17:35:49 +0100 Subject: [PATCH 0042/5273] mode SQL: added special syntax for datetimes * standard SQL syntax for date/time/timestamp values * ODBC syntax for date/time/timestamp * added new syntax in index.html --- mode/sql/index.html | 1 + mode/sql/sql.js | 23 +++++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/mode/sql/index.html b/mode/sql/index.html index e2cdf775ac..36fc2238ab 100644 --- a/mode/sql/index.html +++ b/mode/sql/index.html @@ -41,6 +41,7 @@

    SQL Mode for CodeMirror

    @var1 AS `val1`, @'val2', @global.'sql_mode', 1.1 AS `float_val`, 0.09e3 AS `int_with_esp`, 0xFA5 AS `hex`, x'fa5' AS `hex2`, 0b101 AS `bin`, b'101' AS `bin2`, + DATE '1994-01-01' AS `sql_date`, { T "1994-01-01" } AS `odbc_date`, 'myString', UNKNOWN FROM DUAL -- space needed after '--' diff --git a/mode/sql/sql.js b/mode/sql/sql.js index f2fd001fd1..dc163dd8d5 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -6,7 +6,8 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { builtin = parserConfig.builtin || {}, keywords = parserConfig.keywords, operatorChars = /^[*+\-%<>!=&|~^]/, - hooks = parserConfig.hooks || {}; + hooks = parserConfig.hooks || {}, + dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true}; function tokenBase(stream, state) { var ch = stream.next(); @@ -32,22 +33,32 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { // placeholders return "variable-3"; } else if (ch == '"' || ch == "'") { + // strings state.tokenize = tokenLiteral(ch); return state.tokenize(stream, state); } else if (/^[\(\),\.;\[\]]/.test(ch)) { return null; } else if (ch == "#" || (ch == "-" && stream.eat("-") && stream.eat(" "))) { - stream.skipToEnd(); + // 1-line comments + stream.skipToEnd(); return "comment"; } else if (ch == "/" && stream.eat("*")) { + // multi-line comments state.tokenize = tokenComment; return state.tokenize(stream, state); } else if (operatorChars.test(ch)) { stream.eatWhile(operatorChars); return false; + } else if (ch == '{' && + (stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) { + // dates (weird ODBC syntax) + return "number"; } else { stream.eatWhile(/^[_\w\d]/); var word = stream.current().toLowerCase(); + // dates (standard SQL syntax) + if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/))) + return "number"; if (atoms.hasOwnProperty(word)) return "atom"; if (builtin.hasOwnProperty(word)) return "builtin"; if (keywords.hasOwnProperty(word)) return "keyword"; @@ -192,7 +203,8 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { name: "sql", keywords: set(sqlKeywords + "begin"), builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric"), - atoms: set("false true null unknown") + atoms: set("false true null unknown"), + dateSQL: set("date time timestamp") }); CodeMirror.defineMIME("text/x-mysql", { @@ -201,6 +213,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { keywords: set(sqlKeywords + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed decimal numeric"), atoms: set("false true null unknown"), + dateSQL: set("date time timestamp"), hooks: { "@": hookVar, "`": hookIdentifier, @@ -214,6 +227,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { keywords: set(sqlKeywords + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed decimal numeric"), atoms: set("false true null unknown"), + dateSQL: set("date time timestamp"), hooks: { "@": hookVar, "`": hookIdentifier, @@ -227,6 +241,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"), keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"), functions: set("abs acos add_months ascii asin atan atan2 average bfilename ceil chartorowid chr concat convert cos cosh count decode deref dual dump dup_val_on_index empty error exp false floor found glb greatest hextoraw initcap instr instrb isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mod months_between new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null nvl others power rawtohex reftohex round rowcount rowidtochar rpad rtrim sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid upper user userenv variance vsize"), - builtin: set("bfile blob character clob dec float int integer mlslabel natural naturaln nchar nclob number numeric nvarchar2 real rowtype signtype smallint string varchar varchar2") + builtin: set("bfile blob character clob dec float int integer mlslabel natural naturaln nchar nclob number numeric nvarchar2 real rowtype signtype smallint string varchar varchar2"), + dateSQL: set("date time timestamp"), }); }()); From c9fc36730aa63152245543ae9cb4c92b9bc834bd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 7 Jan 2013 12:00:46 +0100 Subject: [PATCH 0043/5273] Make the hidden textarea wide on Webkit, to prevent wrap=off from making big pastes slow Issue #1136 --- lib/codemirror.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 3a20b39891..32d55b8f9c 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -84,7 +84,8 @@ window.CodeMirror = (function() { function makeDisplay(place) { var d = {}; var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none;"); - if (!webkit) input.setAttribute("wrap", "off"); + if (webkit) input.style.width = "1000px"; + else input.setAttribute("wrap", "off"); input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off"); // Wraps and hides input textarea d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); From 73cc2992a701398c2e06ed138974569c8a1a4c64 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 7 Jan 2013 12:12:36 +0100 Subject: [PATCH 0044/5273] Fix IE problem with clearing parentNode relationships on innerHTML = "" --- lib/codemirror.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 32d55b8f9c..5a87212632 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1107,6 +1107,7 @@ window.CodeMirror = (function() { } removeChildrenAndAdd(display.measure, measureText); var height = measureText.offsetHeight / 50; + display.measure.removeChild(measureText); if (height > 3) display.cachedTextHeight = height; removeChildren(display.measure); return height || 1; From 5a72f24685d489d36148a4d4cf1cfa1820b99875 Mon Sep 17 00:00:00 2001 From: pablo Date: Mon, 7 Jan 2013 12:21:50 +0100 Subject: [PATCH 0045/5273] Add mode/meta.js, which lists all modes in the distribution --- mode/meta.js | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 mode/meta.js diff --git a/mode/meta.js b/mode/meta.js new file mode 100644 index 0000000000..c30888353f --- /dev/null +++ b/mode/meta.js @@ -0,0 +1,69 @@ +CodeMirror.modeInfo = [ + {name: 'C', mime: 'x-csrc', mode: 'clike'}, + {name: 'C++', mime: 'x-c++src', mode: 'clike'}, + {name: 'Java', mime: 'x-java', mode: 'clike'}, + {name: 'C#', mime: 'x-csharp', mode: 'clike'}, + {name: 'Scala', mime: 'text/x-scala', mode: 'clike'}, + {name: 'Clojure', mime: 'text/x-clojure', mode: 'clojure'}, + {name: 'CoffeeScript', mime: 'text/x-coffeescript', mode: 'coffeescript'}, + {name: 'Common Lisp', mime: 'text/x-common-lisp', mode: 'commonlisp'}, + {name: 'CSS', mime: 'text/css', mode: 'css'}, + {name: 'D', mime: 'text/x-d', mode: 'd'}, + {name: 'diff', mime: 'text/x-diff', mode: 'diff'}, + {name: 'ECL', mime: 'text/x-ecl', mode: 'ecl'}, + {name: 'Erlang', mime: 'text/x-erlang', mode: 'erlang'}, + {name: 'GitHub Flavored Markdown', mode: 'gfm'}, + {name: 'GO', mime: 'text/x-go', mode: 'go'}, + {name: 'Groovy', mime: 'text/x-groovy', mode: 'groovy'}, + {name: 'Haskell', mime: 'text/x-haskell', mode: 'haskell'}, + {name: 'Haxe', mime: 'text/x-haxe', mode: 'haxe'}, + {name: 'ASP.NET', mime: 'application/x-aspx', mode: 'htmlembedded'}, + {name: 'Embedded Javascript', mime: 'application/x-ejs', mode: 'htmlembedded'}, + {name: 'JavaServer Pages', mime: 'application/x-jsp', mode: 'htmlembedded'}, + {name: 'HTML', mime: 'text/html', mode: 'htmlmixed'}, + {name: 'HTTP', mime: 'message/http', mode: 'http'}, + {name: 'JavaScript', mime: 'text/javascript', mode: 'javascript'}, + {name: 'JSON', mime: 'application/json', mode: 'javascript'}, + {name: 'TypeScript', mime: 'application/typescript', mode: 'javascript'}, + {name: 'Jinja2', mime: 'jinja2', mode: 'jinja2'}, + {name: 'LESS', mime: 'text/x-less', mode: 'less'}, + {name: 'Lua', mime: 'text/x-lua', mode: 'lua'}, + {name: 'Markdown (GitHub-flavour)', mime: 'text/x-markdown', mode: 'markdown'}, + {name: 'NTriples', mime: 'text/n-triples', mode: 'ntriples'}, + {name: 'OCaml', mime: 'text/x-ocaml', mode: 'ocaml'}, + {name: 'Pascal', mime: 'text/x-pascal', mode: 'pascal'}, + {name: 'Perl', mime: 'text/x-perl', mode: 'perl'}, + {name: 'PHP', mime: 'text/x-php', mode: 'php'}, + {name: 'PHP(HTML)', mime: 'application/x-httpd-php', mode: 'php'}, + {name: 'Pig', mime: 'text/x-pig', mode: 'pig'}, + {name: 'Properties files', mime: 'text/x-properties', mode: 'clike'}, + {name: 'Python', mime: 'text/x-python', mode: 'python'}, + {name: 'R', mime: 'text/x-rsrc', mode: 'r'}, + {name: 'reStructuredText', mime: 'text/x-rst', mode: 'rst'}, + {name: 'Ruby', mime: 'text/x-ruby', mode: 'ruby'}, + {name: 'Rust', mime: 'text/x-rustsrc', mode: 'rust'}, + {name: 'Sass', mime: 'text/x-sass', mode: 'sass'}, + {name: 'Scheme', mime: 'text/x-scheme', mode: 'scheme'}, + {name: 'Shell', mime: 'text/x-sh', mode: 'shell'}, + {name: 'Sieve', mime: 'application/sieve', mode: 'sieve'}, + {name: 'Smalltalk', mime: 'text/x-stsrc', mode: 'smalltalk'}, + {name: 'Smarty', mime: 'text/x-smarty', mode: 'smarty'}, + {name: 'SPARQL', mime: 'application/x-sparql-query', mode: 'sparql'}, + {name: 'SQL', mime: 'text/x-sql', mode: 'sql'}, + {name: 'MySQL', mime: 'text/x-mysql', mode: 'sql'}, + {name: 'MariaDB', mime: 'text/x-mariadb', mode: 'sql'}, + {name: 'PL/SQL', mime: 'text/x-plsql', mode: 'sql'}, + {name: 'sTeX', mime: 'text/x-stex', mode: 'stex'}, + {name: 'LaTeX', mime: 'text/x-latex', mode: 'stex'}, + {name: 'TiddlyWiki ', mime: 'text/x-tiddlywiki', mode: 'tiddlwiki'}, + {name: 'Tiki wiki', mime: 'text/tiki', mode: 'tiki'}, + {name: 'VB.NET', mime: 'text/x-vb', mode: 'vb'}, + {name: 'VBScript', mime: 'text/vbscript', mode: 'vbscript'}, + {name: 'Velocity', mime: 'text/velocity', mode: 'velocity'}, + {name: 'Verilog', mime: 'text/x-verilog', mode: 'verilog'}, + {name: 'XML', mime: 'application/xml', mode: 'xml'}, + {name: 'HTML', mime: 'text/html', mode: 'xml'}, + {name: 'XQuery', mime: 'application/xquery', mode: 'xquery'}, + {name: 'YAML', mime: 'text/x-yaml', mode: 'yaml'}, + {name: 'Z80', mime: 'text/x-z80', mode: 'z80'} +]; From 763e596c604253e4ba359770e94fab48b365ceb3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 8 Jan 2013 10:02:04 +0100 Subject: [PATCH 0046/5273] Add amber-lang.net to real-world uses --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 7d9bce0c6f..6d95f5ba5b 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -23,6 +23,7 @@

    { } CodeMi
    • Adobe Brackets (code editor)
    • +
    • Amber (JavaScript-based Smalltalk system)
    • BlueGriffon (HTML editor)
    • Cargo Collective (creative publishing platform)
    • Codebug (PHP Xdebug front-end)
    • From b637c397d435afafd75852c65915c721c2174c0b Mon Sep 17 00:00:00 2001 From: Stas Kobzar Date: Mon, 7 Jan 2013 22:30:54 -0500 Subject: [PATCH 0047/5273] Add Asterisk dialplan mode --- index.html | 1 + mode/asterisk/asterisk.js | 183 ++++++++++++++++++++++++++++++++++++++ mode/asterisk/index.html | 142 +++++++++++++++++++++++++++++ mode/meta.js | 1 + 4 files changed, 327 insertions(+) create mode 100644 mode/asterisk/asterisk.js create mode 100644 mode/asterisk/index.html diff --git a/index.html b/index.html index 1fc56855fa..878dbea760 100644 --- a/index.html +++ b/index.html @@ -35,6 +35,7 @@

      { } CodeMi

      Supported modes:

        +
      • Asterisk dialplan
      • C, C++, C#
      • Clojure
      • CoffeeScript
      • diff --git a/mode/asterisk/asterisk.js b/mode/asterisk/asterisk.js new file mode 100644 index 0000000000..d491857e92 --- /dev/null +++ b/mode/asterisk/asterisk.js @@ -0,0 +1,183 @@ +/* + * ===================================================================================== + * + * Filename: mode/asterisk/asterisk.js + * + * Description: CodeMirror mode for Asterisk dialplan + * + * Created: 05/17/2012 09:20:25 PM + * Revision: none + * + * Author: Stas Kobzar (stas@modulis.ca), + * Company: Modulis.ca Inc. + * + * ===================================================================================== + */ + +CodeMirror.defineMode("asterisk", function() { + var atoms = ["exten", "same", "include","ignorepat","switch"], + dpcmd = ["#include","#exec"], + apps = [ + "addqueuemember","adsiprog","aelsub","agentlogin","agentmonitoroutgoing","agi", + "alarmreceiver","amd","answer","authenticate","background","backgrounddetect", + "bridge","busy","callcompletioncancel","callcompletionrequest","celgenuserevent", + "changemonitor","chanisavail","channelredirect","chanspy","clearhash","confbridge", + "congestion","continuewhile","controlplayback","dahdiacceptr2call","dahdibarge", + "dahdiras","dahdiscan","dahdisendcallreroutingfacility","dahdisendkeypadfacility", + "datetime","dbdel","dbdeltree","deadagi","dial","dictate","directory","disa", + "dumpchan","eagi","echo","endwhile","exec","execif","execiftime","exitwhile","extenspy", + "externalivr","festival","flash","followme","forkcdr","getcpeid","gosub","gosubif", + "goto","gotoif","gotoiftime","hangup","iax2provision","ices","importvar","incomplete", + "ivrdemo","jabberjoin","jabberleave","jabbersend","jabbersendgroup","jabberstatus", + "jack","log","macro","macroexclusive","macroexit","macroif","mailboxexists","meetme", + "meetmeadmin","meetmechanneladmin","meetmecount","milliwatt","minivmaccmess","minivmdelete", + "minivmgreet","minivmmwi","minivmnotify","minivmrecord","mixmonitor","monitor","morsecode", + "mp3player","mset","musiconhold","nbscat","nocdr","noop","odbc","odbc","odbcfinish", + "originate","ospauth","ospfinish","osplookup","ospnext","page","park","parkandannounce", + "parkedcall","pausemonitor","pausequeuemember","pickup","pickupchan","playback","playtones", + "privacymanager","proceeding","progress","queue","queuelog","raiseexception","read","readexten", + "readfile","receivefax","receivefax","receivefax","record","removequeuemember", + "resetcdr","retrydial","return","ringing","sayalpha","saycountedadj","saycountednoun", + "saycountpl","saydigits","saynumber","sayphonetic","sayunixtime","senddtmf","sendfax", + "sendfax","sendfax","sendimage","sendtext","sendurl","set","setamaflags", + "setcallerpres","setmusiconhold","sipaddheader","sipdtmfmode","sipremoveheader","skel", + "slastation","slatrunk","sms","softhangup","speechactivategrammar","speechbackground", + "speechcreate","speechdeactivategrammar","speechdestroy","speechloadgrammar","speechprocessingsound", + "speechstart","speechunloadgrammar","stackpop","startmusiconhold","stopmixmonitor","stopmonitor", + "stopmusiconhold","stopplaytones","system","testclient","testserver","transfer","tryexec", + "trysystem","unpausemonitor","unpausequeuemember","userevent","verbose","vmauthenticate", + "vmsayname","voicemail","voicemailmain","wait","waitexten","waitfornoise","waitforring", + "waitforsilence","waitmusiconhold","waituntil","while","zapateller" + ]; + + function basicToken(stream,state){ + var cur = ''; + var ch = ''; + ch = stream.next(); + // comment + if(ch == ";") { + stream.skipToEnd(); + return "comment"; + } + // context + if(ch == '[') { + stream.skipTo(']'); + stream.eat(']'); + return "header"; + } + // string + if(ch == '"') { + stream.skipTo('"'); + return "string"; + } + if(ch == "'") { + stream.skipTo("'"); + return "string-2"; + } + // dialplan commands + if(ch == '#') { + stream.eatWhile(/\w/); + cur = stream.current(); + if(dpcmd.indexOf(cur) !== -1) { + stream.skipToEnd(); + return "strong"; + } + } + // application args + if(ch == '$'){ + var ch1 = stream.peek(); + if(ch1 == '{'){ + stream.skipTo('}'); + stream.eat('}'); + return "variable-3"; + } + } + // extension + stream.eatWhile(/\w/); + cur = stream.current(); + if(atoms.indexOf(cur) !== -1) { + state.extenStart = true; + switch(cur) { + case 'same': state.extenSame = true; break; + case 'include': + case 'switch': + case 'ignorepat': + state.extenInclude = true;break; + default:break; + } + return "atom"; + } + } + + return { + startState: function() { + return { + extenStart: false, + extenSame: false, + extenInclude: false, + extenExten: false, + extenPriority: false, + extenApplication: false + }; + }, + token: function(stream, state) { + + var cur = ''; + var ch = ''; + if(stream.eatSpace()) return null; + // extension started + if(state.extenStart){ + stream.eatWhile(/[^\s]/); + cur = stream.current(); + if(/^=>?$/.test(cur)){ + state.extenExten = true; + state.extenStart = false; + return "strong"; + } else { + state.extenStart = false; + stream.skipToEnd(); + return "error"; + } + } else if(state.extenExten) { + // set exten and priority + state.extenExten = false; + state.extenPriority = true; + stream.eatWhile(/[^,]/); + if(state.extenInclude) { + stream.skipToEnd(); + state.extenPriority = false; + state.extenInclude = false; + } + if(state.extenSame) { + state.extenPriority = false; + state.extenSame = false; + state.extenApplication = true; + } + return "tag"; + } else if(state.extenPriority) { + state.extenPriority = false; + state.extenApplication = true; + ch = stream.next(); // get comma + if(state.extenSame) return null; + stream.eatWhile(/[^,]/); + return "number"; + } else if(state.extenApplication) { + stream.eatWhile(/,/); + cur = stream.current(); + if(cur === ',') return null; + stream.eatWhile(/\w/); + cur = stream.current().toLowerCase(); + state.extenApplication = false; + if(apps.indexOf(cur) !== -1){ + return "def strong"; + } + } else{ + return basicToken(stream,state); + } + + return null; + } + }; +}); + +CodeMirror.defineMIME("text/x-asterisk", "asterisk"); diff --git a/mode/asterisk/index.html b/mode/asterisk/index.html new file mode 100644 index 0000000000..0a796a0119 --- /dev/null +++ b/mode/asterisk/index.html @@ -0,0 +1,142 @@ + + + + + CodeMirror: Asterisk dialplan mode + + + + + + + +

        CodeMirror: Asterisk dialplan mode

        + + + +

        MIME types defined: text/x-asterisk.

        + + + diff --git a/mode/meta.js b/mode/meta.js index c30888353f..f670a569a6 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -1,4 +1,5 @@ CodeMirror.modeInfo = [ + {name: 'Asterisk', mime: 'x-asterisk', mode: 'asterisk'}, {name: 'C', mime: 'x-csrc', mode: 'clike'}, {name: 'C++', mime: 'x-c++src', mode: 'clike'}, {name: 'Java', mime: 'x-java', mode: 'clike'}, From 514b496ef8b5f020cb11e3db9be9d98299e97a86 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 8 Jan 2013 10:18:14 +0100 Subject: [PATCH 0048/5273] Add a separate file listing all modes, unlist obscure ones on the front-page The list is getting out of hand. Which is great, actually, but the front-page shouldn't be dominated by it. --- doc/modes.html | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++ index.html | 13 +------- 2 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 doc/modes.html diff --git a/doc/modes.html b/doc/modes.html new file mode 100644 index 0000000000..48fdf88273 --- /dev/null +++ b/doc/modes.html @@ -0,0 +1,86 @@ + + + + + CodeMirror: Mode list + + + + + +

        { } CodeMirror

        + +
        + +
        +/* Full list of
        +   modes */
        +
        +
        + +

        Every mode in the distribution. The list on the front-page leaves +out some of the more obscure ones.

        + + + + + diff --git a/index.html b/index.html index 878dbea760..174bc27fd3 100644 --- a/index.html +++ b/index.html @@ -35,7 +35,6 @@

        { } CodeMi

        Supported modes:

        @@ -135,17 +127,14 @@

        Real-world uses:

      • Eloquent JavaScript (book)
      • Zen Coding (fast XML editing)
      • Paper.js (graphics scripting)
      • -
      • Go language tour
      • Codev (collaborative IDE)
      • Tributary (augmented editing)
      • Prose.io (github content editor)
      • WeScheme (learning tool)
      • WebGL playground
      • ql.io (http API query helper)
      • -
      • Elm language examples
      • The File Tree (collab editor)
      • JSHint (JS linter)
      • -
      • kl1p (paste service)
      • SQLFiddle (SQL playground)
      • Try Haxe (Haxe Playground)
      • CSSDeck (CSS showcase)
      • From 7445a7bd957ea98d846c8c1fbdfa38df60aaf28c Mon Sep 17 00:00:00 2001 From: Shmuel Englard Date: Mon, 7 Jan 2013 16:07:45 -0500 Subject: [PATCH 0049/5273] [util/runmodeonly] Addeds a new util called run mode only that can be used in place of code that only used codemirror.js and runmode.js for run mode --- lib/util/runmodeonly.js | 131 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 lib/util/runmodeonly.js diff --git a/lib/util/runmodeonly.js b/lib/util/runmodeonly.js new file mode 100644 index 0000000000..f25ae47451 --- /dev/null +++ b/lib/util/runmodeonly.js @@ -0,0 +1,131 @@ +/* Just enough of CodeMirror to run runMode under node.js */ + +CodeMirror = {}; + +function splitLines(string){ return string.split(/\r?\n|\r/); }; + +function StringStream(string) { + this.pos = this.start = 0; + this.string = string; +} +StringStream.prototype = { + eol: function() {return this.pos >= this.string.length;}, + sol: function() {return this.pos == 0;}, + peek: function() {return this.string.charAt(this.pos) || null;}, + next: function() { + if (this.pos < this.string.length) + 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;} + }, + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)){} + 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; + }, + 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;} + }, + backUp: function(n) {this.pos -= n;}, + column: function() {return this.start;}, + indentation: function() {return 0;}, + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + function cased(str) {return caseInsensitive ? str.toLowerCase() : str;} + if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) { + if (consume !== false) this.pos += pattern.length; + return true; + } + } + else { + var match = this.string.slice(this.pos).match(pattern); + if (match && consume !== false) this.pos += match[0].length; + return match; + } + }, + current: function(){return this.string.slice(this.start, this.pos);} +}; +CodeMirror.StringStream = StringStream; + +CodeMirror.startState = function (mode, a1, a2) { + return mode.startState ? mode.startState(a1, a2) : true; +}; + +var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; +CodeMirror.defineMode = function (name, mode) { modes[name] = mode; }; +CodeMirror.defineMIME = function (mime, spec) { mimeModes[mime] = spec; }; +CodeMirror.getMode = function (options, spec) { + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) + spec = mimeModes[spec]; + if (typeof spec == "string") + var mname = spec, config = {}; + else if (spec != null) + var mname = spec.name, config = spec; + var mfactory = modes[mname]; + if (!mfactory) throw new Error("Unknown mode: " + spec); + return mfactory(options, config || {}); +}; + +CodeMirror.runMode = function (string, modespec, callback, options) { + var mode = CodeMirror.getMode({ indentUnit: 2 }, modespec); + + if (callback.nodeType == 1) { + var tabSize = (options && options.tabSize) || 4; + var node = callback, col = 0; + node.innerHTML = ""; + callback = function (text, style) { + if (text == "\n") { + node.appendChild(document.createElement("br")); + col = 0; + return; + } + var content = ""; + // replace tabs + for (var pos = 0; ;) { + var idx = text.indexOf("\t", pos); + if (idx == -1) { + content += text.slice(pos); + col += text.length - pos; + break; + } else { + col += idx - pos; + content += text.slice(pos, idx); + var size = tabSize - col % tabSize; + col += size; + for (var i = 0; i < size; ++i) content += " "; + pos = idx + 1; + } + } + + if (style) { + var sp = node.appendChild(document.createElement("span")); + sp.className = "cm-" + style.replace(/ +/g, " cm-"); + sp.appendChild(document.createTextNode(content)); + } else { + node.appendChild(document.createTextNode(content)); + } + }; + } + + var lines = splitLines(string), state = CodeMirror.startState(mode); + for (var i = 0, e = lines.length; i < e; ++i) { + if (i) callback("\n"); + var stream = new CodeMirror.StringStream(lines[i]); + while (!stream.eol()) { + var style = mode.token(stream, state); + callback(stream.current(), style, i, stream.start); + stream.start = stream.pos; + } + } +}; From 7858e2515a4f3ed0a2d030faaefe3308e582ef50 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 8 Jan 2013 10:20:43 +0100 Subject: [PATCH 0050/5273] [util/runmodeonly] Don't directly assign to global variable It upsets the linter. --- lib/util/runmodeonly.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util/runmodeonly.js b/lib/util/runmodeonly.js index f25ae47451..665c1e9999 100644 --- a/lib/util/runmodeonly.js +++ b/lib/util/runmodeonly.js @@ -1,6 +1,6 @@ /* Just enough of CodeMirror to run runMode under node.js */ -CodeMirror = {}; +window.CodeMirror = {}; function splitLines(string){ return string.split(/\r?\n|\r/); }; From eb2969fbc30ba58cbb81acdc9ca5fc0189c9d5e9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 8 Jan 2013 10:48:58 +0100 Subject: [PATCH 0051/5273] Organize add-on scripts into subdirectories Closes #1133 --- {lib/util => addon/dialog}/dialog.css | 0 {lib/util => addon/dialog}/dialog.js | 0 {lib/util => addon/edit}/closetag.js | 0 {lib/util => addon/edit}/continuecomment.js | 0 {lib/util => addon/edit}/continuelist.js | 0 {lib/util => addon/edit}/matchbrackets.js | 0 {lib/util => addon/fold}/collapserange.js | 0 {lib/util => addon/fold}/foldcode.js | 0 {lib/util => addon/format}/formatting.js | 0 {lib/util => addon/hint}/javascript-hint.js | 0 {lib/util => addon/hint}/pig-hint.js | 0 {lib/util => addon/hint}/python-hint.js | 0 {lib/util => addon/hint}/simple-hint.css | 0 {lib/util => addon/hint}/simple-hint.js | 0 {lib/util => addon/hint}/xml-hint.js | 0 {lib/util => addon/mode}/loadmode.js | 0 {lib/util => addon/mode}/multiplex.js | 0 {lib/util => addon/mode}/overlay.js | 0 {lib/util => addon/runmode}/colorize.js | 0 .../runmode/runmode-standalone.js | 0 {lib/util => addon/runmode}/runmode.js | 0 .../runmode/runmode.node.js | 0 .../search}/match-highlighter.js | 0 {lib/util => addon/search}/search.js | 0 {lib/util => addon/search}/searchcursor.js | 0 bin/compress | 3 +- demo/closetag.html | 2 +- demo/collapserange.html | 2 +- demo/complete.html | 10 +-- demo/folding.html | 4 +- demo/formatting.html | 2 +- demo/loadmode.html | 2 +- demo/matchhighlighter.html | 4 +- demo/multiplex.html | 6 +- demo/mustache.html | 4 +- demo/runmode.html | 4 +- demo/search.html | 16 ++--- demo/vim.html | 6 +- demo/xmlcomplete.html | 12 ++-- doc/compress.html | 41 +++++++----- doc/manual.html | 66 ++++++++++--------- doc/oldrelease.html | 6 +- doc/upgrade_v3.html | 8 +-- index.html | 2 +- mode/clike/index.html | 2 +- mode/clike/scala.html | 2 +- mode/d/index.html | 2 +- mode/erlang/index.html | 2 +- mode/gfm/index.html | 2 +- mode/go/index.html | 2 +- mode/groovy/index.html | 2 +- mode/haskell/index.html | 2 +- mode/javascript/index.html | 4 +- mode/less/index.html | 2 +- mode/lua/index.html | 2 +- mode/markdown/index.html | 2 +- mode/ocaml/index.html | 2 +- mode/php/index.html | 2 +- mode/python/index.html | 2 +- mode/ruby/index.html | 2 +- mode/sass/index.html | 2 +- mode/shell/index.html | 2 +- mode/smalltalk/index.html | 2 +- mode/sparql/index.html | 2 +- mode/tiddlywiki/index.html | 2 +- mode/vb/index.html | 2 +- test/index.html | 4 +- test/run.js | 1 + 68 files changed, 132 insertions(+), 119 deletions(-) rename {lib/util => addon/dialog}/dialog.css (100%) rename {lib/util => addon/dialog}/dialog.js (100%) rename {lib/util => addon/edit}/closetag.js (100%) rename {lib/util => addon/edit}/continuecomment.js (100%) rename {lib/util => addon/edit}/continuelist.js (100%) rename {lib/util => addon/edit}/matchbrackets.js (100%) rename {lib/util => addon/fold}/collapserange.js (100%) rename {lib/util => addon/fold}/foldcode.js (100%) rename {lib/util => addon/format}/formatting.js (100%) rename {lib/util => addon/hint}/javascript-hint.js (100%) rename {lib/util => addon/hint}/pig-hint.js (100%) rename {lib/util => addon/hint}/python-hint.js (100%) rename {lib/util => addon/hint}/simple-hint.css (100%) rename {lib/util => addon/hint}/simple-hint.js (100%) rename {lib/util => addon/hint}/xml-hint.js (100%) rename {lib/util => addon/mode}/loadmode.js (100%) rename {lib/util => addon/mode}/multiplex.js (100%) rename {lib/util => addon/mode}/overlay.js (100%) rename {lib/util => addon/runmode}/colorize.js (100%) rename lib/util/runmodeonly.js => addon/runmode/runmode-standalone.js (100%) rename {lib/util => addon/runmode}/runmode.js (100%) rename lib/util/runmode-standalone.js => addon/runmode/runmode.node.js (100%) rename {lib/util => addon/search}/match-highlighter.js (100%) rename {lib/util => addon/search}/search.js (100%) rename {lib/util => addon/search}/searchcursor.js (100%) diff --git a/lib/util/dialog.css b/addon/dialog/dialog.css similarity index 100% rename from lib/util/dialog.css rename to addon/dialog/dialog.css diff --git a/lib/util/dialog.js b/addon/dialog/dialog.js similarity index 100% rename from lib/util/dialog.js rename to addon/dialog/dialog.js diff --git a/lib/util/closetag.js b/addon/edit/closetag.js similarity index 100% rename from lib/util/closetag.js rename to addon/edit/closetag.js diff --git a/lib/util/continuecomment.js b/addon/edit/continuecomment.js similarity index 100% rename from lib/util/continuecomment.js rename to addon/edit/continuecomment.js diff --git a/lib/util/continuelist.js b/addon/edit/continuelist.js similarity index 100% rename from lib/util/continuelist.js rename to addon/edit/continuelist.js diff --git a/lib/util/matchbrackets.js b/addon/edit/matchbrackets.js similarity index 100% rename from lib/util/matchbrackets.js rename to addon/edit/matchbrackets.js diff --git a/lib/util/collapserange.js b/addon/fold/collapserange.js similarity index 100% rename from lib/util/collapserange.js rename to addon/fold/collapserange.js diff --git a/lib/util/foldcode.js b/addon/fold/foldcode.js similarity index 100% rename from lib/util/foldcode.js rename to addon/fold/foldcode.js diff --git a/lib/util/formatting.js b/addon/format/formatting.js similarity index 100% rename from lib/util/formatting.js rename to addon/format/formatting.js diff --git a/lib/util/javascript-hint.js b/addon/hint/javascript-hint.js similarity index 100% rename from lib/util/javascript-hint.js rename to addon/hint/javascript-hint.js diff --git a/lib/util/pig-hint.js b/addon/hint/pig-hint.js similarity index 100% rename from lib/util/pig-hint.js rename to addon/hint/pig-hint.js diff --git a/lib/util/python-hint.js b/addon/hint/python-hint.js similarity index 100% rename from lib/util/python-hint.js rename to addon/hint/python-hint.js diff --git a/lib/util/simple-hint.css b/addon/hint/simple-hint.css similarity index 100% rename from lib/util/simple-hint.css rename to addon/hint/simple-hint.css diff --git a/lib/util/simple-hint.js b/addon/hint/simple-hint.js similarity index 100% rename from lib/util/simple-hint.js rename to addon/hint/simple-hint.js diff --git a/lib/util/xml-hint.js b/addon/hint/xml-hint.js similarity index 100% rename from lib/util/xml-hint.js rename to addon/hint/xml-hint.js diff --git a/lib/util/loadmode.js b/addon/mode/loadmode.js similarity index 100% rename from lib/util/loadmode.js rename to addon/mode/loadmode.js diff --git a/lib/util/multiplex.js b/addon/mode/multiplex.js similarity index 100% rename from lib/util/multiplex.js rename to addon/mode/multiplex.js diff --git a/lib/util/overlay.js b/addon/mode/overlay.js similarity index 100% rename from lib/util/overlay.js rename to addon/mode/overlay.js diff --git a/lib/util/colorize.js b/addon/runmode/colorize.js similarity index 100% rename from lib/util/colorize.js rename to addon/runmode/colorize.js diff --git a/lib/util/runmodeonly.js b/addon/runmode/runmode-standalone.js similarity index 100% rename from lib/util/runmodeonly.js rename to addon/runmode/runmode-standalone.js diff --git a/lib/util/runmode.js b/addon/runmode/runmode.js similarity index 100% rename from lib/util/runmode.js rename to addon/runmode/runmode.js diff --git a/lib/util/runmode-standalone.js b/addon/runmode/runmode.node.js similarity index 100% rename from lib/util/runmode-standalone.js rename to addon/runmode/runmode.node.js diff --git a/lib/util/match-highlighter.js b/addon/search/match-highlighter.js similarity index 100% rename from lib/util/match-highlighter.js rename to addon/search/match-highlighter.js diff --git a/lib/util/search.js b/addon/search/search.js similarity index 100% rename from lib/util/search.js rename to addon/search/search.js diff --git a/lib/util/searchcursor.js b/addon/search/searchcursor.js similarity index 100% rename from lib/util/searchcursor.js rename to addon/search/searchcursor.js diff --git a/bin/compress b/bin/compress index de86ca1f69..eb45e1d194 100755 --- a/bin/compress +++ b/bin/compress @@ -6,7 +6,7 @@ // // bin/compress codemirror runmode javascript xml // -// Will take lib/codemirror.js, lib/util/runmode.js, +// 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. @@ -61,6 +61,7 @@ function walk(dir) { } walk("lib/"); +walk("addon/"); walk("mode/"); if (!blob) help(false); diff --git a/demo/closetag.html b/demo/closetag.html index c33d10875f..87f4f019f6 100644 --- a/demo/closetag.html +++ b/demo/closetag.html @@ -5,7 +5,7 @@ CodeMirror: Close-Tag Demo - + diff --git a/demo/collapserange.html b/demo/collapserange.html index 87aad82307..5a6df0d257 100644 --- a/demo/collapserange.html +++ b/demo/collapserange.html @@ -5,7 +5,7 @@ CodeMirror: Range Collapsing Demo - + diff --git a/demo/complete.html b/demo/complete.html index 13569edf92..2efbd3d622 100644 --- a/demo/complete.html +++ b/demo/complete.html @@ -5,9 +5,9 @@ CodeMirror: Autocomplete Demo - - - + + + @@ -53,8 +53,8 @@

        CodeMirror: Autocomplete demo

        Press ctrl-space to activate autocompletion. See -the code (here -and here) to figure out +the code (here +and here) to figure out how it works.

        - + @@ -25,7 +25,7 @@

        CodeMirror: Code Folding Demo

        Demonstration of code folding using the code - in foldcode.js. + in foldcode.js. Press ctrl-q or click on the gutter to fold a block, again to unfold.
        Try the Range Colapse demo as well.

        diff --git a/demo/formatting.html b/demo/formatting.html index b9e800d9cf..5d2f4b40fc 100644 --- a/demo/formatting.html +++ b/demo/formatting.html @@ -5,7 +5,7 @@ CodeMirror: Formatting Demo - + diff --git a/demo/loadmode.html b/demo/loadmode.html index ffe97e30b6..1bd958f70b 100644 --- a/demo/loadmode.html +++ b/demo/loadmode.html @@ -5,7 +5,7 @@ CodeMirror: Lazy Mode Loading Demo - + - - + + @@ -1103,19 +1103,19 @@

        Programming API

        Add-ons

        -

        The lib/util directory in the distribution - contains a number of reusable components that implement extra - editor functionality. In brief, they are:

        +

        The addon directory in the distribution contains a + number of reusable components that implement extra editor + functionality. In brief, they are:

        -
        dialog.js
        +
        dialog.js
        Provides a very simple way to query users for text input. Adds an openDialog method to CodeMirror instances, which can be called with an HTML fragment that provides the prompt (should include an input tag), and a callback function that is called when text has been entered. - Depends on lib/util/dialog.css.
        -
        searchcursor.js
        + Depends on addon/dialog/dialog.css.

    +
    searchcursor.js
    Adds the getSearchCursor(query, start, caseFold) → cursor method to CodeMirror instances, which can be used to implement search/replace functionality. query @@ -1144,14 +1144,14 @@

    Add-ons

    replacement.
    - +
    Implements the search commands. CodeMirror has keys bound to these by default, but will not do anything with them unless an implementation is provided. Depends on searchcursor.js, and will make use - of openDialog when + of openDialog when available to make prompting for search queries less ugly.
    -
    matchbrackets.js
    +
    matchbrackets.js
    Defines an option matchBrackets which, when set to true, causes matching brackets to be highlighted whenever the cursor is next to them. It also adds a @@ -1159,7 +1159,7 @@

    Add-ons

    once, and a method findMatchingBracket that can be used to run the bracket-finding algorithm that this uses internally.
    -
    foldcode.js
    +
    foldcode.js
    Helps with code folding. See the demo for an example. Call CodeMirror.newFoldFunction with a range-finder @@ -1175,17 +1175,21 @@

    Add-ons

    where indentation determines block structure (Python, Haskell), and CodeMirror.tagRangeFinder, for XML-style languages.
    -
    collapserange.js
    +
    collapserange.js
    Another approach to folding. See demo. Allows the user to select a range to fold by clicking in the gutter.
    -
    runmode.js
    +
    runmode.js
    Can be used to run a CodeMirror mode over text without actually opening an editor instance. - See the demo for an - example.
    -
    overlay.js
    + See the demo for an example. + There alternate version of the file avaible for + running stand-alone + (without including all of CodeMirror) and + for running under + node.js. +
    overlay.js
    Mode combinator that can be used to extend a mode with an 'overlay' — a secondary mode is run over the stream, along with the base mode, and can color specific pieces of text without @@ -1193,7 +1197,7 @@

    Add-ons

    Defines CodeMirror.overlayMode, which is used to create such a mode. See this demo for a detailed example.
    -
    multiplex.js
    +
    multiplex.js
    Mode combinator that can be used to easily 'multiplex' between several modes. Defines CodeMirror.multiplexingMode which, when @@ -1212,7 +1216,7 @@

    Add-ons

    see the content between the delimiters. See this demo for an example.
    -
    simple-hint.js
    +
    simple-hint.js
    Provides a framework for showing autocompletion hints. Defines CodeMirror.simpleHint, which takes a CodeMirror instance and a hinting function, and pops up a widget @@ -1222,36 +1226,36 @@

    Add-ons

    is an array of strings (the completions), and from and to give the start and end of the token that is being completed. Depends - on lib/util/simple-hint.css.
    -
    javascript-hint.js
    + on addon/hint/simple-hint.css. +
    javascript-hint.js
    Defines CodeMirror.javascriptHint and CodeMirror.coffeescriptHint, which are simple hinting functions for the JavaScript and CoffeeScript modes.
    -
    xml-hint.js
    +
    xml-hint.js
    Defines CodeMirror.xmlHint, a hinting function for XML (which requires a schema to be defined).
    -
    python-hint.js
    +
    python-hint.js
    Defines CodeMirror.pythonHint, a hinter for Python code.
    -
    match-highlighter.js
    +
    match-highlighter.js
    Adds a matchHighlight method to CodeMirror instances that can be called (typically from a cursorActivity handler) to highlight all instances of a currently selected word with the a classname given as a first argument to the method. Depends on - the searchcursor + the searchcursor add-on. Demo here.
    -
    formatting.js
    +
    formatting.js
    Adds commentRange, autoIndentRange, and autoFormatRange methods that, respectively, comment (or uncomment), indent, or format (add line breaks) a range of code. Demo here.
    -
    closetag.js
    +
    closetag.js
    Provides utility functions for adding automatic tag closing to XML modes. See the demo.
    -
    loadmode.js
    +
    loadmode.js
    Defines a CodeMirror.requireMode(modename, callback) function that will try to load a given mode and call the callback when it succeeded. You'll have to @@ -1263,7 +1267,7 @@

    Add-ons

    which will ensure the given mode is loaded and cause the given editor instance to refresh its mode when the loading succeeded. See the demo.
    -
    continuecomment.js
    +
    continuecomment.js
    Adds a command called newlineAndIndentContinueComment that you can bind Enter to in order to have the editor prefix @@ -1456,8 +1460,8 @@

    Writing CodeMirror Modes

    extra methods, innerMode which, given a state object, returns a {state, mode} object with the inner mode and its state for the current position. These are used by utility - scripts such as the autoformatter - and the tag closer to get context + scripts such as the autoformatter + and the tag closer to get context information. Use the CodeMirror.innerMode helper function to, starting from a mode and a state, recursively walk down to the innermost mode and state.

    diff --git a/doc/oldrelease.html b/doc/oldrelease.html index dafe738652..aff806e06d 100644 --- a/doc/oldrelease.html +++ b/doc/oldrelease.html @@ -91,8 +91,8 @@

    { } CodeMi
  • Add autoClearEmptyLines option.
  • Properly use tab stops when rendering tabs.
  • Make PHP mode more robust.
  • -
  • Support indentation blocks in code folder.
  • -
  • Add a script for highlighting instances of the selection.
  • +
  • Support indentation blocks in code folder.
  • +
  • Add a script for highlighting instances of the selection.
  • New .properties mode.
  • Fix many bugs.
  • @@ -148,7 +148,7 @@

    { } CodeMi and Rubyblue themes.
  • Add setBookmark method.
  • Move some of the demo code into reusable components - under lib/util.
  • + under lib/util.
  • Make screen-coord-finding code faster and more reliable.
  • Fix drag-and-drop in Firefox.
  • Improve support for IME.
  • diff --git a/doc/upgrade_v3.html b/doc/upgrade_v3.html index eaaffec17f..7e8a6b61ae 100644 --- a/doc/upgrade_v3.html +++ b/doc/upgrade_v3.html @@ -7,8 +7,8 @@ - - + + @@ -174,9 +174,9 @@

    Position properties

    Bracket matching no longer in core

    -

    The matchBrackets +

    The matchBrackets option is no longer defined in the core editor. -Load lib/util/matchbrackets.js to enable it.

    +Load addon/edit/matchbrackets.js to enable it.

    Mode management

    diff --git a/index.html b/index.html index 174bc27fd3..e921f0f300 100644 --- a/index.html +++ b/index.html @@ -329,7 +329,7 @@

    Releases

  • Add defaultTextHeight method.
  • Various extensions to the vim keymap.
  • Make PHP mode build on mixed HTML mode.
  • -
  • Add comment-continuing add-on.
  • +
  • Add comment-continuing add-on.
  • Full list of patches.
  • diff --git a/mode/clike/index.html b/mode/clike/index.html index ca10c4bc23..5f90394d95 100644 --- a/mode/clike/index.html +++ b/mode/clike/index.html @@ -5,7 +5,7 @@ CodeMirror: C-like mode - + diff --git a/mode/clike/scala.html b/mode/clike/scala.html index 39115967ab..f3c7eea498 100644 --- a/mode/clike/scala.html +++ b/mode/clike/scala.html @@ -6,7 +6,7 @@ - + diff --git a/mode/erlang/index.html b/mode/erlang/index.html index f6bee8f723..fd21521c88 100644 --- a/mode/erlang/index.html +++ b/mode/erlang/index.html @@ -5,7 +5,7 @@ CodeMirror: Erlang mode - + diff --git a/mode/gfm/index.html b/mode/gfm/index.html index e4ea473571..b5bdb8888f 100644 --- a/mode/gfm/index.html +++ b/mode/gfm/index.html @@ -5,7 +5,7 @@ CodeMirror: GFM mode - + diff --git a/mode/go/index.html b/mode/go/index.html index 1a9ef53852..8a6aafca29 100644 --- a/mode/go/index.html +++ b/mode/go/index.html @@ -6,7 +6,7 @@ - + diff --git a/mode/groovy/index.html b/mode/groovy/index.html index d0d76bfa90..3d39595774 100644 --- a/mode/groovy/index.html +++ b/mode/groovy/index.html @@ -5,7 +5,7 @@ CodeMirror: Groovy mode - + diff --git a/mode/haskell/index.html b/mode/haskell/index.html index b304a27682..56307b8a95 100644 --- a/mode/haskell/index.html +++ b/mode/haskell/index.html @@ -5,7 +5,7 @@ CodeMirror: Haskell mode - + diff --git a/mode/javascript/index.html b/mode/javascript/index.html index d81413c0a6..9222ddf170 100644 --- a/mode/javascript/index.html +++ b/mode/javascript/index.html @@ -5,8 +5,8 @@ CodeMirror: JavaScript mode - - + + diff --git a/mode/less/index.html b/mode/less/index.html index 7f27cf30e9..78c1e53074 100644 --- a/mode/less/index.html +++ b/mode/less/index.html @@ -5,7 +5,7 @@ CodeMirror: LESS mode - + diff --git a/mode/lua/index.html b/mode/lua/index.html index df83f9b47d..a0a42d91c4 100644 --- a/mode/lua/index.html +++ b/mode/lua/index.html @@ -4,7 +4,7 @@ CodeMirror: Lua mode - + diff --git a/mode/markdown/index.html b/mode/markdown/index.html index 5d7452f1e8..6f97b10e73 100644 --- a/mode/markdown/index.html +++ b/mode/markdown/index.html @@ -5,7 +5,7 @@ CodeMirror: Markdown mode - + diff --git a/mode/ocaml/index.html b/mode/ocaml/index.html index 962fa29eb1..c10a84fade 100644 --- a/mode/ocaml/index.html +++ b/mode/ocaml/index.html @@ -10,7 +10,7 @@ - +

    CodeMirror: OCaml mode

    diff --git a/mode/php/index.html b/mode/php/index.html index 4b21c1900a..3d4c336ce0 100644 --- a/mode/php/index.html +++ b/mode/php/index.html @@ -5,7 +5,7 @@ CodeMirror: PHP mode - + diff --git a/mode/python/index.html b/mode/python/index.html index 7a26d278db..c1df119485 100644 --- a/mode/python/index.html +++ b/mode/python/index.html @@ -5,7 +5,7 @@ CodeMirror: Python mode - + diff --git a/mode/ruby/index.html b/mode/ruby/index.html index f226289d7d..64cfe5ef34 100644 --- a/mode/ruby/index.html +++ b/mode/ruby/index.html @@ -5,7 +5,7 @@ CodeMirror: Ruby mode - + diff --git a/mode/shell/index.html b/mode/shell/index.html index 0827053cee..9a2ef7c4cd 100644 --- a/mode/shell/index.html +++ b/mode/shell/index.html @@ -10,7 +10,7 @@ - +

    CodeMirror: Shell mode

    diff --git a/mode/smalltalk/index.html b/mode/smalltalk/index.html index 690b560fd7..b7aebdb7fb 100644 --- a/mode/smalltalk/index.html +++ b/mode/smalltalk/index.html @@ -5,7 +5,7 @@ CodeMirror: Smalltalk mode - + diff --git a/mode/tiddlywiki/index.html b/mode/tiddlywiki/index.html index 89ae85892b..848f33a592 100644 --- a/mode/tiddlywiki/index.html +++ b/mode/tiddlywiki/index.html @@ -5,7 +5,7 @@ CodeMirror: TiddlyWiki mode - + diff --git a/mode/vb/index.html b/mode/vb/index.html index 1670c7d05b..74dd5e8161 100644 --- a/mode/vb/index.html +++ b/mode/vb/index.html @@ -12,7 +12,7 @@ .CodeMirror-scroll { overflow-x: auto; overflow-y: hidden;} .CodeMirror pre { font-family: Inconsolata; font-size: 14px} - +

    CodeMirror: VB.NET mode

    diff --git a/test/index.html b/test/index.html index 9634ac23e8..4bb4a77be5 100644 --- a/test/index.html +++ b/test/index.html @@ -7,8 +7,8 @@ - - + + diff --git a/test/run.js b/test/run.js index 8c7649a17d..5588d6f388 100755 --- a/test/run.js +++ b/test/run.js @@ -4,6 +4,7 @@ var lint = require("./lint/lint"); lint.checkDir("mode"); lint.checkDir("lib"); +lint.checkDir("addon"); var ok = lint.success(); From 9e7501bb10582e1f1155d318bd1c39ee97a1da38 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 8 Jan 2013 14:40:29 +0100 Subject: [PATCH 0052/5273] Fix links in full mode list Closes #1144 --- doc/modes.html | 112 ++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/doc/modes.html b/doc/modes.html index 48fdf88273..7c072971c2 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -23,62 +23,62 @@

    { } CodeMi
    From 21380af6901c76011548d2fd2c7a2befad99f41f Mon Sep 17 00:00:00 2001 From: Peter Kroon Date: Tue, 8 Jan 2013 15:04:26 +0100 Subject: [PATCH 0053/5273] Update LICENSE Set correct year in license. --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 3916e96b2d..482d55eb73 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2012 by Marijn Haverbeke +Copyright (C) 2013 by Marijn Haverbeke 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 ee071463e9de587abcf2ae47fa4bd59b770e2384 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 10 Jan 2013 11:02:37 +0100 Subject: [PATCH 0054/5273] Check, after updating display, if viewport is really filled Due to changed line heights, the rendered content might not reach to the viewport bottom. Issue #1147 --- lib/codemirror.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 5a87212632..9cce59d93f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -503,6 +503,9 @@ window.CodeMirror = (function() { display.viewOffset = heightAtLine(cm, getLine(doc, from)); // Position the mover div to align with the current virtual scroll position display.mover.style.top = display.viewOffset + "px"; + + if (visibleLines(display, doc, viewPort).to >= to) + updateDisplayInner(cm, [], viewPort); return true; } From db1b28207d5b8b799d7202cf47bb9ece1c0afb3c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 10 Jan 2013 11:44:05 +0100 Subject: [PATCH 0055/5273] Make line widget handles objects with methods. Handle widget height better Closes #1147 Widget handles now have .clear() and .changed() methods. The second informs CodeMirror that the widget changed, and causes it to recompute the line height for the widget's line. Fixes some sloppiness in the tracking of widget heights. --- doc/manual.html | 15 +++++---- lib/codemirror.js | 80 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 8f9574b871..150ef05353 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -978,12 +978,15 @@

    Programming API

    CodeMirror-specific CSS classes, and those classes might in some cases affect it. This method returns an object that represents the widget placement. It'll have a line property - pointing at the line handle that it is associated with, and it - can be passed to removeLineWidget to remove the - widget.

    - -
    removeLineWidget(widget)
    -
    Removes the given line widget.
    + pointing at the line handle that it is associated with, and the following methods: +
    +
    clear()
    Removes the widget.
    +
    changed()
    Call + this if you made some change to the widget's DOM node that + might affect its height. It'll force CodeMirror to update + the height of the line that contains the widget.
    +
    +
    posFromIndex(index) → object
    Calculates and returns a {line, ch} object for a diff --git a/lib/codemirror.js b/lib/codemirror.js index 9cce59d93f..975c8d23b9 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -497,8 +497,12 @@ window.CodeMirror = (function() { } var diff = node.lineObj.height - height; if (height < 2) height = textHeight(display); - if (diff > .001 || diff < -.001) + if (diff > .001 || diff < -.001) { updateLineHeight(node.lineObj, height); + var widgets = node.lineObj.widgets; + if (widgets) for (var i = 0; i < widgets.length; ++i) + widgets[i].height = widgets[i].node.offsetHeight; + } } display.viewOffset = heightAtLine(cm, getLine(doc, from)); // Position the mover div to align with the current virtual scroll position @@ -978,7 +982,7 @@ window.CodeMirror = (function() { // Context is one of "line", "div" (display.lineDiv), "local"/null (editor), or "page" 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 = lineObj.widgets[i].node.offsetHeight; + var size = widgetHeight(lineObj.widgets[i]); rect.top += size; rect.bottom += size; } if (context == "line") return rect; @@ -2597,25 +2601,10 @@ window.CodeMirror = (function() { }), addLineWidget: operation(null, function(handle, node, options) { - var widget = options || {}; - widget.node = node; - if (widget.noHScroll) this.display.alignWidgets = true; - changeLine(this, handle, function(line) { - (line.widgets || (line.widgets = [])).push(widget); - widget.line = line; - return true; - }); - return widget; + return addLineWidget(this, handle, node, options); }), - removeLineWidget: operation(null, function(widget) { - var ws = widget.line.widgets, no = lineNo(widget.line); - if (no == null || !ws) return; - for (var i = 0; i < ws.length; ++i) if (ws[i] == widget) ws.splice(i--, 1); - var newHeight = widget.node.offsetHeight ? widget.line.height - widget.node.offsetHeight : textHeight(this.display); - updateLineHeight(widget.line, newHeight); - regChange(this, no, no + 1); - }), + removeLineWidget: function(widget) { widget.remove(); }, lineInfo: function(line) { if (typeof line == "number") { @@ -3587,6 +3576,59 @@ window.CodeMirror = (function() { line.markedSpans = spans; } + // LINE WIDGETS + + var LineWidget = CodeMirror.LineWidget = function(cm, node, options) { + for (var opt in options) if (options.hasOwnProperty(opt)) + this[opt] = options[opt]; + this.cm = cm; + this.node = node; + }; + function widgetOperation(f) { + return function() { + startOperation(this.cm); + try {var result = f.apply(this, arguments);} + finally {endOperation(this.cm);} + return result; + }; + } + LineWidget.prototype.clear = widgetOperation(function() { + var ws = this.line.widgets, no = lineNo(this.line); + if (no == null || !ws) return; + for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); + updateLineHeight(this.line, Math.max(0, this.line.height - widgetHeight(this))); + regChange(this.cm, no, no + 1); + }); + LineWidget.prototype.changed = widgetOperation(function() { + var oldH = this.height; + this.height = null; + var diff = widgetHeight(this) - oldH; + if (!diff) return; + updateLineHeight(this.line, this.line.height + diff); + var no = lineNo(this.line); + regChange(this.cm, no, no + 1); + }); + + function widgetHeight(widget) { + if (widget.height != null) return widget.height; + if (!widget.node.parentNode) + removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, "position: relative")); + return widget.height = widget.node.offsetHeight; + } + + function addLineWidget(cm, handle, node, options) { + var widget = new LineWidget(cm, node, options); + if (widget.noHScroll) cm.display.alignWidgets = true; + changeLine(cm, handle, function(line) { + (line.widgets || (line.widgets = [])).push(widget); + widget.line = line; + if (!lineIsHidden(line) || widget.showIfHidden) + updateLineHeight(line, line.height + widgetHeight(widget)); + return true; + }); + return widget; + } + // LINE DATA STRUCTURE // Line objects. These hold state related to a line, including From 5af6bb0f1572ea4e0e0d65f85bdfec5dc493a390 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 10 Jan 2013 11:57:34 +0100 Subject: [PATCH 0056/5273] Don't set innerHTML in IE It damages parent-child relationships in subnodes, which we might still need later. --- lib/codemirror.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 975c8d23b9..32f11a7afa 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -550,9 +550,7 @@ window.CodeMirror = (function() { function patchDisplay(cm, from, to, intact, updateNumbersFrom) { var dims = getDimensions(cm); var display = cm.display, lineNumbers = cm.options.lineNumbers; - // IE does bad things to nodes when .innerHTML = "" is used on a parent - // we still need widgets and markers intact to add back to the new content later - if (!intact.length && !ie && (!webkit || !cm.display.currentWheelTarget)) + if (!intact.length && (!webkit || !cm.display.currentWheelTarget)) removeChildren(display.lineDiv); var container = display.lineDiv, cur = container.firstChild; @@ -1114,7 +1112,6 @@ window.CodeMirror = (function() { } removeChildrenAndAdd(display.measure, measureText); var height = measureText.offsetHeight / 50; - display.measure.removeChild(measureText); if (height > 3) display.cachedTextHeight = height; removeChildren(display.measure); return height || 1; @@ -4354,7 +4351,9 @@ window.CodeMirror = (function() { } function removeChildren(e) { - e.innerHTML = ""; + // IE will break all parent-child relations in subnodes when setting innerHTML + if (!ie) e.innerHTML = ""; + else while (e.firstChild) e.removeChild(e.firstChild); return e; } From 7777dce07c3acc9c14cf6ea867e2ee1e6b3f381c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 10 Jan 2013 12:14:19 +0100 Subject: [PATCH 0057/5273] Make sure widgets are added to vertical scroll size Closes #1148 --- lib/codemirror.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 32f11a7afa..4456181cc6 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3608,7 +3608,7 @@ window.CodeMirror = (function() { function widgetHeight(widget) { if (widget.height != null) return widget.height; - if (!widget.node.parentNode) + if (!widget.node.parentNode || widget.node.parentNode.nodeType != 1) removeChildrenAndAdd(widget.cm.display.measure, elt("div", [widget.node], null, "position: relative")); return widget.height = widget.node.offsetHeight; } @@ -3619,8 +3619,12 @@ window.CodeMirror = (function() { changeLine(cm, handle, function(line) { (line.widgets || (line.widgets = [])).push(widget); widget.line = line; - if (!lineIsHidden(line) || widget.showIfHidden) + if (!lineIsHidden(line) || widget.showIfHidden) { + var aboveVisible = heightAtLine(cm, line) < cm.display.scroller.scrollTop; updateLineHeight(line, line.height + widgetHeight(widget)); + if (aboveVisible) + setTimeout(function() {cm.display.scroller.scrollTop += widget.height;}); + } return true; }); return widget; From d8009de4f3a7f88379784023cf2c8f9098a811d6 Mon Sep 17 00:00:00 2001 From: Rahul Date: Thu, 10 Jan 2013 19:00:45 +0100 Subject: [PATCH 0058/5273] Correct spelling from "givne" to "given". --- doc/manual.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index 150ef05353..14d3a3249f 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -620,7 +620,7 @@

    Programming API

    Set the selection range. anchor and head should be {line, ch} objects. head defaults to anchor when - not givne.
    + not given.
    getLine(n) → string
    Get the content of line n.
    From ece10c7208da8f36001f3ff02a86d0bd6612c0bb Mon Sep 17 00:00:00 2001 From: Narciso Jaramillo Date: Thu, 10 Jan 2013 11:54:55 -0800 Subject: [PATCH 0059/5273] Make temporary wheel measurement vars per-instance --- lib/codemirror.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 4456181cc6..45adfdce27 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1637,7 +1637,7 @@ window.CodeMirror = (function() { // is that it gives us a chance to update the display before the // actual scrolling happens, reducing flickering. - var wheelSamples = 0, wheelDX, wheelDY, wheelStartX, wheelStartY, 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 @@ -1678,7 +1678,7 @@ window.CodeMirror = (function() { 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))); e_preventDefault(e); - wheelStartX = null; // Abort measurement, if in progress + cm.wheelStartX = null; // Abort measurement, if in progress return; } @@ -1691,22 +1691,22 @@ window.CodeMirror = (function() { } if (wheelSamples < 20) { - if (wheelStartX == null) { - wheelStartX = scroll.scrollLeft; wheelStartY = scroll.scrollTop; - wheelDX = dx; wheelDY = dy; + if (cm.wheelStartX == null) { + cm.wheelStartX = scroll.scrollLeft; cm.wheelStartY = scroll.scrollTop; + cm.wheelDX = dx; cm.wheelDY = dy; setTimeout(function() { - if (wheelStartX == null) return; - var movedX = scroll.scrollLeft - wheelStartX; - var movedY = scroll.scrollTop - wheelStartY; - var sample = (movedY && wheelDY && movedY / wheelDY) || - (movedX && wheelDX && movedX / wheelDX); - wheelStartX = wheelStartY = null; + if (cm.wheelStartX == null) return; + var movedX = scroll.scrollLeft - cm.wheelStartX; + var movedY = scroll.scrollTop - cm.wheelStartY; + var sample = (movedY && cm.wheelDY && movedY / cm.wheelDY) || + (movedX && cm.wheelDX && movedX / cm.wheelDX); + cm.wheelStartX = cm.wheelStartY = null; if (!sample) return; wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); ++wheelSamples; }, 200); } else { - wheelDX += dx; wheelDY += dy; + cm.wheelDX += dx; cm.wheelDY += dy; } } } From 7f64ae4887cfc093cee6cbe4d3739235dd883e1f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 11 Jan 2013 10:41:37 +0100 Subject: [PATCH 0060/5273] Attach wheel measuring properties to display, not directly to CM instance Issue #1151 --- lib/codemirror.js | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 45adfdce27..da551ffad8 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -166,6 +166,9 @@ window.CodeMirror = (function() { // detected d.pasteIncoming = false; + // Used for measuring wheel scrolling granularity + d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; + return d; } @@ -1666,7 +1669,7 @@ window.CodeMirror = (function() { } } - var scroll = cm.display.scroller; + var display = cm.display, scroll = display.scroller; // On some browsers, horizontal scrolling will cause redraws to // happen before the gutter has been realigned, causing it to // wriggle around in a most unseemly way. When we have an @@ -1678,35 +1681,35 @@ window.CodeMirror = (function() { 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))); e_preventDefault(e); - cm.wheelStartX = null; // Abort measurement, if in progress + display.wheelStartX = null; // Abort measurement, if in progress return; } if (dy && wheelPixelsPerUnit != null) { var pixels = dy * wheelPixelsPerUnit; - var top = cm.view.scrollTop, bot = top + cm.display.wrapper.clientHeight; + var top = cm.view.scrollTop, bot = top + display.wrapper.clientHeight; if (pixels < 0) top = Math.max(0, top + pixels - 50); else bot = Math.min(cm.view.doc.height, bot + pixels + 50); updateDisplay(cm, [], {top: top, bottom: bot}); } if (wheelSamples < 20) { - if (cm.wheelStartX == null) { - cm.wheelStartX = scroll.scrollLeft; cm.wheelStartY = scroll.scrollTop; - cm.wheelDX = dx; cm.wheelDY = dy; + if (display.wheelStartX == null) { + display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; + display.wheelDX = dx; display.wheelDY = dy; setTimeout(function() { - if (cm.wheelStartX == null) return; - var movedX = scroll.scrollLeft - cm.wheelStartX; - var movedY = scroll.scrollTop - cm.wheelStartY; - var sample = (movedY && cm.wheelDY && movedY / cm.wheelDY) || - (movedX && cm.wheelDX && movedX / cm.wheelDX); - cm.wheelStartX = cm.wheelStartY = null; + 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); } else { - cm.wheelDX += dx; cm.wheelDY += dy; + display.wheelDX += dx; display.wheelDY += dy; } } } From 2cf2913ceb1d394a2aa8190a448dd993112d71c1 Mon Sep 17 00:00:00 2001 From: Jason San Jose Date: Thu, 10 Jan 2013 13:53:38 -0800 Subject: [PATCH 0061/5273] widget.remove() should be widget.clear() --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index da551ffad8..4ce1cd0b8f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2604,7 +2604,7 @@ window.CodeMirror = (function() { return addLineWidget(this, handle, node, options); }), - removeLineWidget: function(widget) { widget.remove(); }, + removeLineWidget: function(widget) { widget.clear(); }, lineInfo: function(line) { if (typeof line == "number") { From 67084c2b924908099bc7df1220a03a1f7ace72b4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 11 Jan 2013 11:10:31 +0100 Subject: [PATCH 0062/5273] Add realtime.io to real-world uses --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 6d95f5ba5b..71d9929c63 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -67,6 +67,7 @@

    { } CodeMi
  • QiYun web app platform
  • Qt+Webkit integration (building a desktop CodeMirror app)
  • Rascal (tiny computer)
  • +
  • RealTime.io (Internet-of-Things infrastructure)
  • sketchPatch Livecodelab
  • Skulpt (in-browser Python environment)
  • SolidShops (hosted e-commerce platform)
  • From 2e3c49ab092125337b4b11c68ce85d563169d3b4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 11 Jan 2013 21:38:51 +0100 Subject: [PATCH 0063/5273] Remove improperly copy-pasted piece in mode/sieve/LICENSE --- mode/sieve/LICENSE | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mode/sieve/LICENSE b/mode/sieve/LICENSE index 24e4c94c09..8a74612cba 100644 --- a/mode/sieve/LICENSE +++ b/mode/sieve/LICENSE @@ -17,7 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Please note that some subdirectories of the CodeMirror distribution -include their own LICENSE files, and are released under different -licences. From d9a86095ae7a42968ba9dc8eeacbf9e159127375 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 12 Jan 2013 12:09:13 +0100 Subject: [PATCH 0064/5273] [test/mode_test.js] Remove some obsolete cruft --- test/mode_test.js | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/test/mode_test.js b/test/mode_test.js index f2459b432e..06270aa31e 100644 --- a/test/mode_test.js +++ b/test/mode_test.js @@ -9,12 +9,8 @@ ModeTest = {}; ModeTest.modeOptions = {}; ModeTest.modeName = CodeMirror.defaults.mode; -/* keep track of results for printSummary */ -ModeTest.testCount = 0; -ModeTest.passes = 0; - /** - * Run a test; prettyprints the results using document.write(). + * Run a test. * * @param name Name of test * @param text String to highlight. @@ -24,8 +20,6 @@ ModeTest.passes = 0; * @param expectedFail */ ModeTest.testMode = function(name, text, expected, modeName, modeOptions, expectedFail) { - ModeTest.testCount += 1; - if (!modeName) modeName = ModeTest.modeName; if (!modeOptions) modeOptions = ModeTest.modeOptions; @@ -62,12 +56,11 @@ ModeTest.compare = function (text, expected, mode) { var pass, passStyle = ""; pass = ModeTest.highlightOutputsEqual(expectedOutput, observedOutput); passStyle = pass ? 'mt-pass' : 'mt-fail'; - ModeTest.passes += pass ? 1 : 0; var s = ''; if (pass) { s += '
    '; - s += '
    ' + ModeTest.htmlEscape(text) + '
    '; + s += '
    ' + text + '
    '; s += '
    '; s += ModeTest.prettyPrintOutputTable(observedOutput); s += '
    '; @@ -75,7 +68,7 @@ ModeTest.compare = function (text, expected, mode) { return s; } else { s += '
    '; - s += '
    ' + ModeTest.htmlEscape(text) + '
    '; + s += '
    ' + text + '
    '; s += '
    '; s += 'expected:'; s += ModeTest.prettyPrintOutputTable(expectedOutput); @@ -161,7 +154,7 @@ ModeTest.prettyPrintOutputTable = function(output) { s += '' + '' + - ModeTest.htmlEscape(val).replace(/ /g,'·') + + val.replace(/ /g,'\xb7') + '' + ''; } @@ -172,21 +165,3 @@ ModeTest.prettyPrintOutputTable = function(output) { s += ''; return s; } - -/** - * Print how many tests have run so far and how many of those passed. - */ -ModeTest.printSummary = function() { - ModeTest.runTests(ModeTest.displayTest); - document.write(ModeTest.passes + ' passes for ' + ModeTest.testCount + ' tests'); -} - -/** - * Basic HTML escaping. - */ -ModeTest.htmlEscape = function(str) { - str = str.toString(); - return str.replace(/[<&]/g, - function(str) {return str == "&" ? "&" : "<";}); -} - From a2ad87f27d021a95f661ac9b106e1f79c6c86a1a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 12 Jan 2013 14:07:08 +0100 Subject: [PATCH 0065/5273] [tests] Overhaul mode testing framework Tests are now specified in a less redundant format, and should be easier to read and write. --- mode/css/test.js | 547 ++---------- mode/gfm/test.js | 309 ++----- mode/markdown/test.js | 1870 +++++++++++++---------------------------- mode/stex/test.js | 447 +++------- mode/xquery/test.js | 121 ++- mode/xquery/xquery.js | 16 +- test/mode_test.js | 309 +++---- 7 files changed, 1072 insertions(+), 2547 deletions(-) diff --git a/mode/css/test.js b/mode/css/test.js index fd6a4b8aa8..4336ddabdf 100644 --- a/mode/css/test.js +++ b/mode/css/test.js @@ -1,501 +1,106 @@ -// Initiate ModeTest and set defaults -var MT = ModeTest; -MT.modeName = 'css'; -MT.modeOptions = {}; +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "css"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 2)); } -// Requires at least one media query -MT.testMode( - 'atMediaEmpty', - '@media { }', - [ - 'def', '@media', - null, ' ', - 'error', '{', - null, ' }' - ] -); + // Requires at least one media query + MT("atMediaEmpty", + "[def @media] [error {] }"); -MT.testMode( - 'atMediaMultiple', - '@media not screen and (color), not print and (color) { }', - [ - 'def', '@media', - null, ' ', - 'keyword', 'not', - null, ' ', - 'attribute', 'screen', - null, ' ', - 'operator', 'and', - null, ' (', - 'property', 'color', - null, '), ', - 'keyword', 'not', - null, ' ', - 'attribute', 'print', - null, ' ', - 'operator', 'and', - null, ' (', - 'property', 'color', - null, ') { }' - ] -); + MT("atMediaMultiple", + "[def @media] [keyword not] [attribute screen] [operator and] ([property color]), [keyword not] [attribute print] [operator and] ([property color]) { }"); -MT.testMode( - 'atMediaCheckStack', - '@media screen { } foo { }', - [ - 'def', '@media', - null, ' ', - 'attribute', 'screen', - null, ' { } ', - 'tag', 'foo', - null, ' { }' - ] -); + MT("atMediaCheckStack", + "[def @media] [attribute screen] { } [tag foo] { }"); -MT.testMode( - 'atMediaCheckStack', - '@media screen (color) { } foo { }', - [ - 'def', '@media', - null, ' ', - 'attribute', 'screen', - null, ' (', - 'property', 'color', - null, ') { } ', - 'tag', 'foo', - null, ' { }' - ] -); + MT("atMediaCheckStack", + "[def @media] [attribute screen] ([property color]) { } [tag foo] { }"); -MT.testMode( - 'atMediaCheckStackInvalidAttribute', - '@media foobarhello { } foo { }', - [ - 'def', '@media', - null, ' ', - 'attribute error', 'foobarhello', - null, ' { } ', - 'tag', 'foo', - null, ' { }' - ] -); + MT("atMediaCheckStackInvalidAttribute", + "[def @media] [attribute&error foobarhello] { } [tag foo] { }"); -// Error, because "and" is only allowed immediately preceding a media expression -MT.testMode( - 'atMediaInvalidAttribute', - '@media foobarhello { }', - [ - 'def', '@media', - null, ' ', - 'attribute error', 'foobarhello', - null, ' { }' - ] -); + // Error, because "and" is only allowed immediately preceding a media expression + MT("atMediaInvalidAttribute", + "[def @media] [attribute&error foobarhello] { }"); -// Error, because "and" is only allowed immediately preceding a media expression -MT.testMode( - 'atMediaInvalidAnd', - '@media and screen { }', - [ - 'def', '@media', - null, ' ', - 'error', 'and', - null, ' ', - 'attribute', 'screen', - null, ' { }' - ] -); + // Error, because "and" is only allowed immediately preceding a media expression + MT("atMediaInvalidAnd", + "[def @media] [error and] [attribute screen] { }"); -// Error, because "not" is only allowed as the first item in each media query -MT.testMode( - 'atMediaInvalidNot', - '@media screen not (not) { }', - [ - 'def', '@media', - null, ' ', - 'attribute', 'screen', - null, ' ', - 'error', 'not', - null, ' (', - 'error', 'not', - null, ') { }' - ] -); + // Error, because "not" is only allowed as the first item in each media query + MT("atMediaInvalidNot", + "[def @media] [attribute screen] [error not] ([error not]) { }"); -// Error, because "only" is only allowed as the first item in each media query -MT.testMode( - 'atMediaInvalidOnly', - '@media screen only (only) { }', - [ - 'def', '@media', - null, ' ', - 'attribute', 'screen', - null, ' ', - 'error', 'only', - null, ' (', - 'error', 'only', - null, ') { }' - ] -); + // Error, because "only" is only allowed as the first item in each media query + MT("atMediaInvalidOnly", + "[def @media] [attribute screen] [error only] ([error only]) { }"); -// Error, because "foobarhello" is neither a known type or property, but -// property was expected (after "and"), and it should be in parenthese. -MT.testMode( - 'atMediaUnknownType', - '@media screen and foobarhello { }', - [ - 'def', '@media', - null, ' ', - 'attribute', 'screen', - null, ' ', - 'operator', 'and', - null, ' ', - 'error', 'foobarhello', - null, ' { }' - ] -); + // Error, because "foobarhello" is neither a known type or property, but + // property was expected (after "and"), and it should be in parenthese. + MT("atMediaUnknownType", + "[def @media] [attribute screen] [operator and] [error foobarhello] { }"); -// Error, because "color" is not a known type, but is a known property, and -// should be in parentheses. -MT.testMode( - 'atMediaInvalidType', - '@media screen and color { }', - [ - 'def', '@media', - null, ' ', - 'attribute', 'screen', - null, ' ', - 'operator', 'and', - null, ' ', - 'error', 'color', - null, ' { }' - ] -); + // Error, because "color" is not a known type, but is a known property, and + // should be in parentheses. + MT("atMediaInvalidType", + "[def @media] [attribute screen] [operator and] [error color] { }"); -// Error, because "print" is not a known property, but is a known type, -// and should not be in parenthese. -MT.testMode( - 'atMediaInvalidProperty', - '@media screen and (print) { }', - [ - 'def', '@media', - null, ' ', - 'attribute', 'screen', - null, ' ', - 'operator', 'and', - null, ' (', - 'error', 'print', - null, ') { }' - ] -); + // Error, because "print" is not a known property, but is a known type, + // and should not be in parenthese. + MT("atMediaInvalidProperty", + "[def @media] [attribute screen] [operator and] ([error print]) { }"); -// Soft error, because "foobarhello" is not a known property or type. -MT.testMode( - 'atMediaUnknownProperty', - '@media screen and (foobarhello) { }', - [ - 'def', '@media', - null, ' ', - 'attribute', 'screen', - null, ' ', - 'operator', 'and', - null, ' (', - 'property error', 'foobarhello', - null, ') { }' - ] -); + // Soft error, because "foobarhello" is not a known property or type. + MT("atMediaUnknownProperty", + "[def @media] [attribute screen] [operator and] ([property&error foobarhello]) { }"); -MT.testMode( - 'tagSelector', - 'foo { }', - [ - 'tag', 'foo', - null, ' { }' - ] -); + MT("tagSelector", + "[tag foo] { }"); -MT.testMode( - 'classSelector', - '.foo-bar_hello { }', - [ - 'qualifier', '.foo-bar_hello', - null, ' { }' - ] -); + MT("classSelector", + "[qualifier .foo-bar_hello] { }"); -MT.testMode( - 'idSelector', - '#foo { #foo }', - [ - 'builtin', '#foo', - null, ' { ', - 'error', '#foo', - null, ' }' - ] -); + MT("idSelector", + "[builtin #foo] { [error #foo] }"); -MT.testMode( - 'tagSelectorUnclosed', - 'foo { margin: 0 } bar { }', - [ - 'tag', 'foo', - null, ' { ', - 'property', 'margin', - 'operator', ':', - null, ' ', - 'number', '0', - null, ' } ', - 'tag', 'bar', - null, ' { }' - ] -); + MT("tagSelectorUnclosed", + "[tag foo] { [property margin][operator :] [number 0] } [tag bar] { }"); -MT.testMode( - 'tagStringNoQuotes', - 'foo { font-family: hello world; }', - [ - 'tag', 'foo', - null, ' { ', - 'property', 'font-family', - 'operator', ':', - null, ' ', - 'variable-2', 'hello', - null, ' ', - 'variable-2', 'world', - null, '; }' - ] -); + MT("tagStringNoQuotes", + "[tag foo] { [property font-family][operator :] [variable-2 hello] [variable-2 world]; }"); -MT.testMode( - 'tagStringDouble', - 'foo { font-family: "hello world"; }', - [ - 'tag', 'foo', - null, ' { ', - 'property', 'font-family', - 'operator', ':', - null, ' ', - 'string', '"hello world"', - null, '; }' - ] -); + MT("tagStringDouble", + "[tag foo] { [property font-family][operator :] [string \"hello world\"]; }"); -MT.testMode( - 'tagStringSingle', - 'foo { font-family: \'hello world\'; }', - [ - 'tag', 'foo', - null, ' { ', - 'property', 'font-family', - 'operator', ':', - null, ' ', - 'string', '\'hello world\'', - null, '; }' - ] -); + MT("tagStringSingle", + "[tag foo] { [property font-family][operator :] [string 'hello world']; }"); -MT.testMode( - 'tagColorKeyword', - 'foo { color: black; }', - [ - 'tag', 'foo', - null, ' { ', - 'property', 'color', - 'operator', ':', - null, ' ', - 'keyword', 'black', - null, '; }' - ] -); + MT("tagColorKeyword", + "[tag foo] { [property color][operator :] [keyword black]; }"); -MT.testMode( - 'tagColorHex3', - 'foo { background: #fff; }', - [ - 'tag', 'foo', - null, ' { ', - 'property', 'background', - 'operator', ':', - null, ' ', - 'atom', '#fff', - null, '; }' - ] -); + MT("tagColorHex3", + "[tag foo] { [property background][operator :] [atom #fff]; }"); -MT.testMode( - 'tagColorHex6', - 'foo { background: #ffffff; }', - [ - 'tag', 'foo', - null, ' { ', - 'property', 'background', - 'operator', ':', - null, ' ', - 'atom', '#ffffff', - null, '; }' - ] -); + MT("tagColorHex6", + "[tag foo] { [property background][operator :] [atom #ffffff]; }"); -MT.testMode( - 'tagColorHex4', - 'foo { background: #ffff; }', - [ - 'tag', 'foo', - null, ' { ', - 'property', 'background', - 'operator', ':', - null, ' ', - 'atom error', '#ffff', - null, '; }' - ] -); + MT("tagColorHex4", + "[tag foo] { [property background][operator :] [atom&error #ffff]; }"); -MT.testMode( - 'tagColorHexInvalid', - 'foo { background: #ffg; }', - [ - 'tag', 'foo', - null, ' { ', - 'property', 'background', - 'operator', ':', - null, ' ', - 'atom error', '#ffg', - null, '; }' - ] -); + MT("tagColorHexInvalid", + "[tag foo] { [property background][operator :] [atom&error #ffg]; }"); -MT.testMode( - 'tagNegativeNumber', - 'foo { margin: -5px; }', - [ - 'tag', 'foo', - null, ' { ', - 'property', 'margin', - 'operator', ':', - null, ' ', - 'number', '-5px', - null, '; }' - ] -); + MT("tagNegativeNumber", + "[tag foo] { [property margin][operator :] [number -5px]; }"); -MT.testMode( - 'tagPositiveNumber', - 'foo { padding: 5px; }', - [ - 'tag', 'foo', - null, ' { ', - 'property', 'padding', - 'operator', ':', - null, ' ', - 'number', '5px', - null, '; }' - ] -); + MT("tagPositiveNumber", + "[tag foo] { [property padding][operator :] [number 5px]; }"); -MT.testMode( - 'tagVendor', - 'foo { -foo-box-sizing: -foo-border-box; }', - [ - 'tag', 'foo', - null, ' { ', - 'meta', '-foo-', - 'property', 'box-sizing', - 'operator', ':', - null, ' ', - 'meta', '-foo-', - 'string-2', 'border-box', - null, '; }' - ] -); + MT("tagVendor", + "[tag foo] { [meta -foo-][property box-sizing][operator :] [meta -foo-][string-2 border-box]; }"); -MT.testMode( - 'tagBogusProperty', - 'foo { barhelloworld: 0; }', - [ - 'tag', 'foo', - null, ' { ', - 'property error', 'barhelloworld', - 'operator', ':', - null, ' ', - 'number', '0', - null, '; }' - ] -); + MT("tagBogusProperty", + "[tag foo] { [property&error barhelloworld][operator :] [number 0]; }"); -MT.testMode( - 'tagTwoProperties', - 'foo { margin: 0; padding: 0; }', - [ - 'tag', 'foo', - null, ' { ', - 'property', 'margin', - 'operator', ':', - null, ' ', - 'number', '0', - null, '; ', - 'property', 'padding', - 'operator', ':', - null, ' ', - 'number', '0', - null, '; }' - ] -); -// -//MT.testMode( -// 'tagClass', -// '@media only screen and (min-width: 500px), print {foo.bar#hello { color: black !important; background: #f00; margin: -5px; padding: 5px; -foo-box-sizing: border-box; } /* world */}', -// [ -// 'def', '@media', -// null, ' ', -// 'keyword', 'only', -// null, ' ', -// 'attribute', 'screen', -// null, ' ', -// 'operator', 'and', -// null, ' ', -// 'bracket', '(', -// 'property', 'min-width', -// 'operator', ':', -// null, ' ', -// 'number', '500px', -// 'bracket', ')', -// null, ', ', -// 'attribute', 'print', -// null, ' {', -// 'tag', 'foo', -// 'qualifier', '.bar', -// 'header', '#hello', -// null, ' { ', -// 'property', 'color', -// 'operator', ':', -// null, ' ', -// 'keyword', 'black', -// null, ' ', -// 'keyword', '!important', -// null, '; ', -// 'property', 'background', -// 'operator', ':', -// null, ' ', -// 'atom', '#f00', -// null, '; ', -// 'property', 'padding', -// 'operator', ':', -// null, ' ', -// 'number', '5px', -// null, '; ', -// 'property', 'margin', -// 'operator', ':', -// null, ' ', -// 'number', '-5px', -// null, '; ', -// 'meta', '-foo-', -// 'property', 'box-sizing', -// 'operator', ':', -// null, ' ', -// 'string-2', 'border-box', -// null, '; } ', -// 'comment', '/* world */', -// null, '}' -// ] -//); \ No newline at end of file + MT("tagTwoProperties", + "[tag foo] { [property margin][operator :] [number 0]; [property padding][operator :] [number 0]; }"); +})(); diff --git a/mode/gfm/test.js b/mode/gfm/test.js index 3a261f8f77..cf97df66a5 100644 --- a/mode/gfm/test.js +++ b/mode/gfm/test.js @@ -1,225 +1,84 @@ -// Initiate ModeTest and set defaults -var MT = ModeTest; -MT.modeName = 'gfm'; -MT.modeOptions = {}; - -// Emphasis characters within a word -MT.testMode( - 'emInWordAsterisk', - 'foo*bar*hello', - [ - null, 'foo', - 'em', '*bar*', - null, 'hello' - ] -); -MT.testMode( - 'emInWordUnderscore', - 'foo_bar_hello', - [ - null, 'foo_bar_hello' - ] -); -MT.testMode( - 'emStrongUnderscore', - '___foo___ bar', - [ - 'strong', '__', - 'emstrong', '_foo__', - 'em', '_', - null, ' bar' - ] -); - -// Fenced code blocks -MT.testMode( - 'fencedCodeBlocks', - '```\nfoo\n\n```\nbar', - [ - 'comment', '```', - 'comment', 'foo', - 'comment', '```', - null, 'bar' - ] -); -// Fenced code block mode switching -MT.testMode( - 'fencedCodeBlockModeSwitching', - '```javascript\nfoo\n\n```\nbar', - [ - 'comment', '```javascript', - 'variable', 'foo', - 'comment', '```', - null, 'bar' - ] -); - -// SHA -MT.testMode( - 'SHA', - 'foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 bar', - [ - null, 'foo ', - 'link', 'be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2', - null, ' bar' - ] -); -// GitHub highlights hashes 7-40 chars in length -MT.testMode( - 'shortSHA', - 'foo be6a8cc bar', - [ - null, 'foo ', - 'link', 'be6a8cc', - null, ' bar' - ] -); -// Invalid SHAs -// -// GitHub does not highlight hashes shorter than 7 chars -MT.testMode( - 'tooShortSHA', - 'foo be6a8c bar', - [ - null, 'foo be6a8c bar' - ] -); -// GitHub does not highlight hashes longer than 40 chars -MT.testMode( - 'longSHA', - 'foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd22 bar', - [ - null, 'foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd22 bar' - ] -); -MT.testMode( - 'badSHA', - 'foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cg2 bar', - [ - null, 'foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cg2 bar' - ] -); -// User@SHA -MT.testMode( - 'userSHA', - 'foo bar@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 hello', - [ - null, 'foo ', - 'link', 'bar@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2', - null, ' hello' - ] -); -// User/Project@SHA -MT.testMode( - 'userProjectSHA', - 'foo bar/hello@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 world', - [ - null, 'foo ', - 'link', 'bar/hello@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2', - null, ' world' - ] -); - -// #Num -MT.testMode( - 'num', - 'foo #1 bar', - [ - null, 'foo ', - 'link', '#1', - null, ' bar' - ] -); -// bad #Num -MT.testMode( - 'badNum', - 'foo #1bar hello', - [ - null, 'foo #1bar hello' - ] -); -// User#Num -MT.testMode( - 'userNum', - 'foo bar#1 hello', - [ - null, 'foo ', - 'link', 'bar#1', - null, ' hello' - ] -); -// User/Project#Num -MT.testMode( - 'userProjectNum', - 'foo bar/hello#1 world', - [ - null, 'foo ', - 'link', 'bar/hello#1', - null, ' world' - ] -); - -// Vanilla links -MT.testMode( - 'vanillaLink', - 'foo http://www.example.com/ bar', - [ - null, 'foo ', - 'link', 'http://www.example.com/', - null, ' bar' - ] -); -MT.testMode( - 'vanillaLinkPunctuation', - 'foo http://www.example.com/. bar', - [ - null, 'foo ', - 'link', 'http://www.example.com/', - null, '. bar' - ] -); -MT.testMode( - 'vanillaLinkExtension', - 'foo http://www.example.com/index.html bar', - [ - null, 'foo ', - 'link', 'http://www.example.com/index.html', - null, ' bar' - ] -); -// Not a link -MT.testMode( - 'notALink', - '```css\nfoo {color:black;}\n```http://www.example.com/', - [ - 'comment', '```css', - 'tag', 'foo', - null, ' {', - 'property', 'color', - 'operator', ':', - 'keyword', 'black', - null, ';}', - 'comment', '```', - 'link', 'http://www.example.com/' - ] -); -// Not a link -MT.testMode( - 'notALink', - '``foo `bar` http://www.example.com/`` hello', - [ - 'comment', '``foo `bar` http://www.example.com/``', - null, ' hello' - ] -); -// Not a link -MT.testMode( - 'notALink', - '`foo\nhttp://www.example.com/\n`foo\n\nhttp://www.example.com/', - [ - 'comment', '`foo', - 'link', 'http://www.example.com/', - 'comment', '`foo', - 'link', 'http://www.example.com/' - ] -); \ No newline at end of file +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "gfm"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("emInWordAsterisk", + "foo[em *bar*]hello"); + + MT("emInWordUnderscore", + "foo_bar_hello"); + + MT("emStrongUnderscore", + "[strong __][emstrong _foo__][em _] bar"); + + MT("fencedCodeBlocks", + "[comment ```]", + "[comment foo]", + "", + "[comment ```]", + "bar"); + + MT("fencedCodeBlockModeSwitching", + "[comment ```javascript]", + "[variable foo]", + "", + "[comment ```]", + "bar"); + + MT("SHA", + "foo [link be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2] bar"); + + MT("shortSHA", + "foo [link be6a8cc] bar"); + + MT("tooShortSHA", + "foo be6a8c bar"); + + MT("longSHA", + "foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd22 bar"); + + MT("badSHA", + "foo be6a8cc1c1ecfe9489fb51e4869af15a13fc2cg2 bar"); + + MT("userSHA", + "foo [link bar@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2] hello"); + + MT("userProjectSHA", + "foo [link bar/hello@be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2] world"); + + MT("num", + "foo [link #1] bar"); + + MT("badNum", + "foo #1bar hello"); + + MT("userNum", + "foo [link bar#1] hello"); + + MT("userProjectNum", + "foo [link bar/hello#1] world"); + + MT("vanillaLink", + "foo [link http://www.example.com/] bar"); + + MT("vanillaLinkPunctuation", + "foo [link http://www.example.com/]. bar"); + + MT("vanillaLinkExtension", + "foo [link http://www.example.com/index.html] bar"); + + MT("notALink", + "[comment ```css]", + "[tag foo] {[property color][operator :][keyword black];}", + "[comment ```][link http://www.example.com/]"); + + MT("notALink", + "[comment ``foo `bar` http://www.example.com/``] hello"); + + MT("notALink", + "[comment `foo]", + "[link http://www.example.com/]", + "[comment `foo]", + "", + "[link http://www.example.com/]"); +})(); diff --git a/mode/markdown/test.js b/mode/markdown/test.js index 2e06707c11..eaa7343a20 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -1,1291 +1,579 @@ -// Initiate ModeTest and set defaults -var MT = ModeTest; -MT.modeName = 'markdown'; -MT.modeOptions = {}; - -MT.testMode( - 'plainText', - 'foo', - [ - null, 'foo' - ] -); - -// Code blocks using 4 spaces (regardless of CodeMirror.tabSize value) -MT.testMode( - 'codeBlocksUsing4Spaces', - ' foo', - [ - null, ' ', - 'comment', 'foo' - ] -); -// Code blocks using 4 spaces with internal indentation -MT.testMode( - 'codeBlocksUsing4SpacesIndentation', - ' bar\n hello\n world\n foo\nbar', - [ - null, ' ', - 'comment', 'bar', - null, ' ', - 'comment', 'hello', - null, ' ', - 'comment', 'world', - null, ' ', - 'comment', 'foo', - null, 'bar' - ] -); -// Code blocks using 4 spaces with internal indentation -MT.testMode( - 'codeBlocksUsing4SpacesIndentation', - ' foo\n bar\n hello\n world', - [ - null, ' foo', - null, ' ', - 'comment', 'bar', - null, ' ', - 'comment', 'hello', - null, ' ', - 'comment', 'world' - ] -); - -// Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value) -MT.testMode( - 'codeBlocksUsing1Tab', - '\tfoo', - [ - null, '\t', - 'comment', 'foo' - ] -); - -// Inline code using backticks -MT.testMode( - 'inlineCodeUsingBackticks', - 'foo `bar`', - [ - null, 'foo ', - 'comment', '`bar`' - ] -); - -// Block code using single backtick (shouldn't work) -MT.testMode( - 'blockCodeSingleBacktick', - '`\nfoo\n`', - [ - 'comment', '`', - null, 'foo', - 'comment', '`' - ] -); - -// Unclosed backticks -// Instead of simply marking as CODE, it would be nice to have an -// incomplete flag for CODE, that is styled slightly different. -MT.testMode( - 'unclosedBackticks', - 'foo `bar', - [ - null, 'foo ', - 'comment', '`bar' - ] -); - -// Per documentation: "To include a literal backtick character within a -// code span, you can use multiple backticks as the opening and closing -// delimiters" -MT.testMode( - 'doubleBackticks', - '``foo ` bar``', - [ - 'comment', '``foo ` bar``' - ] -); - -// Tests based on Dingus -// http://daringfireball.net/projects/markdown/dingus -// -// Multiple backticks within an inline code block -MT.testMode( - 'consecutiveBackticks', - '`foo```bar`', - [ - 'comment', '`foo```bar`' - ] -); -// Multiple backticks within an inline code block with a second code block -MT.testMode( - 'consecutiveBackticks', - '`foo```bar` hello `world`', - [ - 'comment', '`foo```bar`', - null, ' hello ', - 'comment', '`world`' - ] -); -// Unclosed with several different groups of backticks -MT.testMode( - 'unclosedBackticks', - '``foo ``` bar` hello', - [ - 'comment', '``foo ``` bar` hello' - ] -); -// Closed with several different groups of backticks -MT.testMode( - 'closedBackticks', - '``foo ``` bar` hello`` world', - [ - 'comment', '``foo ``` bar` hello``', - null, ' world' - ] -); - -// atx headers -// http://daringfireball.net/projects/markdown/syntax#header -// -// H1 -MT.testMode( - 'atxH1', - '# foo', - [ - 'header', '# foo' - ] -); -// H2 -MT.testMode( - 'atxH2', - '## foo', - [ - 'header', '## foo' - ] -); -// H3 -MT.testMode( - 'atxH3', - '### foo', - [ - 'header', '### foo' - ] -); -// H4 -MT.testMode( - 'atxH4', - '#### foo', - [ - 'header', '#### foo' - ] -); -// H5 -MT.testMode( - 'atxH5', - '##### foo', - [ - 'header', '##### foo' - ] -); -// H6 -MT.testMode( - 'atxH6', - '###### foo', - [ - 'header', '###### foo' - ] -); -// H6 - 7x '#' should still be H6, per Dingus -// http://daringfireball.net/projects/markdown/dingus -MT.testMode( - 'atxH6NotH7', - '####### foo', - [ - 'header', '####### foo' - ] -); - -// Setext headers - H1, H2 -// Per documentation, "Any number of underlining =’s or -’s will work." -// http://daringfireball.net/projects/markdown/syntax#header -// Ideally, the text would be marked as `header` as well, but this is -// not really feasible at the moment. So, instead, we're testing against -// what works today, to avoid any regressions. -// -// Check if single underlining = works -MT.testMode( - 'setextH1', - 'foo\n=', - [ - null, 'foo', - 'header', '=' - ] -); -// Check if 3+ ='s work -MT.testMode( - 'setextH1', - 'foo\n===', - [ - null, 'foo', - 'header', '===' - ] -); -// Check if single underlining - works -MT.testMode( - 'setextH2', - 'foo\n-', - [ - null, 'foo', - 'header', '-' - ] -); -// Check if 3+ -'s work -MT.testMode( - 'setextH2', - 'foo\n---', - [ - null, 'foo', - 'header', '---' - ] -); - -// Single-line blockquote with trailing space -MT.testMode( - 'blockquoteSpace', - '> foo', - [ - 'quote', '> foo' - ] -); - -// Single-line blockquote -MT.testMode( - 'blockquoteNoSpace', - '>foo', - [ - 'quote', '>foo' - ] -); - -// Single-line blockquote followed by normal paragraph -MT.testMode( - 'blockquoteThenParagraph', - '>foo\n\nbar', - [ - 'quote', '>foo', - null, 'bar' - ] -); - -// Multi-line blockquote (lazy mode) -MT.testMode( - 'multiBlockquoteLazy', - '>foo\nbar', - [ - 'quote', '>foo', - 'quote', 'bar' - ] -); - -// Multi-line blockquote followed by normal paragraph (lazy mode) -MT.testMode( - 'multiBlockquoteLazyThenParagraph', - '>foo\nbar\n\nhello', - [ - 'quote', '>foo', - 'quote', 'bar', - null, 'hello' - ] -); - -// Multi-line blockquote (non-lazy mode) -MT.testMode( - 'multiBlockquote', - '>foo\n>bar', - [ - 'quote', '>foo', - 'quote', '>bar' - ] -); - -// Multi-line blockquote followed by normal paragraph (non-lazy mode) -MT.testMode( - 'multiBlockquoteThenParagraph', - '>foo\n>bar\n\nhello', - [ - 'quote', '>foo', - 'quote', '>bar', - null, 'hello' - ] -); - -// Check list types -MT.testMode( - 'listAsterisk', - '* foo\n* bar', - [ - 'string', '* foo', - 'string', '* bar' - ] -); -MT.testMode( - 'listPlus', - '+ foo\n+ bar', - [ - 'string', '+ foo', - 'string', '+ bar' - ] -); -MT.testMode( - 'listDash', - '- foo\n- bar', - [ - 'string', '- foo', - 'string', '- bar' - ] -); -MT.testMode( - 'listNumber', - '1. foo\n2. bar', - [ - 'string', '1. foo', - 'string', '2. bar' - ] -); - -// Formatting in lists (*) -MT.testMode( - 'listAsteriskFormatting', - '* *foo* bar\n\n* **foo** bar\n\n* ***foo*** bar\n\n* `foo` bar', - [ - 'string', '* ', - 'string em', '*foo*', - 'string', ' bar', - 'string', '* ', - 'string strong', '**foo**', - 'string', ' bar', - 'string', '* ', - 'string strong', '**', - 'string emstrong', '*foo**', - 'string em', '*', - 'string', ' bar', - 'string', '* ', - 'string comment', '`foo`', - 'string', ' bar' - ] -); -// Formatting in lists (+) -MT.testMode( - 'listPlusFormatting', - '+ *foo* bar\n\n+ **foo** bar\n\n+ ***foo*** bar\n\n+ `foo` bar', - [ - 'string', '+ ', - 'string em', '*foo*', - 'string', ' bar', - 'string', '+ ', - 'string strong', '**foo**', - 'string', ' bar', - 'string', '+ ', - 'string strong', '**', - 'string emstrong', '*foo**', - 'string em', '*', - 'string', ' bar', - 'string', '+ ', - 'string comment', '`foo`', - 'string', ' bar' - ] -); -// Formatting in lists (-) -MT.testMode( - 'listDashFormatting', - '- *foo* bar\n\n- **foo** bar\n\n- ***foo*** bar\n\n- `foo` bar', - [ - 'string', '- ', - 'string em', '*foo*', - 'string', ' bar', - 'string', '- ', - 'string strong', '**foo**', - 'string', ' bar', - 'string', '- ', - 'string strong', '**', - 'string emstrong', '*foo**', - 'string em', '*', - 'string', ' bar', - 'string', '- ', - 'string comment', '`foo`', - 'string', ' bar' - ] -); -// Formatting in lists (1.) -MT.testMode( - 'listNumberFormatting', - '1. *foo* bar\n\n2. **foo** bar\n\n3. ***foo*** bar\n\n4. `foo` bar', - [ - 'string', '1. ', - 'string em', '*foo*', - 'string', ' bar', - 'string', '2. ', - 'string strong', '**foo**', - 'string', ' bar', - 'string', '3. ', - 'string strong', '**', - 'string emstrong', '*foo**', - 'string em', '*', - 'string', ' bar', - 'string', '4. ', - 'string comment', '`foo`', - 'string', ' bar' - ] -); - -// Paragraph lists -MT.testMode( - 'listParagraph', - '* foo\n\n* bar', - [ - 'string', '* foo', - 'string', '* bar' - ] -); - -// Multi-paragraph lists -// -// 4 spaces -MT.testMode( - 'listMultiParagraph', - '* foo\n\n* bar\n\n hello', - [ - 'string', '* foo', - 'string', '* bar', - null, ' ', - 'string', 'hello' - ] -); -// 4 spaces, extra blank lines (should still be list, per Dingus) -MT.testMode( - 'listMultiParagraphExtra', - '* foo\n\n* bar\n\n\n hello', - [ - 'string', '* foo', - 'string', '* bar', - null, ' ', - 'string', 'hello' - ] -); -// 4 spaces, plus 1 space (should still be list, per Dingus) -MT.testMode( - 'listMultiParagraphExtraSpace', - '* foo\n\n* bar\n\n hello\n\n world', - [ - 'string', '* foo', - 'string', '* bar', - null, ' ', - 'string', 'hello', - null, ' ', - 'string', 'world' - ] -); -// 1 tab -MT.testMode( - 'listTab', - '* foo\n\n* bar\n\n\thello', - [ - 'string', '* foo', - 'string', '* bar', - null, '\t', - 'string', 'hello' - ] -); -// No indent -MT.testMode( - 'listNoIndent', - '* foo\n\n* bar\n\nhello', - [ - 'string', '* foo', - 'string', '* bar', - null, 'hello' - ] -); -// Blockquote -MT.testMode( - 'blockquote', - '* foo\n\n* bar\n\n > hello', - [ - 'string', '* foo', - 'string', '* bar', - null, ' ', - 'string quote', '> hello' - ] -); -// Code block -MT.testMode( - 'blockquoteCode', - '* foo\n\n* bar\n\n > hello\n\n world', - [ - 'string', '* foo', - 'string', '* bar', - null, ' ', - 'comment', '> hello', - null, ' ', - 'string', 'world' - ] -); -// Code block followed by text -MT.testMode( - 'blockquoteCodeText', - '* foo\n\n bar\n\n hello\n\n world', - [ - 'string', '* foo', - null, ' ', - 'string', 'bar', - null, ' ', - 'comment', 'hello', - null, ' ', - 'string', 'world' - ] -); - -// Nested list -// -// * -MT.testMode( - 'listAsteriskNested', - '* foo\n\n * bar', - [ - 'string', '* foo', - null, ' ', - 'string', '* bar' - ] -); -// + -MT.testMode( - 'listPlusNested', - '+ foo\n\n + bar', - [ - 'string', '+ foo', - null, ' ', - 'string', '+ bar' - ] -); -// - -MT.testMode( - 'listDashNested', - '- foo\n\n - bar', - [ - 'string', '- foo', - null, ' ', - 'string', '- bar' - ] -); -// 1. -MT.testMode( - 'listNumberNested', - '1. foo\n\n 2. bar', - [ - 'string', '1. foo', - null, ' ', - 'string', '2. bar' - ] -); -// Mixed -MT.testMode( - 'listMixed', - '* foo\n\n + bar\n\n - hello\n\n 1. world', - [ - 'string', '* foo', - null, ' ', - 'string', '+ bar', - null, ' ', - 'string', '- hello', - null, ' ', - 'string', '1. world' - ] -); -// Blockquote -MT.testMode( - 'listBlockquote', - '* foo\n\n + bar\n\n > hello', - [ - 'string', '* foo', - null, ' ', - 'string', '+ bar', - null, ' ', - 'quote string', '> hello' - ] -); -// Code -MT.testMode( - 'listCode', - '* foo\n\n + bar\n\n hello', - [ - 'string', '* foo', - null, ' ', - 'string', '+ bar', - null, ' ', - 'comment', 'hello' - ] -); -// Code with internal indentation -MT.testMode( - 'listCodeIndentation', - '* foo\n\n bar\n hello\n world\n foo\n bar', - [ - 'string', '* foo', - null, ' ', - 'comment', 'bar', - null, ' ', - 'comment', 'hello', - null, ' ', - 'comment', 'world', - null, ' ', - 'comment', 'foo', - null, ' ', - 'string', 'bar' - ] -); -// Code followed by text -MT.testMode( - 'listCodeText', - '* foo\n\n bar\n\nhello', - [ - 'string', '* foo', - null, ' ', - 'comment', 'bar', - null, 'hello' - ] -); - -// Following tests directly from official Markdown documentation -// http://daringfireball.net/projects/markdown/syntax#hr -MT.testMode( - 'hrSpace', - '* * *', - [ - 'hr', '* * *' - ] -); - -MT.testMode( - 'hr', - '***', - [ - 'hr', '***' - ] -); - -MT.testMode( - 'hrLong', - '*****', - [ - 'hr', '*****' - ] -); - -MT.testMode( - 'hrSpaceDash', - '- - -', - [ - 'hr', '- - -' - ] -); - -MT.testMode( - 'hrDashLong', - '---------------------------------------', - [ - 'hr', '---------------------------------------' - ] -); - -// Inline link with title -MT.testMode( - 'linkTitle', - '[foo](http://example.com/ "bar") hello', - [ - 'link', '[foo]', - 'string', '(http://example.com/ "bar")', - null, ' hello' - ] -); - -// Inline link without title -MT.testMode( - 'linkNoTitle', - '[foo](http://example.com/) bar', - [ - 'link', '[foo]', - 'string', '(http://example.com/)', - null, ' bar' - ] -); - -// Inline link with image -MT.testMode( - 'linkImage', - '[![foo](http://example.com/)](http://example.com/) bar', - [ - 'link', '[', - 'tag', '![foo]', - 'string', '(http://example.com/)', - 'link', ']', - 'string', '(http://example.com/)', - null, ' bar' - ] -); - -// Inline link with Em -MT.testMode( - 'linkEm', - '[*foo*](http://example.com/) bar', - [ - 'link', '[', - 'link em', '*foo*', - 'link', ']', - 'string', '(http://example.com/)', - null, ' bar' - ] -); - -// Inline link with Strong -MT.testMode( - 'linkStrong', - '[**foo**](http://example.com/) bar', - [ - 'link', '[', - 'link strong', '**foo**', - 'link', ']', - 'string', '(http://example.com/)', - null, ' bar' - ] -); - -// Inline link with EmStrong -MT.testMode( - 'linkEmStrong', - '[***foo***](http://example.com/) bar', - [ - 'link', '[', - 'link strong', '**', - 'link emstrong', '*foo**', - 'link em', '*', - 'link', ']', - 'string', '(http://example.com/)', - null, ' bar' - ] -); - -// Image with title -MT.testMode( - 'imageTitle', - '![foo](http://example.com/ "bar") hello', - [ - 'tag', '![foo]', - 'string', '(http://example.com/ "bar")', - null, ' hello' - ] -); - -// Image without title -MT.testMode( - 'imageNoTitle', - '![foo](http://example.com/) bar', - [ - 'tag', '![foo]', - 'string', '(http://example.com/)', - null, ' bar' - ] -); - -// Image with asterisks -MT.testMode( - 'imageAsterisks', - '![*foo*](http://example.com/) bar', - [ - 'tag', '![*foo*]', - 'string', '(http://example.com/)', - null, ' bar' - ] -); - -// Not a link. Should be normal text due to square brackets being used -// regularly in text, especially in quoted material, and no space is allowed -// between square brackets and parentheses (per Dingus). -MT.testMode( - 'notALink', - '[foo] (bar)', - [ - null, '[foo] (bar)' - ] -); - -// Reference-style links -MT.testMode( - 'linkReference', - '[foo][bar] hello', - [ - 'link', '[foo]', - 'string', '[bar]', - null, ' hello' - ] -); -// Reference-style links with Em -MT.testMode( - 'linkReferenceEm', - '[*foo*][bar] hello', - [ - 'link', '[', - 'link em', '*foo*', - 'link', ']', - 'string', '[bar]', - null, ' hello' - ] -); -// Reference-style links with Strong -MT.testMode( - 'linkReferenceStrong', - '[**foo**][bar] hello', - [ - 'link', '[', - 'link strong', '**foo**', - 'link', ']', - 'string', '[bar]', - null, ' hello' - ] -); -// Reference-style links with EmStrong -MT.testMode( - 'linkReferenceEmStrong', - '[***foo***][bar] hello', - [ - 'link', '[', - 'link strong', '**', - 'link emstrong', '*foo**', - 'link em', '*', - 'link', ']', - 'string', '[bar]', - null, ' hello' - ] -); - -// Reference-style links with optional space separator (per docuentation) -// "You can optionally use a space to separate the sets of brackets" -MT.testMode( - 'linkReferenceSpace', - '[foo] [bar] hello', - [ - 'link', '[foo]', - null, ' ', - 'string', '[bar]', - null, ' hello' - ] -); -// Should only allow a single space ("...use *a* space...") -MT.testMode( - 'linkReferenceDoubleSpace', - '[foo] [bar] hello', - [ - null, '[foo] [bar] hello' - ] -); - -// Reference-style links with implicit link name -MT.testMode( - 'linkImplicit', - '[foo][] hello', - [ - 'link', '[foo]', - 'string', '[]', - null, ' hello' - ] -); - -// @todo It would be nice if, at some point, the document was actually -// checked to see if the referenced link exists - -// Link label, for reference-style links (taken from documentation) -// -// No title -MT.testMode( - 'labelNoTitle', - '[foo]: http://example.com/', - [ - 'link', '[foo]:', - null, ' ', - 'string', 'http://example.com/' - ] -); -// Indented -MT.testMode( - 'labelIndented', - ' [foo]: http://example.com/', - [ - null, ' ', - 'link', '[foo]:', - null, ' ', - 'string', 'http://example.com/' - ] -); -// Space in ID and title -MT.testMode( - 'labelSpaceTitle', - '[foo bar]: http://example.com/ "hello"', - [ - 'link', '[foo bar]:', - null, ' ', - 'string', 'http://example.com/ "hello"' - ] -); -// Double title -MT.testMode( - 'labelDoubleTitle', - '[foo bar]: http://example.com/ "hello" "world"', - [ - 'link', '[foo bar]:', - null, ' ', - 'string', 'http://example.com/ "hello"', - null, ' "world"' - ] -); -// Double quotes around title -MT.testMode( - 'labelTitleDoubleQuotes', - '[foo]: http://example.com/ "bar"', - [ - 'link', '[foo]:', - null, ' ', - 'string', 'http://example.com/ "bar"' - ] -); -// Single quotes around title -MT.testMode( - 'labelTitleSingleQuotes', - '[foo]: http://example.com/ \'bar\'', - [ - 'link', '[foo]:', - null, ' ', - 'string', 'http://example.com/ \'bar\'' - ] -); -// Parentheses around title -MT.testMode( - 'labelTitleParenthese', - '[foo]: http://example.com/ (bar)', - [ - 'link', '[foo]:', - null, ' ', - 'string', 'http://example.com/ (bar)' - ] -); -// Invalid title -MT.testMode( - 'labelTitleInvalid', - '[foo]: http://example.com/ bar', - [ - 'link', '[foo]:', - null, ' ', - 'string', 'http://example.com/', - null, ' bar' - ] -); -// Angle brackets around URL -MT.testMode( - 'labelLinkAngleBrackets', - '[foo]: "bar"', - [ - 'link', '[foo]:', - null, ' ', - 'string', ' "bar"' - ] -); -// Title on next line per documentation (double quotes) -MT.testMode( - 'labelTitleNextDoubleQuotes', - '[foo]: http://example.com/\n"bar" hello', - [ - 'link', '[foo]:', - null, ' ', - 'string', 'http://example.com/', - 'string', '"bar"', - null, ' hello' - ] -); -// Title on next line per documentation (single quotes) -MT.testMode( - 'labelTitleNextSingleQuotes', - '[foo]: http://example.com/\n\'bar\' hello', - [ - 'link', '[foo]:', - null, ' ', - 'string', 'http://example.com/', - 'string', '\'bar\'', - null, ' hello' - ] -); -// Title on next line per documentation (parentheses) -MT.testMode( - 'labelTitleNextParenthese', - '[foo]: http://example.com/\n(bar) hello', - [ - 'link', '[foo]:', - null, ' ', - 'string', 'http://example.com/', - 'string', '(bar)', - null, ' hello' - ] -); -// Title on next line per documentation (mixed) -MT.testMode( - 'labelTitleNextMixed', - '[foo]: http://example.com/\n(bar" hello', - [ - 'link', '[foo]:', - null, ' ', - 'string', 'http://example.com/', - null, '(bar" hello' - ] -); - -// Automatic links -MT.testMode( - 'linkWeb', - ' foo', - [ - 'link', '', - null, ' foo' - ] -); - -// Automatic email links -MT.testMode( - 'linkEmail', - ' foo', - [ - 'link', '', - null, ' foo' - ] -); - -// Single asterisk -MT.testMode( - 'emAsterisk', - '*foo* bar', - [ - 'em', '*foo*', - null, ' bar' - ] -); - -// Single underscore -MT.testMode( - 'emUnderscore', - '_foo_ bar', - [ - 'em', '_foo_', - null, ' bar' - ] -); - -// Emphasis characters within a word -MT.testMode( - 'emInWordAsterisk', - 'foo*bar*hello', - [ - null, 'foo', - 'em', '*bar*', - null, 'hello' - ] -); -MT.testMode( - 'emInWordUnderscore', - 'foo_bar_hello', - [ - null, 'foo', - 'em', '_bar_', - null, 'hello' - ] -); -// Per documentation: "...surround an * or _ with spaces, it’ll be -// treated as a literal asterisk or underscore." -// -// Inside EM -MT.testMode( - 'emEscapedBySpaceIn', - 'foo _bar _ hello_ world', - [ - null, 'foo ', - 'em', '_bar _ hello_', - null, ' world' - ] -); -// Outside EM -MT.testMode( - 'emEscapedBySpaceOut', - 'foo _ bar_hello_world', - [ - null, 'foo _ bar', - 'em', '_hello_', - null, 'world' - ] -); - -// Unclosed emphasis characters -// Instead of simply marking as EM / STRONG, it would be nice to have an -// incomplete flag for EM and STRONG, that is styled slightly different. -MT.testMode( - 'emIncompleteAsterisk', - 'foo *bar', - [ - null, 'foo ', - 'em', '*bar' - ] -); -MT.testMode( - 'emIncompleteUnderscore', - 'foo _bar', - [ - null, 'foo ', - 'em', '_bar' - ] -); - -// Double asterisk -MT.testMode( - 'strongAsterisk', - '**foo** bar', - [ - 'strong', '**foo**', - null, ' bar' - ] -); - -// Double underscore -MT.testMode( - 'strongUnderscore', - '__foo__ bar', - [ - 'strong', '__foo__', - null, ' bar' - ] -); - -// Triple asterisk -MT.testMode( - 'emStrongAsterisk', - '*foo**bar*hello** world', - [ - 'em', '*foo', - 'emstrong', '**bar*', - 'strong', 'hello**', - null, ' world' - ] -); - -// Triple underscore -MT.testMode( - 'emStrongUnderscore', - '_foo__bar_hello__ world', - [ - 'em', '_foo', - 'emstrong', '__bar_', - 'strong', 'hello__', - null, ' world' - ] -); - -// Triple mixed -// "...same character must be used to open and close an emphasis span."" -MT.testMode( - 'emStrongMixed', - '_foo**bar*hello__ world', - [ - 'em', '_foo', - 'emstrong', '**bar*hello__ world' - ] -); - -MT.testMode( - 'emStrongMixed', - '*foo__bar_hello** world', - [ - 'em', '*foo', - 'emstrong', '__bar_hello** world' - ] -); - -// These characters should be escaped: -// \ backslash -// ` backtick -// * asterisk -// _ underscore -// {} curly braces -// [] square brackets -// () parentheses -// # hash mark -// + plus sign -// - minus sign (hyphen) -// . dot -// ! exclamation mark -// -// Backtick (code) -MT.testMode( - 'escapeBacktick', - 'foo \\`bar\\`', - [ - null, 'foo \\`bar\\`' - ] -); -MT.testMode( - 'doubleEscapeBacktick', - 'foo \\\\`bar\\\\`', - [ - null, 'foo \\\\', - 'comment', '`bar\\\\`' - ] -); -// Asterisk (em) -MT.testMode( - 'escapeAsterisk', - 'foo \\*bar\\*', - [ - null, 'foo \\*bar\\*' - ] -); -MT.testMode( - 'doubleEscapeAsterisk', - 'foo \\\\*bar\\\\*', - [ - null, 'foo \\\\', - 'em', '*bar\\\\*' - ] -); -// Underscore (em) -MT.testMode( - 'escapeUnderscore', - 'foo \\_bar\\_', - [ - null, 'foo \\_bar\\_' - ] -); -MT.testMode( - 'doubleEscapeUnderscore', - 'foo \\\\_bar\\\\_', - [ - null, 'foo \\\\', - 'em', '_bar\\\\_' - ] -); -// Hash mark (headers) -MT.testMode( - 'escapeHash', - '\\# foo', - [ - null, '\\# foo' - ] -); -MT.testMode( - 'doubleEscapeHash', - '\\\\# foo', - [ - null, '\\\\# foo' - ] -); +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "markdown"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("plainText", + "foo"); + + // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value) + MT("codeBlocksUsing4Spaces", + " [comment foo]"); + + // Code blocks using 4 spaces with internal indentation + MT("codeBlocksUsing4SpacesIndentation", + " [comment bar]", + " [comment hello]", + " [comment world]", + " [comment foo]", + "bar"); + + // Code blocks using 4 spaces with internal indentation + MT("codeBlocksUsing4SpacesIndentation", + " foo", + " [comment bar]", + " [comment hello]", + " [comment world]"); + + // Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value) + MT("codeBlocksUsing1Tab", + "\t[comment foo]"); + + // Inline code using backticks + MT("inlineCodeUsingBackticks", + "foo [comment `bar`]"); + + // Block code using single backtick (shouldn't work) + MT("blockCodeSingleBacktick", + "[comment `]", + "foo", + "[comment `]"); + + // Unclosed backticks + // Instead of simply marking as CODE, it would be nice to have an + // incomplete flag for CODE, that is styled slightly different. + MT("unclosedBackticks", + "foo [comment `bar]"); + + // Per documentation: "To include a literal backtick character within a + // code span, you can use multiple backticks as the opening and closing + // delimiters" + MT("doubleBackticks", + "[comment ``foo ` bar``]"); + + // Tests based on Dingus + // http://daringfireball.net/projects/markdown/dingus + // + // Multiple backticks within an inline code block + MT("consecutiveBackticks", + "[comment `foo```bar`]"); + + // Multiple backticks within an inline code block with a second code block + MT("consecutiveBackticks", + "[comment `foo```bar`] hello [comment `world`]"); + + // Unclosed with several different groups of backticks + MT("unclosedBackticks", + "[comment ``foo ``` bar` hello]"); + + // Closed with several different groups of backticks + MT("closedBackticks", + "[comment ``foo ``` bar` hello``] world"); + + // atx headers + // http://daringfireball.net/projects/markdown/syntax#header + + MT("atxH1", + "[header # foo]"); + + MT("atxH2", + "[header ## foo]"); + + MT("atxH3", + "[header ### foo]"); + + MT("atxH4", + "[header #### foo]"); + + MT("atxH5", + "[header ##### foo]"); + + MT("atxH6", + "[header ###### foo]"); + + // H6 - 7x '#' should still be H6, per Dingus + // http://daringfireball.net/projects/markdown/dingus + MT("atxH6NotH7", + "[header ####### foo]"); + + // Setext headers - H1, H2 + // Per documentation, "Any number of underlining =’s or -’s will work." + // http://daringfireball.net/projects/markdown/syntax#header + // Ideally, the text would be marked as `header` as well, but this is + // not really feasible at the moment. So, instead, we're testing against + // what works today, to avoid any regressions. + // + // Check if single underlining = works + MT("setextH1", + "foo", + "[header =]"); + + // Check if 3+ ='s work + MT("setextH1", + "foo", + "[header ===]"); + + // Check if single underlining - works + MT("setextH2", + "foo", + "[header -]"); + + // Check if 3+ -'s work + MT("setextH2", + "foo", + "[header ---]"); + + // Single-line blockquote with trailing space + MT("blockquoteSpace", + "[quote > foo]"); + + // Single-line blockquote + MT("blockquoteNoSpace", + "[quote >foo]"); + + // Single-line blockquote followed by normal paragraph + MT("blockquoteThenParagraph", + "[quote >foo]", + "", + "bar"); + + // Multi-line blockquote (lazy mode) + MT("multiBlockquoteLazy", + "[quote >foo]", + "[quote bar]"); + + // Multi-line blockquote followed by normal paragraph (lazy mode) + MT("multiBlockquoteLazyThenParagraph", + "[quote >foo]", + "[quote bar]", + "", + "hello"); + + // Multi-line blockquote (non-lazy mode) + MT("multiBlockquote", + "[quote >foo]", + "[quote >bar]"); + + // Multi-line blockquote followed by normal paragraph (non-lazy mode) + MT("multiBlockquoteThenParagraph", + "[quote >foo]", + "[quote >bar]", + "", + "hello"); + + // Check list types + + MT("listAsterisk", + "[string * foo]", + "[string * bar]"); + + MT("listPlus", + "[string + foo]", + "[string + bar]"); + + MT("listDash", + "[string - foo]", + "[string - bar]"); + + MT("listNumber", + "[string 1. foo]", + "[string 2. bar]"); + + // Formatting in lists (*) + MT("listAsteriskFormatting", + "[string * ][string&em *foo*][string bar]", + "[string * ][string&strong **foo**][string bar]", + "[string * ][string&strong **][string&emstrong *foo**][string&em *][string bar]", + "[string * ][string&comment `foo`][string bar]"); + + // Formatting in lists (+) + MT("listPlusFormatting", + "[string + ][string&em *foo*][string bar]", + "[string + ][string&strong **foo**][string bar]", + "[string + ][string&strong **][string&emstrong *foo**][string&em *][string bar]", + "[string + ][string&comment `foo`][string bar]"); + + // Formatting in lists (-) + MT("listDashFormatting", + "[string - ][string&em *foo*][string bar]", + "[string - ][string&strong **foo**][string bar]", + "[string - ][string&strong **][string&emstrong *foo**][string&em *][string bar]", + "[string - ][string&comment `foo`][string bar]"); + + // Formatting in lists (1.) + MT("listNumberFormatting", + "[string 1. ][string&em *foo*][string bar]", + "[string 2. ][string&strong **foo**][string bar]", + "[string 3. ][string&strong **][string&emstrong *foo**][string&em *][string bar]", + "[string 4. ][string&comment `foo`][string bar]"); + + // Paragraph lists + MT("listParagraph", + "[string * foo]", + "", + "[string * bar]"); + + // Multi-paragraph lists + // + // 4 spaces + MT("listMultiParagraph", + "[string * foo]", + "", + "[string * bar]", + "", + " [string hello]"); + + // 4 spaces, extra blank lines (should still be list, per Dingus) + MT("listMultiParagraphExtra", + "[string * foo]", + "", + "[string * bar]", + "", + " [string hello]"); + + // 4 spaces, plus 1 space (should still be list, per Dingus) + MT("listMultiParagraphExtraSpace", + "[string * foo]", + "", + "[string * bar]", + "", + " [string hello]", + "", + " [string world]"); + + // 1 tab + MT("listTab", + "[string * foo]", + "", + "[string * bar]", + "", + "\t[string hello]"); + + // No indent + MT("listNoIndent", + "[string * foo]", + "", + "[string * bar]", + "", + "hello"); + + // Blockquote + MT("blockquote", + "[string * foo]", + "", + "[string * bar]", + "", + " [string"e > hello]"); + + // Code block + MT("blockquoteCode", + "[string * foo]", + "", + "[string * bar]", + "", + " [comment > hello]", + "", + " [string world]"); + + // Code block followed by text + MT("blockquoteCodeText", + "[string * foo]", + "", + " [string bar]", + "", + " [comment hello]", + "", + " [string world]"); + + // Nested list + + MT("listAsteriskNested", + "[string * foo]", + "", + " [string * bar]"); + + MT("listPlusNested", + "[string + foo]", + "", + " [string + bar]"); + + MT("listDashNested", + "[string - foo]", + "", + " [string - bar]"); + + MT("listNumberNested", + "[string 1. foo]", + "", + " [string 2. bar]"); + + MT("listMixed", + "[string * foo]", + "", + " [string + bar]", + "", + " [string - hello]", + "", + " [string 1. world]"); + + MT("listBlockquote", + "[string * foo]", + "", + " [string + bar]", + "", + " [quote&string > hello]"); + + MT("listCode", + "[string * foo]", + "", + " [string + bar]", + "", + " [comment hello]"); + + // Code with internal indentation + MT("listCodeIndentation", + "[string * foo]", + "", + " [comment bar]", + " [comment hello]", + " [comment world]", + " [comment foo]", + " [string bar]"); + + // Code followed by text + MT("listCodeText", + "[string * foo]", + "", + " [comment bar]", + "", + "hello"); + + // Following tests directly from official Markdown documentation + // http://daringfireball.net/projects/markdown/syntax#hr + + MT("hrSpace", + "[hr * * *]"); + + MT("hr", + "[hr ***]"); + + MT("hrLong", + "[hr *****]"); + + MT("hrSpaceDash", + "[hr - - -]"); + + MT("hrDashLong", + "[hr ---------------------------------------]"); + + // Inline link with title + MT("linkTitle", + "[link [[foo]]][string (http://example.com/ \"bar\")] hello"); + + // Inline link without title + MT("linkNoTitle", + "[link [[foo]]][string (http://example.com/)] bar"); + + // Inline link with image + MT("linkImage", + "[link [[][tag ![[foo]]][string (http://example.com/)][link ]]][string (http://example.com/)] bar"); + + // Inline link with Em + MT("linkEm", + "[link [[][link&em *foo*][link ]]][string (http://example.com/)] bar"); + + // Inline link with Strong + MT("linkStrong", + "[link [[][link&strong **foo**][link ]]][string (http://example.com/)] bar"); + + // Inline link with EmStrong + MT("linkEmStrong", + "[link [[][link&strong **][link&emstrong *foo**][link&em *][link ]]][string (http://example.com/)] bar"); + + // Image with title + MT("imageTitle", + "[tag ![[foo]]][string (http://example.com/ \"bar\")] hello"); + + // Image without title + MT("imageNoTitle", + "[tag ![[foo]]][string (http://example.com/)] bar"); + + // Image with asterisks + MT("imageAsterisks", + "[tag ![[*foo*]]][string (http://example.com/)] bar"); + + // Not a link. Should be normal text due to square brackets being used + // regularly in text, especially in quoted material, and no space is allowed + // between square brackets and parentheses (per Dingus). + MT("notALink", + "[[foo]] (bar)"); + + // Reference-style links + MT("linkReference", + "[link [[foo]]][string [[bar]]] hello"); + + // Reference-style links with Em + MT("linkReferenceEm", + "[link [[][link&em *foo*][link ]]][string [[bar]]] hello"); + + // Reference-style links with Strong + MT("linkReferenceStrong", + "[link [[][link&strong **foo**][link ]]][string [[bar]]] hello"); + + // Reference-style links with EmStrong + MT("linkReferenceEmStrong", + "[link [[][link&strong **][link&emstrong *foo**][link&em *][link ]]][string [[bar]]] hello"); + + // Reference-style links with optional space separator (per docuentation) + // "You can optionally use a space to separate the sets of brackets" + MT("linkReferenceSpace", + "[link [[foo]]] [string [[bar]]] hello"); + + // Should only allow a single space ("...use *a* space...") + MT("linkReferenceDoubleSpace", + "[[foo]] [[bar]] hello"); + + // Reference-style links with implicit link name + MT("linkImplicit", + "[link [[foo]]][string [[]]] hello"); + + // @todo It would be nice if, at some point, the document was actually + // checked to see if the referenced link exists + + // Link label, for reference-style links (taken from documentation) + + MT("labelNoTitle", + "[link [[foo]]:] [string http://example.com/]"); + + MT("labelIndented", + " [link [[foo]]:] [string http://example.com/]"); + + MT("labelSpaceTitle", + "[link [[foo bar]]:] [string http://example.com/ \"hello\"]"); + + MT("labelDoubleTitle", + "[link [[foo bar]]:] [string http://example.com/ \"hello\"] \"world\""); + + MT("labelTitleDoubleQuotes", + "[link [[foo]]:] [string http://example.com/ \"bar\"]"); + + MT("labelTitleSingleQuotes", + "[link [[foo]]:] [string http://example.com/ 'bar']"); + + MT("labelTitleParenthese", + "[link [[foo]]:] [string http://example.com/ (bar)]"); + + MT("labelTitleInvalid", + "[link [[foo]]:] [string http://example.com/] bar"); + + MT("labelLinkAngleBrackets", + "[link [[foo]]:] [string \"bar\"]"); + + MT("labelTitleNextDoubleQuotes", + "[link [[foo]]:] [string http://example.com/]", + "[string \"bar\"] hello"); + + MT("labelTitleNextSingleQuotes", + "[link [[foo]]:] [string http://example.com/]", + "[string 'bar'] hello"); + + MT("labelTitleNextParenthese", + "[link [[foo]]:] [string http://example.com/]", + "[string (bar)] hello"); + + MT("labelTitleNextMixed", + "[link [[foo]]:] [string http://example.com/]", + "(bar\" hello"); + + MT("linkWeb", + "[link ] foo"); + + MT("linkEmail", + "[link ] foo"); + + MT("emAsterisk", + "[em *foo*] bar"); + + MT("emUnderscore", + "[em _foo_] bar"); + + MT("emInWordAsterisk", + "foo[em *bar*]hello"); + + MT("emInWordUnderscore", + "foo[em _bar_]hello"); + + // Per documentation: "...surround an * or _ with spaces, it’ll be + // treated as a literal asterisk or underscore." + + MT("emEscapedBySpaceIn", + "foo [em _bar _ hello_] world"); + + MT("emEscapedBySpaceOut", + "foo _ bar[em _hello_]world"); + + // Unclosed emphasis characters + // Instead of simply marking as EM / STRONG, it would be nice to have an + // incomplete flag for EM and STRONG, that is styled slightly different. + MT("emIncompleteAsterisk", + "foo [em *bar]"); + + MT("emIncompleteUnderscore", + "foo [em _bar]"); + + MT("strongAsterisk", + "[strong **foo**] bar"); + + MT("strongUnderscore", + "[strong __foo__] bar"); + + MT("emStrongAsterisk", + "[em *foo][emstrong **bar*][strong hello**] world"); + + MT("emStrongUnderscore", + "[em _foo][emstrong __bar_][strong hello__] world"); + + // "...same character must be used to open and close an emphasis span."" + MT("emStrongMixed", + "[em _foo][emstrong **bar*hello__ world]"); + + MT("emStrongMixed", + "[em *foo][emstrong __bar_hello** world]"); + + // These characters should be escaped: + // \ backslash + // ` backtick + // * asterisk + // _ underscore + // {} curly braces + // [] square brackets + // () parentheses + // # hash mark + // + plus sign + // - minus sign (hyphen) + // . dot + // ! exclamation mark + + MT("escapeBacktick", + "foo \\`bar\\`"); + + MT("doubleEscapeBacktick", + "foo \\\\[comment `bar\\\\`]"); + + MT("escapeAsterisk", + "foo \\*bar\\*"); + + MT("doubleEscapeAsterisk", + "foo \\\\[em *bar\\\\*]"); + + MT("escapeUnderscore", + "foo \\_bar\\_"); + + MT("doubleEscapeUnderscore", + "foo \\\\[em _bar\\\\_]"); + + MT("escapeHash", + "\\# foo"); + + MT("doubleEscapeHash", + "\\\\# foo"); +})(); diff --git a/mode/stex/test.js b/mode/stex/test.js index c5a34f3d8d..e7e9c29c1e 100644 --- a/mode/stex/test.js +++ b/mode/stex/test.js @@ -1,343 +1,104 @@ -var MT = ModeTest; -MT.modeName = 'stex'; -MT.modeOptions = {}; - -MT.testMode( - 'word', - 'foo', - [ - null, 'foo' - ] -); - -MT.testMode( - 'twoWords', - 'foo bar', - [ - null, 'foo bar' - ] -); - -MT.testMode( - 'beginEndDocument', - '\\begin{document}\n\\end{document}', - [ - 'tag', '\\begin', - 'bracket', '{', - 'atom', 'document', - 'bracket', '}', - 'tag', '\\end', - 'bracket', '{', - 'atom', 'document', - 'bracket', '}' - ] -); - -MT.testMode( - 'beginEndEquation', - '\\begin{equation}\n E=mc^2\n\\end{equation}', - [ - 'tag', '\\begin', - 'bracket', '{', - 'atom', 'equation', - 'bracket', '}', - null, ' E=mc^2', - 'tag', '\\end', - 'bracket', '{', - 'atom', 'equation', - 'bracket', '}' - ] -); - -MT.testMode( - 'beginModule', - '\\begin{module}[]', - [ - 'tag', '\\begin', - 'bracket', '{', - 'atom', 'module', - 'bracket', '}[]' - ] -); - -MT.testMode( - 'beginModuleId', - '\\begin{module}[id=bbt-size]', - [ - 'tag', '\\begin', - 'bracket', '{', - 'atom', 'module', - 'bracket', '}[', - null, 'id=bbt-size', - 'bracket', ']' - ] -); - -MT.testMode( - 'importModule', - '\\importmodule[b-b-t]{b-b-t}', - [ - 'tag', '\\importmodule', - 'bracket', '[', - 'string', 'b-b-t', - 'bracket', ']{', - 'builtin', 'b-b-t', - 'bracket', '}' - ] -); - -MT.testMode( - 'importModulePath', - '\\importmodule[\\KWARCslides{dmath/en/cardinality}]{card}', - [ - 'tag', '\\importmodule', - 'bracket', '[', - 'tag', '\\KWARCslides', - 'bracket', '{', - 'string', 'dmath/en/cardinality', - 'bracket', '}]{', - 'builtin', 'card', - 'bracket', '}' - ] -); - -MT.testMode( - 'psForPDF', - '\\PSforPDF[1]{#1}', // could treat #1 specially - [ - 'tag', '\\PSforPDF', - 'bracket', '[', - 'atom', '1', - 'bracket', ']{', - null, '#1', - 'bracket', '}' - ] -); - -MT.testMode( - 'comment', - '% foo', - [ - 'comment', '% foo' - ] -); - -MT.testMode( - 'tagComment', - '\\item% bar', - [ - 'tag', '\\item', - 'comment', '% bar' - ] -); - -MT.testMode( - 'commentTag', - ' % \\item', - [ - null, ' ', - 'comment', '% \\item' - ] -); - -MT.testMode( - 'commentLineBreak', - '%\nfoo', - [ - 'comment', '%', - null, 'foo' - ] -); - -MT.testMode( - 'tagErrorCurly', - '\\begin}{', - [ - 'tag', '\\begin', - 'error', '}', - 'bracket', '{' - ] -); - -MT.testMode( - 'tagErrorSquare', - '\\item]{', - [ - 'tag', '\\item', - 'error', ']', - 'bracket', '{' - ] -); - -MT.testMode( - 'commentCurly', - '% }', - [ - 'comment', '% }' - ] -); - -MT.testMode( - 'tagHash', - 'the \\# key', - [ - null, 'the ', - 'tag', '\\#', - null, ' key' - ] -); - -MT.testMode( - 'tagNumber', - 'a \\$5 stetson', - [ - null, 'a ', - 'tag', '\\$', - 'atom', 5, - null, ' stetson' - ] -); - -MT.testMode( - 'tagPercent', - '100\\% beef', - [ - 'atom', '100', - 'tag', '\\%', - null, ' beef' - ] -); - -MT.testMode( - 'tagAmpersand', - 'L \\& N', - [ - null, 'L ', - 'tag', '\\&', - null, ' N' - ] -); - -MT.testMode( - 'tagUnderscore', - 'foo\\_bar', - [ - null, 'foo', - 'tag', '\\_', - null, 'bar' - ] -); - -MT.testMode( - 'tagBracketOpen', - '\\emph{\\{}', - [ - 'tag', '\\emph', - 'bracket', '{', - 'tag', '\\{', - 'bracket', '}' - ] -); - -MT.testMode( - 'tagBracketClose', - '\\emph{\\}}', - [ - 'tag', '\\emph', - 'bracket', '{', - 'tag', '\\}', - 'bracket', '}' - ] -); - -MT.testMode( - 'tagLetterNumber', - 'section \\S1', - [ - null, 'section ', - 'tag', '\\S', - 'atom', '1' - ] -); - -MT.testMode( - 'textTagNumber', - 'para \\P2', - [ - null, 'para ', - 'tag', '\\P', - 'atom', '2' - ] -); - -MT.testMode( - 'thinspace', - 'x\\,y', // thinspace - [ - null, 'x', - 'tag', '\\,', - null, 'y' - ] -); - -MT.testMode( - 'thickspace', - 'x\\;y', // thickspace - [ - null, 'x', - 'tag', '\\;', - null, 'y' - ] -); - -MT.testMode( - 'negativeThinspace', - 'x\\!y', // negative thinspace - [ - null, 'x', - 'tag', '\\!', - null, 'y' - ] -); - -MT.testMode( - 'periodNotSentence', - 'J.\\ L.\\ is', // period not ending a sentence - [ - null, 'J.\\ L.\\ is' - ] -); // maybe could be better - -MT.testMode( - 'periodSentence', - 'X\\@. The', // period ending a sentence - [ - null, 'X', - 'tag', '\\@', - null, '. The' - ] -); - -MT.testMode( - 'italicCorrection', - '{\\em If\\/} I', // italic correction - [ - 'bracket', '{', - 'tag', '\\em', - null, ' If', - 'tag', '\\/', - 'bracket', '}', - null, ' I' - ] -); - -MT.testMode( - 'tagBracket', - '\\newcommand{\\pop}', - [ - 'tag', '\\newcommand', - 'bracket', '{', - 'tag', '\\pop', - 'bracket', '}' - ] -); \ No newline at end of file +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "stex"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT("word", + "foo"); + + MT("twoWords", + "foo bar"); + + MT("beginEndDocument", + "[tag \\begin][bracket {][atom document][bracket }]", + "[tag \\end][bracket {][atom document][bracket }]"); + + MT("beginEndEquation", + "[tag \\begin][bracket {][atom equation][bracket }]", + " E=mc^2", + "[tag \\end][bracket {][atom equation][bracket }]"); + + MT("beginModule", + "[tag \\begin][bracket {][atom module][bracket }[[]]]"); + + MT("beginModuleId", + "[tag \\begin][bracket {][atom module][bracket }[[]id=bbt-size[bracket ]]]"); + + MT("importModule", + "[tag \\importmodule][bracket [[][string b-b-t][bracket ]]{][builtin b-b-t][bracket }]"); + + MT("importModulePath", + "[tag \\importmodule][bracket [[][tag \\KWARCslides][bracket {][string dmath/en/cardinality][bracket }]]{][builtin card][bracket }]"); + + MT("psForPDF", + "[tag \\PSforPDF][bracket [[][atom 1][bracket ]]{]#1[bracket }]"); + + MT("comment", + "[comment % foo]"); + + MT("tagComment", + "[tag \\item][comment % bar]"); + + MT("commentTag", + " [comment % \\item]"); + + MT("commentLineBreak", + "[comment %]", + "foo"); + + MT("tagErrorCurly", + "[tag \\begin][error }][bracket {]"); + + MT("tagErrorSquare", + "[tag \\item][error ]]][bracket {]"); + + MT("commentCurly", + "[comment % }]"); + + MT("tagHash", + "the [tag \\#] key"); + + MT("tagNumber", + "a [tag \\$][atom 5] stetson"); + + MT("tagPercent", + "[atom 100][tag \\%] beef"); + + MT("tagAmpersand", + "L [tag \\&] N"); + + MT("tagUnderscore", + "foo[tag \\_]bar"); + + MT("tagBracketOpen", + "[tag \\emph][bracket {][tag \\{][bracket }]"); + + MT("tagBracketClose", + "[tag \\emph][bracket {][tag \\}][bracket }]"); + + MT("tagLetterNumber", + "section [tag \\S][atom 1]"); + + MT("textTagNumber", + "para [tag \\P][atom 2]"); + + MT("thinspace", + "x[tag \\,]y"); + + MT("thickspace", + "x[tag \\;]y"); + + MT("negativeThinspace", + "x[tag \\!]y"); + + MT("periodNotSentence", + "J.\\ L.\\ is"); + + MT("periodSentence", + "X[tag \\@]. The"); + + MT("italicCorrection", + "[bracket {][tag \\em] If[tag \\/][bracket }] I"); + + MT("tagBracket", + "[tag \\newcommand][bracket {][tag \\pop][bracket }]"); +})(); diff --git a/mode/xquery/test.js b/mode/xquery/test.js index 23ab3d1e3e..41719dd169 100644 --- a/mode/xquery/test.js +++ b/mode/xquery/test.js @@ -1,77 +1,64 @@ -// Initiate ModeTest and set defaults -var MT = ModeTest; -MT.modeName = "xquery"; -MT.modeOptions = {}; +// Don't take these too seriously -- the expected results appear to be +// based on the results of actual runs without any serious manual +// verification. If a change you made causes them to fail, the test is +// as likely to wrong as the code. -MT.testMode("eviltest", - 'xquery version "1.0-ml";\ - (: this is\ - : a \ - "comment" :)\ - let $let := <x attr="value">"test"<func>function() $var {function()} {$var}</func></x>\ - let $joe:=1\ - return element element {\ - attribute attribute { 1 },\ - element test { 'a' }, \ - attribute foo { "bar" },\ - fn:doc()[ foo/@bar eq $let ],\ - //x } \ - \ - (: a more \'evil\' test :)\ - (: Modified Blakeley example (: with nested comment :) ... :)\ - declare private function local:declare() {()};\ - declare private function local:private() {()};\ - declare private function local:function() {()};\ - declare private function local:local() {()};\ - let $let := <let>let $let := "let"</let>\ - return element element {\ - attribute attribute { try { xdmp:version() } catch($e) { xdmp:log($e) } },\ - attribute fn:doc { "bar" castable as xs:string },\ - element text { text { "text" } },\ - fn:doc()[ child::eq/(@bar | attribute::attribute) eq $let ],\ - //fn:doc\ - }', ["keyword","xquery",null," ","keyword","version",null," ","variable",""1","keyword",".","atom","0","keyword","-","variable","ml"","def variable",";",null," ","comment","(: this is : a \"comment\" :)",null," ","keyword","let",null," ","variable","$let",null," ","keyword",":=",null," ","variable","<x",null," ","variable","attr","keyword","=","variable",""value">"test"<func>","def variable",";function","","()",null," ","variable","$var",null," ","","{","keyword","function","","()}",null," ","","{","variable","$var","","}","variable","<","keyword","/","variable","func><","keyword","/","variable","x>",null," ","keyword","let",null," ","variable","$joe","keyword",":=","atom","1",null," ","keyword","return",null," ","keyword","element",null," ","variable","element",null," ","","{",null," ","keyword","attribute",null," ","variable","attribute",null," ","","{",null," ","atom","1",null," ","","},",null," ","keyword","element",null," ","variable","test",null," ","","{",null," ","variable","'a'",null," ","","},",null," ","keyword","attribute",null," ","variable","foo",null," ","","{",null," ","variable",""bar"",null," ","","},",null," ","def variable","fn:doc","","()[",null," ","variable","foo","keyword","/","variable","@bar",null," ","keyword","eq",null," ","variable","$let",null," ","","],",null," ","keyword","//","variable","x",null," ","","}",null," ","comment","(: a more 'evil' test :)",null," ","comment","(: Modified Blakeley example (: with nested comment :) ... :)",null," ","keyword","declare",null," ","keyword","private",null," ","keyword","function",null," ","def variable","local:declare","","()",null," ","","{()}","variable",";",null," ","keyword","declare",null," ","keyword","private",null," ","keyword","function",null," ","def variable","local:private","","()",null," ","","{()}","variable",";",null," ","keyword","declare",null," ","keyword","private",null," ","keyword","function",null," ","def variable","local:function","","()",null," ","","{()}","variable",";",null," ","keyword","declare",null," ","keyword","private",null," ","keyword","function",null," ","def variable","local:local","","()",null," ","","{()}","variable",";",null," ","keyword","let",null," ","variable","$let",null," ","keyword",":=",null," ","variable","<let>let",null," ","variable","$let",null," ","keyword",":=",null," ","variable",""let"<","keyword","/let","variable",">",null," ","keyword","return",null," ","keyword","element",null," ","variable","element",null," ","","{",null," ","keyword","attribute",null," ","variable","attribute",null," ","","{",null," ","keyword","try",null," ","","{",null," ","def variable","xdmp:version","","()",null," ","","}",null," ","keyword","catch","","(","variable","$e","",")",null," ","","{",null," ","def variable","xdmp:log","","(","variable","$e","",")",null," ","","}",null," ","","},",null," ","keyword","attribute",null," ","variable","fn:doc",null," ","","{",null," ","variable",""bar"",null," ","variable","castable",null," ","keyword","as",null," ","atom","xs:string",null," ","","},",null," ","keyword","element",null," ","variable","text",null," ","","{",null," ","keyword","text",null," ","","{",null," ","variable",""text"",null," ","","}",null," ","","},",null," ","def variable","fn:doc","","()[",null," ","qualifier","child::","variable","eq","keyword","/","","(","variable","@bar",null," ","keyword","|",null," ","qualifier","attribute::","variable","attribute","",")",null," ","keyword","eq",null," ","variable","$let",null," ","","],",null," ","keyword","//","variable","fn:doc",null," ","","}"]); +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "xquery"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } -MT.testMode("testEmptySequenceKeyword", - '"foo" instance of empty-sequence()', - ["string","\"foo\"",null," ","keyword","instance",null," ","keyword","of",null," ","keyword","empty-sequence","","()"]); + MT("eviltest", + "[keyword xquery] [keyword version] [variable "1][keyword .][atom 0][keyword -][variable ml"][def&variable ;] [comment (: this is : a \"comment\" :)]", + " [keyword let] [variable $let] [keyword :=] [variable <x] [variable attr][keyword =][variable "value">"test"<func>][def&variable ;function]() [variable $var] {[keyword function]()} {[variable $var]}[variable <][keyword /][variable func><][keyword /][variable x>]", + " [keyword let] [variable $joe][keyword :=][atom 1]", + " [keyword return] [keyword element] [variable element] {", + " [keyword attribute] [variable attribute] { [atom 1] },", + " [keyword element] [variable test] { [variable 'a'] }, [keyword attribute] [variable foo] { [variable "bar"] },", + " [def&variable fn:doc]()[[ [variable foo][keyword /][variable @bar] [keyword eq] [variable $let] ]],", + " [keyword //][variable x] } [comment (: a more 'evil' test :)]", + " [comment (: Modified Blakeley example (: with nested comment :) ... :)]", + " [keyword declare] [keyword private] [keyword function] [def&variable local:declare]() {()}[variable ;]", + " [keyword declare] [keyword private] [keyword function] [def&variable local:private]() {()}[variable ;]", + " [keyword declare] [keyword private] [keyword function] [def&variable local:function]() {()}[variable ;]", + " [keyword declare] [keyword private] [keyword function] [def&variable local:local]() {()}[variable ;]", + " [keyword let] [variable $let] [keyword :=] [variable <let>let] [variable $let] [keyword :=] [variable "let"<][keyword /let][variable >]", + " [keyword return] [keyword element] [variable element] {", + " [keyword attribute] [variable attribute] { [keyword try] { [def&variable xdmp:version]() } [keyword catch]([variable $e]) { [def&variable xdmp:log]([variable $e]) } },", + " [keyword attribute] [variable fn:doc] { [variable "bar"] [variable castable] [keyword as] [atom xs:string] },", + " [keyword element] [variable text] { [keyword text] { [variable "text"] } },", + " [def&variable fn:doc]()[[ [qualifier child::][variable eq][keyword /]([variable @bar] [keyword |] [qualifier attribute::][variable attribute]) [keyword eq] [variable $let] ]],", + " [keyword //][variable fn:doc]", + " }"); + MT("testEmptySequenceKeyword", + "[string \"foo\"] [keyword instance] [keyword of] [keyword empty-sequence]()"); -MT.testMode("testMultiAttr", - '

    hello world

    ', - ["tag","

    ","variable","hello",null," ","variable","world","tag","

    "]); + MT("testMultiAttr", + "[tag

    ][variable hello] [variable world][tag

    ]"); -MT.testMode("test namespaced variable", - 'declare namespace e = "http://example.com/ANamespace";\ -declare variable $e:exampleComThisVarIsNotRecognized as element(*) external;', - ["keyword","declare",null," ","keyword","namespace",null," ","variable","e",null," ","keyword","=",null," ","string","\"http://example.com/ANamespace\"","variable",";declare",null," ","keyword","variable",null," ","variable","$e:exampleComThisVarIsNotRecognized",null," ","keyword","as",null," ","keyword","element","","(","keyword","*","",")",null," ","variable","external;"]); + MT("test namespaced variable", + "[keyword declare] [keyword namespace] [variable e] [keyword =] [string \"http://example.com/ANamespace\"][variable ;declare] [keyword variable] [variable $e:exampleComThisVarIsNotRecognized] [keyword as] [keyword element]([keyword *]) [variable external;]"); -MT.testMode("test EQName variable", - 'declare variable $"http://www.example.com/ns/my":var := 12;\ -{$"http://www.example.com/ns/my":var}', - ["keyword","declare",null," ","keyword","variable",null," ","variable","$\"http://www.example.com/ns/my\":var",null," ","keyword",":=",null," ","atom","12","variable",";","tag","","","{","variable","$\"http://www.example.com/ns/my\":var","","}","tag",""]); + MT("test EQName variable", + "[keyword declare] [keyword variable] [variable $\"http://www.example.com/ns/my\":var] [keyword :=] [atom 12][variable ;]", + "[tag ]{[variable $\"http://www.example.com/ns/my\":var]}[tag ]"); -MT.testMode("test EQName function", - 'declare function "http://www.example.com/ns/my":fn ($a as xs:integer) as xs:integer {\ - $a + 2\ -};\ -{"http://www.example.com/ns/my":fn(12)}', - ["keyword","declare",null," ","keyword","function",null," ","def variable","\"http://www.example.com/ns/my\":fn",null," ","","(","variable","$a",null," ","keyword","as",null," ","atom","xs:integer","",")",null," ","keyword","as",null," ","atom","xs:integer",null," ","","{",null," ","variable","$a",null," ","keyword","+",null," ","atom","2","","}","variable",";","tag","","","{","def variable","\"http://www.example.com/ns/my\":fn","","(","atom","12","",")}","tag",""]); + MT("test EQName function", + "[keyword declare] [keyword function] [def&variable \"http://www.example.com/ns/my\":fn] ([variable $a] [keyword as] [atom xs:integer]) [keyword as] [atom xs:integer] {", + " [variable $a] [keyword +] [atom 2]", + "}[variable ;]", + "[tag ]{[def&variable \"http://www.example.com/ns/my\":fn]([atom 12])}[tag ]"); -MT.testMode("test EQName function with single quotes", - 'declare function \'http://www.example.com/ns/my\':fn ($a as xs:integer) as xs:integer {\ - $a + 2\ -};\ -{\'http://www.example.com/ns/my\':fn(12)}', - ["keyword","declare",null," ","keyword","function",null," ","def variable","'http://www.example.com/ns/my':fn",null," ","","(","variable","$a",null," ","keyword","as",null," ","atom","xs:integer","",")",null," ","keyword","as",null," ","atom","xs:integer",null," ","","{",null," ","variable","$a",null," ","keyword","+",null," ","atom","2","","}","variable",";","tag","","","{","def variable","'http://www.example.com/ns/my':fn","","(","atom","12","",")}","tag",""]); + MT("test EQName function with single quotes", + "[keyword declare] [keyword function] [def&variable 'http://www.example.com/ns/my':fn] ([variable $a] [keyword as] [atom xs:integer]) [keyword as] [atom xs:integer] {", + " [variable $a] [keyword +] [atom 2]", + "}[variable ;]", + "[tag ]{[def&variable 'http://www.example.com/ns/my':fn]([atom 12])}[tag ]"); -MT.testMode("testProcessingInstructions", - 'data() instance of xs:string', - ["def variable","data","","(","comment meta","","",")",null," ","keyword","instance",null," ","keyword","of",null," ","atom","xs:string"]); + MT("testProcessingInstructions", + "[def&variable data]([comment&meta ]) [keyword instance] [keyword of] [atom xs:string]"); -MT.testMode("testQuoteEscapeDouble", - 'let $rootfolder := "c:\\builds\\winnt\\HEAD\\qa\\scripts\\"\ -let $keysfolder := concat($rootfolder, "keys\\")\ -return\ -$keysfolder', - ["keyword","let",null," ","variable","$rootfolder",null," ","keyword",":=",null," ","string","\"c:\\builds\\winnt\\HEAD\\qa\\scripts\\\"","keyword","let",null," ","variable","$keysfolder",null," ","keyword",":=",null," ","def variable","concat","","(","variable","$rootfolder","",",",null," ","string","\"keys\\\"","",")","variable","return$keysfolder"]); + MT("testQuoteEscapeDouble", + "[keyword let] [variable $rootfolder] [keyword :=] [string \"c:\\builds\\winnt\\HEAD\\qa\\scripts\\\"]", + "[keyword let] [variable $keysfolder] [keyword :=] [def&variable concat]([variable $rootfolder], [string \"keys\\\"])"); +})(); diff --git a/mode/xquery/xquery.js b/mode/xquery/xquery.js index e4231d1069..d5c859e00a 100644 --- a/mode/xquery/xquery.js +++ b/mode/xquery/xquery.js @@ -33,7 +33,7 @@ CodeMirror.defineMode("xquery", function() { , C = kw("keyword c") , operator = kw("operator") , atom = {type: "atom", style: "atom"} - , punctuation = {type: "punctuation", style: ""} + , punctuation = {type: "punctuation", style: null} , qualifier = {type: "axis_specifier", style: "qualifier"}; // kwObj is what is return from this function at the end @@ -121,12 +121,12 @@ CodeMirror.defineMode("xquery", function() { // start code block else if(ch == "{") { pushStateStack(state,{ type: "codeblock"}); - return ret("", ""); + return ret("", null); } // end code block else if(ch == "}") { popStateStack(state); - return ret("", ""); + return ret("", null); } // if we're in an XML block else if(isInXmlBlock(state)) { @@ -163,22 +163,22 @@ CodeMirror.defineMode("xquery", function() { // open paren else if(ch === "(") { pushStateStack(state, { type: "paren"}); - return ret("", ""); + return ret("", null); } // close paren else if(ch === ")") { popStateStack(state); - return ret("", ""); + return ret("", null); } // open paren else if(ch === "[") { pushStateStack(state, { type: "bracket"}); - return ret("", ""); + return ret("", null); } // close paren else if(ch === "]") { popStateStack(state); - return ret("", ""); + return ret("", null); } else { var known = keywords.propertyIsEnumerable(ch) && keywords[ch]; @@ -342,7 +342,7 @@ CodeMirror.defineMode("xquery", function() { return ret("tag", "tag"); } if(ch == "=") - return ret("", ""); + return ret("", null); // quoted string if (ch == '"' || ch == "'") return chain(stream, state, tokenString(ch, tokenAttribute)); diff --git a/test/mode_test.js b/test/mode_test.js index 06270aa31e..51e51b9525 100644 --- a/test/mode_test.js +++ b/test/mode_test.js @@ -2,166 +2,191 @@ * Helper to test CodeMirror highlighting modes. It pretty prints output of the * highlighter and can check against expected styles. * - * See test.html in the stex mode for examples. - */ -ModeTest = {}; - -ModeTest.modeOptions = {}; -ModeTest.modeName = CodeMirror.defaults.mode; - -/** - * Run a test. - * - * @param name Name of test - * @param text String to highlight. - * @param expected Expected styles and tokens: Array(style, token, [style, token,...]) - * @param modeName - * @param modeOptions - * @param expectedFail + * Mode tests are registered by calling test.mode(testName, mode, + * tokens), where mode is a mode object as returned by + * CodeMirror.getMode, and tokens is an array of lines that make up + * the test. + * + * These lines are strings, in which styled stretches of code are + * enclosed in brackets `[]`, and prefixed by their style. For + * example, `[keyword if]`. Brackets in the code itself must be + * duplicated to prevent them from being interpreted as token + * boundaries. For example `a[[i]]` for `a[i]`. If a token has + * multiple styles, the styles must be separated by ampersands, for + * example `[tag&error ]`. + * + * See the test.js files in the css, markdown, gfm, and stex mode + * directories for examples. */ -ModeTest.testMode = function(name, text, expected, modeName, modeOptions, expectedFail) { - if (!modeName) modeName = ModeTest.modeName; - - if (!modeOptions) modeOptions = ModeTest.modeOptions; - - var mode = CodeMirror.getMode(modeOptions, modeName); - - if (expected.length < 0) { - throw "must have text for test (" + name + ")"; +(function() { + function findSingle(str, pos, ch) { + for (;;) { + var found = str.indexOf(ch, pos); + if (found == -1) return null; + if (str.charAt(found + 1) != ch) return found; + pos = found + 2; + } } - if (expected.length % 2 != 0) { - throw "must have text for test (" + name + ") plus expected (style, token) pairs"; + + var styleName = /[\w&-_]+/g; + function parseTokens(strs) { + var tokens = [], plain = ""; + for (var i = 0; i < strs.length; ++i) { + if (i) plain += "\n"; + var str = strs[i], pos = 0; + while (pos < str.length) { + var style = null, text; + if (str.charAt(pos) == "[" && str.charAt(pos+1) != "[") { + styleName.lastIndex = pos + 1; + var m = styleName.exec(str); + style = m[0].replace(/&/g, " "); + var textStart = pos + style.length + 2; + var end = findSingle(str, textStart, "]"); + if (end == null) throw new Error("Unterminated token at " + pos + " in '" + str + "'" + style); + text = str.slice(textStart, end); + pos = end + 1; + } else { + var end = findSingle(str, pos, "["); + if (end == null) end = str.length; + text = str.slice(pos, end); + pos = end; + } + text = text.replace(/\[\[|\]\]/g, function(s) {return s.charAt(0);}); + tokens.push(style, text); + plain += text; + } + } + return {tokens: tokens, plain: plain}; } - return test( - modeName + "_" + name, - function(){ - return ModeTest.compare(text, expected, mode); - }, - expectedFail - ); - -} -ModeTest.compare = function (text, expected, mode) { + test.mode = function(name, mode, tokens) { + var data = parseTokens(tokens); + return test(mode.name + "_" + name, function() { + return compare(data.plain, data.tokens, mode); + }); + }; - var expectedOutput = []; - for (var i = 0; i < expected.length; i += 2) { - var sty = expected[i]; - if (sty && sty.indexOf(" ")) sty = sty.split(' ').sort().join(' '); - expectedOutput.push(sty, expected[i + 1]); - } + function compare(text, expected, mode) { - var observedOutput = ModeTest.highlight(text, mode); + var expectedOutput = []; + for (var i = 0; i < expected.length; i += 2) { + var sty = expected[i]; + if (sty && sty.indexOf(" ")) sty = sty.split(' ').sort().join(' '); + expectedOutput.push(sty, expected[i + 1]); + } - var pass, passStyle = ""; - pass = ModeTest.highlightOutputsEqual(expectedOutput, observedOutput); - passStyle = pass ? 'mt-pass' : 'mt-fail'; + var observedOutput = highlight(text, mode); - var s = ''; - if (pass) { - s += '
    '; - s += '
    ' + text + '
    '; - s += '
    '; - s += ModeTest.prettyPrintOutputTable(observedOutput); - s += '
    '; - s += '
    '; - return s; - } else { - s += '
    '; - s += '
    ' + text + '
    '; - s += '
    '; - s += 'expected:'; - s += ModeTest.prettyPrintOutputTable(expectedOutput); - s += 'observed:'; - s += ModeTest.prettyPrintOutputTable(observedOutput); - s += '
    '; - s += '
    '; - throw s; + var pass, passStyle = ""; + pass = highlightOutputsEqual(expectedOutput, observedOutput); + passStyle = pass ? 'mt-pass' : 'mt-fail'; + + var s = ''; + if (pass) { + s += '
    '; + s += '
    ' + text + '
    '; + s += '
    '; + s += prettyPrintOutputTable(observedOutput); + s += '
    '; + s += '
    '; + return s; + } else { + s += '
    '; + s += '
    ' + text + '
    '; + s += '
    '; + s += 'expected:'; + s += prettyPrintOutputTable(expectedOutput); + s += 'observed:'; + s += prettyPrintOutputTable(observedOutput); + s += '
    '; + s += '
    '; + throw s; + } } -} -/** - * Emulation of CodeMirror's internal highlight routine for testing. Multi-line - * input is supported. - * - * @param string to highlight - * - * @param mode the mode that will do the actual highlighting - * - * @return array of [style, token] pairs - */ -ModeTest.highlight = function(string, mode) { - var state = mode.startState() + /** + * Emulation of CodeMirror's internal highlight routine for testing. Multi-line + * input is supported. + * + * @param string to highlight + * + * @param mode the mode that will do the actual highlighting + * + * @return array of [style, token] pairs + */ + function highlight(string, mode) { + var state = mode.startState() - var lines = string.replace(/\r\n/g,'\n').split('\n'); - var st = [], pos = 0; - for (var i = 0; i < lines.length; ++i) { - var line = lines[i], newLine = true; - var stream = new CodeMirror.StringStream(line); - if (line == "" && mode.blankLine) mode.blankLine(state); - /* Start copied code from CodeMirror.highlight */ - while (!stream.eol()) { - var style = mode.token(stream, state), substr = stream.current(); - if (style && style.indexOf(" ") > -1) style = style.split(' ').sort().join(' '); + var lines = string.replace(/\r\n/g,'\n').split('\n'); + var st = [], pos = 0; + for (var i = 0; i < lines.length; ++i) { + var line = lines[i], newLine = true; + var stream = new CodeMirror.StringStream(line); + if (line == "" && mode.blankLine) mode.blankLine(state); + /* Start copied code from CodeMirror.highlight */ + while (!stream.eol()) { + var style = mode.token(stream, state), substr = stream.current(); + if (style && style.indexOf(" ") > -1) style = style.split(' ').sort().join(' '); - stream.start = stream.pos; - if (pos && st[pos-2] == style && !newLine) { - st[pos-1] += substr; - } else if (substr) { - st[pos++] = style; st[pos++] = substr; - } - // Give up when line is ridiculously long - if (stream.pos > 5000) { - st[pos++] = null; st[pos++] = this.text.slice(stream.pos); - break; + stream.start = stream.pos; + if (pos && st[pos-2] == style && !newLine) { + st[pos-1] += substr; + } else if (substr) { + st[pos++] = style; st[pos++] = substr; + } + // Give up when line is ridiculously long + if (stream.pos > 5000) { + st[pos++] = null; st[pos++] = this.text.slice(stream.pos); + break; + } + newLine = false; } - newLine = false; } - } - return st; -} + return st; + } -/** - * Compare two arrays of output from ModeTest.highlight. - * - * @param o1 array of [style, token] pairs - * - * @param o2 array of [style, token] pairs - * - * @return boolean; true iff outputs equal - */ -ModeTest.highlightOutputsEqual = function(o1, o2) { - if (o1.length != o2.length) return false; - for (var i = 0; i < o1.length; ++i) - if (o1[i] != o2[i]) return false; - return true; -} + /** + * Compare two arrays of output from highlight. + * + * @param o1 array of [style, token] pairs + * + * @param o2 array of [style, token] pairs + * + * @return boolean; true iff outputs equal + */ + function highlightOutputsEqual(o1, o2) { + if (o1.length != o2.length) return false; + for (var i = 0; i < o1.length; ++i) + if (o1[i] != o2[i]) return false; + return true; + } -/** - * Print tokens and corresponding styles in a table. Spaces in the token are - * replaced with 'interpunct' dots (·). - * - * @param output array of [style, token] pairs - * - * @return html string - */ -ModeTest.prettyPrintOutputTable = function(output) { - var s = ''; - s += ''; - for (var i = 0; i < output.length; i += 2) { - var style = output[i], val = output[i+1]; - s += + /** + * Print tokens and corresponding styles in a table. Spaces in the token are + * replaced with 'interpunct' dots (·). + * + * @param output array of [style, token] pairs + * + * @return html string + */ + function prettyPrintOutputTable(output) { + var s = '
    '; + s += ''; + for (var i = 0; i < output.length; i += 2) { + var style = output[i], val = output[i+1]; + s += ''; - } - s += ''; - for (var i = 0; i < output.length; i += 2) { - s += ''; + ''; + } + s += ''; + for (var i = 0; i < output.length; i += 2) { + s += ''; + } + s += '
    ' + '' + - val.replace(/ /g,'\xb7') + + val.replace(/ /g,'\xb7') + '' + - '
    ' + output[i] + '
    ' + output[i] + '
    '; + return s; } - s += ''; - return s; -} +})(); From 03f8aaed47b947fe0edfe73c29889d49483fd88f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 12 Jan 2013 14:22:16 +0100 Subject: [PATCH 0066/5273] Make the tester accurately report total test count Even when a subset is selected. --- test/driver.js | 24 ++++++++++++++---------- test/index.html | 4 +--- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/test/driver.js b/test/driver.js index 6306991328..6d480e9460 100644 --- a/test/driver.js +++ b/test/driver.js @@ -48,10 +48,6 @@ function runTests(callback) { } if (debug.length < 1) { debug = null; - } else { - if (totalTests > debug.length) { - totalTests = debug.length; - } } } var totalTime = 0; @@ -67,7 +63,7 @@ function runTests(callback) { // Remove from array for reporting incorrect tests later debug.splice(debugIndex, 1); } else { - var wildcardName = test.name.split("_").shift() + "_*"; + var wildcardName = test.name.split("_")[0] + "_*"; debugIndex = indexOf(debug, wildcardName); if (debugIndex !== -1) { // Remove from array for reporting incorrect tests later @@ -75,11 +71,7 @@ function runTests(callback) { debugUsed.push(wildcardName); } else { debugIndex = indexOf(debugUsed, wildcardName); - if (debugIndex !== -1) { - totalTests++; - } else { - return step(i + 1); - } + if (debugIndex == -1) return step(i + 1); } } } @@ -132,3 +124,15 @@ function eqPos(a, b, msg) { function is(a, msg) { if (!a) throw new Failure(label("assertion failed", msg)); } + +function countTests() { + if (!debug) return tests.length; + var sum = 0; + for (var i = 0; i < tests.length; ++i) { + var name = tests[i].name; + if (indexOf(debug, name) != -1 || + indexOf(debug, name.split("_")[0] + "_*") != -1) + ++sum; + } + return sum; +} \ No newline at end of file diff --git a/test/index.html b/test/index.html index 4bb4a77be5..d4cec017f6 100644 --- a/test/index.html +++ b/test/index.html @@ -107,7 +107,7 @@

    CodeMirror: Test Suite

    bad = ""; verbose = false; debugUsed = Array(); - totalTests = tests.length; + totalTests = countTests(); progressTotal.nodeValue = " of " + totalTests; progressRan.nodeValue = count; output.innerHTML = ''; @@ -141,8 +141,6 @@

    CodeMirror: Test Suite

    var message = "???"; if (type != "done") ++count; progress.style.width = (count * (progress.parentNode.clientWidth - 2) / totalTests) + "px"; - progressTotal.nodeValue = " of " + totalTests + - (debugUsed.length && type != "done" ? "+" : ""); progressRan.nodeValue = count; if (type == "ok") { message = "Test '" + name + "' succeeded"; From 8416706c40c6c7dda5356f3e7f88365d6b13ea5a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 14 Jan 2013 08:27:28 +0100 Subject: [PATCH 0067/5273] Add MIHTool to real-world uses --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 71d9929c63..870c28d312 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -57,6 +57,7 @@

    { } CodeMi
  • kl1p (paste service)
  • Light Table (experimental IDE)
  • Mergely (interactive diffing)
  • +
  • MIHTool (iOS web-app debugging tool)
  • My2ndGeneration (social coding)
  • NoTex (rST authoring)
  • ORG (z80 assembly IDE)
  • From 2165c76e6e8620298b3695e112bdecb61437e2a0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 14 Jan 2013 09:05:50 +0100 Subject: [PATCH 0068/5273] Reinstate the fixedGutter option --- doc/manual.html | 5 +++++ lib/codemirror.js | 16 +++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 14d3a3249f..5bf582ca0d 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -222,6 +222,11 @@

    Configuration

    names are the keys passed to setGutterMarker. +
    fixedGutter (boolean)
    +
    Determines whether the gutter scrolls along with the content + horizontally (false) or whether it stays fixed during horizontal + scrolling (true, the default).
    +
    readOnly (boolean)
    This disables editing of the editor content by the user. If the special value "nocursor" is given (instead of diff --git a/lib/codemirror.js b/lib/codemirror.js index 4ce1cd0b8f..a771a1e643 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -358,13 +358,14 @@ window.CodeMirror = (function() { function alignHorizontally(cm) { var display = cm.display; - if (!display.alignWidgets && !display.gutters.firstChild) return; + if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.view.scrollLeft; var gutterW = display.gutters.offsetWidth, l = comp + "px"; for (var n = display.lineDiv.firstChild; n; n = n.nextSibling) if (n.alignable) { for (var i = 0, a = n.alignable; i < a.length; ++i) a[i].style.left = l; } - display.gutters.style.left = (comp + gutterW) + "px"; + if (cm.options.fixedGutter) + display.gutters.style.left = (comp + gutterW) + "px"; } function maybeUpdateLineNumberWidth(cm) { @@ -428,7 +429,8 @@ window.CodeMirror = (function() { if (changes && maybeUpdateLineNumberWidth(cm)) changes = true; - display.sizer.style.marginLeft = display.scrollbarH.style.left = display.gutters.offsetWidth + "px"; + var gutterW = display.sizer.style.marginLeft = display.gutters.offsetWidth + "px"; + display.scrollbarH.style.left = cm.options.fixedGutter ? gutterW : "0"; // When merged lines are present, the line that needs to be // redrawn might not be the one that was changed. @@ -616,8 +618,8 @@ window.CodeMirror = (function() { var wrap = elt("div", null, line.wrapClass, "position: relative"); if (cm.options.lineNumbers || markers) { var gutterWrap = wrap.appendChild(elt("div", null, null, "position: absolute; left: " + - dims.fixedPos + "px")); - wrap.alignable = [gutterWrap]; + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px")); + if (cm.options.fixedGutter) wrap.alignable = [gutterWrap]; if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) wrap.lineNumber = gutterWrap.appendChild( elt("div", lineNumberFor(cm.options, lineNo), @@ -2883,6 +2885,10 @@ window.CodeMirror = (function() { 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("lineNumbers", false, function(cm) { setGuttersForLineNumbers(cm.options); guttersChanged(cm); From c606a14d0e6da16dd4a11ac2596293a9d475f902 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 14 Jan 2013 14:10:02 +0100 Subject: [PATCH 0069/5273] Use document.documentMode when detecting IE versions Closes #1149 --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index a771a1e643..d0c0e83511 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -8,8 +8,8 @@ window.CodeMirror = (function() { // bugs and behavior differences. var gecko = /gecko\/\d/i.test(navigator.userAgent); var ie = /MSIE \d/.test(navigator.userAgent); - var ie_lt8 = /MSIE [1-7]\b/.test(navigator.userAgent); - var ie_lt9 = /MSIE [1-8]\b/.test(navigator.userAgent); + var ie_lt8 = ie && (document.documentMode == null || document.documentMode < 8); + var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); var webkit = /WebKit\//.test(navigator.userAgent); var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); var chrome = /Chrome\//.test(navigator.userAgent); From 4857377f478821925d74c8f6a13f56ade1755d7c Mon Sep 17 00:00:00 2001 From: sonson Date: Mon, 14 Jan 2013 14:15:33 +0100 Subject: [PATCH 0070/5273] Support Scala in GFM mode. --- mode/markdown/markdown.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 531c2b5469..63de81e6ee 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -10,7 +10,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { "c++": "text/x-c++src", java: "text/x-java", csharp: "text/x-csharp", - "c#": "text/x-csharp" + "c#": "text/x-csharp", + scala: "text/x-scala" }; var getMode = (function () { From 8eca1bc713f923088371254e49ddb31d08002cf6 Mon Sep 17 00:00:00 2001 From: Akeksandr Motsjonov Date: Sat, 12 Jan 2013 18:14:22 +0200 Subject: [PATCH 0071/5273] SearchCursor.matches() doesn't work properly if query is /.*/ issue #1155 --- 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 58fed74d00..5684690d1f 100644 --- a/addon/search/searchcursor.js +++ b/addon/search/searchcursor.js @@ -30,7 +30,7 @@ var line = cm.getLine(pos.line), match = query.exec(line), start = match && match.index; } - if (match) + if (match && match[0]) return {from: {line: pos.line, ch: start}, to: {line: pos.line, ch: start + match[0].length}, match: match}; From 1960b0d378270098d37aab223ff29237fa0b0372 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 14 Jan 2013 14:37:24 +0100 Subject: [PATCH 0072/5273] Guard against search cursors with a query of "" They'd exhibit the same infinite traversal behavior mentioned in #1155 --- addon/search/searchcursor.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/addon/search/searchcursor.js b/addon/search/searchcursor.js index 5684690d1f..b7e7a79054 100644 --- a/addon/search/searchcursor.js +++ b/addon/search/searchcursor.js @@ -40,15 +40,21 @@ var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;}; var target = query.split("\n"); // Different methods for single-line and multi-line queries - if (target.length == 1) - this.matches = function(reverse, pos) { - var line = fold(cm.getLine(pos.line)), len = query.length, match; - if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1) - : (match = line.indexOf(query, pos.ch)) != -1) - return {from: {line: pos.line, ch: match}, - to: {line: pos.line, ch: match + len}}; - }; - else + if (target.length == 1) { + if (!query.length) { + // Empty string would match anything and never progress, so + // we define it to match nothing instead. + this.matches = function() {}; + } else { + this.matches = function(reverse, pos) { + var line = fold(cm.getLine(pos.line)), len = query.length, match; + if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1) + : (match = line.indexOf(query, pos.ch)) != -1) + return {from: {line: pos.line, ch: match}, + to: {line: pos.line, ch: match + len}}; + }; + } + } else { this.matches = function(reverse, pos) { var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(cm.getLine(ln)); var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match)); @@ -70,6 +76,7 @@ return {from: reverse ? end : start, to: reverse ? start : end}; } }; + } } } From b1b1dd55281ccb33130c5f3df99472f1a76469c2 Mon Sep 17 00:00:00 2001 From: santec Date: Tue, 15 Jan 2013 23:52:23 +0100 Subject: [PATCH 0073/5273] Improve Mode SQL * mysql & mariadb: ** .21 syntax ** .table_name syntax ** added keywords * MIMEs define their operatorChars * MIMEs have a support prop * use spaces as tab in index.html for consistency * some return false -> null * more comments --- mode/sql/index.html | 93 ++++++++++++++++++++++++--------------------- mode/sql/sql.js | 49 +++++++++++++++++------- 2 files changed, 85 insertions(+), 57 deletions(-) diff --git a/mode/sql/index.html b/mode/sql/index.html index 36fc2238ab..7ec938a121 100644 --- a/mode/sql/index.html +++ b/mode/sql/index.html @@ -1,47 +1,49 @@ - - - SQL Mode for CodeMirror - - - - - - - - -

    SQL Mode for CodeMirror

    - - - -

    MIME types defined: - text/x-sql, - text/x-mysql, - text/x-mariadb, - text/x-plsql. -

    - + +

    MIME types defined: + text/x-sql, + text/x-mysql, + text/x-mariadb, + text/x-plsql. +

    +

    + Tests: + normal, + verbose. +

    + diff --git a/mode/sql/sql.js b/mode/sql/sql.js index dc163dd8d5..2a16882aea 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -5,13 +5,15 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { atoms = parserConfig.atoms || {"false": true, "true": true, "null": true}, builtin = parserConfig.builtin || {}, keywords = parserConfig.keywords, - operatorChars = /^[*+\-%<>!=&|~^]/, + operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/, + support = parserConfig.support || {}, hooks = parserConfig.hooks || {}, dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true}; - + function tokenBase(stream, state) { var ch = stream.next(); + // call hooks from the mime type if (hooks[ch]) { var result = hooks[ch](stream, state); if (result !== false) return result; @@ -36,7 +38,8 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { // strings state.tokenize = tokenLiteral(ch); return state.tokenize(stream, state); - } else if (/^[\(\),\.;\[\]]/.test(ch)) { + } else if (/^[\(\),\;\[\]]/.test(ch)) { + // no highlightning return null; } else if (ch == "#" || (ch == "-" && stream.eat("-") && stream.eat(" "))) { // 1-line comments @@ -46,9 +49,19 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { // multi-line comments state.tokenize = tokenComment; return state.tokenize(stream, state); + } else if (ch == ".") { + // .1 for 0.1 + if (stream.match(/^[0-9eE]+/) && support.zerolessFloat == true) { + return "number"; + } + // .table_name (ODBC) + if (stream.match(/^[a-zA-Z_]+/) && support.ODBCdotTable == true) { + return "variable-2"; + } } else if (operatorChars.test(ch)) { + // operators stream.eatWhile(operatorChars); - return false; + return null; } else if (ch == '{' && (stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) { // dates (weird ODBC syntax) @@ -63,10 +76,11 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { if (builtin.hasOwnProperty(word)) return "builtin"; if (keywords.hasOwnProperty(word)) return "keyword"; if (client.hasOwnProperty(word)) return "string-2"; - return "variable"; + return null; } } + // 'string', with char specified in quote escaped by '\' function tokenLiteral(quote) { return function(stream, state) { var escaped = false, ch; @@ -149,15 +163,15 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { (function() { "use strict"; - + + // `identifier` function hookIdentifier(stream) { var escaped = false, ch; - while ((ch = stream.next()) != null) { if (ch == "`" && !escaped) return "variable-2"; escaped = !escaped && ch == "`"; } - return false; + return null; } // variable token @@ -182,13 +196,13 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { } else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) { return "variable-2"; } - return false; + return null; }; // short client keyword token function hookClient(stream) { // \g, etc - return stream.match(/^[a-zA-Z]\b/) ? "variable-2" : false; + return stream.match(/^[a-zA-Z]\b/) ? "variable-2" : null; } var sqlKeywords = "alter and as asc between by count create delete desc distinct drop from having in insert into is join like not on or order select set table union update values where "; @@ -204,16 +218,20 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { keywords: set(sqlKeywords + "begin"), builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision real date datetime year unsigned signed decimal numeric"), atoms: set("false true null unknown"), - dateSQL: set("date time timestamp") + operatorChars: /^[*+\-%<>!=]/, + dateSQL: set("date time timestamp"), + support: set("ODBCdotTable") }); CodeMirror.defineMIME("text/x-mysql", { 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 + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), - builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed decimal numeric"), + builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^]/, dateSQL: set("date time timestamp"), + support: set("ODBCdotTable zerolessFloat"), hooks: { "@": hookVar, "`": hookIdentifier, @@ -225,9 +243,11 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { 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 + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), - builtin: set("bool boolean bit blob enum long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed decimal numeric"), + builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), atoms: set("false true null unknown"), + operatorChars: /^[*+\-%<>!=&|^]/, dateSQL: set("date time timestamp"), + support: set("ODBCdotTable zerolessFloat"), hooks: { "@": hookVar, "`": hookIdentifier, @@ -242,6 +262,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"), functions: set("abs acos add_months ascii asin atan atan2 average bfilename ceil chartorowid chr concat convert cos cosh count decode deref dual dump dup_val_on_index empty error exp false floor found glb greatest hextoraw initcap instr instrb isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mod months_between new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null nvl others power rawtohex reftohex round rowcount rowidtochar rpad rtrim sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid upper user userenv variance vsize"), builtin: set("bfile blob character clob dec float int integer mlslabel natural naturaln nchar nclob number numeric nvarchar2 real rowtype signtype smallint string varchar varchar2"), - dateSQL: set("date time timestamp"), + operatorChars: /^[*+\-%<>!=~]/, + dateSQL: set("date time timestamp") }); }()); From 9e4a3cd381c97d705da665082c6495c3e048a95a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 16 Jan 2013 11:07:44 +0100 Subject: [PATCH 0074/5273] Fix bug in lineIsHidden test It would occasionally mark lines as hidden that were needed to display parts of other lines. Issue #1161 --- lib/codemirror.js | 22 ++++++++++++++++------ test/test.js | 14 ++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index d0c0e83511..d9cf6571f8 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1057,8 +1057,9 @@ window.CodeMirror = (function() { var lineObj = getLine(doc, lineNo); var found = coordsCharInner(cm, lineObj, lineNo, x, y); var merged = collapsedSpanAtEnd(lineObj); - if (merged && found.ch == lineRight(lineObj)) - lineNo = merged.find().to.line; + var mergedPos = merged && merged.find(); + if (merged && found.ch >= mergedPos.from.ch) + lineNo = mergedPos.to.line; else return found; } @@ -3360,10 +3361,11 @@ window.CodeMirror = (function() { else updateLineHeight(line, 0); } addMarkedSpan(line, span); - if (marker.collapsed && curLine == from.line && lineIsHidden(line)) - updateLineHeight(line, 0); ++curLine; }); + if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) { + if (lineIsHidden(line)) updateLineHeight(line, 0); + }); if (marker.readOnly) { sawReadOnlySpans = true; @@ -3538,9 +3540,12 @@ window.CodeMirror = (function() { return true; } } - window.lineIsHidden = lineIsHidden; function lineIsHiddenInner(line, span) { - if (span.to == null || span.marker.inclusiveRight && span.to == line.text.length) + if (span.to == null) { + var end = span.marker.find().to, endLine = getLine(lineDoc(line), end.line); + return lineIsHiddenInner(endLine, getMarkedSpanFor(endLine.markedSpans, span.marker)); + } + if (span.marker.inclusiveRight && span.to == line.text.length) return true; for (var sp, i = 0; i < line.markedSpans.length; ++i) { sp = line.markedSpans[i]; @@ -4083,6 +4088,11 @@ window.CodeMirror = (function() { return no; } + function lineDoc(line) { + for (var d = line.parent; d.parent; d = d.parent) {} + return d; + } + function lineAtHeight(chunk, h) { var n = 0; outer: do { diff --git a/test/test.js b/test/test.js index 6eea43b5ac..b71114f319 100644 --- a/test/test.js +++ b/test/test.js @@ -543,6 +543,20 @@ testCM("collapsedLines", function(cm) { eq(cleared, 1); }); +testCM("collapsedRangeCoordsChar", function(cm) { + var pos_1_3 = cm.charCoords({line: 1, ch: 3}); + var opts = {collapsed: true, inclusiveLeft: true, inclusiveRight: true}; + var m1 = cm.markText({line: 0, ch: 0}, {line: 2, ch: 0}, opts); + eqPos(cm.coordsChar(pos_1_3), {line: 3, ch: 3}); + m1.clear(); + var m1 = cm.markText({line: 0, ch: 0}, {line: 1, ch: 1}, opts); + var m2 = cm.markText({line: 1, ch: 1}, {line: 2, ch: 0}, opts); + eqPos(cm.coordsChar(pos_1_3), {line: 3, ch: 3}); + m1.clear(); m2.clear(); + var m1 = cm.markText({line: 0, ch: 0}, {line: 1, ch: 6}, opts); + eqPos(cm.coordsChar(pos_1_3), {line: 3, ch: 3}); +}, {value: "123456\nabcdef\nghijkl\nmnopqr\n"}); + testCM("hiddenLinesAutoUnfold", function(cm) { var range = foldLines(cm, 1, 3, true), cleared = 0; CodeMirror.on(range, "clear", function() {cleared++;}); From d9d9eb7d74d4ad62f2c85b1238121628434fd029 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 16 Jan 2013 11:35:04 +0100 Subject: [PATCH 0075/5273] Update maxLine when adding or clearing a collapsed range Closes #1161 --- lib/codemirror.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index d9cf6571f8..f0f5ff3eec 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1967,7 +1967,7 @@ window.CodeMirror = (function() { if (!cm.options.lineWrapping) { checkWidthStart = lineNo(visualLine(doc, firstLine)); doc.iter(checkWidthStart, to.line + 1, function(line) { - if (lineLength(doc, line) == view.maxLineLength) { + if (line == view.maxLine) { recomputeMaxLength = true; return true; } @@ -3288,7 +3288,7 @@ window.CodeMirror = (function() { TextMarker.prototype.clear = function() { if (this.explicitlyCleared) return; startOperation(this.cm); - var min = null, max = null; + var view = this.cm.view, min = null, max = null; for (var i = 0; i < this.lines.length; ++i) { var line = this.lines[i]; var span = getMarkedSpanFor(line.markedSpans, this); @@ -3299,6 +3299,15 @@ window.CodeMirror = (function() { else if (this.collapsed && !lineIsHidden(line)) updateLineHeight(line, textHeight(this.cm.display)); } + if (this.collapsed && !this.cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { + var visual = visualLine(view.doc, this.lines[i]), len = lineLength(view.doc, visual); + if (len > view.maxLineLength) { + view.maxLine = visual; + view.maxLineLength = len; + view.maxLineChanged = true; + } + } + if (min != null) regChange(this.cm, min, max + 1); this.lines.length = 0; this.explicitlyCleared = true; @@ -3351,6 +3360,8 @@ window.CodeMirror = (function() { var curLine = from.line, size = 0, collapsedAtStart, collapsedAtEnd; doc.iter(curLine, to.line + 1, function(line) { + if (marker.collapsed && !cm.options.lineWrapping && visualLine(doc, line) == cm.view.maxLine) + cm.curOp.updateMaxLine = true; var span = {from: null, to: null, marker: marker}; size += line.text.length; if (curLine == from.line) {span.from = from.ch; size -= from.ch;} From 169947226d85270ee3c7e1136e3877c9584723ca Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 16 Jan 2013 11:48:43 +0100 Subject: [PATCH 0076/5273] Adjust test to work in Phantom.js --- test/test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test.js b/test/test.js index b71114f319..b4405d8b96 100644 --- a/test/test.js +++ b/test/test.js @@ -545,6 +545,7 @@ testCM("collapsedLines", function(cm) { testCM("collapsedRangeCoordsChar", function(cm) { var pos_1_3 = cm.charCoords({line: 1, ch: 3}); + pos_1_3.left += 2; pos_1_3.top += 2; var opts = {collapsed: true, inclusiveLeft: true, inclusiveRight: true}; var m1 = cm.markText({line: 0, ch: 0}, {line: 2, ch: 0}, opts); eqPos(cm.coordsChar(pos_1_3), {line: 3, ch: 3}); From 2dafec9d8fdd6f72eaccff3df1fa1d5afc655238 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 16 Jan 2013 13:20:18 +0100 Subject: [PATCH 0077/5273] [gfm mode] Remove link to nonexistent stylesheet --- mode/gfm/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/mode/gfm/index.html b/mode/gfm/index.html index b5bdb8888f..f413db19ef 100644 --- a/mode/gfm/index.html +++ b/mode/gfm/index.html @@ -16,7 +16,6 @@ - From 1c41c417f222483692a4f70af971a745632e8ae7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 16 Jan 2013 14:59:24 +0100 Subject: [PATCH 0078/5273] [gfm mode] Simplify URL regexp, since it's crashing Chrome Issue #1160 --- mode/gfm/gfm.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mode/gfm/gfm.js b/mode/gfm/gfm.js index 6ff557f266..1aec9f8c43 100644 --- a/mode/gfm/gfm.js +++ b/mode/gfm/gfm.js @@ -75,9 +75,10 @@ CodeMirror.defineMode("gfm", function(config) { return "link"; } } - if (stream.match(/^((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/i)) { + if (stream.match(/^((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/i)) { // URLs // Taken from http://daringfireball.net/2010/07/improved_regex_for_matching_urls + // And then (issue #1160) simplified to make it not crash the Chrome Regexp engine return "link"; } stream.next(); From 7fc76ca55ad72ab2ec6c8a792f240bd508d337fe Mon Sep 17 00:00:00 2001 From: shaun gilchrist Date: Mon, 21 Jan 2013 10:00:55 +0100 Subject: [PATCH 0079/5273] Add APL mode --- mode/apl/apl.js | 160 ++++++++++++++++++++++++++++++++++++++++++++ mode/apl/index.html | 61 +++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 mode/apl/apl.js create mode 100644 mode/apl/index.html diff --git a/mode/apl/apl.js b/mode/apl/apl.js new file mode 100644 index 0000000000..4accd3f7ce --- /dev/null +++ b/mode/apl/apl.js @@ -0,0 +1,160 @@ +CodeMirror.defineMode("apl", function(config, parserConfig) { + var builtInOps = { + ".": "innerProduct", + "\\": "scan", + "/": "reduce", + "⌿": "reduce1Axis", + "⍀": "scan1Axis", + "¨": "each", + "⍣": "power" + }; + var builtInFuncs = { + "+": ["conjugate", "add"], + "−": ["negate", "subtract"], + "×": ["signOf", "multiply"], + "÷": ["reciprocal", "divide"], + "⌈": ["ceiling", "greaterOf"], + "⌊": ["floor", "lesserOf"], + "∣": ["absolute", "residue"], + "⍳": ["indexGenerate", "indexOf"], + "?": ["roll", "deal"], + "⋆": ["exponentiate", "toThePowerOf"], + "⍟": ["naturalLog", "logToTheBase"], + "○": ["piTimes", "circularFuncs"], + "!": ["factorial", "binomial"], + "⌹": ["matrixInverse", "matrixDivide"], + "<": [null, "lessThan"], + "≤": [null, "lessThanOrEqual"], + "=": [null, "equals"], + ">": [null, "greaterThan"], + "≥": [null, "greaterThanOrEqual"], + "≠": [null, "notEqual"], + "≡": ["depth", "match"], + "≢": [null, "notMatch"], + "∈": ["enlist", "membership"], + "⍷": [null, "find"], + "∪": ["unique", "union"], + "∩": [null, "intersection"], + "∼": ["not", "without"], + "∨": [null, "or"], + "∧": [null, "and"], + "⍱": [null, "nor"], + "⍲": [null, "nand"], + "⍴": ["shapeOf", "reshape"], + ",": ["ravel", "catenate"], + "⍪": [null, "firstAxisCatenate"], + "⌽": ["reverse", "rotate"], + "⊖": ["axis1Reverse", "axis1Rotate"], + "⍉": ["transpose", null], + "↑": ["first", "take"], + "↓": [null, "drop"], + "⊂": ["enclose", "partitionWithAxis"], + "⊃": ["diclose", "pick"], + "⌷": [null, "index"], + "⍋": ["gradeUp", null], + "⍒": ["gradeDown", null], + "⊤": ["encode", null], + "⊥": ["decode", null], + "⍕": ["format", "formatByExample"], + "⍎": ["execute", null], + "⊣": ["stop", "left"], + "⊢": ["pass", "right"] + }; + + var isOperator = /[\.\/⌿⍀¨⍣]/; + var isNiladic = /⍬/; + var isFunction = /[\+−×÷⌈⌊∣⍳\?⋆⍟○!⌹<≤=>≥≠≡≢∈⍷∪∩∼∨∧⍱⍲⍴,⍪⌽⊖⍉↑↓⊂⊃⌷⍋⍒⊤⊥⍕⍎⊣⊢]/; + var isArrow = /←/; + var isComment = /[⍝#].*$/; + + var stringEater = function(type) { + var prev; + prev = false; + return function(c) { + prev = c; + if (c === type) { + return prev === "\\"; + } + return true; + }; + }; + return { + startState: function() { + return { + prev: false, + func: false, + op: false, + string: false, + escape: false + }; + }, + token: function(stream, state) { + var ch, funcName, word; + if (stream.eatSpace()) { + return null; + } + ch = stream.next(); + if (ch === '"' || ch === "'") { + stream.eatWhile(stringEater(ch)); + stream.next(); + state.prev = true; + return "string"; + } + if (/[\[{\(]/.test(ch)) { + state.prev = false; + return null; + } + if (/[\]}\)]/.test(ch)) { + state.prev = true; + return null; + } + if (isNiladic.test(ch)) { + state.prev = false; + return "niladic"; + } + if (/[¯\d]/.test(ch)) { + if (state.func) { + state.func = false; + state.prev = false; + } else { + state.prev = true; + } + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (isOperator.test(ch)) { + return "operator apl-" + builtInOps[ch]; + } + if (isArrow.test(ch)) { + return "apl-arrow"; + } + if (isFunction.test(ch)) { + funcName = "apl-"; + if (builtInFuncs[ch] != null) { + if (state.prev) { + funcName += builtInFuncs[ch][1]; + } else { + funcName += builtInFuncs[ch][0]; + } + } + state.func = true; + state.prev = false; + return "function " + funcName; + } + if (isComment.test(ch)) { + stream.skipToEnd(); + return "comment"; + } + if (ch === "∘" && stream.peek() === ".") { + stream.next(); + return "function jot-dot"; + } + stream.eatWhile(/[\w\$_]/); + word = stream.current(); + state.prev = true; + return "keyword"; + } + }; +}); + +CodeMirror.defineMIME("text/apl", "apl"); diff --git a/mode/apl/index.html b/mode/apl/index.html new file mode 100644 index 0000000000..119ff17f19 --- /dev/null +++ b/mode/apl/index.html @@ -0,0 +1,61 @@ + + + + + CodeMirror: APL mode + + + + + + + + +

    CodeMirror: APL mode

    + +
    + + + +

    Simple mode that tries to handle APL as well as it can.

    +

    It attempts to label functions/operators based upon + monadic/dyadic usage (but this is far from fully fleshed out). + This means there are meaningful classnames so hover states can + have popups etc.

    + +

    MIME types defined: text/apl (APL code)

    + + From 180e75271b9562e8f5f59e56590a431d4fe99427 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Jan 2013 10:03:04 +0100 Subject: [PATCH 0080/5273] Integrate APL mode --- doc/compress.html | 1 + doc/modes.html | 1 + mode/apl/apl.js | 2 +- mode/meta.js | 11 ++++++----- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 2315838c80..313735f234 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -68,6 +68,7 @@

    { } CodeMi + diff --git a/doc/modes.html b/doc/modes.html index 7c072971c2..877227492f 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -23,6 +23,7 @@

    { } CodeMi
      +
    • APL
    • Asterisk dialplan
    • C, C++, C#
    • Clojure
    • diff --git a/mode/apl/apl.js b/mode/apl/apl.js index 4accd3f7ce..5c23af85da 100644 --- a/mode/apl/apl.js +++ b/mode/apl/apl.js @@ -1,4 +1,4 @@ -CodeMirror.defineMode("apl", function(config, parserConfig) { +CodeMirror.defineMode("apl", function() { var builtInOps = { ".": "innerProduct", "\\": "scan", diff --git a/mode/meta.js b/mode/meta.js index f670a569a6..ad212f9663 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -1,9 +1,10 @@ CodeMirror.modeInfo = [ - {name: 'Asterisk', mime: 'x-asterisk', mode: 'asterisk'}, - {name: 'C', mime: 'x-csrc', mode: 'clike'}, - {name: 'C++', mime: 'x-c++src', mode: 'clike'}, - {name: 'Java', mime: 'x-java', mode: 'clike'}, - {name: 'C#', mime: 'x-csharp', mode: 'clike'}, + {name: 'APL', mime: 'text/apl', mode: 'apl'}, + {name: 'Asterisk', mime: 'text/x-asterisk', mode: 'asterisk'}, + {name: 'C', mime: 'text/x-csrc', mode: 'clike'}, + {name: 'C++', mime: 'text/x-c++src', mode: 'clike'}, + {name: 'Java', mime: 'text/x-java', mode: 'clike'}, + {name: 'C#', mime: 'text/x-csharp', mode: 'clike'}, {name: 'Scala', mime: 'text/x-scala', mode: 'clike'}, {name: 'Clojure', mime: 'text/x-clojure', mode: 'clojure'}, {name: 'CoffeeScript', mime: 'text/x-coffeescript', mode: 'coffeescript'}, From 2f37f66531abd6f0d20bfdf7819e0a7f345f12ce Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Jan 2013 10:28:11 +0100 Subject: [PATCH 0081/5273] Properly restore horizonal scroll position on refresh() calls Issue #1164 --- lib/codemirror.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index f0f5ff3eec..487ed90d69 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2829,8 +2829,11 @@ window.CodeMirror = (function() { refresh: function() { clearCaches(this); - if (this.display.scroller.scrollHeight > this.view.scrollTop) - this.display.scrollbarV.scrollTop = this.display.scroller.scrollTop = this.view.scrollTop; + var sTop = this.view.scrollTop, sLeft = this.view.scrollLeft; + if (this.display.scroller.scrollHeight > sTop) + this.display.scrollbarV.scrollTop = this.display.scroller.scrollTop = sTop; + if (this.display.scroller.scrollWidth > sLeft) + this.display.scrollbarH.scrollLeft = this.display.scroller.scrollLeft = sLeft; updateDisplay(this, true); }, From 48c2e8e454035c1849a1cbcce4503b564a4f26e9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Jan 2013 10:47:06 +0100 Subject: [PATCH 0082/5273] Fix workaround for webkit bug in rendering of overlong text nodes Issue #1163 --- lib/codemirror.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 487ed90d69..08a33030be 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -565,7 +565,7 @@ window.CodeMirror = (function() { node.style.display = "none"; node.lineObj = null; } else { - container.removeChild(node); + node.parentNode.removeChild(node); } return next; } @@ -3697,8 +3697,9 @@ window.CodeMirror = (function() { while (!stream.eol()) { var style = mode.token(stream, state); if (stream.pos > 5000) { + flattenSpans = false; // Webkit seems to refuse to render text nodes longer than 57444 characters - stream.pos = Math.min(text.length, stream.pos + 50000); + stream.pos = Math.min(text.length, stream.start + 50000); style = null; } var substr = stream.current(); From 83889141142bf897bfcce164dfa4c871232a3b6d Mon Sep 17 00:00:00 2001 From: Peter Kroon Date: Fri, 18 Jan 2013 13:09:40 +0100 Subject: [PATCH 0083/5273] Add Opera Mobile UA to the mobile list Add Opera Mobile UA to the mobile list. --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 08a33030be..308d0ecb82 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -22,7 +22,7 @@ window.CodeMirror = (function() { var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent); // This is woefully incomplete. Suggestions for alternative methods welcome. - var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|IEMobile/i.test(navigator.userAgent); + var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent); var mac = ios || /Mac/.test(navigator.platform); var windows = /windows/i.test(navigator.platform); From a14e1e91df89d5058191b324a2ed59fcca8e8d95 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Jan 2013 11:07:02 +0100 Subject: [PATCH 0084/5273] Make sure the editor is re-focused after a no-op drag Closes #1168 --- lib/codemirror.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 308d0ecb82..6f8f09b1f3 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1560,7 +1560,8 @@ window.CodeMirror = (function() { // Don't do a replace if the drop happened inside of the selected text. if (cm.view.draggingText && !(posLess(pos, cm.view.sel.from) || posLess(cm.view.sel.to, pos))) { cm.view.draggingText(e); - if (ie) setTimeout(bind(focusInput, cm), 50); + // Ensure the editor is re-focused + setTimeout(bind(focusInput, cm), 20); return; } try { From e4c42b562d94dfe3f22c31ba9db70c10fa5dbd7f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Jan 2013 11:24:59 +0100 Subject: [PATCH 0085/5273] [formatting addon] Don't line-break around inline tags --- addon/format/formatting.js | 10 ++++++++-- demo/formatting.html | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/addon/format/formatting.js b/addon/format/formatting.js index 25ee1531a8..88b84307f6 100644 --- a/addon/format/formatting.js +++ b/addon/format/formatting.js @@ -22,11 +22,17 @@ } }); + var inlineElements = /^(a|abbr|acronym|area|base|bdo|big|br|button|caption|cite|code|col|colgroup|dd|del|dfn|em|frame|hr|iframe|img|input|ins|kbd|label|legend|link|map|object|optgroup|option|param|q|samp|script|select|small|span|strong|sub|sup|textarea|tt|var)$/; + CodeMirror.extendMode("xml", { commentStart: "", - newlineAfterToken: function(type, content, textAfter) { - return type == "tag" && />$/.test(content) || /^$/.test(content) && state.context) || + /^CodeMirror: Formatting demo

    function test(c){ for (var i = 0; i < 10; i++){ process("a.b();c = null;", 300);} } -
    test 1
    test 2
    +
    test 1
    test 2
    From e653b1b87fe9e39b1a0eef3f87d0108d19d02acc Mon Sep 17 00:00:00 2001 From: Adam King Date: Sun, 20 Jan 2013 18:34:26 -0500 Subject: [PATCH 0086/5273] Fix brace indenting for clojure maps. --- mode/clojure/clojure.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mode/clojure/clojure.js b/mode/clojure/clojure.js index 3fdabd263a..5d90edb8a5 100644 --- a/mode/clojure/clojure.js +++ b/mode/clojure/clojure.js @@ -142,7 +142,7 @@ CodeMirror.defineMode("clojure", function () { returnType = COMMENT; } else if (isNumber(ch,stream)){ returnType = NUMBER; - } else if (ch == "(" || ch == "[") { + } else if (ch == "(" || ch == "[" || ch == "{" ) { var keyWord = '', indentTemp = stream.column(), letter; /** Either @@ -172,9 +172,9 @@ CodeMirror.defineMode("clojure", function () { stream.backUp(stream.current().length - 1); // undo all the eating returnType = BRACKET; - } else if (ch == ")" || ch == "]") { + } else if (ch == ")" || ch == "]" || ch == "}") { returnType = BRACKET; - if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : "[")) { + if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : (ch == "]" ? "[" :"{"))) { popStack(state); } } else if ( ch == ":" ) { From f2d2938724a81b17c26e8f5017e48c253791b9ff Mon Sep 17 00:00:00 2001 From: Peter Kroon Date: Fri, 18 Jan 2013 15:51:21 +0100 Subject: [PATCH 0087/5273] Append image to wrapper Append image to wrapper. No more appending to document. Works with multiple editors. Tested: 3 editors beneath each other on 1 page. --- lib/codemirror.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 6f8f09b1f3..39df6944c2 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -168,6 +168,15 @@ window.CodeMirror = (function() { // Used for measuring wheel scrolling granularity d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; + + //opera setDragImage hack + if (opera) { + var img = elt('img'); + img.width = '1'; + img.height = '1'; + img.setAttribute('style','position:fixed; top:0; left:0; right:0'); + d.wrapper.appendChild(img); + } return d; } @@ -1612,8 +1621,9 @@ window.CodeMirror = (function() { // 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. + var img = opera ? cm.display.wrapper.getElementsByTagName('img')[0] : elt('img'); if (e.dataTransfer.setDragImage && !safari) - e.dataTransfer.setDragImage(elt('img'), 0, 0); + e.dataTransfer.setDragImage(img, 0, 0); } function setScrollTop(cm, val) { From 4797771d9028f825bc93ce7ce5e0b3f2dc382ca9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Jan 2013 12:39:59 +0100 Subject: [PATCH 0088/5273] Clean up Opera setDragImage patch Issue #1166 --- lib/codemirror.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 39df6944c2..27d1132d49 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -169,15 +169,6 @@ window.CodeMirror = (function() { // Used for measuring wheel scrolling granularity d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; - //opera setDragImage hack - if (opera) { - var img = elt('img'); - img.width = '1'; - img.height = '1'; - img.setAttribute('style','position:fixed; top:0; left:0; right:0'); - d.wrapper.appendChild(img); - } - return d; } @@ -1621,9 +1612,17 @@ window.CodeMirror = (function() { // 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. - var img = opera ? cm.display.wrapper.getElementsByTagName('img')[0] : elt('img'); - if (e.dataTransfer.setDragImage && !safari) + if (e.dataTransfer.setDragImage && !safari) { + var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); + if (opera) { + 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; + } e.dataTransfer.setDragImage(img, 0, 0); + if (opera) img.parentNode.removeChild(img); + } } function setScrollTop(cm, val) { From 32abd31833b7e9f18b8929f5996bf7ae1f00d99f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Jan 2013 13:25:23 +0100 Subject: [PATCH 0089/5273] Mark release 3.01 --- doc/compress.html | 6 ++---- doc/oldrelease.html | 18 ++++++++++++++++++ index.html | 44 +++++++++++++++++++++++++------------------ lib/codemirror.js | 2 +- mode/mysql/index.html | 2 ++ mode/plsql/index.html | 2 ++ package.json | 2 +- 7 files changed, 52 insertions(+), 24 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 313735f234..94f293c725 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -30,11 +30,9 @@

    { } CodeMi

    Version: +     +

    +
    +
    + Select buffer: +     +
    + + + +

    Demonstration of + using linked documents + to provide a split view on a document, and + using swapDoc + to use a single editor to display multiple documents.

    + + + diff --git a/keymap/vim.js b/keymap/vim.js index ec85c28228..fb11848a11 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -810,9 +810,6 @@ selectionStart.ch = lineLength(cm, selectionStart.line); } } - // Need to set the cursor to clear the selection. Otherwise, - // CodeMirror can't figure out that we changed directions... - cm.setCursor(selectionStart); cm.setSelection(selectionStart, selectionEnd); updateMark(cm, vim, '<', cursorIsBefore(selectionStart, selectionEnd) ? selectionStart diff --git a/lib/codemirror.js b/lib/codemirror.js index 61c72a5ae0..58cbc0da14 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -45,24 +45,32 @@ window.CodeMirror = (function() { options[opt] = defaults[opt]; setGuttersForLineNumbers(options); - var display = this.display = makeDisplay(place); + var docStart = typeof options.value == "string" ? 0 : options.value.first; + var display = this.display = makeDisplay(place, docStart); display.wrapper.CodeMirror = this; updateGutters(this); if (options.autofocus && !mobile) focusInput(this); - this.view = makeView(new BranchChunk([new LeafChunk([makeLine("", null, textHeight(display))])])); + this.state = {keyMaps: [], + overlays: [], + modeGen: 0, + overwrite: false, focused: false, + suppressEdits: false, pasteIncoming: false, + draggingText: false, + highlight: new Delayed()}; + this.nextOpId = 0; - loadMode(this); themeChanged(this); if (options.lineWrapping) this.display.wrapper.className += " CodeMirror-wrap"; - // Initialize the content. - this.setValue(options.value || ""); + var doc = options.value; + if (typeof doc == "string") doc = new Doc(options.value, options.mode); + operation(this, attachDoc)(this, doc); + // Override magic textarea content restore that IE sometimes does // on our hidden textarea on reload if (ie) setTimeout(bind(resetInput, this, true), 20); - this.view.history = makeHistory(); registerEventHandlers(this); // IE throws unspecified error in certain cases, when @@ -81,7 +89,7 @@ window.CodeMirror = (function() { // DISPLAY CONSTRUCTOR - function makeDisplay(place) { + function makeDisplay(place, docStart) { var d = {}; var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none;"); if (webkit) input.style.width = "1000px"; @@ -135,7 +143,8 @@ window.CodeMirror = (function() { else if (ie_lt8) d.scrollbarH.style.minWidth = d.scrollbarV.style.minWidth = "18px"; // Current visible range (may be bigger than the view window). - d.viewOffset = d.showingFrom = d.showingTo = d.lastSizeC = 0; + d.viewOffset = d.lastSizeC = 0; + d.showingFrom = d.showingTo = docStart; // Used to only resize the line number gutter when necessary (when // the amount of lines crosses a boundary that makes its width change) @@ -162,9 +171,11 @@ window.CodeMirror = (function() { // string instead of the (large) selection. d.inaccurateSelection = false; - // Used to adjust overwrite behaviour when a paste has been - // detected - d.pasteIncoming = false; + // 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; // Used for measuring wheel scrolling granularity d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; @@ -172,70 +183,55 @@ window.CodeMirror = (function() { return d; } - // VIEW CONSTRUCTOR - - function makeView(doc) { - var selPos = {line: 0, ch: 0}; - return { - doc: doc, - // frontier is the point up to which the content has been parsed, - frontier: 0, highlight: new Delayed(), - sel: {from: selPos, to: selPos, head: selPos, anchor: selPos, shift: false, extend: false}, - scrollTop: 0, scrollLeft: 0, - overwrite: false, focused: false, - // Tracks the maximum line length so that - // the horizontal scrollbar can be kept - // static when scrolling. - maxLine: getLine(doc, 0), - maxLineLength: 0, - maxLineChanged: false, - suppressEdits: false, - goalColumn: null, - cantEdit: false, - keyMaps: [], - overlays: [], - modeGen: 0 - }; - } - // STATE UPDATES // Used to get the editor into a consistent state again when options change. function loadMode(cm) { - var doc = cm.view.doc; - cm.view.mode = CodeMirror.getMode(cm.options, cm.options.mode); - doc.iter(0, doc.size, function(line) { + cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); + cm.doc.iter(function(line) { if (line.stateAfter) line.stateAfter = null; if (line.styles) line.styles = null; }); - cm.view.frontier = 0; + cm.doc.frontier = cm.doc.first; startWorker(cm, 100); - cm.view.modeGen++; - if (cm.curOp) regChange(cm, 0, doc.size); + cm.state.modeGen++; + if (cm.curOp) regChange(cm); } function wrappingChanged(cm) { - var doc = cm.view.doc, th = textHeight(cm.display); if (cm.options.lineWrapping) { cm.display.wrapper.className += " CodeMirror-wrap"; - var perLine = cm.display.scroller.clientWidth / charWidth(cm.display) - 3; - doc.iter(0, doc.size, function(line) { - if (line.height == 0) return; - var guess = Math.ceil(line.text.length / perLine) || 1; - if (guess != 1) updateLineHeight(line, guess * th); - }); cm.display.sizer.style.minWidth = ""; } else { cm.display.wrapper.className = cm.display.wrapper.className.replace(" CodeMirror-wrap", ""); - computeMaxLength(cm.view); - doc.iter(0, doc.size, function(line) { - if (line.height != 0) updateLineHeight(line, th); - }); + computeMaxLength(cm); } - regChange(cm, 0, doc.size); + estimateLineHeights(cm); + regChange(cm); clearCaches(cm); - setTimeout(function(){updateScrollbars(cm.display, cm.view.doc.height);}, 100); + setTimeout(function(){updateScrollbars(cm.display, cm.doc.height);}, 100); + } + + 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); + return function(line) { + if (lineIsHidden(line)) + return 0; + else if (wrapping) + return (Math.ceil(line.text.length / perLine) || 1) * th; + else + return th; + }; + } + + function estimateLineHeights(cm) { + var doc = cm.doc, est = estimateHeight(cm); + doc.iter(function(line) { + var estHeight = est(line); + if (estHeight != line.height) updateLineHeight(line, estHeight); + }); } function keyMapChanged(cm) { @@ -287,15 +283,16 @@ window.CodeMirror = (function() { return len; } - function computeMaxLength(view) { - view.maxLine = getLine(view.doc, 0); - view.maxLineLength = lineLength(view.doc, view.maxLine); - view.maxLineChanged = true; - view.doc.iter(1, view.doc.size, function(line) { - var len = lineLength(view.doc, line); - if (len > view.maxLineLength) { - view.maxLineLength = len; - view.maxLine = line; + function computeMaxLength(cm) { + var d = cm.display, doc = cm.doc; + d.maxLine = getLine(doc, doc.first); + d.maxLineLength = lineLength(doc, d.maxLine); + d.maxLineChanged = true; + doc.iter(function(line) { + var len = lineLength(doc, line); + if (len > d.maxLineLength) { + d.maxLineLength = len; + d.maxLine = line; } }); } @@ -359,7 +356,7 @@ window.CodeMirror = (function() { function alignHorizontally(cm) { var display = cm.display; if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; - var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.view.scrollLeft; + var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; var gutterW = display.gutters.offsetWidth, l = comp + "px"; for (var n = display.lineDiv.firstChild; n; n = n.nextSibling) if (n.alignable) { for (var i = 0, a = n.alignable; i < a.length; ++i) a[i].style.left = l; @@ -370,7 +367,7 @@ window.CodeMirror = (function() { function maybeUpdateLineNumberWidth(cm) { if (!cm.options.lineNumbers) return false; - var doc = cm.view.doc, last = lineNumberFor(cm.options, doc.size - 1), display = cm.display; + 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")); @@ -398,12 +395,12 @@ window.CodeMirror = (function() { var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo; var updated = updateDisplayInner(cm, changes, viewPort); if (updated) { - signalLater(cm, cm, "update", cm); + signalLater(cm, "update", cm); if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo) - signalLater(cm, cm, "viewportChange", cm, cm.display.showingFrom, cm.display.showingTo); + signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display.showingTo); } updateSelection(cm); - updateScrollbars(cm.display, cm.view.doc.height); + updateScrollbars(cm.display, cm.doc.height); return updated; } @@ -412,9 +409,10 @@ window.CodeMirror = (function() { // determine which DOM updates have to be made, and makes the // updates. function updateDisplayInner(cm, changes, viewPort) { - var display = cm.display, doc = cm.view.doc; + var display = cm.display, doc = cm.doc; if (!display.wrapper.clientWidth) { - display.showingFrom = display.showingTo = display.viewOffset = 0; + display.showingFrom = display.showingTo = doc.first; + display.viewOffset = 0; return; } @@ -445,24 +443,26 @@ window.CodeMirror = (function() { } // Used to determine which lines need their line numbers updated - var positionsChangedFrom = changes === true ? 0 : Infinity; + var positionsChangedFrom = changes === true ? doc.first : Infinity; if (cm.options.lineNumbers && changes && changes !== true) for (var i = 0; i < changes.length; ++i) if (changes[i].diff) { positionsChangedFrom = changes[i].from; break; } - var from = Math.max(visible.from - cm.options.viewportMargin, 0); - var to = Math.min(doc.size, visible.to + cm.options.viewportMargin); - if (display.showingFrom < from && from - display.showingFrom < 20) from = display.showingFrom; - if (display.showingTo > to && display.showingTo - to < 20) to = Math.min(doc.size, display.showingTo); + var end = doc.first + doc.size; + var from = Math.max(visible.from - cm.options.viewportMargin, doc.first); + var to = Math.min(end, visible.to + cm.options.viewportMargin); + if (display.showingFrom < from && from - display.showingFrom < 20) from = Math.max(doc.first, display.showingFrom); + if (display.showingTo > to && display.showingTo - to < 20) to = Math.min(end, display.showingTo); if (sawCollapsedSpans) { from = lineNo(visualLine(doc, getLine(doc, from))); - while (to < doc.size && lineIsHidden(getLine(doc, to))) ++to; + while (to < end && lineIsHidden(getLine(doc, to))) ++to; } // Create a range of theoretically intact lines, and punch holes // in that using the change info. var intact = changes === true ? [] : computeIntact([{from: display.showingFrom, to: display.showingTo}], changes); + // Clip off the parts that won't be visible var intactLines = 0; for (var i = 0; i < intact.length; ++i) { @@ -570,9 +570,9 @@ window.CodeMirror = (function() { return next; } - var nextIntact = intact.shift(), lineNo = from; - cm.view.doc.iter(from, to, function(line) { - if (nextIntact && nextIntact.to == lineNo) nextIntact = intact.shift(); + var nextIntact = intact.shift(), lineN = from; + cm.doc.iter(from, to, function(line) { + if (nextIntact && nextIntact.to == lineN) nextIntact = intact.shift(); if (lineIsHidden(line)) { if (line.height != 0) updateLineHeight(line, 0); if (line.widgets && cur.previousSibling) for (var i = 0; i < line.widgets.length; ++i) @@ -586,20 +586,20 @@ window.CodeMirror = (function() { } prev.appendChild(buildLineWidget(line.widgets[i], prev, dims)); } - } else if (nextIntact && nextIntact.from <= lineNo && nextIntact.to > lineNo) { + } else if (nextIntact && nextIntact.from <= lineN && nextIntact.to > lineN) { // This line is intact. Skip to the actual node. Update its // line number if needed. while (cur.lineObj != line) cur = rm(cur); - if (lineNumbers && updateNumbersFrom <= lineNo && cur.lineNumber) - setTextContent(cur.lineNumber, lineNumberFor(cm.options, lineNo)); + if (lineNumbers && updateNumbersFrom <= lineN && cur.lineNumber) + setTextContent(cur.lineNumber, lineNumberFor(cm.options, lineN)); cur = cur.nextSibling; } else { // This line needs to be generated. - var lineNode = buildLineElement(cm, line, lineNo, dims); + var lineNode = buildLineElement(cm, line, lineN, dims); container.insertBefore(lineNode, cur); lineNode.lineObj = line; } - ++lineNo; + ++lineN; }); while (cur) cur = rm(cur); } @@ -674,7 +674,7 @@ window.CodeMirror = (function() { function updateSelection(cm) { var display = cm.display; - var collapsed = posEq(cm.view.sel.from, cm.view.sel.to); + var collapsed = posEq(cm.doc.sel.from, cm.doc.sel.to); if (collapsed || cm.options.showCursorWhenSelecting) updateSelectionCursor(cm); else @@ -685,7 +685,7 @@ window.CodeMirror = (function() { display.selectionDiv.style.display = "none"; // Move the hidden textarea near the cursor to prevent scrolling artifacts - var headPos = cursorCoords(cm, cm.view.sel.head, "div"); + var headPos = cursorCoords(cm, cm.doc.sel.head, "div"); var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); display.inputDiv.style.top = Math.max(0, Math.min(display.wrapper.clientHeight - 10, headPos.top + lineOff.top - wrapOff.top)) + "px"; @@ -695,7 +695,7 @@ window.CodeMirror = (function() { // No selection, plain cursor function updateSelectionCursor(cm) { - var display = cm.display, pos = cursorCoords(cm, cm.view.sel.head, "div"); + var display = cm.display, pos = cursorCoords(cm, cm.doc.sel.head, "div"); display.cursor.style.left = pos.left + "px"; display.cursor.style.top = pos.top + "px"; display.cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; @@ -711,7 +711,7 @@ window.CodeMirror = (function() { // Highlight selection function updateSelectionRange(cm) { - var display = cm.display, doc = cm.view.doc, sel = cm.view.sel; + var display = cm.display, doc = cm.doc, sel = cm.doc.sel; var fragment = document.createDocumentFragment(); var clientWidth = display.lineSpace.offsetWidth, pl = paddingLeft(cm.display); @@ -804,33 +804,33 @@ window.CodeMirror = (function() { // HIGHLIGHT WORKER function startWorker(cm, time) { - if (cm.view.mode.startState && cm.view.frontier < cm.display.showingTo) - cm.view.highlight.set(time, bind(highlightWorker, cm)); + if (cm.doc.mode.startState && cm.doc.frontier < cm.display.showingTo) + cm.state.highlight.set(time, bind(highlightWorker, cm)); } function highlightWorker(cm) { - var view = cm.view, doc = view.doc; - if (view.frontier >= cm.display.showingTo) return; + var doc = cm.doc; + if (doc.frontier < doc.first) doc.frontier = doc.first; + if (doc.frontier >= cm.display.showingTo) return; var end = +new Date + cm.options.workTime; - var state = copyState(view.mode, getStateBefore(cm, view.frontier)); + var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); var changed = [], prevChange; - doc.iter(view.frontier, Math.min(doc.size, cm.display.showingTo + 500), function(line) { - if (view.frontier >= cm.display.showingFrom) { // Visible + doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.showingTo + 500), function(line) { + if (doc.frontier >= cm.display.showingFrom) { // Visible var oldStyles = line.styles; line.styles = highlightLine(cm, line, state); var ischange = !oldStyles || oldStyles.length != line.styles.length; - for (var i = 0; !ischange && i < oldStyles.length; ++i) - ischange = oldStyles[i] != line.styles[i]; + for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; if (ischange) { - if (prevChange && prevChange.end == view.frontier) prevChange.end++; - else changed.push(prevChange = {start: view.frontier, end: view.frontier + 1}); + if (prevChange && prevChange.end == doc.frontier) prevChange.end++; + else changed.push(prevChange = {start: doc.frontier, end: doc.frontier + 1}); } - line.stateAfter = copyState(view.mode, state); + line.stateAfter = copyState(doc.mode, state); } else { processLine(cm, line, state); - line.stateAfter = view.frontier % 5 == 0 ? copyState(view.mode, state) : null; + line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; } - ++view.frontier; + ++doc.frontier; if (+new Date > end) { startWorker(cm, cm.options.workDelay); return true; @@ -849,10 +849,10 @@ window.CodeMirror = (function() { // smallest indentation, which tends to need the least context to // parse correctly. function findStartLine(cm, n) { - var minindent, minline, doc = cm.view.doc; + var minindent, minline, doc = cm.doc; for (var search = n, lim = n - 100; search > lim; --search) { - if (search == 0) return 0; - var line = getLine(doc, search-1); + if (search <= doc.first) return doc.first; + var line = getLine(doc, search - 1); if (line.stateAfter) return search; var indented = countColumn(line.text, null, cm.options.tabSize); if (minline == null || minindent > indented) { @@ -864,15 +864,15 @@ window.CodeMirror = (function() { } function getStateBefore(cm, n) { - var view = cm.view; - if (!view.mode.startState) return true; - var pos = findStartLine(cm, n), state = pos && getLine(view.doc, pos-1).stateAfter; - if (!state) state = startState(view.mode); - else state = copyState(view.mode, state); - view.doc.iter(pos, n, function(line) { + var doc = cm.doc, display = cm.display; + if (!doc.mode.startState) return true; + var pos = findStartLine(cm, n), 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, state); - var save = pos == n - 1 || pos % 5 == 0 || pos >= view.showingFrom && pos < view.showingTo; - line.stateAfter = save ? copyState(view.mode, state) : null; + var save = pos == n - 1 || pos % 5 == 0 || pos >= display.showingFrom && pos < display.showingTo; + line.stateAfter = save ? copyState(doc.mode, state) : null; ++pos; }); return state; @@ -979,7 +979,7 @@ window.CodeMirror = (function() { function clearCaches(cm) { cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0; cm.display.cachedCharWidth = cm.display.cachedTextHeight = null; - cm.view.maxLineChanged = true; + cm.display.maxLineChanged = true; } // Context is one of "line", "div" (display.lineDiv), "local"/null (editor), or "page" @@ -1003,12 +1003,12 @@ window.CodeMirror = (function() { } function charCoords(cm, pos, context, lineObj) { - if (!lineObj) lineObj = getLine(cm.view.doc, pos.line); + if (!lineObj) lineObj = getLine(cm.doc, pos.line); return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch), context); } function cursorCoords(cm, pos, context, lineObj, measurement) { - lineObj = lineObj || getLine(cm.view.doc, pos.line); + lineObj = lineObj || getLine(cm.doc, pos.line); if (!measurement) measurement = measureLine(cm, lineObj); function get(ch, right) { var m = measureChar(cm, lineObj, ch, measurement); @@ -1046,11 +1046,12 @@ window.CodeMirror = (function() { // Coords must be lineSpace-local function coordsChar(cm, x, y) { - var doc = cm.view.doc; + var doc = cm.doc; y += cm.display.viewOffset; - if (y < 0) return {line: 0, ch: 0, outside: true}; - var lineNo = lineAtHeight(doc, y); - if (lineNo >= doc.size) return {line: doc.size - 1, ch: getLine(doc, doc.size - 1).text.length}; + if (y < 0) return {line: doc.first, ch: 0, outside: true}; + var lineNo = lineAtHeight(doc, y), last = doc.first + doc.size - 1; + if (lineNo > last) + return {line: doc.size - 1, ch: getLine(doc, last).text.length}; if (x < 0) x = 0; for (;;) { @@ -1141,80 +1142,106 @@ window.CodeMirror = (function() { // batched and then all combined and executed at once. function startOperation(cm) { - if (cm.curOp) ++cm.curOp.depth; - else cm.curOp = { - // Nested operations delay update until the outermost one - // finishes. - depth: 1, + cm.curOp = { // An array of ranges of lines that have to be updated. See // updateDisplay. changes: [], - delayedCallbacks: [], updateInput: null, userSelChange: null, textChanged: null, selectionChanged: false, updateMaxLine: false, + updateScrollPos: false, id: ++cm.nextOpId }; + if (!delayedCallbackDepth++) delayedCallbacks = []; } function endOperation(cm) { - var op = cm.curOp; - if (--op.depth) return; + var op = cm.curOp, doc = cm.doc, delayed; + if (!--delayedCallbackDepth) { + delayed = delayedCallbacks; + delayedCallbacks = null; + } cm.curOp = null; - var view = cm.view, display = cm.display; - if (op.updateMaxLine) computeMaxLength(view); - if (view.maxLineChanged && !cm.options.lineWrapping) { - var width = measureChar(cm, view.maxLine, view.maxLine.text.length).right; + var display = cm.display; + if (op.updateMaxLine) computeMaxLength(cm); + if (cm.display.maxLineChanged && !cm.options.lineWrapping) { + var width = measureChar(cm, cm.display.maxLine, cm.display.maxLine.text.length).right; display.sizer.style.minWidth = (width + 3 + scrollerCutOff) + "px"; - view.maxLineChanged = false; + cm.display.maxLineChanged = false; var maxScrollLeft = Math.max(0, display.sizer.offsetLeft + display.sizer.offsetWidth - display.scroller.clientWidth); - if (maxScrollLeft < view.scrollLeft) + if (maxScrollLeft < doc.scrollLeft && !op.updateScrollPos) setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), true); } var newScrollPos, updated; - if (op.selectionChanged) { - var coords = cursorCoords(cm, view.sel.head); + if (op.updateScrollPos) { + newScrollPos = {scrollTop: doc.scrollTop, scrollLeft: doc.scrollLeft}; + } else if (op.selectionChanged) { + var coords = cursorCoords(cm, doc.sel.head); newScrollPos = calculateScrollPos(cm, coords.left, coords.top, coords.left, coords.bottom); } if (op.changes.length || newScrollPos && newScrollPos.scrollTop != null) updated = updateDisplay(cm, op.changes, newScrollPos && newScrollPos.scrollTop); if (!updated && op.selectionChanged) updateSelection(cm); - if (newScrollPos) scrollCursorIntoView(cm); + if (op.updateScrollPos) { + cm.display.scroller.scrollTop = doc.scrollTop; + cm.display.scroller.scrollLeft = doc.scrollLeft; + alignHorizontally(cm); + } else if (newScrollPos) { + scrollCursorIntoView(cm); + } if (op.selectionChanged) restartBlink(cm); - if (view.focused && op.updateInput) + if (cm.state.focused && op.updateInput) resetInput(cm, op.userSelChange); if (op.textChanged) signal(cm, "change", cm, op.textChanged); if (op.selectionChanged) signal(cm, "cursorActivity", cm); - for (var i = 0; i < op.delayedCallbacks.length; ++i) op.delayedCallbacks[i](cm); + if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i](cm); } // Wraps a function in an operation. Returns the wrapped function. function operation(cm1, f) { return function() { - var cm = cm1 || this; - startOperation(cm); - try {var result = f.apply(cm, arguments);} - finally {endOperation(cm);} + var cm = cm1 || this, mustEnd; + if (mustEnd = !cm.curOp) startOperation(cm); + try { var result = f.apply(cm, arguments); } + finally { if (mustEnd) endOperation(cm); } + return result; + }; + } + function docOperation(f) { + return function() { + var mustEnd, result; + if (mustEnd = this.cm && !this.cm.curOp) startOperation(this.cm); + try { result = f.apply(this, arguments); } + finally { if (mustEnd) endOperation(this.cm); } return result; }; } + function runInOp(cm, f) { + var mustEnd, result; + if (mustEnd = !cm.curOp) startOperation(cm); + try { result = f(); } + finally { if (mustEnd) endOperation(cm); } + return result; + } function regChange(cm, from, to, lendiff) { + if (from == null) from = cm.doc.first; + if (to == null) to = cm.doc.first + cm.doc.size; cm.curOp.changes.push({from: from, to: to, diff: lendiff}); } // INPUT HANDLING function slowPoll(cm) { - if (cm.view.pollingFast) return; + if (cm.display.pollingFast) return; cm.display.poll.set(cm.options.pollInterval, function() { readInput(cm); - if (cm.view.focused) slowPoll(cm); + if (cm.state.focused) slowPoll(cm); }); } @@ -1235,39 +1262,41 @@ window.CodeMirror = (function() { // events that indicate IME taking place, but these are not widely // supported or compatible enough yet to rely on.) function readInput(cm) { - var input = cm.display.input, prevInput = cm.display.prevInput, view = cm.view, sel = view.sel; - if (!view.focused || hasSelection(input) || isReadOnly(cm)) return false; + var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc, sel = doc.sel; + if (!cm.state.focused || hasSelection(input) || isReadOnly(cm)) return false; var text = input.value; if (text == prevInput && posEq(sel.from, sel.to)) return false; - startOperation(cm); - view.sel.shift = false; + var mustStart = !cm.curOp; + if (mustStart) startOperation(cm); + sel.shift = false; var same = 0, l = Math.min(prevInput.length, text.length); while (same < l && prevInput[same] == text[same]) ++same; var from = sel.from, to = sel.to; if (same < prevInput.length) from = {line: from.line, ch: from.ch - (prevInput.length - same)}; - else if (view.overwrite && posEq(from, to) && !cm.display.pasteIncoming) - to = {line: to.line, ch: Math.min(getLine(cm.view.doc, to.line).text.length, to.ch + (text.length - same))}; + else if (cm.state.overwrite && posEq(from, to) && !cm.state.pasteIncoming) + to = {line: to.line, ch: Math.min(getLine(doc, to.line).text.length, to.ch + (text.length - same))}; var updateInput = cm.curOp.updateInput; - updateDoc(cm, from, to, splitLines(text.slice(same)), "end", - cm.display.pasteIncoming ? "paste" : "input", {from: from, to: to}); + makeChange(cm.doc, {from: from, to: to, text: splitLines(text.slice(same)), + origin: cm.state.pasteIncoming ? "paste" : "input"}, "end"); + cm.curOp.updateInput = updateInput; if (text.length > 1000) input.value = cm.display.prevInput = ""; else cm.display.prevInput = text; - endOperation(cm); - cm.display.pasteIncoming = false; + if (mustStart) endOperation(cm); + cm.state.pasteIncoming = false; return true; } function resetInput(cm, user) { - var view = cm.view, minimal, selected; - if (!posEq(view.sel.from, view.sel.to)) { + var minimal, selected, doc = cm.doc; + if (!posEq(doc.sel.from, doc.sel.to)) { cm.display.prevInput = ""; minimal = hasCopyEvent && - (view.sel.to.line - view.sel.from.line > 100 || (selected = cm.getSelection()).length > 1000); + (doc.sel.to.line - doc.sel.from.line > 100 || (selected = cm.getSelection()).length > 1000); if (minimal) cm.display.input.value = "-"; else cm.display.input.value = selected || cm.getSelection(); - if (view.focused) selectInput(cm.display.input); + if (cm.state.focused) selectInput(cm.display.input); } else if (user) cm.display.prevInput = cm.display.input.value = ""; cm.display.inaccurateSelection = minimal; } @@ -1278,7 +1307,7 @@ window.CodeMirror = (function() { } function isReadOnly(cm) { - return cm.options.readOnly || cm.view.cantEdit; + return cm.options.readOnly || cm.doc.cantEdit; } // EVENT HANDLERS @@ -1310,7 +1339,7 @@ window.CodeMirror = (function() { on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); - function reFocus() { if (cm.view.focused) setTimeout(bind(focusInput, cm), 0); } + function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); } on(d.scrollbarH, "mousedown", reFocus); on(d.scrollbarV, "mousedown", reFocus); // Prevent wrapper from ever scrolling @@ -1325,7 +1354,7 @@ window.CodeMirror = (function() { on(d.input, "keyup", operation(cm, function(e) { if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; - if (e_prop(e, "keyCode") == 16) cm.view.sel.shift = false; + if (e_prop(e, "keyCode") == 16) cm.doc.sel.shift = false; })); on(d.input, "input", bind(fastPoll, cm)); on(d.input, "keydown", operation(cm, onKeyDown)); @@ -1349,7 +1378,7 @@ window.CodeMirror = (function() { fastPoll(cm); }); on(d.input, "paste", function() { - d.pasteIncoming = true; + cm.state.pasteIncoming = true; fastPoll(cm); }); @@ -1395,7 +1424,7 @@ window.CodeMirror = (function() { var lastClick, lastDoubleClick; function onMouseDown(e) { - var cm = this, display = cm.display, view = cm.view, sel = view.sel, doc = view.doc; + var cm = this, display = cm.display, doc = cm.doc, sel = doc.sel; sel.shift = e_prop(e, "shiftKey"); if (eventInWidget(display, e)) { @@ -1413,7 +1442,7 @@ window.CodeMirror = (function() { if (gecko) onContextMenu.call(cm, cm, e); return; case 2: - if (start) extendSelection(cm, start); + if (start) extendSelection(cm.doc, start); setTimeout(bind(focusInput, cm), 20); e_preventDefault(e); return; @@ -1423,7 +1452,7 @@ window.CodeMirror = (function() { // selection. if (!start) {if (e_target(e) == display.scroller) e_preventDefault(e); return;} - if (!view.focused) onFocus(cm); + if (!cm.state.focused) onFocus(cm); var now = +new Date, type = "single"; if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) { @@ -1436,7 +1465,7 @@ window.CodeMirror = (function() { lastDoubleClick = {time: now, pos: start}; e_preventDefault(e); var word = findWordAt(getLine(doc, start.line).text, start); - extendSelection(cm, word.from, word.to); + extendSelection(cm.doc, word.from, word.to); } else { lastClick = {time: now, pos: start}; } var last = start; @@ -1444,18 +1473,18 @@ window.CodeMirror = (function() { !posLess(start, sel.from) && !posLess(sel.to, start) && type == "single") { var dragEnd = operation(cm, function(e2) { if (webkit) display.scroller.draggable = false; - view.draggingText = 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); - extendSelection(cm, start); + extendSelection(cm.doc, start); focusInput(cm); } }); // Let the drag handler handle this. if (webkit) display.scroller.draggable = true; - view.draggingText = dragEnd; + cm.state.draggingText = dragEnd; // IE's approach to draggable if (display.scroller.dragDrop) display.scroller.dragDrop(); on(document, "mouseup", dragEnd); @@ -1463,13 +1492,13 @@ window.CodeMirror = (function() { return; } e_preventDefault(e); - if (type == "single") extendSelection(cm, clipPos(doc, start)); + if (type == "single") extendSelection(cm.doc, clipPos(doc, start)); var startstart = sel.from, startend = sel.to; function doSelect(cur) { if (type == "single") { - extendSelection(cm, clipPos(doc, start), cur); + extendSelection(cm.doc, clipPos(doc, start), cur); return; } @@ -1477,11 +1506,11 @@ window.CodeMirror = (function() { startend = clipPos(doc, startend); if (type == "double") { var word = findWordAt(getLine(doc, cur.line).text, cur); - if (posLess(cur, startstart)) extendSelection(cm, word.from, startend); - else extendSelection(cm, startstart, word.to); + if (posLess(cur, startstart)) extendSelection(cm.doc, word.from, startend); + else extendSelection(cm.doc, startstart, word.to); } else if (type == "triple") { - if (posLess(cur, startstart)) extendSelection(cm, startend, clipPos(doc, {line: cur.line, ch: 0})); - else extendSelection(cm, startstart, clipPos(doc, {line: cur.line + 1, ch: 0})); + if (posLess(cur, startstart)) extendSelection(cm.doc, startend, clipPos(doc, {line: cur.line, ch: 0})); + else extendSelection(cm.doc, startstart, clipPos(doc, {line: cur.line + 1, ch: 0})); } } @@ -1497,7 +1526,7 @@ window.CodeMirror = (function() { var cur = posFromMouse(cm, e, true); if (!cur) return; if (!posEq(cur, last)) { - if (!view.focused) onFocus(cm); + if (!cm.state.focused) onFocus(cm); last = cur; doSelect(cur); var visible = visibleLines(display, doc); @@ -1546,11 +1575,8 @@ window.CodeMirror = (function() { reader.onload = function() { text[i] = reader.result; if (++read == n) { - pos = clipPos(cm.view.doc, pos); - operation(cm, function() { - var end = replaceRange(cm, text.join(""), pos, pos, "paste"); - setSelection(cm, pos, end); - })(); + pos = clipPos(cm.doc, pos); + replaceRange(cm.doc, text.join(""), pos, "around", "paste"); } }; reader.readAsText(file); @@ -1558,8 +1584,8 @@ window.CodeMirror = (function() { for (var i = 0; i < n; ++i) loadFile(files[i], i); } else { // Don't do a replace if the drop happened inside of the selected text. - if (cm.view.draggingText && !(posLess(pos, cm.view.sel.from) || posLess(cm.view.sel.to, pos))) { - cm.view.draggingText(e); + if (cm.state.draggingText && !(posLess(pos, cm.doc.sel.from) || posLess(cm.doc.sel.to, pos))) { + cm.state.draggingText(e); // Ensure the editor is re-focused setTimeout(bind(focusInput, cm), 20); return; @@ -1567,9 +1593,9 @@ window.CodeMirror = (function() { try { var text = e.dataTransfer.getData("Text"); if (text) { - var curFrom = cm.view.sel.from, curTo = cm.view.sel.to; - setSelection(cm, pos, pos); - if (cm.view.draggingText) replaceRange(cm, "", curFrom, curTo, "paste"); + var curFrom = cm.doc.sel.from, curTo = cm.doc.sel.to; + setSelection(cm.doc, pos, pos); + if (cm.state.draggingText) replaceRange(cm.doc, "", curFrom, curTo, "paste"); cm.replaceSelection(text, null, "paste"); focusInput(cm); onFocus(cm); @@ -1595,9 +1621,9 @@ window.CodeMirror = (function() { for (var i = 0; i < cm.options.gutters.length; ++i) { var g = display.gutters.childNodes[i]; if (g && g.getBoundingClientRect().right >= mX) { - var line = lineAtHeight(cm.view.doc, mY); + var line = lineAtHeight(cm.doc, mY); var gutter = cm.options.gutters[i]; - signalLater(cm, cm, "gutterClick", cm, line, gutter, e); + signalLater(cm, "gutterClick", cm, line, gutter, e); break; } } @@ -1626,17 +1652,17 @@ window.CodeMirror = (function() { } function setScrollTop(cm, val) { - if (Math.abs(cm.view.scrollTop - val) < 2) return; - cm.view.scrollTop = val; + if (Math.abs(cm.doc.scrollTop - val) < 2) return; + cm.doc.scrollTop = val; if (!gecko) updateDisplay(cm, [], val); if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val; if (gecko) updateDisplay(cm, []); } function setScrollLeft(cm, val, isScroller) { - if (isScroller ? val == cm.view.scrollLeft : Math.abs(cm.view.scrollLeft - val) < 2) return; + 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.view.scrollLeft = val; + cm.doc.scrollLeft = val; alignHorizontally(cm); if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val; @@ -1700,9 +1726,9 @@ window.CodeMirror = (function() { if (dy && wheelPixelsPerUnit != null) { var pixels = dy * wheelPixelsPerUnit; - var top = cm.view.scrollTop, bot = top + display.wrapper.clientHeight; + 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.view.doc.height, bot + pixels + 50); + else bot = Math.min(cm.doc.height, bot + pixels + 50); updateDisplay(cm, [], {top: top, bottom: bot}); } @@ -1735,23 +1761,23 @@ window.CodeMirror = (function() { // Ensure previous input has been read, so that the handler sees a // consistent view of the document if (cm.display.pollingFast && readInput(cm)) cm.display.pollingFast = false; - var view = cm.view, prevShift = view.sel.shift; + var doc = cm.doc, prevShift = doc.sel.shift; try { - if (isReadOnly(cm)) view.suppressEdits = true; - if (dropShift) view.sel.shift = false; + if (isReadOnly(cm)) cm.state.suppressEdits = true; + if (dropShift) doc.sel.shift = false; bound(cm); } catch(e) { if (e != Pass) throw e; return false; } finally { - view.sel.shift = prevShift; - view.suppressEdits = false; + doc.sel.shift = prevShift; + cm.state.suppressEdits = false; } return true; } function allKeyMaps(cm) { - var maps = cm.view.keyMaps.slice(0); + var maps = cm.state.keyMaps.slice(0); maps.push(cm.options.keyMap); if (cm.options.extraKeys) maps.unshift(cm.options.extraKeys); return maps; @@ -1809,12 +1835,12 @@ window.CodeMirror = (function() { var lastStoppedKey = null; function onKeyDown(e) { var cm = this; - if (!cm.view.focused) onFocus(cm); + if (!cm.state.focused) onFocus(cm); if (ie && e.keyCode == 27) { e.returnValue = false; } if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; var code = e_prop(e, "keyCode"); // IE does strange things with escape. - cm.view.sel.shift = code == 16 || e_prop(e, "shiftKey"); + cm.doc.sel.shift = code == 16 || e_prop(e, "shiftKey"); // First give onKeyEvent option a chance to handle this. var handled = handleKeyBinding(cm, e); if (opera) { @@ -1832,19 +1858,19 @@ window.CodeMirror = (function() { if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return; var ch = String.fromCharCode(charCode == null ? keyCode : charCode); - if (this.options.electricChars && this.view.mode.electricChars && + if (this.options.electricChars && this.doc.mode.electricChars && this.options.smartIndent && !isReadOnly(this) && - this.view.mode.electricChars.indexOf(ch) > -1) - setTimeout(operation(cm, function() {indentLine(cm, cm.view.sel.to.line, "smart");}), 75); + this.doc.mode.electricChars.indexOf(ch) > -1) + setTimeout(operation(cm, function() {indentLine(cm, cm.doc.sel.to.line, "smart");}), 75); if (handleCharBinding(cm, e, ch)) return; fastPoll(cm); } function onFocus(cm) { if (cm.options.readOnly == "nocursor") return; - if (!cm.view.focused) { + if (!cm.state.focused) { signal(cm, "focus", cm); - cm.view.focused = true; + cm.state.focused = true; if (cm.display.scroller.className.search(/\bCodeMirror-focused\b/) == -1) cm.display.scroller.className += " CodeMirror-focused"; resetInput(cm, true); @@ -1853,25 +1879,24 @@ window.CodeMirror = (function() { restartBlink(cm); } function onBlur(cm) { - if (cm.view.focused) { + if (cm.state.focused) { signal(cm, "blur", cm); - cm.view.focused = false; + cm.state.focused = false; cm.display.scroller.className = cm.display.scroller.className.replace(" CodeMirror-focused", ""); } clearInterval(cm.display.blinker); - setTimeout(function() {if (!cm.view.focused) cm.view.sel.shift = false;}, 150); + setTimeout(function() {if (!cm.state.focused) cm.doc.sel.shift = false;}, 150); } var detectingSelectAll; function onContextMenu(cm, e) { - var display = cm.display; + var display = cm.display, sel = cm.doc.sel; if (eventInWidget(display, e)) return; - - var sel = cm.view.sel; + var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; if (!pos || opera) return; // Opera is difficult. if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to)) - operation(cm, setSelection)(cm, pos, pos); + operation(cm, setSelection)(cm.doc, pos, pos); var oldCSS = display.input.style.cssText; display.inputDiv.style.position = "absolute"; @@ -1917,124 +1942,150 @@ window.CodeMirror = (function() { // UPDATING - // Replace the range from from to to by the strings in newText. - // Afterwards, set the selection to selFrom, selTo. - function updateDoc(cm, from, to, newText, selUpdate, origin) { + function changeEnd(change) { + return {line: change.from.line + change.text.length - 1, + ch: lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)}; + } + + // Hint can be null|"end"|"start"|"around"|{anchor,head} + function computeSelAfterChange(sel, change, hint) { + if (hint && typeof hint == "object") return hint; // Assumed to be {from, to} object + if (hint == "start") return {anchor: change.from, head: change.from}; + + var end = changeEnd(change); + if (hint == "around") return {anchor: change.from, head: end}; + if (hint == "end") return {anchor: end, head: end}; + + // hint is null, leave the selection alone as much as possible + var adjustPos = function(pos) { + if (posLess(pos, change.from)) return pos; + if (!posLess(change.to, pos)) return end; + + var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; + if (pos.line == change.to.line) ch += end.ch - change.to.ch; + return {line: line, ch: ch}; + }; + return {anchor: adjustPos(sel.anchor), head: adjustPos(sel.head)}; + } + + // Replace the range from from to to by the strings in replacement. + // change is a {from, to, text [, origin]} object + function makeChange(doc, change, selUpdate, ignoreReadOnly) { + if (doc.cm) { + if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, selUpdate, ignoreReadOnly); + if (doc.cm.state.suppressEdits) return; + } + // Possibly split or suppress the update based on the presence // of read-only spans in its range. - var split = sawReadOnlySpans && - removeReadOnlyRanges(cm.view.doc, from, to); + var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); if (split) { for (var i = split.length - 1; i >= 1; --i) - updateDocInner(cm, split[i].from, split[i].to, [""], origin); + makeChangeNoReadonly(doc, {from: split[i].from, to: split[i].to, text: [""]}); if (split.length) - return updateDocInner(cm, split[0].from, split[0].to, newText, selUpdate, origin); + makeChangeNoReadonly(doc, {from: split[0].from, to: split[0].to, text: change.text}, selUpdate); } else { - return updateDocInner(cm, from, to, newText, selUpdate, origin); + makeChangeNoReadonly(doc, change, selUpdate); } } - function updateDocInner(cm, from, to, newText, selUpdate, origin) { - if (cm.view.suppressEdits) return; + function makeChangeNoReadonly(doc, change, selUpdate) { + var selAfter = computeSelAfterChange(doc.sel, change, selUpdate); + addToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); - var view = cm.view, doc = view.doc, old = []; - doc.iter(from.line, to.line + 1, function(line) { - old.push(newHL(line.text, line.markedSpans)); + makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); + + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist) rebaseHist(doc.history, change); + makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); }); - var startSelFrom = view.sel.from, startSelTo = view.sel.to; - var lines = updateMarkedSpans(hlSpans(old[0]), hlSpans(lst(old)), from.ch, to.ch, newText); - var retval = updateDocNoUndo(cm, from, to, lines, selUpdate, origin); - if (view.history) addChange(cm, from.line, newText.length, old, origin, - startSelFrom, startSelTo, view.sel.from, view.sel.to); - return retval; - } - - function unredoHelper(cm, type) { - var doc = cm.view.doc, hist = cm.view.history; - var set = (type == "undo" ? hist.done : hist.undone).pop(); - if (!set) return; - var anti = {events: [], fromBefore: set.fromAfter, toBefore: set.toAfter, - fromAfter: set.fromBefore, toAfter: set.toBefore}; - for (var i = set.events.length - 1; i >= 0; i -= 1) { - hist.dirtyCounter += type == "undo" ? -1 : 1; - var change = set.events[i]; - var replaced = [], end = change.start + change.added; - doc.iter(change.start, end, function(line) { replaced.push(newHL(line.text, line.markedSpans)); }); - anti.events.push({start: change.start, added: change.old.length, old: replaced}); - var selPos = i ? null : {from: set.fromBefore, to: set.toBefore}; - updateDocNoUndo(cm, {line: change.start, ch: 0}, {line: end - 1, ch: getLine(doc, end-1).text.length}, - change.old, selPos, type); - } + } + + function makeChangeFromHistory(doc, type) { + var hist = doc.history; + var event = (type == "undo" ? hist.done : hist.undone).pop(); + if (!event) return; + hist.dirtyCounter += type == "undo" ? -1 : 1; + + var anti = {changes: [], anchorBefore: event.anchorAfter, headBefore: event.headAfter, + anchorAfter: event.anchorBefore, headAfter: event.headBefore}; (type == "undo" ? hist.undone : hist.done).push(anti); + + for (var i = event.changes.length - 1; i >= 0; --i) { + var change = event.changes[i]; + change.origin = type; + anti.changes.push(historyChangeFromChange(doc, change)); + + var after = i ? computeSelAfterChange(doc.sel, change, null) + : {anchor: event.anchorBefore, head: event.headBefore}; + makeChangeSingleDoc(doc, change, after, getOldSpans(doc, change)); + + linkedDocs(doc, function(doc, sharedHist) { + if (!sharedHist) rebaseHist(doc.history, change); + makeChangeSingleDoc(doc, change, null, getOldSpans(doc, change)); + }); + } + } + + function shiftDoc(doc, distance) { + function shiftPos(pos) {return {line: pos.line + distance, ch: pos.ch};} + doc.first += distance; + if (doc.cm) regChange(doc.cm, doc.first, doc.first, distance); + doc.sel.head = shiftPos(doc.sel.head); doc.sel.anchor = shiftPos(doc.sel.anchor); + doc.sel.from = shiftPos(doc.sel.from); doc.sel.to = shiftPos(doc.sel.to); + } + + function makeChangeSingleDoc(doc, change, selAfter, spans) { + if (doc.cm && !doc.cm.curOp) + 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; + } + 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); + change = {from: {line: doc.first, ch: 0}, to: {line: change.to.line + shift, ch: change.to.ch}, + text: [lst(change.text)], origin: change.origin}; + } + var last = doc.lastLine(); + if (change.to.line > last) { + change = {from: change.from, to: {line: last, ch: getLine(doc, last).text.length}, + text: [change.text[0]], origin: change.origin}; + } + + if (!selAfter) selAfter = computeSelAfterChange(doc.sel, change, null); + if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans, selAfter); + else updateDoc(doc, change, spans, selAfter); } - function updateDocNoUndo(cm, from, to, lines, selUpdate, origin) { - var view = cm.view, doc = view.doc, display = cm.display; - if (view.suppressEdits) return; + function makeChangeSingleDocInEditor(cm, change, spans, selAfter) { + var doc = cm.doc, display = cm.display, from = change.from, to = change.to; - var nlines = to.line - from.line, firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); var recomputeMaxLength = false, checkWidthStart = from.line; if (!cm.options.lineWrapping) { - checkWidthStart = lineNo(visualLine(doc, firstLine)); + checkWidthStart = lineNo(visualLine(doc, getLine(doc, from.line))); doc.iter(checkWidthStart, to.line + 1, function(line) { - if (line == view.maxLine) { + if (line == display.maxLine) { recomputeMaxLength = true; return true; } }); } - var lastHL = lst(lines), th = textHeight(display); + updateDoc(doc, change, spans, selAfter, estimateHeight(cm)); - // First adjust the line structure - if (from.ch == 0 && to.ch == 0 && hlText(lastHL) == "") { - // This is a whole-line replace. Treated specially to make - // sure line objects move the way they are supposed to. - var added = []; - for (var i = 0, e = lines.length - 1; i < e; ++i) - added.push(makeLine(hlText(lines[i]), hlSpans(lines[i]), th)); - updateLine(cm, lastLine, lastLine.text, hlSpans(lastHL)); - if (nlines) doc.remove(from.line, nlines, cm); - if (added.length) doc.insert(from.line, added); - } else if (firstLine == lastLine) { - if (lines.length == 1) { - updateLine(cm, firstLine, firstLine.text.slice(0, from.ch) + hlText(lines[0]) + - firstLine.text.slice(to.ch), hlSpans(lines[0])); - } else { - for (var added = [], i = 1, e = lines.length - 1; i < e; ++i) - added.push(makeLine(hlText(lines[i]), hlSpans(lines[i]), th)); - added.push(makeLine(hlText(lastHL) + firstLine.text.slice(to.ch), hlSpans(lastHL), th)); - updateLine(cm, firstLine, firstLine.text.slice(0, from.ch) + hlText(lines[0]), hlSpans(lines[0])); - doc.insert(from.line + 1, added); - } - } else if (lines.length == 1) { - updateLine(cm, firstLine, firstLine.text.slice(0, from.ch) + hlText(lines[0]) + - lastLine.text.slice(to.ch), hlSpans(lines[0])); - doc.remove(from.line + 1, nlines, cm); - } else { - var added = []; - updateLine(cm, firstLine, firstLine.text.slice(0, from.ch) + hlText(lines[0]), hlSpans(lines[0])); - updateLine(cm, lastLine, hlText(lastHL) + lastLine.text.slice(to.ch), hlSpans(lastHL)); - for (var i = 1, e = lines.length - 1; i < e; ++i) - added.push(makeLine(hlText(lines[i]), hlSpans(lines[i]), th)); - if (nlines > 1) doc.remove(from.line + 1, nlines - 1, cm); - doc.insert(from.line + 1, added); - } - - if (cm.options.lineWrapping) { - var perLine = Math.max(5, display.scroller.clientWidth / charWidth(display) - 3); - doc.iter(from.line, from.line + lines.length, function(line) { - if (line.height == 0) return; - var guess = (Math.ceil(line.text.length / perLine) || 1) * th; - if (guess != line.height) updateLineHeight(line, guess); - }); - } else { - doc.iter(checkWidthStart, from.line + lines.length, function(line) { + if (!cm.options.lineWrapping) { + doc.iter(checkWidthStart, from.line + change.text.length, function(line) { var len = lineLength(doc, line); - if (len > view.maxLineLength) { - view.maxLine = line; - view.maxLineLength = len; - view.maxLineChanged = true; + if (len > display.maxLineLength) { + display.maxLine = line; + display.maxLineLength = len; + display.maxLineChanged = true; recomputeMaxLength = false; } }); @@ -2042,57 +2093,26 @@ window.CodeMirror = (function() { } // Adjust frontier, schedule worker - view.frontier = Math.min(view.frontier, from.line); + doc.frontier = Math.min(doc.frontier, from.line); startWorker(cm, 400); - var lendiff = lines.length - nlines - 1; + var lendiff = change.text.length - (to.line - from.line) - 1; // Remember that these lines changed, for updating the display regChange(cm, from.line, to.line + 1, lendiff); if (hasHandler(cm, "change")) { - // Normalize lines to contain only strings, since that's what - // the change event handler expects - for (var i = 0; i < lines.length; ++i) - if (typeof lines[i] != "string") lines[i] = lines[i].text; - var changeObj = {from: from, to: to, text: lines, origin: origin}; + var changeObj = {from: from, to: to, text: change.text, origin: origin}; if (cm.curOp.textChanged) { for (var cur = cm.curOp.textChanged; cur.next; cur = cur.next) {} cur.next = changeObj; } else cm.curOp.textChanged = changeObj; } - - // Update the selection - var newSelFrom, newSelTo, end = {line: from.line + lines.length - 1, - ch: hlText(lastHL).length + (lines.length == 1 ? from.ch : 0)}; - if (selUpdate && typeof selUpdate != "string") { - if (selUpdate.from) { newSelFrom = selUpdate.from; newSelTo = selUpdate.to; } - else newSelFrom = newSelTo = selUpdate; - } else if (selUpdate == "end") { - newSelFrom = newSelTo = end; - } else if (selUpdate == "start") { - newSelFrom = newSelTo = from; - } else if (selUpdate == "around") { - newSelFrom = from; newSelTo = end; - } else { - var adjustPos = function(pos) { - if (posLess(pos, from)) return pos; - if (!posLess(to, pos)) return end; - var line = pos.line + lendiff; - var ch = pos.ch; - if (pos.line == to.line) - ch += hlText(lastHL).length - (to.ch - (to.line == from.line ? from.ch : 0)); - return {line: line, ch: ch}; - }; - newSelFrom = adjustPos(view.sel.from); - newSelTo = adjustPos(view.sel.to); - } - setSelection(cm, newSelFrom, newSelTo, null, true); - return end; } - function replaceRange(cm, code, from, to, origin) { + function replaceRange(doc, code, from, to, origin) { if (!to) to = from; if (posLess(to, from)) { var tmp = to; to = from; from = tmp; } - return updateDoc(cm, from, to, splitLines(code), null, origin); + if (typeof code == "string") code = splitLines(code); + makeChange(doc, {from: from, to: to, text: code, origin: origin}, null); } // SELECTION @@ -2101,23 +2121,23 @@ window.CodeMirror = (function() { function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);} function copyPos(x) {return {line: x.line, ch: x.ch};} - function clipLine(doc, n) {return Math.max(0, Math.min(n, doc.size-1));} + function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));} function clipPos(doc, pos) { - if (pos.line < 0) return {line: 0, ch: 0}; - if (pos.line >= doc.size) return {line: doc.size-1, ch: getLine(doc, doc.size-1).text.length}; + if (pos.line < doc.first) return {line: doc.first, ch: 0}; + var last = doc.first + doc.size - 1; + if (pos.line > last) return {line: last, ch: getLine(doc, last).text.length}; var ch = pos.ch, linelen = getLine(doc, pos.line).text.length; if (ch == null || ch > linelen) return {line: pos.line, ch: linelen}; else if (ch < 0) return {line: pos.line, ch: 0}; else return pos; } - function isLine(doc, l) {return l >= 0 && l < doc.size;} + function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;} // If shift is held, this will move the selection anchor. Otherwise, // it'll set the whole selection. - function extendSelection(cm, pos, other, bias) { - var sel = cm.view.sel; - if (sel.shift || sel.extend) { - var anchor = sel.anchor; + function extendSelection(doc, pos, other, bias) { + if (doc.sel.shift || doc.sel.extend) { + var anchor = doc.sel.anchor; if (other) { var posBefore = posLess(pos, anchor); if (posBefore != posLess(other, anchor)) { @@ -2127,24 +2147,24 @@ window.CodeMirror = (function() { pos = other; } } - setSelection(cm, anchor, pos, bias); + setSelection(doc, anchor, pos, bias); } else { - setSelection(cm, pos, other || pos, bias); + setSelection(doc, pos, other || pos, bias); } - cm.curOp.userSelChange = true; + if (doc.cm) doc.cm.curOp.userSelChange = true; } // Update the selection. Last two args are only used by // updateDoc, since they have to be expressed in the line // numbers before the update. - function setSelection(cm, anchor, head, bias, checkAtomic) { - cm.view.goalColumn = null; - var sel = cm.view.sel; + function setSelection(doc, anchor, head, bias, checkAtomic) { + var sel = doc.sel; + sel.goalColumn = null; // Skip over atomic spans. if (checkAtomic || !posEq(anchor, sel.anchor)) - anchor = skipAtomic(cm, anchor, bias, checkAtomic != "push"); + anchor = skipAtomic(doc, anchor, bias, checkAtomic != "push"); if (checkAtomic || !posEq(head, sel.head)) - head = skipAtomic(cm, head, bias, checkAtomic != "push"); + head = skipAtomic(doc, head, bias, checkAtomic != "push"); if (posEq(sel.anchor, anchor) && posEq(sel.head, head)) return; @@ -2153,18 +2173,18 @@ window.CodeMirror = (function() { sel.from = inv ? head : anchor; sel.to = inv ? anchor : head; - cm.curOp.updateInput = true; - cm.curOp.selectionChanged = true; + if (doc.cm) + doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; } function reCheckSelection(cm) { - setSelection(cm, cm.view.sel.from, cm.view.sel.to, null, "push"); + setSelection(cm.doc, cm.doc.sel.from, cm.doc.sel.to, null, "push"); } - function skipAtomic(cm, pos, bias, mayClear) { - var doc = cm.view.doc, flipped = false, curPos = pos; + function skipAtomic(doc, pos, bias, mayClear) { + var flipped = false, curPos = pos; var dir = bias || 1; - cm.view.cantEdit = false; + doc.cantEdit = false; search: for (;;) { var line = getLine(doc, curPos.line), toClear; if (line.markedSpans) { @@ -2180,20 +2200,20 @@ window.CodeMirror = (function() { if (posEq(newPos, curPos)) { newPos.ch += dir; if (newPos.ch < 0) { - if (newPos.line) newPos = clipPos(doc, {line: newPos.line - 1}); + if (newPos.line > doc.first) newPos = clipPos(doc, {line: newPos.line - 1}); else newPos = null; } else if (newPos.ch > line.text.length) { - if (newPos.line < doc.size - 1) newPos = {line: newPos.line + 1, ch: 0}; + if (newPos.line < doc.first + doc.size - 1) newPos = {line: newPos.line + 1, ch: 0}; else newPos = null; } if (!newPos) { if (flipped) { // Driven in a corner -- no valid cursor position found at all // -- try again *with* clearing, if we didn't already - if (!mayClear) return skipAtomic(cm, pos, bias, true); + if (!mayClear) return skipAtomic(doc, pos, bias, true); // Otherwise, turn off editing until further notice, and return the start of the doc - cm.view.cantEdit = true; - return {line: 0, ch: 0}; + doc.cantEdit = true; + return {line: doc.first, ch: 0}; } flipped = true; newPos = pos; dir = -dir; } @@ -2211,9 +2231,8 @@ window.CodeMirror = (function() { // SCROLLING function scrollCursorIntoView(cm) { - var view = cm.view; - var coords = scrollPosIntoView(cm, view.sel.head); - if (!view.focused) return; + var coords = scrollPosIntoView(cm, cm.doc.sel.head); + if (!cm.state.focused) 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; @@ -2233,14 +2252,14 @@ window.CodeMirror = (function() { for (;;) { var changed = false, coords = cursorCoords(cm, pos); var scrollPos = calculateScrollPos(cm, coords.left, coords.top, coords.left, coords.bottom); - var startTop = cm.view.scrollTop, startLeft = cm.view.scrollLeft; + var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; if (scrollPos.scrollTop != null) { setScrollTop(cm, scrollPos.scrollTop); - if (Math.abs(cm.view.scrollTop - startTop) > 1) changed = true; + if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; } if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); - if (Math.abs(cm.view.scrollLeft - startLeft) > 1) changed = true; + if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; } if (!changed) return coords; } @@ -2256,7 +2275,7 @@ window.CodeMirror = (function() { var display = cm.display, pt = paddingTop(display); y1 += pt; y2 += pt; var screen = display.scroller.clientHeight - scrollerCutOff, screentop = display.scroller.scrollTop, result = {}; - var docBottom = cm.view.doc.height + 2 * pt; + var docBottom = cm.doc.height + 2 * pt; var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10; if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1); else if (y2 > screentop + screen) result.scrollTop = (atBottom ? docBottom : y2) - screen; @@ -2277,10 +2296,10 @@ window.CodeMirror = (function() { // API UTILITIES function indentLine(cm, n, how, aggressive) { - var doc = cm.view.doc; + var doc = cm.doc; if (!how) how = "add"; if (how == "smart") { - if (!cm.view.mode.indent) how = "prev"; + if (!cm.doc.mode.indent) how = "prev"; else var state = getStateBefore(cm, n); } @@ -2288,18 +2307,20 @@ window.CodeMirror = (function() { var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); var curSpaceString = line.text.match(/^\s*/)[0], indentation; if (how == "smart") { - indentation = cm.view.mode.indent(state, line.text.slice(curSpaceString.length), line.text); + indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); if (indentation == Pass) { if (!aggressive) return; how = "prev"; } } if (how == "prev") { - if (n) indentation = countColumn(getLine(doc, n-1).text, null, tabSize); + 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; + } else if (how == "subtract") { + indentation = curSpace - cm.options.indentUnit; } - else if (how == "add") indentation = curSpace + cm.options.indentUnit; - else if (how == "subtract") indentation = curSpace - cm.options.indentUnit; indentation = Math.max(0, indentation); var indentString = "", pos = 0; @@ -2308,12 +2329,12 @@ window.CodeMirror = (function() { if (pos < indentation) indentString += spaceStr(indentation - pos); if (indentString != curSpaceString) - replaceRange(cm, indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length}, "input"); + replaceRange(cm.doc, indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length}, "input"); line.stateAfter = null; } function changeLine(cm, handle, op) { - var no = handle, line = handle, doc = cm.view.doc; + var no = handle, line = handle, doc = cm.doc; if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); else no = lineNo(handle); if (no == null) return null; @@ -2322,12 +2343,12 @@ window.CodeMirror = (function() { return line; } - function findPosH(cm, dir, unit, visually) { - var doc = cm.view.doc, end = cm.view.sel.head, line = end.line, ch = end.ch; + function findPosH(doc, dir, unit, visually) { + var end = doc.sel.head, line = end.line, ch = end.ch; var lineObj = getLine(doc, line); function findNextLine() { var l = line + dir; - if (l < 0 || l == doc.size) return false; + if (l < doc.first || l >= doc.first + doc.size) return false; line = l; return lineObj = getLine(doc, l); } @@ -2352,7 +2373,7 @@ window.CodeMirror = (function() { if (dir > 0) if (!moveOnce()) break; } } - return skipAtomic(cm, {line: line, ch: ch}, dir, true); + return skipAtomic(doc, {line: line, ch: ch}, dir, true); } function findWordAt(line, pos) { @@ -2370,7 +2391,7 @@ window.CodeMirror = (function() { } function selectLine(cm, line) { - extendSelection(cm, {line: line, ch: 0}, clipPos(cm.view.doc, {line: line + 1, ch: 0})); + extendSelection(cm.doc, {line: line, ch: 0}, clipPos(cm.doc, {line: line + 1, ch: 0})); } // PROTOTYPE @@ -2379,24 +2400,6 @@ window.CodeMirror = (function() { // 'wrap f in an operation, performed on its `this` parameter' CodeMirror.prototype = { - getValue: function(lineSep) { - var text = [], doc = this.view.doc; - doc.iter(0, doc.size, function(line) { text.push(line.text); }); - return text.join(lineSep || "\n"); - }, - - setValue: operation(null, function(code) { - var doc = this.view.doc, top = {line: 0, ch: 0}, lastLen = getLine(doc, doc.size-1).text.length; - updateDocInner(this, top, {line: doc.size - 1, ch: lastLen}, splitLines(code), top, top, "setValue"); - }), - - getSelection: function(lineSep) { return this.getRange(this.view.sel.from, this.view.sel.to, lineSep); }, - - replaceSelection: operation(null, function(code, collapse, origin) { - var sel = this.view.sel; - updateDoc(this, sel.from, sel.to, splitLines(code), collapse || "around", origin); - }), - focus: function(){window.focus(); focusInput(this); onFocus(this); fastPoll(this);}, setOption: function(option, value) { @@ -2408,15 +2411,14 @@ window.CodeMirror = (function() { }, getOption: function(option) {return this.options[option];}, - - getMode: function() {return this.view.mode;}, + getMode: function() {return this.doc.mode;}, + getDoc: function() {return this.doc;}, addKeyMap: function(map) { - this.view.keyMaps.push(map); + this.state.keyMaps.push(map); }, - removeKeyMap: function(map) { - var maps = this.view.keyMaps; + var maps = this.state.keyMaps; for (var i = 0; i < maps.length; ++i) if ((typeof map == "string" ? maps[i].name : maps[i]) == map) { maps.splice(i, 1); @@ -2427,84 +2429,42 @@ window.CodeMirror = (function() { addOverlay: operation(null, function(spec, options) { var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); if (mode.startState) throw new Error("Overlays may not be stateful."); - this.view.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque}); - this.view.modeGen++; - regChange(this, 0, this.view.doc.size); + this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque}); + this.state.modeGen++; + regChange(this); }), removeOverlay: operation(null, function(spec) { - var overlays = this.view.overlays; + var overlays = this.state.overlays; for (var i = 0; i < overlays.length; ++i) { if (overlays[i].modeSpec == spec) { overlays.splice(i, 1); - this.view.modeGen++; - regChange(this, 0, this.view.doc.size); + this.state.modeGen++; + regChange(this); return; } } }), - undo: operation(null, function() {unredoHelper(this, "undo");}), - redo: operation(null, function() {unredoHelper(this, "redo");}), - indentLine: operation(null, function(n, dir, aggressive) { if (typeof dir != "string") { if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; else dir = dir ? "add" : "subtract"; } - if (isLine(this.view.doc, n)) indentLine(this, n, dir, aggressive); + if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); }), - indentSelection: operation(null, function(how) { - var sel = this.view.sel; + var sel = this.doc.sel; if (posEq(sel.from, sel.to)) return indentLine(this, sel.from.line, how); var e = sel.to.line - (sel.to.ch ? 0 : 1); for (var i = sel.from.line; i <= e; ++i) indentLine(this, i, how); }), - historySize: function() { - var hist = this.view.history; - return {undo: hist.done.length, redo: hist.undone.length}; - }, - - clearHistory: function() {this.view.history = makeHistory();}, - - markClean: function() { - this.view.history.dirtyCounter = 0; - this.view.history.lastOp = this.view.history.lastOrigin = null; - }, - - isClean: function () {return this.view.history.dirtyCounter == 0;}, - - getHistory: function() { - var hist = this.view.history; - function cp(arr) { - for (var i = 0, nw = [], nwelt; i < arr.length; ++i) { - var set = arr[i]; - nw.push({events: nwelt = [], fromBefore: set.fromBefore, toBefore: set.toBefore, - fromAfter: set.fromAfter, toAfter: set.toAfter}); - for (var j = 0, elt = set.events; j < elt.length; ++j) { - var old = [], cur = elt[j]; - nwelt.push({start: cur.start, added: cur.added, old: old}); - for (var k = 0; k < cur.old.length; ++k) old.push(hlText(cur.old[k])); - } - } - return nw; - } - return {done: cp(hist.done), undone: cp(hist.undone)}; - }, - - setHistory: function(histData) { - var hist = this.view.history = makeHistory(); - hist.done = histData.done; - hist.undone = histData.undone; - }, - // Fetch the parser token for a given character. Useful for hacks // that want to inspect the mode state (say, for completion). getTokenAt: function(pos) { - var doc = this.view.doc; + var doc = this.doc; pos = clipPos(doc, pos); - var state = getStateBefore(this, pos.line), mode = this.view.mode; + var state = getStateBefore(this, pos.line), mode = this.doc.mode; var line = getLine(doc, pos.line); var stream = new StringStream(line.text, this.options.tabSize); while (stream.pos < pos.ch && !stream.eol()) { @@ -2520,21 +2480,21 @@ window.CodeMirror = (function() { }, getStateAfter: function(line) { - var doc = this.view.doc; - line = clipLine(doc, line == null ? doc.size - 1: line); + var doc = this.doc; + line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); return getStateBefore(this, line + 1); }, cursorCoords: function(start, mode) { - var pos, sel = this.view.sel; + var pos, sel = this.doc.sel; if (start == null) pos = sel.head; - else if (typeof start == "object") pos = clipPos(this.view.doc, start); + else if (typeof start == "object") pos = clipPos(this.doc, start); else pos = start ? sel.from : sel.to; return cursorCoords(this, pos, mode || "page"); }, charCoords: function(pos, mode) { - return charCoords(this, clipPos(this.view.doc, pos), mode || "page"); + return charCoords(this, clipPos(this.doc, pos), mode || "page"); }, coordsChar: function(coords) { @@ -2544,29 +2504,6 @@ window.CodeMirror = (function() { defaultTextHeight: function() { return textHeight(this.display); }, - markText: operation(null, function(from, to, options) { - return markText(this, clipPos(this.view.doc, from), clipPos(this.view.doc, to), - options, "range"); - }), - - setBookmark: operation(null, function(pos, widget) { - pos = clipPos(this.view.doc, pos); - return markText(this, pos, pos, widget ? {replacedWith: widget} : {}, "bookmark"); - }), - - findMarksAt: function(pos) { - var doc = this.view.doc; - pos = clipPos(doc, pos); - var markers = [], spans = getLine(doc, pos.line).markedSpans; - if (spans) for (var i = 0; i < spans.length; ++i) { - var span = spans[i]; - if ((span.from == null || span.from <= pos.ch) && - (span.to == null || span.to >= pos.ch)) - markers.push(span.marker); - } - return markers; - }, - setGutterMarker: operation(null, function(line, gutterID, value) { return changeLine(this, line, function(line) { var markers = line.gutterMarkers || (line.gutterMarkers = {}); @@ -2577,8 +2514,8 @@ window.CodeMirror = (function() { }), clearGutter: operation(null, function(gutterID) { - var i = 0, cm = this, doc = cm.view.doc; - doc.iter(0, doc.size, function(line) { + var cm = this, doc = cm.doc, i = doc.first; + doc.iter(function(line) { if (line.gutterMarkers && line.gutterMarkers[gutterID]) { line.gutterMarkers[gutterID] = null; regChange(cm, i, i + 1); @@ -2621,9 +2558,9 @@ window.CodeMirror = (function() { lineInfo: function(line) { if (typeof line == "number") { - if (!isLine(this.view.doc, line)) return null; + if (!isLine(this.doc, line)) return null; var n = line; - line = getLine(this.view.doc, line); + line = getLine(this.doc, line); if (!line) return null; } else { var n = lineNo(line); @@ -2638,13 +2575,13 @@ window.CodeMirror = (function() { addWidget: function(pos, node, scroll, vert, horiz) { var display = this.display; - pos = cursorCoords(this, clipPos(this.view.doc, pos)); + pos = cursorCoords(this, clipPos(this.doc, pos)); var top = pos.top, left = pos.left; node.style.position = "absolute"; display.sizer.appendChild(node); if (vert == "over") top = pos.top; else if (vert == "near") { - var vspace = Math.max(display.wrapper.clientHeight, this.view.doc.height), + var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); if (pos.bottom + node.offsetHeight > vspace && pos.top > node.offsetHeight) top = pos.top - node.offsetHeight; @@ -2665,100 +2602,30 @@ window.CodeMirror = (function() { scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); }, - lineCount: function() {return this.view.doc.size;}, - - clipPos: function(pos) {return clipPos(this.view.doc, pos);}, - - getCursor: function(start) { - var sel = this.view.sel, pos; - if (start == null || start == "head") pos = sel.head; - else if (start == "anchor") pos = sel.anchor; - else if (start == "end" || start === false) pos = sel.to; - else pos = sel.from; - return copyPos(pos); - }, - - somethingSelected: function() {return !posEq(this.view.sel.from, this.view.sel.to);}, - - setCursor: operation(null, function(line, ch, extend) { - var pos = clipPos(this.view.doc, typeof line == "number" ? {line: line, ch: ch || 0} : line); - if (extend) extendSelection(this, pos); - else setSelection(this, pos, pos); - }), - - setSelection: operation(null, function(anchor, head) { - var doc = this.view.doc; - setSelection(this, clipPos(doc, anchor), clipPos(doc, head || anchor)); - }), - - extendSelection: operation(null, function(from, to) { - var doc = this.view.doc; - extendSelection(this, clipPos(doc, from), to && clipPos(doc, to)); - }), - - setExtending: function(val) {this.view.sel.extend = val;}, - - getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, - - getLineHandle: function(line) { - var doc = this.view.doc; - if (isLine(doc, line)) return getLine(doc, line); - }, - - getLineNumber: function(line) {return lineNo(line);}, - - setLine: operation(null, function(line, text) { - if (isLine(this.view.doc, line)) - replaceRange(this, text, {line: line, ch: 0}, {line: line, ch: getLine(this.view.doc, line).text.length}); - }), - - removeLine: operation(null, function(line) { - if (isLine(this.view.doc, line)) - replaceRange(this, "", {line: line, ch: 0}, clipPos(this.view.doc, {line: line+1, ch: 0})); - }), - - replaceRange: operation(null, function(code, from, to) { - var doc = this.view.doc; - from = clipPos(doc, from); - to = to ? clipPos(doc, to) : from; - return replaceRange(this, code, from, to); - }), - - getRange: function(from, to, lineSep) { - var doc = this.view.doc; - from = clipPos(doc, from); to = clipPos(doc, to); - var l1 = from.line, l2 = to.line; - if (l1 == l2) return getLine(doc, l1).text.slice(from.ch, to.ch); - var code = [getLine(doc, l1).text.slice(from.ch)]; - doc.iter(l1 + 1, l2, function(line) { code.push(line.text); }); - code.push(getLine(doc, l2).text.slice(0, to.ch)); - return code.join(lineSep || "\n"); - }, - triggerOnKeyDown: operation(null, onKeyDown), execCommand: function(cmd) {return commands[cmd](this);}, // Stuff used by commands, probably not much use to outside code. moveH: operation(null, function(dir, unit) { - var sel = this.view.sel, pos = dir < 0 ? sel.from : sel.to; + var sel = this.doc.sel, pos = dir < 0 ? sel.from : sel.to; if (sel.shift || sel.extend || posEq(sel.from, sel.to)) - pos = findPosH(this, dir, unit, this.options.rtlMoveVisually); - extendSelection(this, pos, pos, dir); + pos = findPosH(this.doc, dir, unit, this.options.rtlMoveVisually); + extendSelection(this.doc, pos, pos, dir); }), deleteH: operation(null, function(dir, unit) { - var sel = this.view.sel; - if (!posEq(sel.from, sel.to)) replaceRange(this, "", sel.from, sel.to, "delete"); - else replaceRange(this, "", sel.from, findPosH(this, dir, unit, false), "delete"); + var sel = this.doc.sel; + if (!posEq(sel.from, sel.to)) replaceRange(this.doc, "", sel.from, sel.to, "delete"); + else replaceRange(this.doc, "", sel.from, findPosH(this.doc, dir, unit, false), "delete"); this.curOp.userSelChange = true; }), moveV: operation(null, function(dir, unit) { - var view = this.view, doc = view.doc, display = this.display; - var cur = view.sel.head, pos = cursorCoords(this, cur, "div"); + var doc = this.doc, display = this.display; + var cur = doc.sel.head, pos = cursorCoords(this, cur, "div"); var x = pos.left, y; - if (view.goalColumn != null) x = view.goalColumn; + if (doc.sel.goalColumn != null) x = doc.sel.goalColumn; if (unit == "page") { var pageSize = Math.min(display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); y = pos.top + dir * pageSize; @@ -2771,36 +2638,17 @@ window.CodeMirror = (function() { } while (target.outside && (dir < 0 ? y > 0 : y < doc.height)); if (unit == "page") display.scrollbarV.scrollTop += charCoords(this, target, "div").top - pos.top; - extendSelection(this, target, target, dir); - view.goalColumn = x; + extendSelection(this.doc, target, target, dir); + doc.sel.goalColumn = x; }), toggleOverwrite: function() { - if (this.view.overwrite = !this.view.overwrite) + if (this.state.overwrite = !this.state.overwrite) this.display.cursor.className += " CodeMirror-overwrite"; else this.display.cursor.className = this.display.cursor.className.replace(" CodeMirror-overwrite", ""); }, - posFromIndex: function(off) { - var lineNo = 0, ch, doc = this.view.doc; - doc.iter(0, doc.size, function(line) { - var sz = line.text.length + 1; - if (sz > off) { ch = off; return true; } - off -= sz; - ++lineNo; - }); - return clipPos(doc, {line: lineNo, ch: ch}); - }, - indexFromPos: function (coords) { - coords = clipPos(this.view.doc, coords); - var index = coords.ch; - this.view.doc.iter(0, coords.line, function (line) { - index += line.text.length + 1; - }); - return index; - }, - scrollTo: function(x, y) { if (x != null) this.display.scrollbarH.scrollLeft = this.display.scroller.scrollLeft = x; if (y != null) this.display.scrollbarV.scrollTop = this.display.scroller.scrollTop = y; @@ -2816,7 +2664,7 @@ window.CodeMirror = (function() { scrollIntoView: function(pos) { if (typeof pos == "number") pos = {line: pos, ch: 0}; if (!pos || pos.line != null) { - pos = pos ? clipPos(this.view.doc, pos) : this.view.sel.head; + pos = pos ? clipPos(this.doc, pos) : this.doc.sel.head; scrollPosIntoView(this, pos); } else { scrollIntoView(this, pos.left, pos.top, pos.right, pos.bottom); @@ -2835,11 +2683,11 @@ window.CodeMirror = (function() { on: function(type, f) {on(this, type, f);}, off: function(type, f) {off(this, type, f);}, - operation: function(f){return operation(this, f)();}, + operation: function(f){return runInOp(this, f);}, refresh: function() { clearCaches(this); - var sTop = this.view.scrollTop, sLeft = this.view.scrollLeft; + var sTop = this.doc.scrollTop, sLeft = this.doc.scrollLeft; if (this.display.scroller.scrollHeight > sTop) this.display.scrollbarV.scrollTop = this.display.scroller.scrollTop = sTop; if (this.display.scroller.scrollWidth > sLeft) @@ -2847,6 +2695,15 @@ window.CodeMirror = (function() { updateDisplay(this, true); }, + swapDoc: operation(null, function(doc) { + var old = this.doc; + old.cm = null; + attachDoc(this, doc); + clearCaches(this); + this.curOp.updateScrollPos = true; + return old; + }), + getInputField: function(){return this.display.input;}, getWrapperElement: function(){return this.display.wrapper;}, getScrollerElement: function(){return this.display.scroller;}, @@ -2870,8 +2727,13 @@ window.CodeMirror = (function() { // 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, loadMode, true); + option("value", "", function(cm, val) { + cm.setValue(val); + }, true); + option("mode", null, function(cm, val) { + cm.doc.modeOption = val; + loadMode(cm); + }, true); option("indentUnit", 2, loadMode, true); option("indentWithTabs", false); @@ -2923,7 +2785,7 @@ window.CodeMirror = (function() { option("workDelay", 100); option("flattenSpans", true); option("pollInterval", 100); - option("undoDepth", 40); + option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;}); option("viewportMargin", 10, function(cm){cm.refresh();}, true); option("tabindex", null, function(cm, val) { @@ -3032,7 +2894,7 @@ window.CodeMirror = (function() { // STANDARD COMMANDS var commands = CodeMirror.commands = { - selectAll: function(cm) {cm.setSelection({line: 0, ch: 0}, {line: cm.lineCount() - 1});}, + selectAll: function(cm) {cm.setSelection({line: cm.firstLine(), ch: 0}, {line: cm.lastLine()});}, killLine: function(cm) { var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to); if (!sel && cm.getLine(from.line).length == from.ch) @@ -3045,8 +2907,8 @@ window.CodeMirror = (function() { }, undo: function(cm) {cm.undo();}, redo: function(cm) {cm.redo();}, - goDocStart: function(cm) {cm.extendSelection({line: 0, ch: 0});}, - goDocEnd: function(cm) {cm.extendSelection({line: cm.lineCount() - 1});}, + goDocStart: function(cm) {cm.extendSelection({line: cm.firstLine(), ch: 0});}, + goDocEnd: function(cm) {cm.extendSelection({line: cm.lastLine()});}, goLineStart: function(cm) { cm.extendSelection(lineStart(cm, cm.getCursor().line)); }, @@ -3291,17 +3153,18 @@ window.CodeMirror = (function() { // TEXTMARKERS - function TextMarker(cm, type) { + function TextMarker(doc, type) { this.lines = []; this.type = type; - this.cm = cm; + this.doc = doc; } CodeMirror.TextMarker = TextMarker; TextMarker.prototype.clear = function() { if (this.explicitlyCleared) return; - startOperation(this.cm); - var view = this.cm.view, min = null, max = null; + var cm = this.doc.cm, mustStart = cm && !cm.curOp; + if (mustStart) startOperation(cm); + 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); @@ -3309,27 +3172,27 @@ window.CodeMirror = (function() { line.markedSpans = removeMarkedSpan(line.markedSpans, span); if (span.from != null) min = lineNo(line); - else if (this.collapsed && !lineIsHidden(line)) - updateLineHeight(line, textHeight(this.cm.display)); - } - if (this.collapsed && !this.cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { - var visual = visualLine(view.doc, this.lines[i]), len = lineLength(view.doc, visual); - if (len > view.maxLineLength) { - view.maxLine = visual; - view.maxLineLength = len; - view.maxLineChanged = true; + else if (this.collapsed && !lineIsHidden(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(cm.doc, this.lines[i]), len = lineLength(cm.doc, visual); + if (len > cm.display.maxLineLength) { + cm.display.maxLine = visual; + cm.display.maxLineLength = len; + cm.display.maxLineChanged = true; } } - if (min != null) regChange(this.cm, min, max + 1); + if (min != null && cm) regChange(cm, min, max + 1); this.lines.length = 0; this.explicitlyCleared = true; - if (this.collapsed && this.cm.view.cantEdit) { - this.cm.view.cantEdit = false; - reCheckSelection(this.cm); + if (this.collapsed && this.doc.cantEdit) { + this.doc.cantEdit = false; + if (cm) reCheckSelection(cm); } - endOperation(this.cm); - signalLater(this.cm, this, "clear"); + if (mustStart) endOperation(cm); + signalLater(this, "clear"); }; TextMarker.prototype.find = function() { @@ -3359,9 +3222,8 @@ window.CodeMirror = (function() { startStyle: this.startStyle, endStyle: this.endStyle}; }; - function markText(cm, from, to, options, type) { - var doc = cm.view.doc; - var marker = new TextMarker(cm, type); + function markText(doc, from, to, options, type) { + var marker = new TextMarker(doc, type); if (type == "range" && !posLess(from, to)) return marker; if (options) for (var opt in options) if (options.hasOwnProperty(opt)) marker[opt] = options[opt]; @@ -3371,10 +3233,10 @@ window.CodeMirror = (function() { } if (marker.collapsed) sawCollapsedSpans = true; - var curLine = from.line, size = 0, collapsedAtStart, collapsedAtEnd; + var curLine = from.line, size = 0, collapsedAtStart, collapsedAtEnd, cm = doc.cm, updateMaxLine; doc.iter(curLine, to.line + 1, function(line) { - if (marker.collapsed && !cm.options.lineWrapping && visualLine(doc, line) == cm.view.maxLine) - cm.curOp.updateMaxLine = true; + if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(doc, line) == cm.display.maxLine) + updateMaxLine = true; var span = {from: null, to: null, marker: marker}; size += line.text.length; if (curLine == from.line) {span.from = from.ch; size -= from.ch;} @@ -3393,8 +3255,8 @@ window.CodeMirror = (function() { if (marker.readOnly) { sawReadOnlySpans = true; - if (cm.view.history.done.length || cm.view.history.undone.length) - cm.clearHistory(); + if (doc.history.done.length || doc.history.undone.length) + doc.clearHistory(); } if (marker.collapsed) { if (collapsedAtStart != collapsedAtEnd) @@ -3402,9 +3264,12 @@ window.CodeMirror = (function() { marker.size = size; marker.atomic = true; } - if (marker.className || marker.startStyle || marker.endStyle || marker.collapsed) - regChange(cm, from.line, to.line + 1); - if (marker.atomic) reCheckSelection(cm); + if (cm) runInOp(cm, function() { + if (updateMaxLine) cm.curOp.updateMaxLine = true; + if (marker.className || marker.startStyle || marker.endStyle || marker.collapsed) + regChange(cm, from.line, to.line + 1); + if (marker.atomic) reCheckSelection(cm); + }); return marker; } @@ -3454,14 +3319,18 @@ window.CodeMirror = (function() { return nw; } - function updateMarkedSpans(oldFirst, oldLast, startCh, endCh, newText) { - if (!oldFirst && !oldLast) return newText; + function stretchSpansOverChange(doc, change) { + 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; // Get the spans that 'stick out' on both sides var first = markedSpansBefore(oldFirst, startCh); var last = markedSpansAfter(oldLast, startCh, endCh); // Next, merge those two ends - var sameLine = newText.length == 1, offset = lst(newText).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) { @@ -3491,17 +3360,17 @@ window.CodeMirror = (function() { } } - var newMarkers = [newHL(newText[0], first)]; + var newMarkers = [first]; if (!sameLine) { // Fill gap with whole-line-spans - var gap = newText.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({from: null, to: null, marker: first[i].marker}); for (var i = 0; i < gap; ++i) - newMarkers.push(newHL(newText[i+1], gapMarkers)); - newMarkers.push(newHL(lst(newText), last)); + newMarkers.push(gapMarkers); + newMarkers.push(last); } return newMarkers; } @@ -3579,20 +3448,6 @@ window.CodeMirror = (function() { } } - // hl stands for history-line, a data structure that can be either a - // string (line without markers) or a {text, markedSpans} object. - function hlText(val) { return typeof val == "string" ? val : val.text; } - function hlSpans(val) { - if (typeof val == "string") return null; - var spans = val.markedSpans, out = null; - for (var 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]); - } - return !out ? spans : out.length ? out : null; - } - function newHL(text, spans) { return spans ? {text: text, markedSpans: spans} : text; } - function detachMarkedSpans(line) { var spans = line.markedSpans; if (!spans) return; @@ -3672,23 +3527,23 @@ window.CodeMirror = (function() { // Line objects. These hold state related to a line, including // highlighting info (the styles array). - function makeLine(text, markedSpans, height) { - var line = {text: text, height: height}; + function makeLine(text, markedSpans, estimateHeight) { + var line = {text: text}; attachMarkedSpans(line, markedSpans); - if (lineIsHidden(line)) line.height = 0; + line.height = estimateHeight ? estimateHeight(line) : 1; return line; } - function updateLine(cm, line, text, markedSpans) { + 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); - if (lineIsHidden(line)) line.height = 0; - else if (!line.height) line.height = textHeight(cm.display); - signalLater(cm, line, "change"); + var estHeight = estimateHeight ? estimateHeight(line) : 1; + if (estHeight != line.height) updateLineHeight(line, estHeight); + signalLater(line, "change"); } function cleanUpLine(line) { @@ -3725,13 +3580,13 @@ window.CodeMirror = (function() { function highlightLine(cm, line, state) { // A styles array always starts with a number identifying the // mode/overlays that it is based on (for easy invalidation). - var st = [cm.view.modeGen]; + var st = [cm.state.modeGen]; // Compute the base array of styles - runMode(cm, line.text, cm.view.mode, state, function(txt, style) {st.push(txt, style);}); + runMode(cm, line.text, cm.doc.mode, state, function(txt, style) {st.push(txt, style);}); // Run overlays, adjust style array. - for (var o = 0; o < cm.view.overlays.length; ++o) { - var overlay = cm.view.overlays[o], i = 1; + for (var o = 0; o < cm.state.overlays.length; ++o) { + var overlay = cm.state.overlays[o], i = 1; runMode(cm, line.text, overlay.mode, true, function(txt, style) { var start = i, len = txt.length; // Ensure there's a token end at the current position, and that i points at it @@ -3762,7 +3617,7 @@ window.CodeMirror = (function() { } function getLineStyles(cm, line) { - if (!line.styles || line.styles[0] != cm.view.modeGen) + if (!line.styles || line.styles[0] != cm.state.modeGen) line.styles = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line))); return line.styles; } @@ -3770,7 +3625,7 @@ window.CodeMirror = (function() { // Lightweight form of highlight -- proceed over this line and // update state, but don't save a style array. function processLine(cm, line, state) { - var mode = cm.view.mode; + var mode = cm.doc.mode; var stream = new StringStream(line.text, cm.options.tabSize); if (line.text == "" && mode.blankLine) mode.blankLine(state); while (!stream.eol() && stream.pos <= 5000) { @@ -3790,7 +3645,7 @@ window.CodeMirror = (function() { var merged, line = realLine, lineBefore, sawBefore, simple = true; while (merged = collapsedSpanAtStart(line)) { simple = false; - line = getLine(cm.view.doc, merged.find().from.line); + line = getLine(cm.doc, merged.find().from.line); if (!lineBefore) lineBefore = line; } @@ -3809,7 +3664,7 @@ window.CodeMirror = (function() { var next = insertLineContent(line, builder, getLineStyles(cm, line)); sawBefore = line == lineBefore; if (next) { - line = getLine(cm.view.doc, next.to.line); + line = getLine(cm.doc, next.to.line); simple = false; } } while (next); @@ -3948,6 +3803,49 @@ window.CodeMirror = (function() { // DOCUMENT DATA STRUCTURE + function updateDoc(doc, change, markedSpans, selAfter, estimateHeight) { + function spansFor(n) {return markedSpans ? markedSpans[n] : null;} + + 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; + + // First adjust the line structure + if (from.ch == 0 && to.ch == 0 && lastText == "") { + // This is a whole-line replace. Treated specially to make + // sure line objects move the way they are supposed to. + for (var i = 0, e = text.length - 1, added = []; i < e; ++i) + added.push(makeLine(text[i], spansFor(i), estimateHeight)); + updateLine(lastLine, lastLine.text, lastSpans, estimateHeight); + if (nlines) doc.remove(from.line, nlines); + if (added.length) doc.insert(from.line, added); + } else if (firstLine == lastLine) { + if (text.length == 1) { + updateLine(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), + lastSpans, estimateHeight); + } else { + for (var added = [], i = 1, e = text.length - 1; i < e; ++i) + added.push(makeLine(text[i], spansFor(i), estimateHeight)); + added.push(makeLine(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); + updateLine(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0), estimateHeight); + doc.insert(from.line + 1, added); + } + } else if (text.length == 1) { + updateLine(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), + spansFor(0), estimateHeight); + doc.remove(from.line + 1, nlines); + } else { + updateLine(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0), estimateHeight); + updateLine(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans, estimateHeight); + for (var i = 1, e = text.length - 1, added = []; i < e; ++i) + added.push(makeLine(text[i], spansFor(i), estimateHeight)); + if (nlines > 1) doc.remove(from.line + 1, nlines - 1); + doc.insert(from.line + 1, added); + } + + setSelection(doc, selAfter.anchor, selAfter.head, null, true); + } + function LeafChunk(lines) { this.lines = lines; this.parent = null; @@ -3960,19 +3858,19 @@ window.CodeMirror = (function() { LeafChunk.prototype = { chunkSize: function() { return this.lines.length; }, - remove: function(at, n, cm) { + 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(cm, line, "delete"); + signalLater(line, "delete"); } this.lines.splice(at, n); }, collapse: function(lines) { lines.splice.apply(lines, [lines.length, 0].concat(this.lines)); }, - insertHeight: function(at, lines, 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, e = lines.length; i < e; ++i) lines[i].parent = this; @@ -3998,13 +3896,13 @@ window.CodeMirror = (function() { BranchChunk.prototype = { chunkSize: function() { return this.size; }, - remove: function(at, n, callbacks) { + removeInner: function(at, n) { this.size -= n; for (var i = 0; i < this.children.length; ++i) { var child = this.children[i], sz = child.chunkSize(); if (at < sz) { var rm = Math.min(n, sz - at), oldHeight = child.height; - child.remove(at, rm, callbacks); + 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; @@ -4021,18 +3919,13 @@ window.CodeMirror = (function() { collapse: function(lines) { for (var i = 0, e = this.children.length; i < e; ++i) this.children[i].collapse(lines); }, - insert: function(at, lines) { - var height = 0; - for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height; - this.insertHeight(at, lines, height); - }, - insertHeight: function(at, lines, height) { + insertInner: function(at, lines, height) { this.size += lines.length; this.height += height; for (var i = 0, e = this.children.length; i < e; ++i) { var child = this.children[i], sz = child.chunkSize(); if (at <= sz) { - child.insertHeight(at, lines, height); + child.insertInner(at, lines, height); if (child.lines && child.lines.length > 50) { while (child.lines.length > 50) { var spilled = child.lines.splice(child.lines.length - 25, 25); @@ -4069,7 +3962,6 @@ window.CodeMirror = (function() { } while (me.children.length > 10); me.parent.maybeSpill(); }, - iter: function(from, to, op) { this.iterN(from, to - from, op); }, iterN: function(at, n, op) { for (var i = 0, e = this.children.length; i < e; ++i) { var child = this.children[i], sz = child.chunkSize(); @@ -4083,9 +3975,257 @@ window.CodeMirror = (function() { } }; + var nextDocId = 0; + var Doc = CodeMirror.Doc = function Doc(text, mode, firstLine) { + if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); + if (firstLine == null) firstLine = 0; + + BranchChunk.call(this, [new LeafChunk([makeLine("", null)])]); + this.first = firstLine; + this.scrollTop = this.scrollLeft = 0; + this.cantEdit = false; + this.history = makeHistory(); + this.frontier = firstLine; + var start = {line: firstLine, ch: 0}; + this.sel = {from: start, to: start, head: start, anchor: start, shift: false, extend: false, goalColumn: null}; + this.id = ++nextDocId; + this.modeOption = mode; + + if (typeof text == "string") text = splitLines(text); + updateDoc(this, {from: start, to: start, text: text}, null, {head: start, anchor: start}); + }; + + Doc.prototype = createObj(BranchChunk.prototype, { + iter: function(from, to, op) { + if (op) this.iterN(from - this.first, to - (from - this.first), op); + else this.iterN(this.first, this.first + this.size, from); + }, + + insert: function(at, lines) { + var height = 0; + for (var i = 0, e = lines.length; i < e; ++i) height += lines[i].height; + this.insertInner(at - this.first, lines, height); + }, + remove: function(at, n) { this.removeInner(at - this.first, n); }, + + getValue: function(lineSep) { + var lines = getLines(this, this.first, this.first + this.size); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + setValue: function(code) { + var top = {line: this.first, ch: 0}, last = this.first + this.size - 1; + makeChange(this, {from: top, to: {line: last, ch: getLine(this, last).text.length}, + text: splitLines(code), origin: "setValue"}, + {head: top, anchor: top}, true); + }, + replaceRange: function(code, from, to) { + from = clipPos(this, from); + to = to ? clipPos(this, to) : from; + replaceRange(this, code, from, to); + }, + getRange: function(from, to, lineSep) { + var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); + if (lineSep === false) return lines; + return lines.join(lineSep || "\n"); + }, + + getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, + setLine: function(line, text) { + if (isLine(this, line)) + replaceRange(this, text, {line: line, ch: 0}, {line: line, ch: getLine(this, line).text.length}); + }, + removeLine: function(line) { + if (isLine(this, line)) + replaceRange(this, "", {line: line, ch: 0}, clipPos(this, {line: line+1, ch: 0})); + }, + + getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, + getLineNumber: function(line) {return lineNo(line);}, + + 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);}, + + getCursor: function(start) { + var sel = this.sel, pos; + if (start == null || start == "head") pos = sel.head; + else if (start == "anchor") pos = sel.anchor; + else if (start == "end" || start === false) pos = sel.to; + else pos = sel.from; + return copyPos(pos); + }, + somethingSelected: function() {return !posEq(this.sel.head, this.sel.anchor);}, + + setCursor: docOperation(function(line, ch, extend) { + var pos = clipPos(this, typeof line == "number" ? {line: line, ch: ch || 0} : line); + if (extend) extendSelection(this, pos); + else setSelection(this, pos, pos); + }), + setSelection: docOperation(function(anchor, head) { + setSelection(this, clipPos(this, anchor), clipPos(this, head || anchor)); + }), + extendSelection: docOperation(function(from, to) { + extendSelection(this, clipPos(this, from), to && clipPos(this, to)); + }), + + getSelection: function(lineSep) {return this.getRange(this.sel.from, this.sel.to, lineSep);}, + replaceSelection: function(code, collapse, origin) { + makeChange(this, {from: this.sel.from, to: this.sel.to, text: splitLines(code), origin: origin}, collapse || "around"); + }, + undo: function() {makeChangeFromHistory(this, "undo");}, + redo: function() {makeChangeFromHistory(this, "redo");}, + + setExtending: function(val) {this.sel.extend = val;}, + + historySize: function() { + var hist = this.history; + return {undo: hist.done.length, redo: hist.undone.length}; + }, + clearHistory: function() {this.history = makeHistory();}, + + markClean: function() { + this.history.dirtyCounter = 0; + this.history.lastOp = this.history.lastOrigin = null; + }, + isClean: function () {return this.history.dirtyCounter == 0;}, + + getHistory: function() { + return {done: copyHistoryArray(this.history.done), + undone: copyHistoryArray(this.history.undone)}; + }, + setHistory: function(histData) { + var hist = this.history = makeHistory(); + hist.done = histData.done.slice(0); + hist.undone = histData.undone.slice(0); + }, + + markText: function(from, to, options) { + return markText(this, clipPos(this, from), clipPos(this, to), options, "range"); + }, + setBookmark: function(pos, widget) { + pos = clipPos(this, pos); + return markText(this, pos, pos, widget ? {replacedWith: widget} : {}, "bookmark"); + }, + 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]; + if ((span.from == null || span.from <= pos.ch) && + (span.to == null || span.to >= pos.ch)) + markers.push(span.marker); + } + return markers; + }, + + posFromIndex: function(off) { + var ch, lineNo = this.first; + this.iter(function(line) { + var sz = line.text.length + 1; + if (sz > off) { ch = off; return true; } + off -= sz; + ++lineNo; + }); + return clipPos(this, {line: lineNo, ch: ch}); + }, + indexFromPos: function (coords) { + coords = clipPos(this, coords); + var index = coords.ch; + if (coords.line < this.first || coords.ch < 0) return 0; + this.iter(this.first, coords.line, function (line) { + index += line.text.length + 1; + }); + return index; + }, + + copy: function(copyHistory) { + var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first); + doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; + doc.sel = {from: this.sel.from, to: this.sel.to, head: this.sel.head, anchor: this.sel.anchor, + shift: this.sel.shift, extend: false, goalColumn: this.sel.goalColumn}; + if (copyHistory) { + doc.history.undoDepth = this.history.undoDepth; + doc.setHistory(this.getHistory()); + } + 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); + 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}]; + return copy; + }, + 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 (link.doc != other) continue; + this.linked.splice(i, 1); + other.unlinkDoc(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 = makeHistory(); + other.history.done = copyHistoryArray(this.history.done, splitIds); + other.history.undone = copyHistoryArray(this.history.undone, splitIds); + } + }, + iterLinkedDocs: function(f) {linkedDocs(this, f);}, + + getEditor: function() {return this.cm;} + }); + + // The Doc methods that should be available on CodeMirror instances + var toDelegate = ("setValue getValue getSelection replaceSelection undo redo historySize clearHistory markClean isClean " + + "getHistory setHistory markText setBookmark findMarksAt lineCount firstLine lastLine clipPos getCursor " + + "somethingSelected setCursor setSelection extendSelection setExtending getLine setLine removeLine " + + "replaceRange getRange getLineHandle getLineNumber posFromIndex indexFromPos linkedDoc unlinkDoc iterLinkedDocs").split(" "); + for (var i = 0; i < toDelegate.length; ++i) (function(method) { + var target = Doc.prototype[method]; + CodeMirror.prototype[method] = function() {return target.apply(this.doc, arguments);}; + })(toDelegate[i]); + + 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); + } + } + propagate(doc, null, true); + } + + 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) computeMaxLength(cm); + cm.options.mode = doc.modeOption; + regChange(cm); + } + // LINE UTILITIES function getLine(chunk, n) { + n -= chunk.first; while (!chunk.lines) { for (var i = 0;; ++i) { var child = chunk.children[i], sz = child.chunkSize(); @@ -4096,6 +4236,23 @@ window.CodeMirror = (function() { return chunk.lines[n]; } + function getBetween(doc, start, end) { + 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; + } + function getLines(doc, from, to) { + var out = []; + doc.iter(from, to, function(line) { out.push(line.text); }); + return out; + } + function updateLineHeight(line, height) { var diff = height - line.height; for (var n = line; n; n = n.parent) n.height += diff; @@ -4110,7 +4267,7 @@ window.CodeMirror = (function() { no += chunk.children[i].chunkSize(); } } - return no; + return no + cur.first; } function lineDoc(line) { @@ -4119,7 +4276,7 @@ window.CodeMirror = (function() { } function lineAtHeight(chunk, h) { - var n = 0; + var n = chunk.first; outer: do { for (var i = 0, e = chunk.children.length; i < e; ++i) { var child = chunk.children[i], ch = child.height; @@ -4138,7 +4295,7 @@ window.CodeMirror = (function() { } function heightAtLine(cm, lineObj) { - lineObj = visualLine(cm.view.doc, lineObj); + lineObj = visualLine(cm.doc, lineObj); var h = 0, chunk = lineObj.parent; for (var i = 0; i < chunk.lines.length; ++i) { @@ -4169,7 +4326,7 @@ window.CodeMirror = (function() { // Arrays of history events. Doing something adds an event to // done and clears undo. Undoing moves events from done to // undone, redoing moves them in the other direction. - done: [], undone: [], + done: [], undone: [], undoDepth: Infinity, // Used to track when changes can be merged into a single undo // event lastTime: 0, lastOp: null, lastOrigin: null, @@ -4178,47 +4335,157 @@ window.CodeMirror = (function() { }; } - function addChange(cm, start, added, old, origin, fromBefore, toBefore, fromAfter, toAfter) { - var history = cm.view.history; - history.undone.length = 0; - var time = +new Date, cur = lst(history.done); - + function attachLocalSpans(doc, change, from, to) { + 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; + }); + } + + function historyChangeFromChange(doc, change) { + var histChange = {from: 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; + } + + function addToHistory(doc, change, selAfter, opId) { + var hist = doc.history; + hist.undone.length = 0; + var time = +new Date, cur = lst(hist.done); + if (cur && - (history.lastOp == cm.curOp.id || - history.lastOrigin == origin && (origin == "input" || origin == "delete") && - history.lastTime > time - 600)) { + (hist.lastOp == opId || + hist.lastOrigin == change.origin && (change.origin == "input" || change.origin == "delete") && + hist.lastTime > time - 600)) { // Merge this change into the last event - var last = lst(cur.events); - if (last.start > start + old.length || last.start + last.added < start) { - // Doesn't intersect with last sub-event, add new sub-event - cur.events.push({start: start, added: added, old: old}); + var last = lst(cur.changes); + if (posEq(change.from, change.to) && posEq(change.from, last.to)) { + // Optimized case for simple insertion -- don't want to add + // new changesets for every character typed + last.to = changeEnd(change); } else { - // Patch up the last sub-event - var startBefore = Math.max(0, last.start - start), - endAfter = Math.max(0, (start + old.length) - (last.start + last.added)); - for (var i = startBefore; i > 0; --i) last.old.unshift(old[i - 1]); - for (var i = endAfter; i > 0; --i) last.old.push(old[old.length - i]); - if (startBefore) last.start = start; - last.added += added - (old.length - startBefore - endAfter); + // Add new sub-event + cur.changes.push(historyChangeFromChange(doc, change)); } - cur.fromAfter = fromAfter; cur.toAfter = toAfter; + cur.anchorAfter = selAfter.anchor; cur.headAfter = selAfter.head; } else { // Can not be merged, start a new event. - cur = {events: [{start: start, added: added, old: old}], - fromBefore: fromBefore, toBefore: toBefore, fromAfter: fromAfter, toAfter: toAfter}; - history.done.push(cur); - while (history.done.length > cm.options.undoDepth) - history.done.shift(); - if (history.dirtyCounter < 0) - // The user has made a change after undoing past the last clean state. - // We can never get back to a clean state now until markClean() is called. - history.dirtyCounter = NaN; + cur = {changes: [historyChangeFromChange(doc, change)], + anchorBefore: doc.sel.anchor, headBefore: doc.sel.head, + anchorAfter: selAfter.anchor, headAfter: selAfter.head}; + hist.done.push(cur); + while (hist.done.length > hist.undoDepth) + hist.done.shift(); + if (hist.dirtyCounter < 0) + // The user has made a change after undoing past the last clean state. + // We can never get back to a clean state now until markClean() is called. + hist.dirtyCounter = NaN; else - history.dirtyCounter++; + hist.dirtyCounter++; } - history.lastTime = time; - history.lastOp = cm.curOp.id; - history.lastOrigin = origin; + hist.lastTime = time; + hist.lastOp = opId; + hist.lastOrigin = change.origin; + } + + function removeClearedSpans(spans) { + 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]); + } + return !out ? spans : out.length ? out : null; + } + + // FIXME this goes wrong when + // - making a change on line n + // - setting a marker on line n outside of change + // - undoing the change (will wrongly clear the marker) + // needs an algorithm for selectively merging the undone ranges into + // the current surrounding + function getOldSpans(doc, change) { + 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; + } + + // Used both to provide a JSON-safe object in .getHistory, and, when + // detaching a document, to split the history in two + function copyHistoryArray(events, newGroup) { + for (var i = 0, copy = []; i < events.length; ++i) { + var event = events[i], changes = event.changes, newChanges = []; + copy.push({changes: newChanges, anchorBefore: event.anchorBefore, headBefore: event.headBefore, + anchorAfter: event.anchorAfter, headAfter: event.headAfter}); + for (var j = 0; j < changes.length; ++j) { + 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]; + } + } + } + } + return copy; + } + + // Rebasing/resetting history to deal with externally-sourced changes + + function rebaseHistSel(pos, from, to, diff) { + if (to < pos.line) { + pos.line += diff; + } else if (from < pos.line) { + pos.line = from; + pos.ch = 0; + } + } + + // Tries to rebase an array of history events given a change in the + // document. If the change touches the same lines as the event, the + // event, and everything 'behind' it, is discarded. If the change is + // before the event, the event's positions are updated. Uses a + // copy-on-write scheme for the positions, to avoid having to + // 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 (var j = 0; j < sub.changes.length; ++j) { + var cur = sub.changes[j]; + if (!sub.copied) { cur.from = copyPos(cur.from); cur.to = copyPos(cur.to); } + if (to < cur.from.line) { + cur.from.line += diff; + cur.to.line += diff; + } else if (from <= cur.to.line) { + ok = false; + break; + } + } + if (!sub.copied) { + sub.anchorBefore = copyPos(sub.anchorBefore); sub.headBefore = copyPos(sub.headBefore); + sub.anchorAfter = copyPos(sub.anchorAfter); sub.readAfter = copyPos(sub.headAfter); + sub.copied = true; + } + if (!ok) { + array.splice(0, i + 1); + i = 0; + } else { + rebaseHistSel(sub.anchorBefore); rebaseHistSel(sub.headBefore); + rebaseHistSel(sub.anchorAfter); rebaseHistSel(sub.headAfter); + } + } + } + + 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); } // EVENT OPERATORS @@ -4296,13 +4563,14 @@ window.CodeMirror = (function() { for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args); } - function signalLater(cm, emitter, type /*, values...*/) { + var delayedCallbacks, delayedCallbackDepth = 0; + function signalLater(emitter, type /*, values...*/) { var arr = emitter._handlers && emitter._handlers[type]; if (!arr) return; - var args = Array.prototype.slice.call(arguments, 3), flist = cm.curOp && cm.curOp.delayedCallbacks; + var args = Array.prototype.slice.call(arguments, 3); function bnd(f) {return function(){f.apply(null, args);};}; for (var i = 0; i < arr.length; ++i) - if (flist) flist.push(bnd(arr[i])); + if (delayedCallbacks) delayedCallbacks.push(bnd(arr[i])); else arr[i].apply(null, args); } @@ -4363,6 +4631,15 @@ window.CodeMirror = (function() { return -1; } + function createObj(base, props) { + if (!base) return; + createObj.prototype = base; + var inst = new createObj(); + if (props) for (var n in props) if (props.hasOwnProperty(n)) + inst[n] = props[n]; + return inst; + } + function emptyArray(size) { for (var a = [], i = 0; i < size; ++i) a.push(undefined); return a; @@ -4540,8 +4817,8 @@ window.CodeMirror = (function() { } function lineStart(cm, lineN) { - var line = getLine(cm.view.doc, lineN); - var visual = visualLine(cm.view.doc, line); + var line = getLine(cm.doc, lineN); + var visual = visualLine(cm.doc, line); if (visual != line) lineN = lineNo(visual); var order = getOrder(visual); var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); @@ -4549,7 +4826,7 @@ window.CodeMirror = (function() { } function lineEnd(cm, lineNo) { var merged, line; - while (merged = collapsedSpanAtEnd(line = getLine(cm.view.doc, lineNo))) + while (merged = collapsedSpanAtEnd(line = getLine(cm.doc, lineNo))) lineNo = merged.find().to.line; var order = getOrder(line); var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); diff --git a/test/doc_test.js b/test/doc_test.js new file mode 100644 index 0000000000..567a577ac4 --- /dev/null +++ b/test/doc_test.js @@ -0,0 +1,290 @@ +(function() { + // A minilanguage for instantiating linked CodeMirror instances and Docs + function instantiateSpec(spec, place, opts) { + var names = {}, pos = 0, l = spec.length, editors = []; + while (spec) { + var m = spec.match(/^(\w+)(\*?)(?:='([^\']*)'|<(~?)(\w+)(?:\/(\d+)-(\d+))?)\s*/); + var name = m[1], isDoc = m[2], cur; + if (m[3]) { + cur = isDoc ? CodeMirror.Doc(m[3]) : CodeMirror(place, clone(opts, {value: m[3]})); + } else { + var other = m[5]; + if (!names.hasOwnProperty(other)) { + names[other] = editors.length; + editors.push(CodeMirror(place, opts)); + } + var doc = editors[names[other]].linkedDoc({ + sharedHist: !m[4], + from: m[6] && Number(m[6]), + to: m[7] && Number(m[7]) + }); + cur = isDoc ? doc : CodeMirror(place, clone(opts, {value: doc})); + } + names[name] = editors.length; + editors.push(cur); + spec = spec.slice(m[0].length); + } + return editors; + } + + function clone(obj, props) { + if (!obj) return; + clone.prototype = obj; + var inst = new clone(); + if (props) for (var n in props) if (props.hasOwnProperty(n)) + inst[n] = props[n]; + return inst; + } + + function eqAll(val) { + var end = arguments.length, msg = null; + if (typeof arguments[end-1] == "string") + msg = arguments[--end]; + if (i == end) throw new Error("No editors provided to eqAll"); + for (var i = 1; i < end; ++i) + eq(arguments[i].getValue(), val, msg) + } + + function testDoc(name, spec, run, opts) { + if (!opts) opts = {}; + + return test("doc_" + name, function() { + var place = document.getElementById("testground"); + var editors = instantiateSpec(spec, place, opts); + var successful = false; + + try { + run.apply(null, editors); + successful = true; + } finally { + if ((debug && !successful) || verbose) { + place.style.visibility = ""; + } else { + for (var i = 0; i < editors.length; ++i) + if (editors[i] instanceof CodeMirror) + place.removeChild(editors[i].getWrapperElement()); + } + } + }); + } + + function testBasic(a, b) { + eqAll("x", a, b); + a.setValue("hey"); + eqAll("hey", a, b); + b.setValue("wow"); + eqAll("wow", a, b); + a.replaceRange("u\nv\nw", {line: 0, ch: 3}); + b.replaceRange("i", {line: 0, ch: 4}); + b.replaceRange("j", {line: 2, ch: 1}); + eqAll("wowui\nv\nwj", a, b); + } + + testDoc("basic", "A='x' B 0, "not at left"); + is(pos.top > 0, "not at top"); + }); + + testDoc("copyDoc", "A='u'", function(a) { + var copy = a.getDoc().copy(true); + a.setValue("foo"); + copy.setValue("bar"); + var old = a.swapDoc(copy); + eq(a.getValue(), "bar"); + a.undo(); + eq(a.getValue(), "u"); + a.swapDoc(old); + eq(a.getValue(), "foo"); + eq(old.historySize().undo, 1); + eq(old.copy(false).historySize().undo, 0); + }); + + testDoc("docKeepsMode", "A='1+1'", function(a) { + var other = CodeMirror.Doc("hi", "text/x-markdown"); + a.setOption("mode", "text/javascript"); + var old = a.swapDoc(other); + eq(a.getOption("mode"), "text/x-markdown"); + eq(a.getMode().name, "markdown"); + a.swapDoc(old); + eq(a.getOption("mode"), "text/javascript"); + eq(a.getMode().name, "javascript"); + }); + + testDoc("subview", "A='1\n2\n3\n4\n5' B<~A/1-3", function(a, b) { + eq(b.getValue(), "2\n3"); + eq(b.firstLine(), 1); + b.setCursor({line: 4}); + eqPos(b.getCursor(), {line: 2, ch: 1}); + a.replaceRange("-1\n0\n", {line: 0, ch: 0}); + eq(b.firstLine(), 3); + eqPos(b.getCursor(), {line: 4, ch: 1}); + a.undo(); + eqPos(b.getCursor(), {line: 2, ch: 1}); + b.replaceRange("oyoy\n", {line: 2, ch: 0}); + eq(a.getValue(), "1\n2\noyoy\n3\n4\n5"); + b.undo(); + eq(a.getValue(), "1\n2\n3\n4\n5"); + }); + + testDoc("subviewEditOnBoundary", "A='11\n22\n33\n44\n55' B<~A/1-4", function(a, b) { + a.replaceRange("x\nyy\nz", {line: 0, ch: 1}, {line: 2, ch: 1}); + eq(b.firstLine(), 2); + eq(b.lineCount(), 2); + eq(b.getValue(), "z3\n44"); + a.replaceRange("q\nrr\ns", {line: 3, ch: 1}, {line: 4, ch: 1}); + eq(b.firstLine(), 2); + eq(b.getValue(), "z3\n4q"); + eq(a.getValue(), "1x\nyy\nz3\n4q\nrr\ns5"); + a.execCommand("selectAll"); + a.replaceSelection("!"); + eqAll("!", a, b); + }); +})(); diff --git a/test/driver.js b/test/driver.js index 6d480e9460..aba427702e 100644 --- a/test/driver.js +++ b/test/driver.js @@ -117,8 +117,8 @@ function eq(a, b, msg) { function eqPos(a, b, msg) { function str(p) { return "{line:" + p.line + ",ch:" + p.ch + "}"; } if (a == b) return; - if (a == null) throw new Failure(label("comparing null to " + str(b))); - if (b == null) throw new Failure(label("comparing " + str(a) + " to null")); + if (a == null) throw new Failure(label("comparing null to " + str(b), msg)); + if (b == null) throw new Failure(label("comparing " + str(a) + " to null", msg)); if (a.line != b.line || a.ch != b.ch) throw new Failure(label(str(a) + " != " + str(b), msg)); } function is(a, msg) { @@ -135,4 +135,4 @@ function countTests() { ++sum; } return sum; -} \ No newline at end of file +} diff --git a/test/index.html b/test/index.html index d4cec017f6..24bdf999d8 100644 --- a/test/index.html +++ b/test/index.html @@ -52,6 +52,7 @@

    CodeMirror: Test Suite

    + @@ -65,12 +66,8 @@

    CodeMirror: Test Suite

    From f861359412e902d3b635726623a530691878baaf Mon Sep 17 00:00:00 2001 From: Ice White Date: Wed, 23 Jan 2013 14:24:33 +0800 Subject: [PATCH 0113/5273] tiddlwiki => tiddlywiki --- mode/meta.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/meta.js b/mode/meta.js index ad212f9663..d6296c332f 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -57,7 +57,7 @@ CodeMirror.modeInfo = [ {name: 'PL/SQL', mime: 'text/x-plsql', mode: 'sql'}, {name: 'sTeX', mime: 'text/x-stex', mode: 'stex'}, {name: 'LaTeX', mime: 'text/x-latex', mode: 'stex'}, - {name: 'TiddlyWiki ', mime: 'text/x-tiddlywiki', mode: 'tiddlwiki'}, + {name: 'TiddlyWiki ', mime: 'text/x-tiddlywiki', mode: 'tiddlywiki'}, {name: 'Tiki wiki', mime: 'text/tiki', mode: 'tiki'}, {name: 'VB.NET', mime: 'text/x-vb', mode: 'vb'}, {name: 'VBScript', mime: 'text/vbscript', mode: 'vbscript'}, From 56f1f15a7ee3fc1711aeb3a326a4c30887fff729 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 23 Jan 2013 12:54:56 +0100 Subject: [PATCH 0114/5273] Add "hide"/"unhide" events for markers These fire when the marker is removed/resurrected by editing and undo operations. Closes #1093 --- doc/manual.html | 6 ++++++ lib/codemirror.js | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 93271c51ca..da2a6580c2 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -423,6 +423,12 @@

    Events

    be fired once per handle. Note that deleting the range through text editing does not fire this event, because an undo action might bring the range back into existence. +
    "hide" ()
    +
    Fired when the last part of the marker is removed from the + document by editing operations.
    +
    "unhide" ()
    +
    Fired when, after the marker was removed by editing, a undo + operation brought the marker back.

    Line widgets, returned diff --git a/lib/codemirror.js b/lib/codemirror.js index cee61ac586..2575cd9b62 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1241,6 +1241,12 @@ window.CodeMirror = (function() { if (cm.state.focused && op.updateInput) resetInput(cm, op.userSelChange); + 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 (unhidden) for (var i = 0; i < unhidden.length; ++i) + if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); + if (op.textChanged) signal(cm, "change", cm, op.textChanged); if (op.selectionChanged) signal(cm, "cursorActivity", cm); @@ -3269,8 +3275,25 @@ window.CodeMirror = (function() { startStyle: this.startStyle, endStyle: this.endStyle}; }; + TextMarker.prototype.attachLine = function(line) { + if (!this.lines.length && this.doc.cm) { + var op = this.doc.cm.curOp; + if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) + (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); + } + this.lines.push(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; + (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); + } + }; + function markText(doc, from, to, options, type) { if (options && options.shared) return markTextShared(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); if (type == "range" && !posLess(from, to)) return marker; @@ -3312,12 +3335,12 @@ window.CodeMirror = (function() { marker.size = size; marker.atomic = true; } - if (cm) runInOp(cm, function() { + if (cm) { if (updateMaxLine) cm.curOp.updateMaxLine = true; if (marker.className || marker.startStyle || marker.endStyle || marker.collapsed) regChange(cm, from.line, to.line + 1); if (marker.atomic) reCheckSelection(cm); - }); + } return marker; } @@ -3377,7 +3400,7 @@ window.CodeMirror = (function() { } function addMarkedSpan(line, span) { line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; - span.marker.lines.push(line); + span.marker.attachLine(line); } function markedSpansBefore(old, startCh) { @@ -3562,18 +3585,15 @@ window.CodeMirror = (function() { function detachMarkedSpans(line) { var spans = line.markedSpans; if (!spans) return; - for (var i = 0; i < spans.length; ++i) { - var lines = spans[i].marker.lines; - var ix = indexOf(lines, line); - lines.splice(ix, 1); - } + for (var i = 0; i < spans.length; ++i) + spans[i].marker.detachLine(line); line.markedSpans = null; } function attachMarkedSpans(line, spans) { if (!spans) return; for (var i = 0; i < spans.length; ++i) - spans[i].marker.lines.push(line); + spans[i].marker.attachLine(line); line.markedSpans = spans; } From b6149ccbab7282d9929eb48e86de77b4c612d019 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 23 Jan 2013 14:48:20 +0100 Subject: [PATCH 0115/5273] Add show-hint add-on to replace simple-hint --- addon/hint/show-hint.css | 37 ++++++++++++++ addon/hint/show-hint.js | 101 +++++++++++++++++++++++++++++++++++++++ demo/complete.html | 6 +-- doc/manual.html | 11 ++++- 4 files changed, 150 insertions(+), 5 deletions(-) create mode 100644 addon/hint/show-hint.css create mode 100644 addon/hint/show-hint.js diff --git a/addon/hint/show-hint.css b/addon/hint/show-hint.css new file mode 100644 index 0000000000..55661c9c0c --- /dev/null +++ b/addon/hint/show-hint.css @@ -0,0 +1,37 @@ +.CodeMirror-hints { + position: absolute; + z-index: 10; + overflow: hidden; + list-style: none; + + margin: 0; + padding: 2px; + + -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); + box-shadow: 2px 3px 5px rgba(0,0,0,.2); + border-radius: 3px; + + background: white; + font-size: 90%; + font-family: monospace; + + max-height: 20em; + overflow-y: auto; +} + +.CodeMirror-hint { + margin: 0; + padding: 0 4px; + border-radius: 2px; + max-width: 19em; + overflow: hidden; + white-space: pre; + color: black; + cursor: pointer; +} + +.CodeMirror-hint-active { + background: #08f; + color: white; +} diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js new file mode 100644 index 0000000000..dc381d8510 --- /dev/null +++ b/addon/hint/show-hint.js @@ -0,0 +1,101 @@ +CodeMirror.showHint = function(cm, getHints, options) { + if (!options) options = {}; + + function collectHints(previousToken) { + // We want a single cursor position. + if (cm.somethingSelected()) return; + + var token = cm.getTokenAt(cm.getCursor()); + + // Don't show completions if token has changed + if (previousToken != null && + (token.start != previousToken.start || token.type != previousToken.type)) + return; + + var result = getHints(cm, options); + if (!result || !result.list.length) return; + var completions = result.list; + // When there is only one completion, use it directly. + if (!previousToken && options.completeSingle !== false && completions.length == 1) { + cm.replaceRange(completions[0], result.from, result.to); + return true; + } + + // Build the select widget + var hints = document.createElement("ul"), selectedHint = 0; + hints.className = "CodeMirror-hints"; + for (var i = 0; i < completions.length; ++i) { + var elt = hints.appendChild(document.createElement("li")); + elt.className = "CodeMirror-hint" + (i ? "" : " CodeMirror-hint-active"); + elt.appendChild(document.createTextNode(completions[i])); + elt.hintId = i; + } + var pos = cm.cursorCoords(options.alignWithWord !== false ? result.from : null); + hints.style.left = pos.left + "px"; + hints.style.top = pos.bottom + "px"; + document.body.appendChild(hints); + + // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. + var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); + if (winW - pos.left < hints.clientWidth) + hints.style.left = (pos.left - sel.clientWidth) + "px"; + + function changeActive(i) { + if (i < 0 || i >= completions.length || selectedHint == i) return; + hints.childNodes[selectedHint].className = "CodeMirror-hint"; + var node = hints.childNodes[selectedHint = i]; + node.className = "CodeMirror-hint CodeMirror-hint-active"; + if (node.offsetTop < hints.scrollTop) + hints.scrollTop = node.offsetTop - 3; + else if (node.offsetTop + node.offsetHeight > hints.scrollTop + hints.clientHeight) + hints.scrollTop = node.offsetTop + node.offsetHeight - hints.clientHeight + 3; + } + + var ourMap = { + Up: function() {changeActive(selectedHint - 1);}, + Down: function() {changeActive(selectedHint + 1);}, + Enter: pick, + Tab: pick, + Esc: close + }; + if (options.customKeys) for (var key in options.customKeys) if (options.customKeys.hasOwnProperty(key)) { + var val = options.customKeys[key]; + if (/^(Up|Down|Enter|Esc)$/.test(key)) val = ourMap[val]; + ourMap[key] = val; + } + + cm.addKeyMap(ourMap); + cm.on("cursorActivity", cursorActivity); + CodeMirror.on(hints, "dblclick", function(e) { + var t = e.target || e.srcElement; + if (t.hintId != null) {selectedHint = t.hintId; pick();} + setTimeout(function(){cm.focus();}, 20); + }); + CodeMirror.on(hints, "click", function(e) { + var t = e.target || e.srcElement; + if (t.hintId != null) changeActive(t.hintId); + setTimeout(function(){cm.focus();}, 20); + }); + + var done = false, once; + function close() { + if (done) return; + done = true; + clearTimeout(once); + hints.parentNode.removeChild(hints); + cm.removeKeyMap(ourMap); + cm.off("cursorActivity", cursorActivity); + } + function pick() { + cm.replaceRange(completions[selectedHint], result.from, result.to); + close(); + } + var once; + function cursorActivity() { + clearTimeout(once); + once = setTimeout(function(){close(); collectHints(token);}, 70); + } + return true; + } + return collectHints(); +}; diff --git a/demo/complete.html b/demo/complete.html index 2efbd3d622..c94f6b40d6 100644 --- a/demo/complete.html +++ b/demo/complete.html @@ -5,8 +5,8 @@ CodeMirror: Autocomplete Demo - - + + @@ -59,7 +59,7 @@

    CodeMirror: Autocomplete demo

    - - + + @@ -23,7 +23,7 @@

    CodeMirror: XML Autocomplete demo

    Type '<' or space inside tag or press ctrl-space to activate autocompletion. See - the code (here + the code (here and here) to figure out how it works.

    @@ -57,14 +57,22 @@

    CodeMirror: XML Autocomplete demo

    'x-three' ]; + CodeMirror.commands.autocomplete = function(cm) { + CodeMirror.showHint(cm, CodeMirror.xmlHint); + } + function passAndHint(cm) { + setTimeout(function() {cm.execCommand("autocomplete");}, 100); + throw CodeMirror.Pass; + } + var editor = CodeMirror.fromTextArea(document.getElementById("code"), { value: '', mode: 'text/html', lineNumbers: true, extraKeys: { - "' '": function(cm) { CodeMirror.xmlHint(cm, ' '); }, - "'<'": function(cm) { CodeMirror.xmlHint(cm, '<'); }, - "Ctrl-Space": function(cm) { CodeMirror.xmlHint(cm, ''); } + "' '": passAndHint, + "'<'": passAndHint, + "Ctrl-Space": "autocomplete" }, autoCloseTags: true }); From e8c7955c4139844786ead37a0a2eb8ba4f7204af Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 23 Jan 2013 19:26:29 +0100 Subject: [PATCH 0117/5273] Fix bug in the way event handlers are called Issue #1178 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 2575cd9b62..d4d575537f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4696,7 +4696,7 @@ window.CodeMirror = (function() { function signalLater(emitter, type /*, values...*/) { var arr = emitter._handlers && emitter._handlers[type]; if (!arr) return; - var args = Array.prototype.slice.call(arguments, 3); + var args = Array.prototype.slice.call(arguments, 2); function bnd(f) {return function(){f.apply(null, args);};}; for (var i = 0; i < arr.length; ++i) if (delayedCallbacks) delayedCallbacks.push(bnd(arr[i])); From 8a5aee5462586630df455caf9067759c8d35b7d1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 25 Jan 2013 13:06:40 +0100 Subject: [PATCH 0118/5273] Add Code Monster & Code Maven to real-world uses --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 870c28d312..13eea24b1b 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -28,6 +28,7 @@

    { } CodeMi
  • Cargo Collective (creative publishing platform)
  • Codebug (PHP Xdebug front-end)
  • CodeMirror2-GWT (Google Web Toolkit wrapper)
  • +
  • Code Monster & Code Maven (learning environment)
  • Codepen (gallery of animations)
  • Code School (online tech learning environment)
  • Codev (collaborative IDE)
  • From 7525611d361d451ed67fb1861707fff2a3ec5aff Mon Sep 17 00:00:00 2001 From: Jochen Berger Date: Thu, 24 Jan 2013 08:12:41 +0100 Subject: [PATCH 0119/5273] when checking whether the wrapper element is still part of the DOM, check all the way up to the document body --- lib/codemirror.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index d4d575537f..2de52a094f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1396,10 +1396,14 @@ window.CodeMirror = (function() { // Prevent wrapper from ever scrolling on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); on(window, "resize", function resizeHandler() { + var currentParent = d.wrapper.parentNode; // Might be a text scaling operation, clear size caches. d.cachedCharWidth = d.cachedTextHeight = null; clearCaches(cm); - if (d.wrapper.parentNode) runInOp(cm, bind(regChange, cm)); + while (currentParent !== document.body && currentParent !== null) { + currentParent = currentParent.parentNode; + } + if (currentParent === document.body) runInOp(cm, bind(regChange, cm)); else off(window, "resize", resizeHandler); }); From 02088b8ff92f05f0448faa16e65191622a266476 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 25 Jan 2013 13:09:27 +0100 Subject: [PATCH 0120/5273] Fix memory leak The window.onresize handlers registered for each editor would prevent them from ever getting collected. --- lib/codemirror.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 2de52a094f..4f7b06535b 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1395,17 +1395,24 @@ window.CodeMirror = (function() { on(d.scrollbarV, "mousedown", reFocus); // Prevent wrapper from ever scrolling on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); - on(window, "resize", function resizeHandler() { - var currentParent = d.wrapper.parentNode; + + if (!window.registered) window.registered = 0; + ++window.registered; + function onResize() { // Might be a text scaling operation, clear size caches. d.cachedCharWidth = d.cachedTextHeight = null; clearCaches(cm); - while (currentParent !== document.body && currentParent !== null) { - currentParent = currentParent.parentNode; - } - if (currentParent === document.body) runInOp(cm, bind(regChange, cm)); - else off(window, "resize", resizeHandler); - }); + runInOp(cm, bind(regChange, cm)); + } + on(window, "resize", onResize); + // Above handler holds on to the editor and its data structures. + // Here we poll to unregister it when the editor is no longer in + // the document, so that it can be garbage-collected. + setTimeout(function unregister() { + for (var p = d.wrapper.parentNode; p && p != document.body; p = p.parentNode) {} + if (p) setTimeout(unregister, 5000); + else {--window.registered; off(window, "resize", onResize);} + }, 5000); on(d.input, "keyup", operation(cm, function(e) { if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; From 335ac34e73556d32780540f5b0caaef04cd6aec0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 25 Jan 2013 13:46:46 +0100 Subject: [PATCH 0121/5273] Note release 3.02 --- doc/compress.html | 1 + index.html | 6 ++++++ lib/codemirror.js | 2 +- package.json | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 94f293c725..aa94d70dd6 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -30,6 +30,7 @@

    { } CodeMi

    Version: + + + +

    Simple addon to easily mark (and style) selected text.

    + + + diff --git a/demo/matchhighlighter.html b/demo/matchhighlighter.html index ea5944ce33..dd59af36c6 100644 --- a/demo/matchhighlighter.html +++ b/demo/matchhighlighter.html @@ -11,9 +11,9 @@ @@ -26,11 +26,11 @@

    CodeMirror: Match Highlighter Demo

    -

    Highlight matches of selected text on select

    +

    Search and highlight occurences of the selected text.

    From 4388df166fa5c7e0535d41292f4bbf97324a8d13 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Feb 2013 10:01:00 +0100 Subject: [PATCH 0166/5273] Clean up mark-selection add-on --- addon/selection/mark-selection.js | 50 ++++++++++++------------------- demo/markselection.html | 11 ++++--- 2 files changed, 24 insertions(+), 37 deletions(-) diff --git a/addon/selection/mark-selection.js b/addon/selection/mark-selection.js index 755f3ed1f9..7342135545 100644 --- a/addon/selection/mark-selection.js +++ b/addon/selection/mark-selection.js @@ -1,38 +1,26 @@ // Because sometimes you need to mark the selected *text*. -// Use by attaching the following function call to the cursorActivity event: - //myCodeMirror.markSelection(); -// To clear the selection mark, run: - //myCodeMirror.markSelection.clear(myCodeMirror); -// The selection will be marked with `.CodeMirror-selection`. -"use strict"; +// +// Adds an option 'styleSelectedText' which, when enabled, gives +// selected text the CSS class "CodeMirror-selectedtext". (function() { - function lessthan(a, b) { - if (a.line < b.line) return true; - if (a.line == b.line) return a.ch < b.ch; - } + "use strict"; + + CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) + cm.on("cursorActivity", updateSelectedText); + else if (!val && prev) + cm.off("cursorActivity", updateSelectedText); + }); - function clear(cm) { + function updateSelectedText(cm) { if (cm._selectionMark) cm._selectionMark.clear(); + + if (cm.somethingSelected()) + cm._selectionMark = cm.markText(cm.getCursor("start"), cm.getCursor("end"), + {className: "CodeMirror-selectedtext"}); + else + cm._selectionMark = null; } - - function markSelection(minChars, className) { - var cm = this; - clear(cm); - if (!cm.somethingSelected()) return; - - var start = cm.getCursor('anchor') - , end = cm.getCursor(); - - if (lessthan(end, start)) { - var i = end; - end = start; - start = i; - } - - cm._selectionMark = cm.markText(start, end, {className:'CodeMirror-selection'}); - } - - markSelection.clear = clear; - CodeMirror.defineExtension("markSelection", markSelection); })(); diff --git a/demo/markselection.html b/demo/markselection.html index 9a7d64ea1a..e1c054869f 100644 --- a/demo/markselection.html +++ b/demo/markselection.html @@ -11,9 +11,8 @@ @@ -25,9 +24,9 @@

    CodeMirror: Mark Selection Demo

    behind the text, you'll need something like this to change its colour. From 5f7171ed556b571bab3cd0e248ecff25497baec6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Feb 2013 10:18:43 +0100 Subject: [PATCH 0167/5273] [match-highlighter addon] Rewrite to use defineOption and an overlay --- addon/search/match-highlighter.js | 89 +++++++++++++++++-------------- demo/matchhighlighter.html | 10 ++-- 2 files changed, 53 insertions(+), 46 deletions(-) diff --git a/addon/search/match-highlighter.js b/addon/search/match-highlighter.js index b8e7e3e388..c6e35cd97e 100644 --- a/addon/search/match-highlighter.js +++ b/addon/search/match-highlighter.js @@ -1,53 +1,60 @@ -// Define match-highlighter commands. Depends on searchcursor.js -// Use by attaching the following function call to the cursorActivity event: -// myCodeMirror.matchHighlight([minChars], [className]); -// And including a CSS rules for `span.CodeMirror-matchhighlight` (also -// optionally a separate one for `.CodeMirror-focused` -- see demo matchhighlighter.html). -// To clear all marks, run: -// myCodeMirror.matchHighlight.clear(myCodeMirror); +// Highlighting text that matches the selection +// +// Defines an option highlightSelectionMatches, which, when enabled, +// will style strings that match the selection throughout the +// document. +// +// The option can be set to true to simply enable it, or to a +// {minChars, style} object to explicitly configure it. minChars is +// the minimum amount of characters that should be selected for the +// behavior to occur, and style is the token style to apply to the +// matches. This will be prefixed by "cm-" to create an actual CSS +// class name. (function() { var DEFAULT_MIN_CHARS = 2; - var DEFAULT_CLASS_NAME = "CodeMirror-matchhighlight"; + var DEFAULT_TOKEN_STYLE = "matchhighlight"; - function MatchHighlightState() { - this.marked = []; + function State(options) { + this.minChars = typeof options == "object" && options.minChars || DEFAULT_MIN_CHARS; + this.style = typeof options == "object" && options.style || DEFAULT_TOKEN_STYLE; + this.overlay = null; } - function getMatchHighlightState(cm) { - return cm._matchHighlightState || (cm._matchHighlightState = new MatchHighlightState()); - } - - function clearMarks(state) { - for (var i = 0; i < state.marked.length; ++i) - state.marked[i].clear(); - state.marked = []; - } - - function markDocument(cm, minChars, className) { - var state = getMatchHighlightState(cm); - clearMarks(state); - // If not enough chars selected, don't search - if (cm.somethingSelected() && cm.getSelection().replace(/^\s+|\s+$/g, "").length < minChars) return; - // This is too expensive on big documents - if (cm.lineCount() > 2000) return; - var query = cm.getSelection(); + CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + cm._matchHighlightState = new State(val); + cm.on("cursorActivity", highlightMatches); + } else if (!val && prev) { + var over = cm._matchHighlightState.overlay; + if (over) cm.removeOverlay(over); + cm._matchHighlightState = null; + cm.off("cursorActivity", highlightMatches); + } + }); + + function highlightMatches(cm) { cm.operation(function() { - for (var cursor = cm.getSearchCursor(query); cursor.findNext();) { - // Only apply matchhighlight to the matches other than the one actually selected - if (cursor.from().line !== cm.getCursor(true).line || cursor.from().ch !== cm.getCursor(true).ch) - state.marked.push(cm.markText(cursor.from(), cursor.to(), {className: className})); + var state = cm._matchHighlightState; + if (state.overlay) { + cm.removeOverlay(state.overlay); + state.overlay = null; } + + if (!cm.somethingSelected()) return; + var selection = cm.getSelection().replace(/^\s+|\s+$/g, ""); + if (selection.length < state.minChars) return; + + cm.addOverlay(state.overlay = makeOverlay(selection, state.style)); }); } - var plugin = function(minChars, className) { - if (typeof minChars === 'undefined') minChars = DEFAULT_MIN_CHARS; - if (typeof className === 'undefined') className = DEFAULT_CLASS_NAME; - markDocument(this, minChars, className); - }; - plugin.clear = function(cm) { - clearMarks(getMatchHighlightState(cm)); - }; - CodeMirror.defineExtension("matchHighlight", plugin); + function makeOverlay(query, style) { + return {token: function(stream) { + if (stream.match(query)) return style; + stream.next(); + stream.skipTo(query.charAt(0)) || stream.skipToEnd(); + }}; + } })(); diff --git a/demo/matchhighlighter.html b/demo/matchhighlighter.html index dd59af36c6..7fd1b2b792 100644 --- a/demo/matchhighlighter.html +++ b/demo/matchhighlighter.html @@ -12,8 +12,8 @@ @@ -24,9 +24,9 @@

    CodeMirror: Match Highlighter Demo

    Give it a try! No more hardToSpotVars. From 31d2e736203d7fc163d30983c1310707d7419bea Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Feb 2013 10:21:19 +0100 Subject: [PATCH 0168/5273] [match-highlighter addon] Update documentation --- doc/manual.html | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index cf29ba7bbb..632e010ca1 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1412,14 +1412,10 @@

    Add-ons

    python-hint.js
    Defines CodeMirror.pythonHint, a hinter for Python code.
    match-highlighter.js
    -
    Adds a matchHighlight method to CodeMirror - instances that can be called (typically from - a cursorActivity - handler) to highlight all instances of a currently selected word - with the a classname given as a first argument to the method. - Depends on - the searchcursor - add-on. Demo here.
    +
    Adds a highlightSelectionMatches option that + can be enabled to highlight all instances of a currently + selected word. + Demo here.
    formatting.js
    Adds commentRange, autoIndentRange, and autoFormatRange methods that, respectively, From c98271e6a0f0692610e02154029d16a71ecfff2e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Feb 2013 10:45:34 +0100 Subject: [PATCH 0169/5273] Repair context menu on IE9 --- lib/codemirror.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 19f4421530..53a4ebff6f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -30,6 +30,7 @@ window.CodeMirror = (function() { if (opera_version) opera_version = Number(opera_version[1]); // Some browsers use the wrong event properties to signal cmd/ctrl on OS X var flipCtrlCmd = mac && (qtwebkit || opera && (opera_version == null || opera_version < 12.11)); + var captureMiddleClick = gecko || (ie && !ie_lt9); // Optimize some code when these features are not used var sawReadOnlySpans = false, sawCollapsedSpans = false; @@ -1385,7 +1386,7 @@ window.CodeMirror = (function() { // Gecko browsers fire contextmenu *after* opening the menu, at // which point we can't mess with it anymore. Context menu is // handled in onMouseDown for Gecko. - if (!gecko) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); + if (captureMiddleClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); on(d.scroller, "scroll", function() { setScrollTop(cm, d.scroller.scrollTop); @@ -1512,7 +1513,7 @@ window.CodeMirror = (function() { switch (e_button(e)) { case 3: - if (gecko) onContextMenu.call(cm, cm, e); + if (captureMiddleClick) onContextMenu.call(cm, cm, e); return; case 2: if (start) extendSelection(cm.doc, start); @@ -1968,7 +1969,7 @@ window.CodeMirror = (function() { display.inputDiv.style.position = "absolute"; display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: white; outline: none;" + - "border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; + "border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opacity: .05; filter: alpha(opacity=5);"; focusInput(cm); resetInput(cm, true); // Adds "Select all" to context menu in FF @@ -1981,7 +1982,7 @@ window.CodeMirror = (function() { slowPoll(cm); // Try to detect the user choosing select-all - if (display.input.selectionStart != null) { + if (display.input.selectionStart != null && (!ie || ie_lt9)) { clearTimeout(detectingSelectAll); var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" : display.input.value), i = 0; display.prevInput = " "; @@ -1996,7 +1997,7 @@ window.CodeMirror = (function() { } } - if (gecko) { + if (captureMiddleClick) { e_stop(e); var mouseup = function() { off(window, "mouseup", mouseup); From 712522647fa7adb39d670529975b25f0af3a2d37 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Feb 2013 14:28:59 +0100 Subject: [PATCH 0170/5273] Use a Pos constructor instead of repeating {line, ch} literals This helps performance on v8 (in microbenchmarks) and is less noisy. Regular literals are still accepted, the constructor is only used to create objects, doesn't attach any methods. --- addon/edit/closetag.js | 2 +- addon/edit/continuecomment.js | 2 +- addon/edit/matchbrackets.js | 12 +- addon/fold/collapserange.js | 2 +- addon/fold/foldcode.js | 18 +- addon/hint/javascript-hint.js | 14 +- addon/hint/pig-hint.js | 4 +- addon/hint/python-hint.js | 4 +- addon/hint/xml-hint.js | 4 +- addon/search/search.js | 2 +- addon/search/searchcursor.js | 24 +- lib/codemirror.js | 114 +++---- test/doc_test.js | 104 +++---- test/test.js | 552 +++++++++++++++++----------------- 14 files changed, 437 insertions(+), 421 deletions(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index 653fc0b216..44bbca7c6f 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -61,7 +61,7 @@ throw CodeMirror.Pass; var doIndent = indentTags && indexOf(indentTags, lowerTagName) > -1; - var curPos = doIndent ? {line: pos.line + 1, ch: 0} : {line: pos.line, ch: pos.ch + 1}; + var curPos = doIndent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1); cm.replaceSelection(">" + (doIndent ? "\n\n" : "") + "", {head: curPos, anchor: curPos}); if (doIndent) { diff --git a/addon/edit/continuecomment.js b/addon/edit/continuecomment.js index dac83a81f6..0def40008f 100644 --- a/addon/edit/continuecomment.js +++ b/addon/edit/continuecomment.js @@ -12,7 +12,7 @@ if (token.type == "comment" && mode.blockCommentStart) { var end = token.string.indexOf(mode.blockCommentEnd); - var full = cm.getRange({line: pos.line, ch: 0}, {line: pos.line, ch: token.end}), found; + var full = cm.getRange(CodeMirro.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found; if (end != -1 && end == token.string.length - mode.blockCommentEnd.length) { // Comment ended, don't continue it } else if (token.string.indexOf(mode.blockCommentStart) == 0) { diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js index a5d0998b07..d8ae0787a8 100644 --- a/addon/edit/matchbrackets.js +++ b/addon/edit/matchbrackets.js @@ -2,13 +2,15 @@ var ie_lt8 = /MSIE \d/.test(navigator.userAgent) && (document.documentMode == null || document.documentMode < 8); + var Pos = CodeMirror.Pos; + var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"}; function findMatchingBracket(cm) { var cur = cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1; var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)]; if (!match) return null; var forward = match.charAt(1) == ">", d = forward ? 1 : -1; - var style = cm.getTokenAt({line: cur.line, ch: pos + 1}).type; + var style = cm.getTokenAt(Pos(cur.line, pos + 1)).type; var stack = [line.text.charAt(pos)], re = /[(){}[\]]/; function scan(line, lineNo, start) { @@ -17,7 +19,7 @@ if (start != null) pos = start + d; for (; pos != end; pos += d) { var ch = line.text.charAt(pos); - if (re.test(ch) && cm.getTokenAt({line: lineNo, ch: pos + 1}).type == style) { + if (re.test(ch) && cm.getTokenAt(Pos(lineNo, pos + 1)).type == style) { var match = matching[ch]; if (match.charAt(1) == ">" == forward) stack.push(ch); else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false}; @@ -30,16 +32,16 @@ else found = scan(cm.getLineHandle(i), i); if (found) break; } - return {from: {line: cur.line, ch: pos}, to: found && {line: i, ch: found.pos}, match: found && found.match}; + return {from: Pos(cur.line, pos), to: found && Pos(i, found.pos), match: found && found.match}; } function matchBrackets(cm, autoclear) { var found = findMatchingBracket(cm); if (!found) return; var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; - var one = cm.markText(found.from, {line: found.from.line, ch: found.from.ch + 1}, + var one = cm.markText(found.from, Pos(found.from.line, found.from.ch + 1), {className: style}); - var two = found.to && cm.markText(found.to, {line: found.to.line, ch: found.to.ch + 1}, + var two = found.to && cm.markText(found.to, Pos(found.to.line, found.to.ch + 1), {className: style}); // Kludge to work around the IE bug from issue #1193, where text // input stops going to the textare whever this fires. diff --git a/addon/fold/collapserange.js b/addon/fold/collapserange.js index ebcdda2755..e2c013734d 100644 --- a/addon/fold/collapserange.js +++ b/addon/fold/collapserange.js @@ -33,7 +33,7 @@ var from = Math.min(old, line), to = Math.max(old, line); if (from != to) { // Finish this fold - var fold = cm.markText({line: from + 1, ch: 0}, {line: to - 1}, { + var fold = cm.markText(CodeMirror.Pos(from + 1, 0), {line: to - 1}, { collapsed: true, inclusiveLeft: true, inclusiveRight: true, diff --git a/addon/fold/foldcode.js b/addon/fold/foldcode.js index 12e5d1d7b4..90019762fc 100644 --- a/addon/fold/foldcode.js +++ b/addon/fold/foldcode.js @@ -95,8 +95,8 @@ CodeMirror.tagRangeFinder = function(cm, start) { depth--; else depth++; - if (!depth) return {from: {line: start.line, ch: gtPos + 1}, - to: {line: l, ch: match.index}}; + if (!depth) return {from: CodeMirror.Pos(start.line, gtPos + 1), + to: CodeMirror.Pos(l, match.index)}; } } l++; @@ -111,7 +111,7 @@ CodeMirror.braceRangeFinder = function(cm, start) { for (;;) { var found = lineText.lastIndexOf("{", at); if (found < start.ch) break; - tokenType = cm.getTokenAt({line: line, ch: found + 1}).type; + tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type; if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; } at = found - 1; } @@ -125,7 +125,7 @@ CodeMirror.braceRangeFinder = function(cm, start) { if (nextClose < 0) nextClose = text.length; pos = Math.min(nextOpen, nextClose); if (pos == text.length) break; - if (cm.getTokenAt({line: i, ch: pos + 1}).type == tokenType) { + if (cm.getTokenAt(CodeMirror.Pos(i, pos + 1)).type == tokenType) { if (pos == nextOpen) ++count; else if (!--count) { end = i; endCh = pos; break outer; } } @@ -133,8 +133,8 @@ CodeMirror.braceRangeFinder = function(cm, start) { } } if (end == null || end == line + 1) return; - return {from: {line: line, ch: startChar + 1}, - to: {line: end, ch: endCh}}; + return {from: CodeMirror.Pos(line, startChar + 1), + to: CodeMirror.Pos(end, endCh)}; }; CodeMirror.indentRangeFinder = function(cm, start) { @@ -144,8 +144,8 @@ CodeMirror.indentRangeFinder = function(cm, start) { var curLine = cm.getLine(i); if (CodeMirror.countColumn(curLine, null, tabSize) < myIndent && CodeMirror.countColumn(cm.getLine(i-1), null, tabSize) > myIndent) - return {from: {line: start.line, ch: firstLine.length}, - to: {line: i, ch: curLine.length}}; + return {from: CodeMirror.Pos(start.line, firstLine.length), + to: CodeMirror.Pos(i, curLine.length)}; } }; @@ -159,7 +159,7 @@ CodeMirror.newFoldFunction = function(rangeFinder, widget) { } return function(cm, pos) { - if (typeof pos == "number") pos = {line: pos, ch: 0}; + if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0); var range = rangeFinder(cm, pos); if (!range) return; diff --git a/addon/hint/javascript-hint.js b/addon/hint/javascript-hint.js index d44ff2968d..fe2240af1c 100644 --- a/addon/hint/javascript-hint.js +++ b/addon/hint/javascript-hint.js @@ -1,4 +1,6 @@ (function () { + var Pos = CodeMirror.Pos; + function forEach(arr, f) { for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); } @@ -26,20 +28,20 @@ } // If it is a property, find out what it is a property of. while (tprop.type == "property") { - tprop = getToken(editor, {line: cur.line, ch: tprop.start}); + tprop = getToken(editor, Pos(cur.line, tprop.start)); if (tprop.string != ".") return; - tprop = getToken(editor, {line: cur.line, ch: tprop.start}); + tprop = getToken(editor, Pos(cur.line, tprop.start)); if (tprop.string == ')') { var level = 1; do { - tprop = getToken(editor, {line: cur.line, ch: tprop.start}); + tprop = getToken(editor, Pos(cur.line, tprop.start)); switch (tprop.string) { case ')': level++; break; case '(': level--; break; default: break; } } while (level > 0); - tprop = getToken(editor, {line: cur.line, ch: tprop.start}); + tprop = getToken(editor, Pos(cur.line, tprop.start)); if (tprop.type.indexOf("variable") === 0) tprop.type = "function"; else return; // no clue @@ -48,8 +50,8 @@ context.push(tprop); } return {list: getCompletions(token, context, keywords, options), - from: {line: cur.line, ch: token.start}, - to: {line: cur.line, ch: token.end}}; + from: Pos(cur.line, token.start), + to: Pos(cur.line, token.end)}; } CodeMirror.javascriptHint = function(editor, options) { diff --git a/addon/hint/pig-hint.js b/addon/hint/pig-hint.js index 149b468158..9847996be9 100644 --- a/addon/hint/pig-hint.js +++ b/addon/hint/pig-hint.js @@ -37,8 +37,8 @@ } return {list: completionList, - from: {line: cur.line, ch: token.start}, - to: {line: cur.line, ch: token.end}}; + from: CodeMirror.Pos(cur.line, token.start), + to: CodeMirror.Pos(cur.line, token.end)}; } CodeMirror.pigHint = function(editor) { diff --git a/addon/hint/python-hint.js b/addon/hint/python-hint.js index 56b077b3fb..60221b89ec 100644 --- a/addon/hint/python-hint.js +++ b/addon/hint/python-hint.js @@ -37,8 +37,8 @@ } return {list: completionList, - from: {line: cur.line, ch: token.start}, - to: {line: cur.line, ch: token.end}}; + from: CodeMirror.Pos(cur.line, token.start), + to: CodeMirror.Pos(cur.line, token.end)}; } CodeMirror.pythonHint = function(editor) { diff --git a/addon/hint/xml-hint.js b/addon/hint/xml-hint.js index 354eb297f3..1609aafd40 100644 --- a/addon/hint/xml-hint.js +++ b/addon/hint/xml-hint.js @@ -8,7 +8,7 @@ if (cursor.ch > 0) { - var text = cm.getRange({line: 0, ch: 0}, cursor); + var text = cm.getRange(CodeMirror.Pos(0, 0), cursor); var typed = ''; var simbol = ''; for(var i = text.length - 1; i >= 0; i--) { @@ -38,7 +38,7 @@ return { list: hints, - from: { line: cursor.line, ch: cursor.ch - typed.length }, + from: CodeMirror.Pos(cursor.line, cursor.ch - typed.length), to: cursor }; } diff --git a/addon/search/search.js b/addon/search/search.js index d8d866b04d..6331b86555 100644 --- a/addon/search/search.js +++ b/addon/search/search.js @@ -66,7 +66,7 @@ var state = getSearchState(cm); var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); if (!cursor.find(rev)) { - cursor = getSearchCursor(cm, state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0}); + cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)); if (!cursor.find(rev)) return; } cm.setSelection(cursor.from(), cursor.to()); diff --git a/addon/search/searchcursor.js b/addon/search/searchcursor.js index 5ccf7723bb..e6554ce56b 100644 --- a/addon/search/searchcursor.js +++ b/addon/search/searchcursor.js @@ -1,9 +1,11 @@ (function(){ + var Pos = CodeMirror.Pos; + function SearchCursor(cm, query, pos, caseFold) { this.atOccurrence = false; this.cm = cm; if (caseFold == null && typeof query == "string") caseFold = false; - pos = pos ? cm.clipPos(pos) : {line: 0, ch: 0}; + pos = pos ? cm.clipPos(pos) : Pos(0, 0); this.pos = {from: pos, to: pos}; // The matches method is filled in based on the type of query. @@ -31,8 +33,8 @@ start = match && match.index; } if (match && match[0]) - return {from: {line: pos.line, ch: start}, - to: {line: pos.line, ch: start + match[0].length}, + return {from: Pos(pos.line, start), + to: Pos(pos.line, start + match[0].length), match: match}; }; } else { // String query @@ -50,8 +52,8 @@ var line = fold(cm.getLine(pos.line)), len = query.length, match; if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1) : (match = line.indexOf(query, pos.ch)) != -1) - return {from: {line: pos.line, ch: match}, - to: {line: pos.line, ch: match + len}}; + return {from: Pos(pos.line, match), + to: Pos(pos.line, match + len)}; }; } } else { @@ -72,7 +74,7 @@ var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length); if (reverse ? offsetB != line.length - match.length : offsetB != match.length) return; - var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB}; + var start = Pos(pos.line, offsetA), end = Pos(ln, offsetB); return {from: reverse ? end : start, to: reverse ? start : end}; } }; @@ -87,7 +89,7 @@ find: function(reverse) { var self = this, pos = this.cm.clipPos(reverse ? this.pos.from : this.pos.to); function savePosAndFail(line) { - var pos = {line: line, ch: 0}; + var pos = Pos(line, 0); self.pos = {from: pos, to: pos}; self.atOccurrence = false; return false; @@ -101,12 +103,12 @@ } if (reverse) { if (!pos.line) return savePosAndFail(0); - pos = {line: pos.line-1, ch: this.cm.getLine(pos.line-1).length}; + pos = Pos(pos.line-1, this.cm.getLine(pos.line-1).length); } else { var maxLine = this.cm.lineCount(); if (pos.line == maxLine - 1) return savePosAndFail(maxLine); - pos = {line: pos.line+1, ch: 0}; + pos = Pos(pos.line + 1, 0); } } }, @@ -118,8 +120,8 @@ if (!this.atOccurrence) return; var lines = CodeMirror.splitLines(newText); this.cm.replaceRange(lines, this.pos.from, this.pos.to); - this.pos.to = {line: this.pos.from.line + lines.length - 1, - ch: lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0)}; + this.pos.to = Pos(this.pos.from.line + lines.length - 1, + lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0)); } }; diff --git a/lib/codemirror.js b/lib/codemirror.js index 53a4ebff6f..e9e485570e 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -773,7 +773,7 @@ window.CodeMirror = (function() { var lineObj = getLine(doc, line); var lineLen = lineObj.text.length, rVal = retTop ? Infinity : -Infinity; function coords(ch) { - return charCoords(cm, {line: line, ch: ch}, "div", lineObj); + return charCoords(cm, Pos(line, ch), "div", lineObj); } iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { @@ -1109,7 +1109,7 @@ window.CodeMirror = (function() { if (y < 0) return {line: doc.first, ch: 0, outside: true}; var lineNo = lineAtHeight(doc, y), last = doc.first + doc.size - 1; if (lineNo > last) - return {line: doc.size - 1, ch: getLine(doc, last).text.length}; + return Pos(doc.size - 1, getLine(doc, last).text.length); if (x < 0) x = 0; for (;;) { @@ -1130,7 +1130,7 @@ window.CodeMirror = (function() { var measurement = measureLine(cm, lineObj); function getX(ch) { - var sp = cursorCoords(cm, {line: lineNo, ch: ch}, "line", + var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, measurement); wrongLine = true; if (innerOff > sp.bottom) return Math.max(0, sp.left - cWidth); @@ -1337,9 +1337,9 @@ window.CodeMirror = (function() { while (same < l && prevInput[same] == text[same]) ++same; var from = sel.from, to = sel.to; if (same < prevInput.length) - from = {line: from.line, ch: from.ch - (prevInput.length - same)}; + from = Pos(from.line, from.ch - (prevInput.length - same)); else if (cm.state.overwrite && posEq(from, to) && !cm.state.pasteIncoming) - to = {line: to.line, ch: Math.min(getLine(doc, to.line).text.length, to.ch + (text.length - same))}; + to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + (text.length - same))); var updateInput = cm.curOp.updateInput; makeChange(cm.doc, {from: from, to: to, text: splitLines(text.slice(same)), origin: cm.state.pasteIncoming ? "paste" : "+input"}, "end"); @@ -1583,8 +1583,8 @@ window.CodeMirror = (function() { if (posLess(cur, startstart)) extendSelection(cm.doc, word.from, startend); else extendSelection(cm.doc, startstart, word.to); } else if (type == "triple") { - if (posLess(cur, startstart)) extendSelection(cm.doc, startend, clipPos(doc, {line: cur.line, ch: 0})); - else extendSelection(cm.doc, startstart, clipPos(doc, {line: cur.line + 1, ch: 0})); + if (posLess(cur, startstart)) extendSelection(cm.doc, startend, clipPos(doc, Pos(cur.line, 0))); + else extendSelection(cm.doc, startstart, clipPos(doc, Pos(cur.line + 1, 0))); } } @@ -2012,8 +2012,8 @@ window.CodeMirror = (function() { // UPDATING function changeEnd(change) { - return {line: change.from.line + change.text.length - 1, - ch: lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)}; + return Pos(change.from.line + change.text.length - 1, + lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); } // Hint can be null|"end"|"start"|"around"|{anchor,head} @@ -2032,7 +2032,7 @@ window.CodeMirror = (function() { var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; if (pos.line == change.to.line) ch += end.ch - change.to.ch; - return {line: line, ch: ch}; + return Pos(line, ch); }; return {anchor: adjustPos(sel.anchor), head: adjustPos(sel.head)}; } @@ -2105,7 +2105,7 @@ window.CodeMirror = (function() { } function shiftDoc(doc, distance) { - function shiftPos(pos) {return {line: pos.line + distance, ch: pos.ch};} + function shiftPos(pos) {return Pos(pos.line + distance, pos.ch);} doc.first += distance; if (doc.cm) regChange(doc.cm, doc.first, doc.first, distance); doc.sel.head = shiftPos(doc.sel.head); doc.sel.anchor = shiftPos(doc.sel.anchor); @@ -2126,12 +2126,12 @@ window.CodeMirror = (function() { if (change.from.line < doc.first) { var shift = change.text.length - 1 - (doc.first - change.from.line); shiftDoc(doc, shift); - change = {from: {line: doc.first, ch: 0}, to: {line: change.to.line + shift, ch: change.to.ch}, + 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(); if (change.to.line > last) { - change = {from: change.from, to: {line: last, ch: getLine(doc, last).text.length}, + change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), text: [change.text[0]], origin: change.origin}; } @@ -2192,20 +2192,28 @@ window.CodeMirror = (function() { makeChange(doc, {from: from, to: to, text: code, origin: origin}, null); } - // SELECTION + // POSITION OBJECT + + function Pos(line, ch) { + if (!(this instanceof Pos)) return new Pos(line, ch); + this.line = line; this.ch = ch; + } + CodeMirror.Pos = Pos; function posEq(a, b) {return a.line == b.line && a.ch == b.ch;} function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);} - function copyPos(x) {return {line: x.line, ch: x.ch};} + function copyPos(x) {return Pos(x.line, x.ch);} + + // SELECTION function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));} function clipPos(doc, pos) { - if (pos.line < doc.first) return {line: doc.first, ch: 0}; + if (pos.line < doc.first) return Pos(doc.first, 0); var last = doc.first + doc.size - 1; - if (pos.line > last) return {line: last, ch: getLine(doc, last).text.length}; + if (pos.line > last) return Pos(last, getLine(doc, last).text.length); var ch = pos.ch, linelen = getLine(doc, pos.line).text.length; - if (ch == null || ch > linelen) return {line: pos.line, ch: linelen}; - else if (ch < 0) return {line: pos.line, ch: 0}; + if (ch == null || ch > linelen) return Pos(pos.line, linelen); + else if (ch < 0) return Pos(pos.line, 0); else return pos; } function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;} @@ -2277,10 +2285,10 @@ window.CodeMirror = (function() { if (posEq(newPos, curPos)) { newPos.ch += dir; if (newPos.ch < 0) { - if (newPos.line > doc.first) newPos = clipPos(doc, {line: newPos.line - 1}); + if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1)); else newPos = null; } else if (newPos.ch > line.text.length) { - if (newPos.line < doc.first + doc.size - 1) newPos = {line: newPos.line + 1, ch: 0}; + if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0); else newPos = null; } if (!newPos) { @@ -2290,7 +2298,7 @@ window.CodeMirror = (function() { if (!mayClear) return skipAtomic(doc, pos, bias, true); // Otherwise, turn off editing until further notice, and return the start of the doc doc.cantEdit = true; - return {line: doc.first, ch: 0}; + return Pos(doc.first, 0); } flipped = true; newPos = pos; dir = -dir; } @@ -2406,7 +2414,7 @@ window.CodeMirror = (function() { if (pos < indentation) indentString += spaceStr(indentation - pos); if (indentString != curSpaceString) - replaceRange(cm.doc, indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length}, "+input"); + replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); line.stateAfter = null; } @@ -2450,7 +2458,7 @@ window.CodeMirror = (function() { if (dir > 0) if (!moveOnce()) break; } } - return skipAtomic(doc, {line: line, ch: ch}, dir, true); + return skipAtomic(doc, Pos(line, ch), dir, true); } function findWordAt(line, pos) { @@ -2464,11 +2472,11 @@ window.CodeMirror = (function() { while (start > 0 && check(line.charAt(start - 1))) --start; while (end < line.length && check(line.charAt(end))) ++end; } - return {from: {line: pos.line, ch: start}, to: {line: pos.line, ch: end}}; + return {from: Pos(pos.line, start), to: Pos(pos.line, end)}; } function selectLine(cm, line) { - extendSelection(cm.doc, {line: line, ch: 0}, clipPos(cm.doc, {line: line + 1, ch: 0})); + extendSelection(cm.doc, Pos(line, 0), clipPos(cm.doc, Pos(line + 1, 0))); } // PROTOTYPE @@ -2742,7 +2750,7 @@ window.CodeMirror = (function() { }, scrollIntoView: function(pos) { - if (typeof pos == "number") pos = {line: pos, ch: 0}; + if (typeof pos == "number") pos = Pos(pos, 0); if (!pos || pos.line != null) { pos = pos ? clipPos(this.doc, pos) : this.doc.sel.head; scrollPosIntoView(this, pos); @@ -2969,21 +2977,21 @@ window.CodeMirror = (function() { // STANDARD COMMANDS var commands = CodeMirror.commands = { - selectAll: function(cm) {cm.setSelection({line: cm.firstLine(), ch: 0}, {line: cm.lastLine()});}, + selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()));}, killLine: function(cm) { var from = cm.getCursor(true), to = cm.getCursor(false), sel = !posEq(from, to); if (!sel && cm.getLine(from.line).length == from.ch) - cm.replaceRange("", from, {line: from.line + 1, ch: 0}, "+delete"); - else cm.replaceRange("", from, sel ? to : {line: from.line}, "+delete"); + cm.replaceRange("", from, Pos(from.line + 1, 0), "+delete"); + else cm.replaceRange("", from, sel ? to : Pos(from.line), "+delete"); }, deleteLine: function(cm) { var l = cm.getCursor().line; - cm.replaceRange("", {line: l, ch: 0}, {line: l}, "+delete"); + cm.replaceRange("", Pos(l, 0), Pos(l), "+delete"); }, undo: function(cm) {cm.undo();}, redo: function(cm) {cm.redo();}, - goDocStart: function(cm) {cm.extendSelection({line: cm.firstLine(), ch: 0});}, - goDocEnd: function(cm) {cm.extendSelection({line: cm.lastLine()});}, + goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));}, + goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));}, goLineStart: function(cm) { cm.extendSelection(lineStart(cm, cm.getCursor().line)); }, @@ -2994,7 +3002,7 @@ window.CodeMirror = (function() { if (!order || order[0].level == 0) { var firstNonWS = Math.max(0, line.text.search(/\S/)); var inWS = cur.line == start.line && cur.ch <= firstNonWS && cur.ch; - cm.extendSelection({line: start.line, ch: inWS ? 0 : firstNonWS}); + cm.extendSelection(Pos(start.line, inWS ? 0 : firstNonWS)); } else cm.extendSelection(start); }, goLineEnd: function(cm) { @@ -3026,7 +3034,7 @@ window.CodeMirror = (function() { var cur = cm.getCursor(), line = cm.getLine(cur.line); if (cur.ch > 0 && cur.ch < line.length - 1) cm.replaceRange(line.charAt(cur.ch) + line.charAt(cur.ch - 1), - {line: cur.line, ch: cur.ch - 1}, {line: cur.line, ch: cur.ch + 1}); + Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1)); }, newlineAndIndent: function(cm) { operation(cm, function() { @@ -3290,8 +3298,8 @@ window.CodeMirror = (function() { var span = getMarkedSpanFor(line.markedSpans, this); if (span.from != null || span.to != null) { var found = lineNo(line); - if (span.from != null) from = {line: found, ch: span.from}; - if (span.to != null) to = {line: found, ch: span.to}; + if (span.from != null) from = Pos(found, span.from); + if (span.to != null) to = Pos(found, span.to); } } if (this.type == "bookmark") return from; @@ -3558,14 +3566,14 @@ window.CodeMirror = (function() { for (var i = 0; i < markers.length; ++i) { var mk = markers[i], m = mk.find(); if (mk.inclusiveLeft) { - m.from = {line: m.from.line, ch: m.from.ch - 1}; + m.from = Pos(m.from.line, m.from.ch - 1); if (m.from.ch < 0 && m.from.line > doc.first) - m.from = {line: m.from.line - 1, ch: getLine(doc, m.from.line - 1).text.length}; + m.from = Pos(m.from.line - 1, getLine(doc, m.from.line - 1).text.length); } if (mk.inclusiveRight) { - m.to = {line: m.to.line, ch: m.to.ch + 1}; + m.to = Pos(m.to.line, m.to.ch + 1); if (m.to.line < doc.first + doc.size - 1 && m.to.ch > getLine(doc, m.to.line).text.length) - m.to = {line: m.to.line + 1, ch: 0}; + m.to = Pos(m.to.line + 1, 0); } for (var j = 0; j < parts.length; ++j) { var p = parts[j]; @@ -4165,7 +4173,7 @@ window.CodeMirror = (function() { this.cantEdit = false; this.history = makeHistory(); this.frontier = firstLine; - var start = {line: firstLine, ch: 0}; + var start = Pos(firstLine, 0); this.sel = {from: start, to: start, head: start, anchor: start, shift: false, extend: false, goalColumn: null}; this.id = ++nextDocId; this.modeOption = mode; @@ -4193,8 +4201,8 @@ window.CodeMirror = (function() { return lines.join(lineSep || "\n"); }, setValue: function(code) { - var top = {line: this.first, ch: 0}, last = this.first + this.size - 1; - makeChange(this, {from: top, to: {line: last, ch: getLine(this, last).text.length}, + 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: splitLines(code), origin: "setValue"}, {head: top, anchor: top}, true); }, @@ -4212,11 +4220,11 @@ window.CodeMirror = (function() { getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, setLine: function(line, text) { if (isLine(this, line)) - replaceRange(this, text, {line: line, ch: 0}, {line: line, ch: getLine(this, line).text.length}); + replaceRange(this, text, Pos(line, 0), clipPos(this, Pos(line))); }, removeLine: function(line) { if (isLine(this, line)) - replaceRange(this, "", {line: line, ch: 0}, clipPos(this, {line: line+1, ch: 0})); + replaceRange(this, "", Pos(line, 0), clipPos(this, Pos(line + 1, 0))); }, getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, @@ -4239,7 +4247,7 @@ window.CodeMirror = (function() { somethingSelected: function() {return !posEq(this.sel.head, this.sel.anchor);}, setCursor: docOperation(function(line, ch, extend) { - var pos = clipPos(this, typeof line == "number" ? {line: line, ch: ch || 0} : line); + var pos = clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line); if (extend) extendSelection(this, pos); else setSelection(this, pos, pos); }), @@ -4310,7 +4318,7 @@ window.CodeMirror = (function() { off -= sz; ++lineNo; }); - return clipPos(this, {line: lineNo, ch: ch}); + return clipPos(this, Pos(lineNo, ch)); }, indexFromPos: function (coords) { coords = clipPos(this, coords); @@ -4999,15 +5007,15 @@ window.CodeMirror = (function() { if (visual != line) lineN = lineNo(visual); var order = getOrder(visual); var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); - return {line: lineN, ch: ch}; + return Pos(lineN, ch); } - function lineEnd(cm, lineNo) { + function lineEnd(cm, lineN) { var merged, line; - while (merged = collapsedSpanAtEnd(line = getLine(cm.doc, lineNo))) - lineNo = merged.find().to.line; + while (merged = collapsedSpanAtEnd(line = getLine(cm.doc, lineN))) + lineN = merged.find().to.line; var order = getOrder(line); var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); - return {line: lineNo, ch: ch}; + return Pos(lineN, ch); } // This is somewhat involved. It is needed in order to move diff --git a/test/doc_test.js b/test/doc_test.js index 20c910f5fa..6609230dc0 100644 --- a/test/doc_test.js +++ b/test/doc_test.js @@ -76,9 +76,9 @@ eqAll("hey", a, b); b.setValue("wow"); eqAll("wow", a, b); - a.replaceRange("u\nv\nw", {line: 0, ch: 3}); - b.replaceRange("i", {line: 0, ch: 4}); - b.replaceRange("j", {line: 2, ch: 1}); + a.replaceRange("u\nv\nw", Pos(0, 3)); + b.replaceRange("i", Pos(0, 4)); + b.replaceRange("j", Pos(2, 1)); eqAll("wowui\nv\nwj", a, b); } @@ -86,9 +86,9 @@ testDoc("basicSeparate", "A='x' B<~A", testBasic); testDoc("sharedHist", "A='ab\ncd\nef' B top2.top); eq(top.left, top2.left); }); @@ -210,9 +212,9 @@ testCM("coordsChar", function(cm) { for (var ch = 0; ch <= 35; ch += 5) { for (var line = 0; line < 70; line += 5) { cm.setCursor(line, ch); - var coords = cm.charCoords({line: line, ch: ch}); + var coords = cm.charCoords(Pos(line, ch)); var pos = cm.coordsChar({left: coords.left, top: coords.top + 5}); - eqPos(pos, {line: line, ch: ch}); + eqPos(pos, Pos(line, ch)); } } }); @@ -259,8 +261,8 @@ testCM("undo", function(cm) { cm.clearHistory(); eq(cm.historySize().undo, 0); for (var i = 0; i < 20; ++i) { - cm.replaceRange("a", {line: 0, ch: 0}); - cm.replaceRange("b", {line: 3, ch: 0}); + cm.replaceRange("a", Pos(0, 0)); + cm.replaceRange("b", Pos(3, 0)); } eq(cm.historySize().undo, 40); for (var i = 0; i < 40; ++i) @@ -270,9 +272,9 @@ testCM("undo", function(cm) { }, {value: "abc"}); testCM("undoDepth", function(cm) { - cm.replaceRange("d", {line: 0}); - cm.replaceRange("e", {line: 0}); - cm.replaceRange("f", {line: 0}); + cm.replaceRange("d", Pos(0)); + cm.replaceRange("e", Pos(0)); + cm.replaceRange("f", Pos(0)); cm.undo(); cm.undo(); cm.undo(); eq(cm.getValue(), "abcd"); }, {value: "abc", undoDepth: 2}); @@ -284,31 +286,31 @@ testCM("undoDoesntClearValue", function(cm) { testCM("undoMultiLine", function(cm) { cm.operation(function() { - cm.replaceRange("x", {line:0, ch: 0}); - cm.replaceRange("y", {line:1, ch: 0}); + cm.replaceRange("x", Pos(0, 0)); + cm.replaceRange("y", Pos(1, 0)); }); cm.undo(); eq(cm.getValue(), "abc\ndef\nghi"); cm.operation(function() { - cm.replaceRange("y", {line:1, ch: 0}); - cm.replaceRange("x", {line:0, ch: 0}); + cm.replaceRange("y", Pos(1, 0)); + cm.replaceRange("x", Pos(0, 0)); }); cm.undo(); eq(cm.getValue(), "abc\ndef\nghi"); cm.operation(function() { - cm.replaceRange("y", {line:2, ch: 0}); - cm.replaceRange("x", {line:1, ch: 0}); - cm.replaceRange("z", {line:2, ch: 0}); + cm.replaceRange("y", Pos(2, 0)); + cm.replaceRange("x", Pos(1, 0)); + cm.replaceRange("z", Pos(2, 0)); }); cm.undo(); eq(cm.getValue(), "abc\ndef\nghi", 3); }, {value: "abc\ndef\nghi"}); testCM("undoComposite", function(cm) { - cm.replaceRange("y", {line: 1}); + cm.replaceRange("y", Pos(1)); cm.operation(function() { - cm.replaceRange("x", {line: 0}); - cm.replaceRange("z", {line: 2}); + cm.replaceRange("x", Pos(0)); + cm.replaceRange("z", Pos(2)); }); eq(cm.getValue(), "ax\nby\ncz\n"); cm.undo(); @@ -320,16 +322,16 @@ testCM("undoComposite", function(cm) { }, {value: "a\nb\nc\n"}); testCM("undoSelection", function(cm) { - cm.setSelection({line: 0, ch: 2}, {line: 0, ch: 4}); + cm.setSelection(Pos(0, 2), Pos(0, 4)); cm.replaceSelection(""); - cm.setCursor({line: 1, ch: 0}); + cm.setCursor(Pos(1, 0)); cm.undo(); - eqPos(cm.getCursor(true), {line: 0, ch: 2}); - eqPos(cm.getCursor(false), {line: 0, ch: 4}); - cm.setCursor({line: 1, ch: 0}); + eqPos(cm.getCursor(true), Pos(0, 2)); + eqPos(cm.getCursor(false), Pos(0, 4)); + cm.setCursor(Pos(1, 0)); cm.redo(); - eqPos(cm.getCursor(true), {line: 0, ch: 2}); - eqPos(cm.getCursor(false), {line: 0, ch: 2}); + eqPos(cm.getCursor(true), Pos(0, 2)); + eqPos(cm.getCursor(false), Pos(0, 2)); }, {value: "abcdefgh\n"}); testCM("markTextSingleLine", function(cm) { @@ -348,15 +350,15 @@ testCM("markTextSingleLine", function(cm) { {a: 6, b: 6, c: "a", f: 3, t: 6}, {a: 8, b: 9, c: "", f: 3, t: 6}], function(test) { cm.setValue("1234567890"); - var r = cm.markText({line: 0, ch: 3}, {line: 0, ch: 6}, {className: "foo"}); - cm.replaceRange(test.c, {line: 0, ch: test.a}, {line: 0, ch: test.b}); + var r = cm.markText(Pos(0, 3), Pos(0, 6), {className: "foo"}); + cm.replaceRange(test.c, Pos(0, test.a), Pos(0, test.b)); var f = r.find(); eq(f && f.from.ch, test.f); eq(f && f.to.ch, test.t); }); }); testCM("markTextMultiLine", function(cm) { - function p(v) { return v && {line: v[0], ch: v[1]}; } + function p(v) { return v && Pos(v[0], v[1]); } forEach([{a: [0, 0], b: [0, 5], c: "", f: [0, 0], t: [2, 5]}, {a: [0, 0], b: [0, 5], c: "foo\n", f: [1, 0], t: [3, 5]}, {a: [0, 1], b: [0, 10], c: "", f: [0, 1], t: [2, 5]}, @@ -373,7 +375,7 @@ testCM("markTextMultiLine", function(cm) { {a: [2, 3], b: [3, 0], c: "x", f: [0, 5], t: [2, 3]}, {a: [1, 1], b: [1, 9], c: "1\n2\n3", f: [0, 5], t: [4, 5]}], function(test) { cm.setValue("aaaaaaaaaa\nbbbbbbbbbb\ncccccccccc\ndddddddd\n"); - var r = cm.markText({line: 0, ch: 5}, {line: 2, ch: 5}, + var r = cm.markText(Pos(0, 5), Pos(2, 5), {className: "CodeMirror-matchingbracket"}); cm.replaceRange(test.c, p(test.a), p(test.b)); var f = r.find(); @@ -383,68 +385,68 @@ testCM("markTextMultiLine", function(cm) { testCM("markTextUndo", function(cm) { var marker1, marker2, bookmark; - marker1 = cm.markText({line: 0, ch: 1}, {line: 0, ch: 3}, + marker1 = cm.markText(Pos(0, 1), Pos(0, 3), {className: "CodeMirror-matchingbracket"}); - marker2 = cm.markText({line: 0, ch: 0}, {line: 2, ch: 1}, + marker2 = cm.markText(Pos(0, 0), Pos(2, 1), {className: "CodeMirror-matchingbracket"}); - bookmark = cm.setBookmark({line: 1, ch: 5}); + bookmark = cm.setBookmark(Pos(1, 5)); cm.operation(function(){ - cm.replaceRange("foo", {line: 0, ch: 2}); - cm.replaceRange("bar\nbaz\nbug\n", {line: 2, ch: 0}, {line: 3, ch: 0}); + cm.replaceRange("foo", Pos(0, 2)); + cm.replaceRange("bar\nbaz\nbug\n", Pos(2, 0), Pos(3, 0)); }); var v1 = cm.getValue(); cm.setValue(""); eq(marker1.find(), null); eq(marker2.find(), null); eq(bookmark.find(), null); cm.undo(); - eqPos(bookmark.find(), {line: 1, ch: 5}, "still there"); + eqPos(bookmark.find(), Pos(1, 5), "still there"); cm.undo(); var m1Pos = marker1.find(), m2Pos = marker2.find(); - eqPos(m1Pos.from, {line: 0, ch: 1}); eqPos(m1Pos.to, {line: 0, ch: 3}); - eqPos(m2Pos.from, {line: 0, ch: 0}); eqPos(m2Pos.to, {line: 2, ch: 1}); - eqPos(bookmark.find(), {line: 1, ch: 5}); + eqPos(m1Pos.from, Pos(0, 1)); eqPos(m1Pos.to, Pos(0, 3)); + eqPos(m2Pos.from, Pos(0, 0)); eqPos(m2Pos.to, Pos(2, 1)); + eqPos(bookmark.find(), Pos(1, 5)); cm.redo(); cm.redo(); eq(bookmark.find(), null); cm.undo(); - eqPos(bookmark.find(), {line: 1, ch: 5}); + eqPos(bookmark.find(), Pos(1, 5)); eq(cm.getValue(), v1); }, {value: "1234\n56789\n00\n"}); testCM("markTextStayGone", function(cm) { - var m1 = cm.markText({line: 0, ch: 0}, {line: 0, ch: 1}); - cm.replaceRange("hi", {line: 0, ch: 2}); + var m1 = cm.markText(Pos(0, 0), Pos(0, 1)); + cm.replaceRange("hi", Pos(0, 2)); m1.clear(); cm.undo(); eq(m1.find(), null); }, {value: "hello"}); testCM("undoPreservesNewMarks", function(cm) { - cm.markText({line: 0, ch: 3}, {line: 0, ch: 4}); - cm.markText({line: 1, ch: 1}, {line: 1, ch: 3}); - cm.replaceRange("", {line: 0, ch: 3}, {line: 3, ch: 1}); - var mBefore = cm.markText({line: 0, ch: 0}, {line: 0, ch: 1}); - var mAfter = cm.markText({line: 0, ch: 5}, {line: 0, ch: 6}); - var mAround = cm.markText({line: 0, ch: 2}, {line: 0, ch: 4}); + cm.markText(Pos(0, 3), Pos(0, 4)); + cm.markText(Pos(1, 1), Pos(1, 3)); + cm.replaceRange("", Pos(0, 3), Pos(3, 1)); + var mBefore = cm.markText(Pos(0, 0), Pos(0, 1)); + var mAfter = cm.markText(Pos(0, 5), Pos(0, 6)); + var mAround = cm.markText(Pos(0, 2), Pos(0, 4)); cm.undo(); - eqPos(mBefore.find().from, {line: 0, ch: 0}); - eqPos(mBefore.find().to, {line: 0, ch: 1}); - eqPos(mAfter.find().from, {line: 3, ch: 3}); - eqPos(mAfter.find().to, {line: 3, ch: 4}); - eqPos(mAround.find().from, {line: 0, ch: 2}); - eqPos(mAround.find().to, {line: 3, ch: 2}); - var found = cm.findMarksAt({line: 2, ch: 2}); + eqPos(mBefore.find().from, Pos(0, 0)); + eqPos(mBefore.find().to, Pos(0, 1)); + eqPos(mAfter.find().from, Pos(3, 3)); + eqPos(mAfter.find().to, Pos(3, 4)); + eqPos(mAround.find().from, Pos(0, 2)); + eqPos(mAround.find().to, Pos(3, 2)); + var found = cm.findMarksAt(Pos(2, 2)); eq(found.length, 1); eq(found[0], mAround); }, {value: "aaaa\nbbbb\ncccc\ndddd"}); testCM("markClearBetween", function(cm) { cm.setValue("aaa\nbbb\nccc\nddd\n"); - cm.markText({line: 0, ch: 0}, {line: 2}); - cm.replaceRange("aaa\nbbb\nccc", {line: 0, ch: 0}, {line: 2}); - eq(cm.findMarksAt({line: 1, ch: 1}).length, 0); + cm.markText(Pos(0, 0), Pos(2)); + cm.replaceRange("aaa\nbbb\nccc", Pos(0, 0), Pos(2)); + eq(cm.findMarksAt(Pos(1, 1)).length, 0); }); testCM("bookmark", function(cm) { - function p(v) { return v && {line: v[0], ch: v[1]}; } + function p(v) { return v && Pos(v[0], v[1]); } forEach([{a: [1, 0], b: [1, 1], c: "", d: [1, 4]}, {a: [1, 1], b: [1, 1], c: "xx", d: [1, 7]}, {a: [1, 4], b: [1, 5], c: "ab", d: [1, 6]}, @@ -454,25 +456,25 @@ testCM("bookmark", function(cm) { {a: [1, 4], b: [1, 4], c: "\n\n", d: [3, 1]}, {bm: [1, 9], a: [1, 1], b: [1, 1], c: "\n", d: [2, 8]}], function(test) { cm.setValue("1234567890\n1234567890\n1234567890"); - var b = cm.setBookmark(p(test.bm) || {line: 1, ch: 5}); + var b = cm.setBookmark(p(test.bm) || Pos(1, 5)); cm.replaceRange(test.c, p(test.a), p(test.b)); eqPos(b.find(), p(test.d)); }); }); testCM("bookmarkInsertLeft", function(cm) { - var br = cm.setBookmark({line: 0, ch: 2}, {insertLeft: false}); - var bl = cm.setBookmark({line: 0, ch: 2}, {insertLeft: true}); - cm.setCursor({line: 0, ch: 2}); + var br = cm.setBookmark(Pos(0, 2), {insertLeft: false}); + var bl = cm.setBookmark(Pos(0, 2), {insertLeft: true}); + cm.setCursor(Pos(0, 2)); cm.replaceSelection("hi"); - eqPos(br.find(), {line: 0, ch: 2}); - eqPos(bl.find(), {line: 0, ch: 4}); - cm.replaceRange("", {line: 0, ch: 4}, {line: 0, ch: 5}); - cm.replaceRange("", {line: 0, ch: 2}, {line: 0, ch: 4}); - cm.replaceRange("", {line: 0, ch: 1}, {line: 0, ch: 2}); + eqPos(br.find(), Pos(0, 2)); + eqPos(bl.find(), Pos(0, 4)); + cm.replaceRange("", Pos(0, 4), Pos(0, 5)); + cm.replaceRange("", Pos(0, 2), Pos(0, 4)); + cm.replaceRange("", Pos(0, 1), Pos(0, 2)); // Verify that deleting next to bookmarks doesn't kill them - eqPos(br.find(), {line: 0, ch: 1}); - eqPos(bl.find(), {line: 0, ch: 1}); + eqPos(br.find(), Pos(0, 1)); + eqPos(bl.find(), Pos(0, 1)); }, {value: "abcdef"}); testCM("bug577", function(cm) { @@ -485,14 +487,14 @@ testCM("bug577", function(cm) { testCM("scrollSnap", function(cm) { cm.setSize(100, 100); addDoc(cm, 200, 200); - cm.setCursor({line: 100, ch: 180}); + cm.setCursor(Pos(100, 180)); var info = cm.getScrollInfo(); is(info.left > 0 && info.top > 0); - cm.setCursor({line: 0, ch: 0}); + cm.setCursor(Pos(0, 0)); info = cm.getScrollInfo(); is(info.left == 0 && info.top == 0, "scrolled clean to top"); - cm.setCursor({line: 100, ch: 180}); - cm.setCursor({line: 199, ch: 0}); + cm.setCursor(Pos(100, 180)); + cm.setCursor(Pos(199, 0)); info = cm.getScrollInfo(); is(info.left == 0 && info.top + 2 > info.height - cm.getScrollerElement().clientHeight, "scrolled clean to bottom"); }); @@ -500,9 +502,9 @@ testCM("scrollSnap", function(cm) { testCM("selectionPos", function(cm) { cm.setSize(100, 100); addDoc(cm, 200, 100); - cm.setSelection({line: 1, ch: 100}, {line: 98, ch: 100}); - var lineWidth = cm.charCoords({line: 0, ch: 200}, "local").left; - var lineHeight = (cm.charCoords({line: 99}).top - cm.charCoords({line: 0}).top) / 100; + cm.setSelection(Pos(1, 100), Pos(98, 100)); + var lineWidth = cm.charCoords(Pos(0, 200), "local").left; + var lineHeight = (cm.charCoords(Pos(99)).top - cm.charCoords(Pos(0)).top) / 100; cm.scrollTo(0, 0); var selElt = byClassName(cm.getWrapperElement(), "CodeMirror-selected"); var outer = cm.getWrapperElement().getBoundingClientRect(); @@ -584,7 +586,7 @@ testCM("setSize", function(cm) { }); function foldLines(cm, start, end, autoClear) { - return cm.markText({line: start, ch: 0}, {line: end - 1}, { + return cm.markText(Pos(start, 0), Pos(end - 1), { inclusiveLeft: true, inclusiveRight: true, collapsed: true, @@ -596,47 +598,47 @@ testCM("collapsedLines", function(cm) { addDoc(cm, 4, 10); var range = foldLines(cm, 4, 5), cleared = 0; CodeMirror.on(range, "clear", function() {cleared++;}); - cm.setCursor({line: 3, ch: 0}); + cm.setCursor(Pos(3, 0)); CodeMirror.commands.goLineDown(cm); - eqPos(cm.getCursor(), {line: 5, ch: 0}); + eqPos(cm.getCursor(), Pos(5, 0)); cm.setLine(3, "abcdefg"); - cm.setCursor({line: 3, ch: 6}); + cm.setCursor(Pos(3, 6)); CodeMirror.commands.goLineDown(cm); - eqPos(cm.getCursor(), {line: 5, ch: 4}); + eqPos(cm.getCursor(), Pos(5, 4)); cm.setLine(3, "ab"); - cm.setCursor({line: 3, ch: 2}); + cm.setCursor(Pos(3, 2)); CodeMirror.commands.goLineDown(cm); - eqPos(cm.getCursor(), {line: 5, ch: 2}); + eqPos(cm.getCursor(), Pos(5, 2)); range.clear(); range.clear(); eq(cleared, 1); }); testCM("collapsedRangeCoordsChar", function(cm) { - var pos_1_3 = cm.charCoords({line: 1, ch: 3}); + var pos_1_3 = cm.charCoords(Pos(1, 3)); pos_1_3.left += 2; pos_1_3.top += 2; var opts = {collapsed: true, inclusiveLeft: true, inclusiveRight: true}; - var m1 = cm.markText({line: 0, ch: 0}, {line: 2, ch: 0}, opts); - eqPos(cm.coordsChar(pos_1_3), {line: 3, ch: 3}); + var m1 = cm.markText(Pos(0, 0), Pos(2, 0), opts); + eqPos(cm.coordsChar(pos_1_3), Pos(3, 3)); m1.clear(); - var m1 = cm.markText({line: 0, ch: 0}, {line: 1, ch: 1}, opts); - var m2 = cm.markText({line: 1, ch: 1}, {line: 2, ch: 0}, opts); - eqPos(cm.coordsChar(pos_1_3), {line: 3, ch: 3}); + var m1 = cm.markText(Pos(0, 0), Pos(1, 1), opts); + var m2 = cm.markText(Pos(1, 1), Pos(2, 0), opts); + eqPos(cm.coordsChar(pos_1_3), Pos(3, 3)); m1.clear(); m2.clear(); - var m1 = cm.markText({line: 0, ch: 0}, {line: 1, ch: 6}, opts); - eqPos(cm.coordsChar(pos_1_3), {line: 3, ch: 3}); + var m1 = cm.markText(Pos(0, 0), Pos(1, 6), opts); + eqPos(cm.coordsChar(pos_1_3), Pos(3, 3)); }, {value: "123456\nabcdef\nghijkl\nmnopqr\n"}); testCM("hiddenLinesAutoUnfold", function(cm) { var range = foldLines(cm, 1, 3, true), cleared = 0; CodeMirror.on(range, "clear", function() {cleared++;}); - cm.setCursor({line: 3, ch: 0}); + cm.setCursor(Pos(3, 0)); eq(cleared, 0); cm.execCommand("goCharLeft"); eq(cleared, 1); range = foldLines(cm, 1, 3, true); CodeMirror.on(range, "clear", function() {cleared++;}); - eqPos(cm.getCursor(), {line: 3, ch: 0}); - cm.setCursor({line: 0, ch: 3}); + eqPos(cm.getCursor(), Pos(3, 0)); + cm.setCursor(Pos(0, 3)); cm.execCommand("goCharRight"); eq(cleared, 2); }, {value: "abc\ndef\nghi\njkl"}); @@ -646,8 +648,8 @@ testCM("hiddenLinesSelectAll", function(cm) { // Issue #484 foldLines(cm, 0, 10); foldLines(cm, 11, 20); CodeMirror.commands.selectAll(cm); - eqPos(cm.getCursor(true), {line: 10, ch: 0}); - eqPos(cm.getCursor(false), {line: 10, ch: 4}); + eqPos(cm.getCursor(true), Pos(10, 0)); + eqPos(cm.getCursor(false), Pos(10, 4)); }); @@ -668,18 +670,18 @@ testCM("everythingFolded", function(cm) { testCM("structuredFold", function(cm) { addDoc(cm, 4, 8); - var range = cm.markText({line: 1, ch: 2}, {line: 6, ch: 2}, { + var range = cm.markText(Pos(1, 2), Pos(6, 2), { replacedWith: document.createTextNode("Q") }); cm.setCursor(0, 3); CodeMirror.commands.goLineDown(cm); - eqPos(cm.getCursor(), {line: 6, ch: 2}); + eqPos(cm.getCursor(), Pos(6, 2)); CodeMirror.commands.goCharLeft(cm); - eqPos(cm.getCursor(), {line: 1, ch: 2}); + eqPos(cm.getCursor(), Pos(1, 2)); CodeMirror.commands.delCharAfter(cm); eq(cm.getValue(), "xxxx\nxxxx\nxxxx"); addDoc(cm, 4, 8); - range = cm.markText({line: 1, ch: 2}, {line: 6, ch: 2}, { + range = cm.markText(Pos(1, 2), Pos(6, 2), { replacedWith: document.createTextNode("x"), clearOnEnter: true }); @@ -687,70 +689,70 @@ testCM("structuredFold", function(cm) { CodeMirror.on(range, "clear", function(){++cleared;}); cm.setCursor(0, 3); CodeMirror.commands.goLineDown(cm); - eqPos(cm.getCursor(), {line: 6, ch: 2}); + eqPos(cm.getCursor(), Pos(6, 2)); CodeMirror.commands.goCharLeft(cm); - eqPos(cm.getCursor(), {line: 6, ch: 1}); + eqPos(cm.getCursor(), Pos(6, 1)); eq(cleared, 1); range.clear(); eq(cleared, 1); - range = cm.markText({line: 1, ch: 2}, {line: 6, ch: 2}, { + range = cm.markText(Pos(1, 2), Pos(6, 2), { replacedWith: document.createTextNode("Q"), clearOnEnter: true }); range.clear(); cm.setCursor(1, 2); CodeMirror.commands.goCharRight(cm); - eqPos(cm.getCursor(), {line: 1, ch: 3}); + eqPos(cm.getCursor(), Pos(1, 3)); }, null); testCM("nestedFold", function(cm) { addDoc(cm, 10, 3); function fold(ll, cl, lr, cr) { - return cm.markText({line: ll, ch: cl}, {line: lr, ch: cr}, {collapsed: true}); + return cm.markText(Pos(ll, cl), Pos(lr, cr), {collapsed: true}); } var inner1 = fold(0, 6, 1, 3), inner2 = fold(0, 2, 1, 8), outer = fold(0, 1, 2, 3), inner0 = fold(0, 5, 0, 6); cm.setCursor(0, 1); CodeMirror.commands.goCharRight(cm); - eqPos(cm.getCursor(), {line: 2, ch: 3}); + eqPos(cm.getCursor(), Pos(2, 3)); inner0.clear(); CodeMirror.commands.goCharLeft(cm); - eqPos(cm.getCursor(), {line: 0, ch: 1}); + eqPos(cm.getCursor(), Pos(0, 1)); outer.clear(); CodeMirror.commands.goCharRight(cm); - eqPos(cm.getCursor(), {line: 0, ch: 2}); + eqPos(cm.getCursor(), Pos(0, 2)); CodeMirror.commands.goCharRight(cm); - eqPos(cm.getCursor(), {line: 1, ch: 8}); + eqPos(cm.getCursor(), Pos(1, 8)); inner2.clear(); CodeMirror.commands.goCharLeft(cm); - eqPos(cm.getCursor(), {line: 1, ch: 7}); + eqPos(cm.getCursor(), Pos(1, 7)); cm.setCursor(0, 5); CodeMirror.commands.goCharRight(cm); - eqPos(cm.getCursor(), {line: 0, ch: 6}); + eqPos(cm.getCursor(), Pos(0, 6)); CodeMirror.commands.goCharRight(cm); - eqPos(cm.getCursor(), {line: 1, ch: 3}); + eqPos(cm.getCursor(), Pos(1, 3)); }); testCM("badNestedFold", function(cm) { addDoc(cm, 4, 4); - cm.markText({line: 0, ch: 2}, {line: 3, ch: 2}, {collapsed: true}); + cm.markText(Pos(0, 2), Pos(3, 2), {collapsed: true}); var caught; - try {cm.markText({line: 0, ch: 1}, {line: 0, ch: 3}, {collapsed: true});} + try {cm.markText(Pos(0, 1), Pos(0, 3), {collapsed: true});} catch(e) {caught = e;} is(caught instanceof Error, "no error"); is(/overlap/i.test(caught.message), "wrong error"); }); testCM("inlineWidget", function(cm) { - var w = cm.setBookmark({line: 0, ch: 2}, {widget: document.createTextNode("uu")}); + var w = cm.setBookmark(Pos(0, 2), {widget: document.createTextNode("uu")}); cm.setCursor(0, 2); CodeMirror.commands.goLineDown(cm); - eqPos(cm.getCursor(), {line: 1, ch: 4}); + eqPos(cm.getCursor(), Pos(1, 4)); cm.setCursor(0, 2); cm.replaceSelection("hi"); - eqPos(w.find(), {line: 0, ch: 2}); + eqPos(w.find(), Pos(0, 2)); cm.setCursor(0, 1); cm.replaceSelection("ay"); - eqPos(w.find(), {line: 0, ch: 4}); + eqPos(w.find(), Pos(0, 4)); eq(cm.getLine(0), "uayuhiuu"); }, {value: "uuuu\nuuuuuu"}); @@ -760,7 +762,7 @@ testCM("wrappingAndResizing", function(cm) { var wrap = cm.getWrapperElement(), h0 = wrap.offsetHeight; var doc = "xxx xxx xxx xxx xxx"; cm.setValue(doc); - for (var step = 10, w = cm.charCoords({line: 0, ch: 18}, "div").right;; w += step) { + for (var step = 10, w = cm.charCoords(Pos(0, 18), "div").right;; w += step) { cm.setSize(w); if (wrap.offsetHeight <= h0 * (opera_lt10 ? 1.2 : 1.5)) { if (step == 10) { w -= 10; step = 1; } @@ -769,7 +771,7 @@ testCM("wrappingAndResizing", function(cm) { } // Ensure that putting the cursor at the end of the maximally long // line doesn't cause wrapping to happen. - cm.setCursor({line: 0, ch: doc.length}); + cm.setCursor(Pos(0, doc.length)); eq(wrap.offsetHeight, h0); cm.replaceSelection("x"); is(wrap.offsetHeight > h0, "wrapping happens"); @@ -777,9 +779,9 @@ testCM("wrappingAndResizing", function(cm) { // almost-wrapped lines, go over it so that a scrollbar appears. cm.setValue(doc + "\n" + doc + "\n"); cm.getScrollerElement().style.maxHeight = "100px"; - cm.replaceRange("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n!\n", {line: 2, ch: 0}); - forEach([{line: 0, ch: doc.length}, {line: 0, ch: doc.length - 1}, - {line: 0, ch: 0}, {line: 1, ch: doc.length}, {line: 1, ch: doc.length - 1}], + cm.replaceRange("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n!\n", Pos(2, 0)); + forEach([Pos(0, doc.length), Pos(0, doc.length - 1), + Pos(0, 0), Pos(1, doc.length), Pos(1, doc.length - 1)], function(pos) { var coords = cm.charCoords(pos); eqPos(pos, cm.coordsChar({left: coords.left + 2, top: coords.top + 5})); @@ -790,7 +792,7 @@ testCM("measureEndOfLine", function(cm) { cm.setSize(null, "auto"); var inner = byClassName(cm.getWrapperElement(), "CodeMirror-lines")[0].firstChild; var lh = inner.offsetHeight; - for (var step = 10, w = cm.charCoords({line: 0, ch: 7}, "div").right;; w += step) { + 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; } @@ -798,11 +800,11 @@ testCM("measureEndOfLine", function(cm) { } } cm.setValue(cm.getValue() + "\n\n"); - var endPos = cm.charCoords({line: 0, ch: 18}, "local"); + var endPos = cm.charCoords(Pos(0, 18), "local"); is(endPos.top > lh * .8, "not at top"); is(endPos.left > w - 20, "not at right"); - endPos = cm.charCoords({line: 0, ch: 18}); - eqPos(cm.coordsChar({left: endPos.left, top: endPos.top + 5}), {line: 0, ch: 18}); + endPos = cm.charCoords(Pos(0, 18)); + eqPos(cm.coordsChar({left: endPos.left, top: endPos.top + 5}), Pos(0, 18)); }, {mode: "text/html", value: "", lineWrapping: true}, ie_lt8 || opera_lt10); testCM("scrollVerticallyAndHorizontally", function(cm) { @@ -821,19 +823,19 @@ testCM("moveVstuck", function(cm) { var lines = byClassName(cm.getWrapperElement(), "CodeMirror-lines")[0].firstChild, h0 = lines.offsetHeight; var val = "fooooooooooooooooooooooooo baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaar\n"; cm.setValue(val); - for (var w = cm.charCoords({line: 0, ch: 26}, "div").right * 2.8;; w += 5) { + for (var w = cm.charCoords(Pos(0, 26), "div").right * 2.8;; w += 5) { cm.setSize(w); if (lines.offsetHeight <= 3.5 * h0) break; } - cm.setCursor({line: 0, ch: val.length - 1}); + cm.setCursor(Pos(0, val.length - 1)); cm.moveV(-1, "line"); - eqPos(cm.getCursor(), {line: 0, ch: 26}); + eqPos(cm.getCursor(), Pos(0, 26)); }, {lineWrapping: true}, ie_lt8 || opera_lt10); testCM("clickTab", function(cm) { - var p0 = cm.charCoords({line: 0, ch: 0}); - eqPos(cm.coordsChar({left: p0.left + 5, top: p0.top + 5}), {line: 0, ch: 0}); - eqPos(cm.coordsChar({left: p0.right - 5, top: p0.top + 5}), {line: 0, ch: 1}); + var p0 = cm.charCoords(Pos(0, 0)); + eqPos(cm.coordsChar({left: p0.left + 5, top: p0.top + 5}), Pos(0, 0)); + eqPos(cm.coordsChar({left: p0.right - 5, top: p0.top + 5}), Pos(0, 1)); }, {value: "\t\n\n", lineWrapping: true, tabSize: 8}); testCM("verticalScroll", function(cm) { @@ -885,76 +887,76 @@ testCM("extraKeys", function(cm) { testCM("wordMovementCommands", function(cm) { cm.execCommand("goWordLeft"); - eqPos(cm.getCursor(), {line: 0, ch: 0}); + eqPos(cm.getCursor(), Pos(0, 0)); cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); - eqPos(cm.getCursor(), {line: 0, ch: 7}); + eqPos(cm.getCursor(), Pos(0, 7)); cm.execCommand("goWordLeft"); - eqPos(cm.getCursor(), {line: 0, ch: 5}); + eqPos(cm.getCursor(), Pos(0, 5)); cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); - eqPos(cm.getCursor(), {line: 0, ch: 12}); + eqPos(cm.getCursor(), Pos(0, 12)); cm.execCommand("goWordLeft"); - eqPos(cm.getCursor(), {line: 0, ch: 9}); + eqPos(cm.getCursor(), Pos(0, 9)); cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); - eqPos(cm.getCursor(), {line: 1, ch: 1}); + eqPos(cm.getCursor(), Pos(1, 1)); cm.execCommand("goWordRight"); - eqPos(cm.getCursor(), {line: 1, ch: 9}); + eqPos(cm.getCursor(), Pos(1, 9)); cm.execCommand("goWordRight"); - eqPos(cm.getCursor(), {line: 1, ch: 13}); + eqPos(cm.getCursor(), Pos(1, 13)); cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); - eqPos(cm.getCursor(), {line: 2, ch: 0}); + eqPos(cm.getCursor(), Pos(2, 0)); }, {value: "this is (the) firstline.\na foo12\u00e9\u00f8\u00d7bar\n"}); testCM("charMovementCommands", function(cm) { cm.execCommand("goCharLeft"); cm.execCommand("goColumnLeft"); - eqPos(cm.getCursor(), {line: 0, ch: 0}); + eqPos(cm.getCursor(), Pos(0, 0)); cm.execCommand("goCharRight"); cm.execCommand("goCharRight"); - eqPos(cm.getCursor(), {line: 0, ch: 2}); - cm.setCursor({line: 1, ch: 0}); + eqPos(cm.getCursor(), Pos(0, 2)); + cm.setCursor(Pos(1, 0)); cm.execCommand("goColumnLeft"); - eqPos(cm.getCursor(), {line: 1, ch: 0}); + eqPos(cm.getCursor(), Pos(1, 0)); cm.execCommand("goCharLeft"); - eqPos(cm.getCursor(), {line: 0, ch: 5}); + eqPos(cm.getCursor(), Pos(0, 5)); cm.execCommand("goColumnRight"); - eqPos(cm.getCursor(), {line: 0, ch: 5}); + eqPos(cm.getCursor(), Pos(0, 5)); cm.execCommand("goCharRight"); - eqPos(cm.getCursor(), {line: 1, ch: 0}); + eqPos(cm.getCursor(), Pos(1, 0)); cm.execCommand("goLineEnd"); - eqPos(cm.getCursor(), {line: 1, ch: 5}); + eqPos(cm.getCursor(), Pos(1, 5)); cm.execCommand("goLineStartSmart"); - eqPos(cm.getCursor(), {line: 1, ch: 1}); + eqPos(cm.getCursor(), Pos(1, 1)); cm.execCommand("goLineStartSmart"); - eqPos(cm.getCursor(), {line: 1, ch: 0}); - cm.setCursor({line: 2, ch: 0}); + eqPos(cm.getCursor(), Pos(1, 0)); + cm.setCursor(Pos(2, 0)); cm.execCommand("goCharRight"); cm.execCommand("goColumnRight"); - eqPos(cm.getCursor(), {line: 2, ch: 0}); + eqPos(cm.getCursor(), Pos(2, 0)); }, {value: "line1\n ine2\n"}); testCM("verticalMovementCommands", function(cm) { cm.execCommand("goLineUp"); - eqPos(cm.getCursor(), {line: 0, ch: 0}); + eqPos(cm.getCursor(), Pos(0, 0)); cm.execCommand("goLineDown"); if (!phantom) // This fails in PhantomJS, though not in a real Webkit - eqPos(cm.getCursor(), {line: 1, ch: 0}); - cm.setCursor({line: 1, ch: 12}); + eqPos(cm.getCursor(), Pos(1, 0)); + cm.setCursor(Pos(1, 12)); cm.execCommand("goLineDown"); - eqPos(cm.getCursor(), {line: 2, ch: 5}); + eqPos(cm.getCursor(), Pos(2, 5)); cm.execCommand("goLineDown"); - eqPos(cm.getCursor(), {line: 3, ch: 0}); + eqPos(cm.getCursor(), Pos(3, 0)); cm.execCommand("goLineUp"); - eqPos(cm.getCursor(), {line: 2, ch: 5}); + eqPos(cm.getCursor(), Pos(2, 5)); cm.execCommand("goLineUp"); - eqPos(cm.getCursor(), {line: 1, ch: 12}); + eqPos(cm.getCursor(), Pos(1, 12)); cm.execCommand("goPageDown"); - eqPos(cm.getCursor(), {line: 5, ch: 0}); + eqPos(cm.getCursor(), Pos(5, 0)); cm.execCommand("goPageDown"); cm.execCommand("goLineDown"); - eqPos(cm.getCursor(), {line: 5, ch: 0}); + eqPos(cm.getCursor(), Pos(5, 0)); cm.execCommand("goPageUp"); - eqPos(cm.getCursor(), {line: 0, ch: 0}); + eqPos(cm.getCursor(), Pos(0, 0)); }, {value: "line1\nlong long line2\nline3\n\nline5\n"}); testCM("verticalMovementCommandsWrapping", function(cm) { cm.setSize(120); - cm.setCursor({line: 0, ch: 5}); + cm.setCursor(Pos(0, 5)); cm.execCommand("goLineDown"); eq(cm.getCursor().line, 0); is(cm.getCursor().ch > 5, "moved beyond wrap"); @@ -993,25 +995,25 @@ testCM("rtlMovement", function(cm) { // Verify that updating a line clears its bidi ordering testCM("bidiUpdate", function(cm) { - cm.setCursor({line: 0, ch: 2}); + cm.setCursor(Pos(0, 2)); cm.replaceSelection("خحج", "start"); cm.execCommand("goCharRight"); - eqPos(cm.getCursor(), {line: 0, ch: 4}); + eqPos(cm.getCursor(), Pos(0, 4)); }, {value: "abcd\n"}); testCM("movebyTextUnit", function(cm) { cm.setValue("בְּרֵאשִ\ńéée\n"); cm.execCommand("goLineEnd"); for (var i = 0; i < 4; ++i) cm.execCommand("goCharRight"); - eqPos(cm.getCursor(), {line: 0, ch: 0}); + eqPos(cm.getCursor(), Pos(0, 0)); cm.execCommand("goCharRight"); - eqPos(cm.getCursor(), {line: 1, ch: 0}); + eqPos(cm.getCursor(), Pos(1, 0)); cm.execCommand("goCharRight"); cm.execCommand("goCharRight"); - eqPos(cm.getCursor(), {line: 1, ch: 3}); + eqPos(cm.getCursor(), Pos(1, 3)); cm.execCommand("goCharRight"); cm.execCommand("goCharRight"); - eqPos(cm.getCursor(), {line: 1, ch: 6}); + eqPos(cm.getCursor(), Pos(1, 6)); }); testCM("lineChangeEvents", function(cm) { @@ -1025,10 +1027,10 @@ testCM("lineChangeEvents", function(cm) { return function() {log.push("ch " + i);}; }(i)); } - cm.replaceRange("x", {line: 0, ch: 1}); - cm.replaceRange("xy", {line: 1, ch: 1}, {line: 2}); - cm.replaceRange("foo\nbar", {line: 0, ch: 1}); - cm.replaceRange("", {line: 0, ch: 0}, {line: cm.lineCount()}); + cm.replaceRange("x", Pos(0, 1)); + cm.replaceRange("xy", Pos(1, 1), Pos(2)); + cm.replaceRange("foo\nbar", Pos(0, 1)); + cm.replaceRange("", Pos(0, 0), Pos(cm.lineCount())); eq(log.length, want.length, "same length"); for (var i = 0; i < log.length; ++i) eq(log[i], want[i]); @@ -1036,23 +1038,23 @@ testCM("lineChangeEvents", function(cm) { testCM("scrollEntirelyToRight", function(cm) { addDoc(cm, 500, 2); - cm.setCursor({line: 0, ch: 500}); + cm.setCursor(Pos(0, 500)); var wrap = cm.getWrapperElement(), cur = byClassName(wrap, "CodeMirror-cursor")[0]; is(wrap.getBoundingClientRect().right > cur.getBoundingClientRect().left); }); testCM("lineWidgets", function(cm) { addDoc(cm, 500, 3); - var last = cm.charCoords({line: 2, ch: 0}); + var last = cm.charCoords(Pos(2, 0)); var node = document.createElement("div"); node.innerHTML = "hi"; var widget = cm.addLineWidget(1, node); - is(last.top < cm.charCoords({line: 2, ch: 0}).top, "took up space"); - cm.setCursor({line: 1, ch: 1}); + is(last.top < cm.charCoords(Pos(2, 0)).top, "took up space"); + cm.setCursor(Pos(1, 1)); cm.execCommand("goLineDown"); - eqPos(cm.getCursor(), {line: 2, ch: 1}); + eqPos(cm.getCursor(), Pos(2, 1)); cm.execCommand("goLineUp"); - eqPos(cm.getCursor(), {line: 1, ch: 1}); + eqPos(cm.getCursor(), Pos(1, 1)); }); testCM("lineWidgetFocus", function(cm) { @@ -1064,7 +1066,7 @@ testCM("lineWidgetFocus", function(cm) { var widget = cm.addLineWidget(1, node); node.focus(); eq(document.activeElement, node); - cm.replaceRange("new stuff", {line: 1, ch: 0}); + cm.replaceRange("new stuff", Pos(1, 0)); eq(document.activeElement, node); } finally { place.className = ""; @@ -1075,7 +1077,7 @@ testCM("getLineNumber", function(cm) { addDoc(cm, 2, 20); var h1 = cm.getLineHandle(1); eq(cm.getLineNumber(h1), 1); - cm.replaceRange("hi\nbye\n", {line: 0, ch: 0}); + cm.replaceRange("hi\nbye\n", Pos(0, 0)); eq(cm.getLineNumber(h1), 3); cm.setValue(""); eq(cm.getLineNumber(h1), null); @@ -1088,27 +1090,27 @@ testCM("jumpTheGap", function(cm) { cm.setSize("200px", null); cm.getWrapperElement().style.lineHeight = 2; cm.refresh(); - cm.setCursor({line: 0, ch: 1}); + cm.setCursor(Pos(0, 1)); cm.execCommand("goLineDown"); - eqPos(cm.getCursor(), {line: 1, ch: 1}); + eqPos(cm.getCursor(), Pos(1, 1)); cm.execCommand("goLineDown"); - eqPos(cm.getCursor(), {line: 2, ch: 1}); + eqPos(cm.getCursor(), Pos(2, 1)); cm.execCommand("goLineDown"); eq(cm.getCursor().line, 2); is(cm.getCursor().ch > 1); cm.execCommand("goLineUp"); - eqPos(cm.getCursor(), {line: 2, ch: 1}); + eqPos(cm.getCursor(), Pos(2, 1)); cm.execCommand("goLineUp"); - eqPos(cm.getCursor(), {line: 1, ch: 1}); + eqPos(cm.getCursor(), Pos(1, 1)); var node = document.createElement("div"); node.innerHTML = "hi"; node.style.height = "30px"; cm.addLineWidget(0, node); cm.addLineWidget(1, node.cloneNode(true), {above: true}); - cm.setCursor({line: 0, ch: 2}); + cm.setCursor(Pos(0, 2)); cm.execCommand("goLineDown"); - eqPos(cm.getCursor(), {line: 1, ch: 2}); + eqPos(cm.getCursor(), Pos(1, 2)); cm.execCommand("goLineUp"); - eqPos(cm.getCursor(), {line: 0, ch: 2}); + eqPos(cm.getCursor(), Pos(0, 2)); }, {lineWrapping: true, value: "abc\ndef\nghi\njkl\n"}); testCM("addLineClass", function(cm) { @@ -1143,82 +1145,82 @@ testCM("addLineClass", function(cm) { testCM("atomicMarker", function(cm) { addDoc(cm, 10, 10); function atom(ll, cl, lr, cr, li, ri) { - return cm.markText({line: ll, ch: cl}, {line: lr, ch: cr}, + return cm.markText(Pos(ll, cl), Pos(lr, cr), {atomic: true, inclusiveLeft: li, inclusiveRight: ri}); } var m = atom(0, 1, 0, 5); - cm.setCursor({line: 0, ch: 1}); + cm.setCursor(Pos(0, 1)); cm.execCommand("goCharRight"); - eqPos(cm.getCursor(), {line: 0, ch: 5}); + eqPos(cm.getCursor(), Pos(0, 5)); cm.execCommand("goCharLeft"); - eqPos(cm.getCursor(), {line: 0, ch: 1}); + eqPos(cm.getCursor(), Pos(0, 1)); m.clear(); m = atom(0, 0, 0, 5, true); - eqPos(cm.getCursor(), {line: 0, ch: 5}, "pushed out"); + eqPos(cm.getCursor(), Pos(0, 5), "pushed out"); cm.execCommand("goCharLeft"); - eqPos(cm.getCursor(), {line: 0, ch: 5}); + eqPos(cm.getCursor(), Pos(0, 5)); m.clear(); m = atom(8, 4, 9, 10, false, true); - cm.setCursor({line: 9, ch: 8}); - eqPos(cm.getCursor(), {line: 8, ch: 4}, "set"); + cm.setCursor(Pos(9, 8)); + eqPos(cm.getCursor(), Pos(8, 4), "set"); cm.execCommand("goCharRight"); - eqPos(cm.getCursor(), {line: 8, ch: 4}, "char right"); + eqPos(cm.getCursor(), Pos(8, 4), "char right"); cm.execCommand("goLineDown"); - eqPos(cm.getCursor(), {line: 8, ch: 4}, "line down"); + eqPos(cm.getCursor(), Pos(8, 4), "line down"); cm.execCommand("goCharLeft"); - eqPos(cm.getCursor(), {line: 8, ch: 3}); + eqPos(cm.getCursor(), Pos(8, 3)); m.clear(); m = atom(1, 1, 3, 8); - cm.setCursor({line: 2, ch: 0}); - eqPos(cm.getCursor(), {line: 3, ch: 8}); + cm.setCursor(Pos(2, 0)); + eqPos(cm.getCursor(), Pos(3, 8)); cm.execCommand("goCharLeft"); - eqPos(cm.getCursor(), {line: 1, ch: 1}); + eqPos(cm.getCursor(), Pos(1, 1)); cm.execCommand("goCharRight"); - eqPos(cm.getCursor(), {line: 3, ch: 8}); + eqPos(cm.getCursor(), Pos(3, 8)); cm.execCommand("goLineUp"); - eqPos(cm.getCursor(), {line: 1, ch: 1}); + eqPos(cm.getCursor(), Pos(1, 1)); cm.execCommand("goLineDown"); - eqPos(cm.getCursor(), {line: 3, ch: 8}); + eqPos(cm.getCursor(), Pos(3, 8)); cm.execCommand("delCharBefore"); eq(cm.getValue().length, 80, "del chunk"); m = atom(3, 0, 5, 5); - cm.setCursor({line: 3, ch: 0}); + cm.setCursor(Pos(3, 0)); cm.execCommand("delWordAfter"); eq(cm.getValue().length, 53, "del chunk"); }); testCM("readOnlyMarker", function(cm) { function mark(ll, cl, lr, cr, at) { - return cm.markText({line: ll, ch: cl}, {line: lr, ch: cr}, + return cm.markText(Pos(ll, cl), Pos(lr, cr), {readOnly: true, atomic: at}); } var m = mark(0, 1, 0, 4); - cm.setCursor({line: 0, ch: 2}); + cm.setCursor(Pos(0, 2)); cm.replaceSelection("hi", "end"); - eqPos(cm.getCursor(), {line: 0, ch: 2}); + eqPos(cm.getCursor(), Pos(0, 2)); eq(cm.getLine(0), "abcde"); cm.execCommand("selectAll"); cm.replaceSelection("oops"); eq(cm.getValue(), "oopsbcd"); cm.undo(); - eqPos(m.find().from, {line: 0, ch: 1}); - eqPos(m.find().to, {line: 0, ch: 4}); + eqPos(m.find().from, Pos(0, 1)); + eqPos(m.find().to, Pos(0, 4)); m.clear(); - cm.setCursor({line: 0, ch: 2}); + cm.setCursor(Pos(0, 2)); cm.replaceSelection("hi"); eq(cm.getLine(0), "abhicde"); - eqPos(cm.getCursor(), {line: 0, ch: 4}); + eqPos(cm.getCursor(), Pos(0, 4)); m = mark(0, 2, 2, 2, true); - cm.setSelection({line: 1, ch: 1}, {line: 2, ch: 4}); + cm.setSelection(Pos(1, 1), Pos(2, 4)); cm.replaceSelection("t", "end"); - eqPos(cm.getCursor(), {line: 2, ch: 3}); + eqPos(cm.getCursor(), Pos(2, 3)); eq(cm.getLine(2), "klto"); cm.execCommand("goCharLeft"); cm.execCommand("goCharLeft"); - eqPos(cm.getCursor(), {line: 0, ch: 2}); - cm.setSelection({line: 0, ch: 1}, {line: 0, ch: 3}); + eqPos(cm.getCursor(), Pos(0, 2)); + cm.setSelection(Pos(0, 1), Pos(0, 3)); cm.replaceSelection("xx"); - eqPos(cm.getCursor(), {line: 0, ch: 3}); + eqPos(cm.getCursor(), Pos(0, 3)); eq(cm.getLine(0), "axxhicde"); }, {value: "abcde\nfghij\nklmno\n"}); @@ -1247,12 +1249,12 @@ testCM("addKeyMap", function(cm) { } sendKey(39); - eqPos(cm.getCursor(), {line: 0, ch: 1}); + eqPos(cm.getCursor(), Pos(0, 1)); var test = 0; var map1 = {Right: function() { ++test; }}, map2 = {Right: function() { test += 10; }} cm.addKeyMap(map1); sendKey(39); - eqPos(cm.getCursor(), {line: 0, ch: 1}); + eqPos(cm.getCursor(), Pos(0, 1)); eq(test, 1); cm.addKeyMap(map2); sendKey(39); @@ -1263,11 +1265,11 @@ testCM("addKeyMap", function(cm) { cm.removeKeyMap(map2); sendKey(39); eq(test, 12); - eqPos(cm.getCursor(), {line: 0, ch: 2}); + eqPos(cm.getCursor(), Pos(0, 2)); cm.addKeyMap({Right: function() { test = 55; }, name: "mymap"}); sendKey(39); eq(test, 55); cm.removeKeyMap("mymap"); sendKey(39); - eqPos(cm.getCursor(), {line: 0, ch: 3}); + eqPos(cm.getCursor(), Pos(0, 3)); }, {value: "abc"}); From 8026d5cd5fbf82018008e5b3c1934a2714b8a1af Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Feb 2013 14:33:34 +0100 Subject: [PATCH 0171/5273] [show-hint addon] Support PageUp/PageDown/Home/End keys when dialog is active --- addon/hint/show-hint.css | 1 + addon/hint/show-hint.js | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/addon/hint/show-hint.css b/addon/hint/show-hint.css index 55661c9c0c..8a4ff052e3 100644 --- a/addon/hint/show-hint.css +++ b/addon/hint/show-hint.css @@ -11,6 +11,7 @@ -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); box-shadow: 2px 3px 5px rgba(0,0,0,.2); border-radius: 3px; + border: 1px solid silver; background: white; font-size: 90%; diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index dc381d8510..38dbbf5335 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -51,9 +51,17 @@ CodeMirror.showHint = function(cm, getHints, options) { hints.scrollTop = node.offsetTop + node.offsetHeight - hints.clientHeight + 3; } + function screenAmount() { + return Math.floor(hints.clientHeight / hints.firstChild.offsetHeight) || 1; + } + var ourMap = { Up: function() {changeActive(selectedHint - 1);}, Down: function() {changeActive(selectedHint + 1);}, + PageUp: function() {changeActive(selectedHint - screenAmount());}, + PageDown: function() {changeActive(selectedHint + screenAmount());}, + Home: function() {changeActive(0);}, + End: function() {changeActive(completions.length - 1);}, Enter: pick, Tab: pick, Esc: close From 3694587040daf791c13c7d41cdc7ce350385c7c8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Feb 2013 14:35:31 +0100 Subject: [PATCH 0172/5273] [show-hint addon] Don't close hinter when typing first letter of word --- 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 38dbbf5335..c1347a9421 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -8,7 +8,7 @@ CodeMirror.showHint = function(cm, getHints, options) { var token = cm.getTokenAt(cm.getCursor()); // Don't show completions if token has changed - if (previousToken != null && + if (previousToken != null && /\w/.test(previousToken.string) && (token.start != previousToken.start || token.type != previousToken.type)) return; From 1648e9d7b2e2fd4979f941f6c9a5ee6673432bb5 Mon Sep 17 00:00:00 2001 From: Xavier Mendez Date: Wed, 6 Feb 2013 14:07:01 +0100 Subject: [PATCH 0173/5273] Roll up the active-line addon! --- addon/selection/active-line.js | 39 ++++++++++++++++++++++++++++++++++ demo/activeline.html | 12 +++-------- 2 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 addon/selection/active-line.js diff --git a/addon/selection/active-line.js b/addon/selection/active-line.js new file mode 100644 index 0000000000..988a0ffbf7 --- /dev/null +++ b/addon/selection/active-line.js @@ -0,0 +1,39 @@ +// 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". + +(function() { + "use strict"; + var WRAP_CLASS = "CodeMirror-activeline"; + var BACK_CLASS = "CodeMirror-activeline-background"; + + CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) { + var prev = old && old != CodeMirror.Init; + if (val && !prev) { + updateActiveLine(cm); + cm.on("cursorActivity", updateActiveLine); + } else if (!val && prev) { + cm.off("cursorActivity", updateActiveLine); + clearActiveLine(cm); + delete cm._activeLine; + } + }); + + function clearActiveLine(cm) { + if ("_activeLine" in cm) { + cm.removeLineClass(cm._activeLine, "wrap", WRAP_CLASS); + cm.removeLineClass(cm._activeLine, "background", BACK_CLASS); + } + } + + function updateActiveLine(cm) { + var line = cm.getLineHandle(cm.getCursor().line); + if (cm._activeLine == line) return; + clearActiveLine(cm); + cm.addLineClass(line, "wrap", WRAP_CLASS); + cm.addLineClass(line, "background", BACK_CLASS); + cm._activeLine = line; + } +})(); diff --git a/demo/activeline.html b/demo/activeline.html index 457d69cad8..b0ea9b9070 100644 --- a/demo/activeline.html +++ b/demo/activeline.html @@ -6,11 +6,12 @@ + @@ -57,17 +58,10 @@

    CodeMirror: Active Line Demo

    Styling the current cursor line.

    From 9bf595221d5e35cc4a89dd2b6b09d0d707b9ad11 Mon Sep 17 00:00:00 2001 From: Xavier Mendez Date: Wed, 6 Feb 2013 14:30:08 +0100 Subject: [PATCH 0174/5273] Fix some issues on mark-selection - When mark-selection is deactivated the mark was not removed. - When mark-selection is [re]activated it immediately calls updateSelectedText() to set the mark if there's already a selection. - In addition to removing the mark, the handle is completely deleted to leave the CodeMirror instance in a clean state, and avoid re-deleting the mark if it's activated again. --- addon/selection/mark-selection.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/addon/selection/mark-selection.js b/addon/selection/mark-selection.js index 7342135545..d7ff30c9a9 100644 --- a/addon/selection/mark-selection.js +++ b/addon/selection/mark-selection.js @@ -8,14 +8,22 @@ CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) { var prev = old && old != CodeMirror.Init; - if (val && !prev) + if (val && !prev) { + updateSelectedText(cm); cm.on("cursorActivity", updateSelectedText); - else if (!val && prev) + } else if (!val && prev) { cm.off("cursorActivity", updateSelectedText); + clearSelectedText(cm); + delete cm._selectionMark; + } }); - function updateSelectedText(cm) { + function clearSelectedText(cm) { if (cm._selectionMark) cm._selectionMark.clear(); + } + + function updateSelectedText(cm) { + clearSelectedText(cm); if (cm.somethingSelected()) cm._selectionMark = cm.markText(cm.getCursor("start"), cm.getCursor("end"), From c708ad73e67521b0d880b02df95c4f026dac28bf Mon Sep 17 00:00:00 2001 From: Xavier Mendez Date: Wed, 6 Feb 2013 14:30:30 +0100 Subject: [PATCH 0175/5273] Talk about mark-selection and active-line on the manual. --- doc/manual.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/manual.html b/doc/manual.html index 632e010ca1..9dcc68abc8 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1416,6 +1416,16 @@

    Add-ons

    can be enabled to highlight all instances of a currently selected word. Demo here.
    +
    mark-selection.js
    +
    Causes the selected text to be marked with the CSS class + CodeMirror-selectedtext when the styleSelectedText option + is enabled. Useful to change the colour of the selection (in addition to the background), + like in this demo.
    +
    active-line.js
    +
    Defines a styleActiveLine option that, when enabled, + gives the wrapper of the active line the class CodeMirror-activeline, + and adds a background with the class CodeMirror-activeline-background. + is enabled. See the demo.
    formatting.js
    Adds commentRange, autoIndentRange, and autoFormatRange methods that, respectively, From 510edf43e05abb9e87cefeec873092c17c211c83 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Feb 2013 16:12:51 +0100 Subject: [PATCH 0176/5273] Add a bi-directional text demo Closes #1180 --- demo/bidi.html | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ index.html | 1 + 2 files changed, 62 insertions(+) create mode 100644 demo/bidi.html diff --git a/demo/bidi.html b/demo/bidi.html new file mode 100644 index 0000000000..47feb8c5aa --- /dev/null +++ b/demo/bidi.html @@ -0,0 +1,61 @@ + + + + + CodeMirror: Bi-directional Text Demo + + + + + + + + +

    CodeMirror: Bi-directional Text Demo

    + +
    + + + +

    Demonstration of bi-directional text support. See + the related + blog post for more background.

    + + + diff --git a/index.html b/index.html index f423ebac6f..477cec3d64 100644 --- a/index.html +++ b/index.html @@ -93,6 +93,7 @@

    Usage demos:

  • Autocompletion (XML)
  • Search/replace
  • Code folding
  • +
  • Bi-directional text
  • Line widgets (via JSHint)
  • Split view
  • Mode overlays
  • From 5810dd040d3d71c4366b463dc991f7bb5042462c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 7 Feb 2013 11:19:10 +0100 Subject: [PATCH 0177/5273] Sanitize logic that prevents editing in readOnly ranges It was really quite misguided before. --- lib/codemirror.js | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index e9e485570e..8dfcff0f09 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3565,22 +3565,14 @@ window.CodeMirror = (function() { var parts = [{from: from, to: to}]; for (var i = 0; i < markers.length; ++i) { var mk = markers[i], m = mk.find(); - if (mk.inclusiveLeft) { - m.from = Pos(m.from.line, m.from.ch - 1); - if (m.from.ch < 0 && m.from.line > doc.first) - m.from = Pos(m.from.line - 1, getLine(doc, m.from.line - 1).text.length); - } - if (mk.inclusiveRight) { - m.to = Pos(m.to.line, m.to.ch + 1); - if (m.to.line < doc.first + doc.size - 1 && m.to.ch > getLine(doc, m.to.line).text.length) - m.to = Pos(m.to.line + 1, 0); - } for (var j = 0; j < parts.length; ++j) { var p = parts[j]; - if (!posLess(m.from, p.to) || posLess(m.to, p.from)) continue; + if (posLess(p.to, m.from) || posLess(m.to, p.from)) continue; var newParts = [j, 1]; - if (posLess(p.from, m.from)) newParts.push({from: p.from, to: m.from}); - if (posLess(m.to, p.to)) newParts.push({from: m.to, to: p.to}); + if (posLess(p.from, m.from) || !mk.inclusiveLeft && posEq(p.from, m.from)) + newParts.push({from: p.from, to: m.from}); + if (posLess(m.to, p.to) || !mk.inclusiveRight && posEq(p.to, m.to)) + newParts.push({from: m.to, to: p.to}); parts.splice.apply(parts, newParts); j += newParts.length - 1; } From 9ca7b0773b88fe071d7287e6df2c70fcded9e868 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 7 Feb 2013 11:38:23 +0100 Subject: [PATCH 0178/5273] [show-hint addon] Improve heuristic for keeping or closing the pop-up --- addon/hint/show-hint.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index c1347a9421..89ea66795f 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -1,22 +1,17 @@ CodeMirror.showHint = function(cm, getHints, options) { if (!options) options = {}; - function collectHints(previousToken) { + function collectHints(startCh, continued) { // We want a single cursor position. if (cm.somethingSelected()) return; var token = cm.getTokenAt(cm.getCursor()); - // Don't show completions if token has changed - if (previousToken != null && /\w/.test(previousToken.string) && - (token.start != previousToken.start || token.type != previousToken.type)) - return; - var result = getHints(cm, options); if (!result || !result.list.length) return; var completions = result.list; // When there is only one completion, use it directly. - if (!previousToken && options.completeSingle !== false && completions.length == 1) { + if (!continued && options.completeSingle !== false && completions.length == 1) { cm.replaceRange(completions[0], result.from, result.to); return true; } @@ -98,10 +93,16 @@ CodeMirror.showHint = function(cm, getHints, options) { cm.replaceRange(completions[selectedHint], result.from, result.to); close(); } - var once; + var once, lastPos = cm.getCursor(), lastLen = cm.getLine(lastPos.line).length; function cursorActivity() { clearTimeout(once); - once = setTimeout(function(){close(); collectHints(token);}, 70); + + var pos = cm.getCursor(), len = cm.getLine(pos.line).length, start = startCh || lastPos.ch; + if (pos.line != lastPos.line || len - pos.ch != lastLen - lastPos.ch || + pos.ch < start || cm.somethingSelected()) + close(); + else + once = setTimeout(function(){close(); collectHints(start, true);}, 70); } return true; } From b3c2ecdd68cc22b656853ac3ba9a0e76ae3ba008 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 7 Feb 2013 11:40:49 +0100 Subject: [PATCH 0179/5273] [show-hint addon] Remove unused variable --- addon/hint/show-hint.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 89ea66795f..2c1cba850b 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -5,8 +5,6 @@ CodeMirror.showHint = function(cm, getHints, options) { // We want a single cursor position. if (cm.somethingSelected()) return; - var token = cm.getTokenAt(cm.getCursor()); - var result = getHints(cm, options); if (!result || !result.list.length) return; var completions = result.list; From b37017c20f6dc5f6f3b2d1d52aefa31a4ab3e305 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 7 Feb 2013 16:29:04 +0100 Subject: [PATCH 0180/5273] [show-hint addon] More careful positioning of pop-up --- addon/hint/show-hint.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 2c1cba850b..30c8df3cd8 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -30,8 +30,26 @@ CodeMirror.showHint = function(cm, getHints, options) { // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); - if (winW - pos.left < hints.clientWidth) - hints.style.left = (pos.left - sel.clientWidth) + "px"; + var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); + var box = hints.getBoundingClientRect(); + var overlapX = box.right - winW, overlapY = box.bottom - winH; + if (overlapX > 0) { + if (box.right - box.left > winW) { + hints.style.width = (winW - 5) + "px"; + overlapX -= (box.right - box.left) - winW; + } + hints.style.left = (pos.left - overlapX) + "px"; + } + if (overlapY > 0) { + var height = box.bottom - box.top; + if (box.top - (pos.bottom - pos.top) - height > 0) { + overlapY = height + (pos.bottom - pos.top); + } else if (height > winH) { + hints.style.height = (winH - 5) + "px"; + overlapY -= height - winH; + } + hints.style.top = (pos.bottom - overlapY) + "px"; + } function changeActive(i) { if (i < 0 || i >= completions.length || selectedHint == i) return; From 89df69dec96976f1d7d7929a7e69c91e7ba64871 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 7 Feb 2013 16:30:55 +0100 Subject: [PATCH 0181/5273] [show-hint addon] Close pop-up on blur, make page-up work when near top of list --- addon/hint/show-hint.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 30c8df3cd8..eb9cfa924f 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -52,7 +52,8 @@ CodeMirror.showHint = function(cm, getHints, options) { } function changeActive(i) { - if (i < 0 || i >= completions.length || selectedHint == i) return; + i = Math.max(0, Math.min(i, completions.length - 1)); + if (selectedHint == i) return; hints.childNodes[selectedHint].className = "CodeMirror-hint"; var node = hints.childNodes[selectedHint = i]; node.className = "CodeMirror-hint CodeMirror-hint-active"; @@ -85,6 +86,7 @@ CodeMirror.showHint = function(cm, getHints, options) { cm.addKeyMap(ourMap); cm.on("cursorActivity", cursorActivity); + cm.on("blur", close); CodeMirror.on(hints, "dblclick", function(e) { var t = e.target || e.srcElement; if (t.hintId != null) {selectedHint = t.hintId; pick();} @@ -104,6 +106,7 @@ CodeMirror.showHint = function(cm, getHints, options) { hints.parentNode.removeChild(hints); cm.removeKeyMap(ourMap); cm.off("cursorActivity", cursorActivity); + cm.off("blur", close); } function pick() { cm.replaceRange(completions[selectedHint], result.from, result.to); From ae179ddd1fe0562ae9f46ddf212d7fad67cc317e Mon Sep 17 00:00:00 2001 From: Narciso Jaramillo Date: Thu, 7 Feb 2013 14:57:53 -0800 Subject: [PATCH 0182/5273] Wrap undo/redo in an operation --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 8dfcff0f09..cc2f33416f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4254,8 +4254,8 @@ window.CodeMirror = (function() { replaceSelection: function(code, collapse, origin) { makeChange(this, {from: this.sel.from, to: this.sel.to, text: splitLines(code), origin: origin}, collapse || "around"); }, - undo: function() {makeChangeFromHistory(this, "undo");}, - redo: function() {makeChangeFromHistory(this, "redo");}, + undo: docOperation(function() {makeChangeFromHistory(this, "undo");}), + redo: docOperation(function() {makeChangeFromHistory(this, "redo");}), setExtending: function(val) {this.sel.extend = val;}, From 70809f8de1ca27d22e7703575edc936da85dd96c Mon Sep 17 00:00:00 2001 From: Randy Edmunds Date: Thu, 7 Feb 2013 13:32:00 -0800 Subject: [PATCH 0183/5273] [htmlmixed mode] support for x-javascript and x-ecmascript script types --- mode/htmlmixed/htmlmixed.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/htmlmixed/htmlmixed.js b/mode/htmlmixed/htmlmixed.js index 44063b3551..7c1fbefcea 100644 --- a/mode/htmlmixed/htmlmixed.js +++ b/mode/htmlmixed/htmlmixed.js @@ -11,7 +11,7 @@ CodeMirror.defineMode("htmlmixed", function(config) { // Script block: mode to change to depends on type attribute var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i); scriptType = scriptType && scriptType[1]; - if (!scriptType || scriptType.match(/(text|application)\/(java|ecma)script/i)) { + if (!scriptType || scriptType.match(/(text|application)\/(x-)?(java|ecma)script/i)) { state.token = javascript; state.localMode = jsMode; state.localState = jsMode.startState(htmlMode.indent(state.htmlState, "")); From 3b37d7ad2bf08cfbcc294dc8861b3a21034c03b3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 8 Feb 2013 09:47:20 +0100 Subject: [PATCH 0184/5273] Remove reference to buildLineWidget It was still being called for showIfHidden widgets, even though it no longer exists. Closes #1225 --- lib/codemirror.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index cc2f33416f..05ebcfebe0 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -590,7 +590,8 @@ window.CodeMirror = (function() { wrap.appendChild(prev); prev = wrap; } - prev.appendChild(buildLineWidget(line.widgets[i], prev, dims)); + var wnode = prev.appendChild(elt("div", [line.widgets[i].node], "CodeMirror-linewidget")); + positionLineWidget(line.widgets[i], wnode, prev, dims); } } else if (nextIntact && nextIntact.from <= lineN && nextIntact.to > lineN) { // This line is intact. Skip to the actual node. Update its @@ -644,7 +645,7 @@ window.CodeMirror = (function() { var widget = line.widgets[i], isFirst = false; if (!widget.above) { isFirst = first; first = false; } if (widget.node == n.firstChild) { - positionLineWidget(n, reuse, dims); + positionLineWidget(widget, n, reuse, dims); ++widgetsSeen; if (isFirst) reuse.insertBefore(lineElement, n); break; @@ -687,8 +688,7 @@ window.CodeMirror = (function() { if (ie_lt8) wrap.style.zIndex = 2; if (line.widgets && wrap != reuse) for (var i = 0, ws = line.widgets; i < ws.length; ++i) { var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); - node.widget = widget; - positionLineWidget(node, wrap, dims); + positionLineWidget(widget, node, wrap, dims); if (widget.above) wrap.insertBefore(node, cm.options.lineNumbers && line.height != 0 ? gutterWrap : lineElement); else @@ -698,8 +698,7 @@ window.CodeMirror = (function() { return wrap; } - function positionLineWidget(node, wrap, dims) { - var widget = node.widget; + function positionLineWidget(widget, node, wrap, dims) { if (widget.noHScroll) { (wrap.alignable || (wrap.alignable = [])).push(node); var width = dims.wrapperWidth; @@ -1027,8 +1026,11 @@ window.CodeMirror = (function() { var vr = cur.top; cur.top = vranges[vr]; cur.bottom = vranges[vr+1]; } - if (!cm.options.lineWrapping) - data.width = pre.lastChild.getBoundingClientRect().right - outer.left; + if (!cm.options.lineWrapping) { + var last = pre.lastChild; + if (last.nodeType == 3) last = pre.appendChild(elt("span", "\u200b")); + data.width = last.getBoundingClientRect().right - outer.left; + } return data; } From 1c8a36e5beeb42ec21124b22fb57d32431affb9a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 8 Feb 2013 10:03:05 +0100 Subject: [PATCH 0185/5273] Fix delayed firing of event handlers The mechanism that was supposed to batch handlers during an operation and fire them afterwards was broken -- handlers triggered during endOperation were fired immediately. Should be better now. Closes #1226 --- lib/codemirror.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 05ebcfebe0..d31422324b 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1218,18 +1218,14 @@ window.CodeMirror = (function() { } function endOperation(cm) { - var op = cm.curOp, doc = cm.doc, delayed; - if (!--delayedCallbackDepth) { - delayed = delayedCallbacks; - delayedCallbacks = null; - } + var op = cm.curOp, doc = cm.doc, display = cm.display; cm.curOp = null; - var display = cm.display; + if (op.updateMaxLine) computeMaxLength(cm); - if (cm.display.maxLineChanged && !cm.options.lineWrapping) { - var width = measureLine(cm, cm.display.maxLine).width; + if (display.maxLineChanged && !cm.options.lineWrapping) { + var width = measureLine(cm, display.maxLine).width; display.sizer.style.minWidth = Math.max(0, width + 3 + scrollerCutOff) + "px"; - cm.display.maxLineChanged = false; + display.maxLineChanged = false; var maxScrollLeft = Math.max(0, display.sizer.offsetLeft + display.sizer.offsetWidth - display.scroller.clientWidth); if (maxScrollLeft < doc.scrollLeft && !op.updateScrollPos) setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), true); @@ -1245,8 +1241,8 @@ window.CodeMirror = (function() { updated = updateDisplay(cm, op.changes, newScrollPos && newScrollPos.scrollTop); if (!updated && op.selectionChanged) updateSelection(cm); if (op.updateScrollPos) { - cm.display.scroller.scrollTop = cm.display.scrollbarV.scrollTop = doc.scrollTop = newScrollPos.scrollTop; - cm.display.scroller.scrollLeft = cm.display.scrollbarH.scrollLeft = doc.scrollLeft = newScrollPos.scrollLeft; + display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = newScrollPos.scrollTop; + display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = newScrollPos.scrollLeft; alignHorizontally(cm); } else if (newScrollPos) { scrollCursorIntoView(cm); @@ -1262,6 +1258,11 @@ window.CodeMirror = (function() { if (unhidden) for (var i = 0; i < unhidden.length; ++i) if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); + var delayed; + if (!--delayedCallbackDepth) { + delayed = delayedCallbacks; + delayedCallbacks = null; + } if (op.textChanged) signal(cm, "change", cm, op.textChanged); if (op.selectionChanged) signal(cm, "cursorActivity", cm); From ba5dc823ef47816b8d7a155960c4272bd103bc05 Mon Sep 17 00:00:00 2001 From: Page Date: Fri, 8 Feb 2013 15:44:52 +0000 Subject: [PATCH 0186/5273] Update the docs to match the current default of 10 for viewportMargin. --- doc/manual.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index 9dcc68abc8..c3e4181df9 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -331,7 +331,7 @@

    Configuration

    below the part of the document that's currently scrolled into view. This affects the amount of updates needed when scrolling, and the amount of work that such an update does. You should - usually leave it at its default, 100. Can be set + usually leave it at its default, 10. Can be set to Infinity to make sure the whole document is always rendered, and thus the browser's text search works on it. This will have bad effects on performance of big From 96c4963bd7d5a45bbe034601c9bff33cace8a256 Mon Sep 17 00:00:00 2001 From: Narciso Jaramillo Date: Fri, 8 Feb 2013 09:56:44 -0800 Subject: [PATCH 0187/5273] Fix recently introduced typo --- addon/edit/continuecomment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/edit/continuecomment.js b/addon/edit/continuecomment.js index 0def40008f..4ee0b48015 100644 --- a/addon/edit/continuecomment.js +++ b/addon/edit/continuecomment.js @@ -12,7 +12,7 @@ if (token.type == "comment" && mode.blockCommentStart) { var end = token.string.indexOf(mode.blockCommentEnd); - var full = cm.getRange(CodeMirro.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found; + 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) { // Comment ended, don't continue it } else if (token.string.indexOf(mode.blockCommentStart) == 0) { From 9cfdd2a2c8e9420532c171056ddbc6db7cfb0a4c Mon Sep 17 00:00:00 2001 From: Glenn Ruehle Date: Fri, 8 Feb 2013 12:39:43 -0800 Subject: [PATCH 0188/5273] Repair context menu. --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index d31422324b..acabd861dc 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1389,7 +1389,7 @@ window.CodeMirror = (function() { // Gecko browsers fire contextmenu *after* opening the menu, at // which point we can't mess with it anymore. Context menu is // handled in onMouseDown for Gecko. - if (captureMiddleClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); + if (!captureMiddleClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); on(d.scroller, "scroll", function() { setScrollTop(cm, d.scroller.scrollTop); From d7bdb71478b8ae7f9ac838d3828a127b538f0cfe Mon Sep 17 00:00:00 2001 From: Brian Sletten Date: Sun, 10 Feb 2013 19:54:18 -0800 Subject: [PATCH 0189/5273] Added support for Turtle RDF serialization --- index.html | 1 + mode/turtle/index.html | 39 +++++++++++ mode/turtle/turtle.js | 145 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 mode/turtle/index.html create mode 100644 mode/turtle/turtle.js diff --git a/index.html b/index.html index 477cec3d64..91e25c8fe1 100644 --- a/index.html +++ b/index.html @@ -74,6 +74,7 @@

    Supported modes:

  • Smarty
  • SQL (several dialects)
  • SPARQL
  • +
  • Turtle
  • sTeX, LaTeX
  • VB.NET
  • VBScript
  • diff --git a/mode/turtle/index.html b/mode/turtle/index.html new file mode 100644 index 0000000000..8e2264e49d --- /dev/null +++ b/mode/turtle/index.html @@ -0,0 +1,39 @@ + + + + CodeMirror: Turtle mode + + + + + + + + +

    CodeMirror: Turtle mode

    +
    + + +

    MIME types defined: text/turtle.

    + + + diff --git a/mode/turtle/turtle.js b/mode/turtle/turtle.js new file mode 100644 index 0000000000..2f1d70cd9a --- /dev/null +++ b/mode/turtle/turtle.js @@ -0,0 +1,145 @@ +CodeMirror.defineMode("turtle", function(config) { + var indentUnit = config.indentUnit; + var curPunc; + + function wordRegexp(words) { + return new RegExp("^(?:" + words.join("|") + ")$", "i"); + } + var ops = wordRegexp([]); + var keywords = wordRegexp(["@prefix", "@base", "a"]); + var operatorChars = /[*+\-<>=&|]/; + + function tokenBase(stream, state) { + var ch = stream.next(); + curPunc = null; + if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) { + stream.match(/^[^\s\u00a0>]*>?/); + return "atom"; + } + else if (ch == "\"" || ch == "'") { + state.tokenize = tokenLiteral(ch); + return state.tokenize(stream, state); + } + else if (/[{}\(\),\.;\[\]]/.test(ch)) { + curPunc = ch; + return null; + } + else if (ch == "#") { + stream.skipToEnd(); + return "comment"; + } + else if (operatorChars.test(ch)) { + stream.eatWhile(operatorChars); + return null; + } + else if (ch == ":") { + return "operator"; + } else { + stream.eatWhile(/[_\w\d]/); + if(stream.peek() == ":") { + return "variable-3"; + } else { + var word = stream.current(); + + if(keywords.test(word)) { + return "meta"; + } + + if(ch >= "A" && ch <= "Z") { + return "comment"; + } else { + return "keyword"; + } + } + var word = stream.current(); + if (ops.test(word)) + return null; + else if (keywords.test(word)) + return "meta"; + else + return "variable"; + } + } + + function tokenLiteral(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return "string"; + }; + } + + function pushContext(state, type, col) { + state.context = {prev: state.context, indent: state.indent, col: col, type: type}; + } + function popContext(state) { + state.indent = state.context.indent; + state.context = state.context.prev; + } + + return { + startState: function(base) { + return {tokenize: tokenBase, + context: null, + indent: 0, + col: 0}; + }, + + token: function(stream, state) { + if (stream.sol()) { + if (state.context && state.context.align == null) state.context.align = false; + state.indent = stream.indentation(); + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + + if (style != "comment" && state.context && state.context.align == null && state.context.type != "pattern") { + state.context.align = true; + } + + if (curPunc == "(") pushContext(state, ")", stream.column()); + else if (curPunc == "[") pushContext(state, "]", stream.column()); + else if (curPunc == "{") pushContext(state, "}", stream.column()); + else if (/[\]\}\)]/.test(curPunc)) { + while (state.context && state.context.type == "pattern") popContext(state); + if (state.context && curPunc == state.context.type) popContext(state); + } + else if (curPunc == "." && state.context && state.context.type == "pattern") popContext(state); + else if (/atom|string|variable/.test(style) && state.context) { + if (/[\}\]]/.test(state.context.type)) + pushContext(state, "pattern", stream.column()); + else if (state.context.type == "pattern" && !state.context.align) { + state.context.align = true; + state.context.col = stream.column(); + } + } + + return style; + }, + + indent: function(state, textAfter) { + var firstChar = textAfter && textAfter.charAt(0); + var context = state.context; + if (/[\]\}]/.test(firstChar)) + while (context && context.type == "pattern") context = context.prev; + + var closing = context && firstChar == context.type; + if (!context) + return 0; + else if (context.type == "pattern") + return context.col; + else if (context.align) + return context.col + (closing ? 0 : 1); + else + return context.indent + (closing ? 0 : indentUnit); + } + }; +}); + +CodeMirror.defineMIME("text/turtle", "turtle"); From 4ccc65e116fed1c97b12073e6fce9654541d2216 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Feb 2013 10:09:48 +0100 Subject: [PATCH 0190/5273] Integrate Turtle mode --- doc/compress.html | 1 + doc/modes.html | 1 + index.html | 1 - mode/turtle/index.html | 4 ++-- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index aa94d70dd6..f2e7634c9f 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -118,6 +118,7 @@

    { } CodeMi + diff --git a/doc/modes.html b/doc/modes.html index 877227492f..8132770cfa 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -72,6 +72,7 @@

    { } CodeMi
  • sTeX, LaTeX
  • Tiddlywiki
  • Tiki wiki
  • +
  • Turtle
  • VB.NET
  • VBScript
  • Velocity
  • diff --git a/index.html b/index.html index 91e25c8fe1..477cec3d64 100644 --- a/index.html +++ b/index.html @@ -74,7 +74,6 @@

    Supported modes:

  • Smarty
  • SQL (several dialects)
  • SPARQL
  • -
  • Turtle
  • sTeX, LaTeX
  • VB.NET
  • VBScript
  • diff --git a/mode/turtle/index.html b/mode/turtle/index.html index 8e2264e49d..5e56e5755c 100644 --- a/mode/turtle/index.html +++ b/mode/turtle/index.html @@ -1,13 +1,13 @@ + CodeMirror: Turtle mode - - +

    CodeMirror: Turtle mode

    From 0cddeeda43c578f3d4623b98c7abfabf350be7e0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Feb 2013 10:25:03 +0100 Subject: [PATCH 0191/5273] Fix bug in measuring surrogate pair characters Splitting them into two spans apparently prevents them from rendering at all (not unexpectedly). --- lib/codemirror.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index acabd861dc..b8e48f5117 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3900,13 +3900,19 @@ window.CodeMirror = (function() { function buildTokenMeasure(builder, text, style, startStyle, endStyle) { for (var i = 0; i < text.length; ++i) { - if (i && i < text.length && - builder.cm.options.lineWrapping && - spanAffectsWrapping.test(text.slice(i - 1, i + 1))) + var ch = text.charAt(i), start = i == 0; + if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) { + ch = text.slice(i, i + 2); + ++i; + } else if (i && i < text.length && + builder.cm.options.lineWrapping && + spanAffectsWrapping.test(text.slice(i - 1, i + 1))) { builder.pre.appendChild(elt("wbr")); - builder.measure[builder.pos++] = - buildToken(builder, text.charAt(i), style, - i == 0 && startStyle, i == text.length - 1 && endStyle); + } + builder.measure[builder.pos] = + buildToken(builder, ch, style, + start && startStyle, i == text.length - 1 && endStyle); + builder.pos += ch.length; } if (text.length) builder.addedOne = true; } @@ -4842,7 +4848,7 @@ window.CodeMirror = (function() { return true; } - var isExtendingChar = /[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\uA670-\uA672\uA674-\uA67D\uA69F]/; + var isExtendingChar = /[\u0300-\u036F\u0483-\u0487\u0488-\u0489\u0591-\u05BD\u05BF\u05C1-\u05C2\u05C4-\u05C5\u05C7\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7-\u06E8\u06EA-\u06ED\uA66F\uA670-\uA672\uA674-\uA67D\uA69F\udc00-\udfff]/; // DOM UTILITIES From 5d529152486169222cfd1d891648d9470f4d45c1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Feb 2013 10:26:11 +0100 Subject: [PATCH 0192/5273] Remove useless (always true) test --- lib/codemirror.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index b8e48f5117..2bdb654149 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3904,8 +3904,7 @@ window.CodeMirror = (function() { if (ch >= "\ud800" && ch < "\udbff" && i < text.length - 1) { ch = text.slice(i, i + 2); ++i; - } else if (i && i < text.length && - builder.cm.options.lineWrapping && + } else if (i && builder.cm.options.lineWrapping && spanAffectsWrapping.test(text.slice(i - 1, i + 1))) { builder.pre.appendChild(elt("wbr")); } From efc041477e83263ebba18760aebd2a2aebca80c6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Feb 2013 10:26:39 +0100 Subject: [PATCH 0193/5273] [turtle mode] Remove unused argument --- mode/turtle/turtle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/turtle/turtle.js b/mode/turtle/turtle.js index 2f1d70cd9a..5c7c28eb02 100644 --- a/mode/turtle/turtle.js +++ b/mode/turtle/turtle.js @@ -84,7 +84,7 @@ CodeMirror.defineMode("turtle", function(config) { } return { - startState: function(base) { + startState: function() { return {tokenize: tokenBase, context: null, indent: 0, From 8d1668b5f03a04c93e1aaaa7dbffdeea0c4b7cf2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Feb 2013 10:52:02 +0100 Subject: [PATCH 0194/5273] [matchhighlighter demo] Use a pseudo-underline background instead of a color Closes #1232 --- demo/matchhighlighter.html | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/demo/matchhighlighter.html b/demo/matchhighlighter.html index 7fd1b2b792..c574fbae81 100644 --- a/demo/matchhighlighter.html +++ b/demo/matchhighlighter.html @@ -11,9 +11,11 @@ From d6a0c0daf00e7d1a920cb766dd359f1739c7d08c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Feb 2013 11:00:44 +0100 Subject: [PATCH 0195/5273] Use a helper for getBoundingClientRect, allow this helper to be overwritten --- lib/codemirror.js | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 2bdb654149..96b71fc0e4 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -387,7 +387,7 @@ window.CodeMirror = (function() { return String(options.lineNumberFormatter(i + options.firstLineNumber)); } function compensateForHScroll(display) { - return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left; + return getRect(display.scroller).left - getRect(display.sizer).left; } // DISPLAY DRAWING @@ -499,7 +499,7 @@ window.CodeMirror = (function() { height = bot - prevBottom; prevBottom = bot; } else { - var box = node.getBoundingClientRect(); + var box = getRect(node); height = box.bottom - box.top; } var diff = node.lineObj.height - height; @@ -732,7 +732,7 @@ window.CodeMirror = (function() { // Move the hidden textarea near the cursor to prevent scrolling artifacts var headPos = cursorCoords(cm, cm.doc.sel.head, "div"); - var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); + var wrapOff = getRect(display.wrapper), lineOff = getRect(display.lineDiv); display.inputDiv.style.top = Math.max(0, Math.min(display.wrapper.clientHeight - 10, headPos.top + lineOff.top - wrapOff.top)) + "px"; display.inputDiv.style.left = Math.max(0, Math.min(display.wrapper.clientWidth - 10, @@ -998,7 +998,7 @@ window.CodeMirror = (function() { removeChildrenAndAdd(display.measure, pre); - var outer = display.lineDiv.getBoundingClientRect(); + var outer = getRect(display.lineDiv); var vranges = [], data = emptyArray(line.text.length), maxBot = pre.offsetHeight; // Work around an IE7/8 bug where it will sometimes have randomly // replaced our pre with a clone at this point. @@ -1006,7 +1006,7 @@ window.CodeMirror = (function() { removeChildrenAndAdd(display.measure, pre); for (var i = 0, cur; i < measure.length; ++i) if (cur = measure[i]) { - var size = cur.getBoundingClientRect(); + var size = getRect(cur); var top = Math.max(0, size.top - outer.top), bot = Math.min(size.bottom - outer.top, maxBot); for (var j = 0; j < vranges.length; j += 2) { var rtop = vranges[j], rbot = vranges[j+1]; @@ -1029,7 +1029,7 @@ window.CodeMirror = (function() { if (!cm.options.lineWrapping) { var last = pre.lastChild; if (last.nodeType == 3) last = pre.appendChild(elt("span", "\u200b")); - data.width = last.getBoundingClientRect().right - outer.left; + data.width = getRect(last).right - outer.left; } return data; @@ -1053,7 +1053,7 @@ window.CodeMirror = (function() { var yOff = heightAtLine(cm, lineObj); if (context != "local") yOff -= cm.display.viewOffset; if (context == "page") { - var lOff = cm.display.lineSpace.getBoundingClientRect(); + var lOff = getRect(cm.display.lineSpace); yOff += lOff.top + (window.pageYOffset || (document.documentElement || document.body).scrollTop); var xOff = lOff.left + (window.pageXOffset || (document.documentElement || document.body).scrollLeft); rect.left += xOff; rect.right += xOff; @@ -1493,7 +1493,7 @@ window.CodeMirror = (function() { target == display.scrollbarV || target == display.scrollbarV.firstChild || target == display.scrollbarFiller) return null; } - var x, y, space = display.lineSpace.getBoundingClientRect(); + var x, y, space = getRect(display.lineSpace); // Fails unpredictably on IE[67] when mouse is dragged around quickly. try { x = e.clientX; y = e.clientY; } catch (e) { return null; } return coordsChar(cm, x - space.left, y - space.top); @@ -1591,7 +1591,7 @@ window.CodeMirror = (function() { } } - var editorSize = display.wrapper.getBoundingClientRect(); + var editorSize = getRect(display.wrapper); // 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, @@ -1687,17 +1687,17 @@ window.CodeMirror = (function() { try { var mX = e.clientX, mY = e.clientY; } catch(e) { return false; } - if (mX >= Math.floor(display.gutters.getBoundingClientRect().right)) return false; + if (mX >= Math.floor(getRect(display.gutters).right)) return false; e_preventDefault(e); if (!hasHandler(cm, "gutterClick")) return true; - var lineBox = display.lineDiv.getBoundingClientRect(); + var lineBox = getRect(display.lineDiv); if (mY > lineBox.bottom) return true; mY -= lineBox.top - display.viewOffset; for (var i = 0; i < cm.options.gutters.length; ++i) { var g = display.gutters.childNodes[i]; - if (g && g.getBoundingClientRect().right >= mX) { + if (g && getRect(g).right >= mX) { var line = lineAtHeight(cm.doc, mY); var gutter = cm.options.gutters[i]; signalLater(cm, "gutterClick", cm, line, gutter, e); @@ -2321,7 +2321,7 @@ window.CodeMirror = (function() { function scrollCursorIntoView(cm) { var coords = scrollPosIntoView(cm, cm.doc.sel.head); if (!cm.state.focused) return; - var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; + var display = cm.display, box = getRect(display.sizer), 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) { @@ -2585,7 +2585,7 @@ window.CodeMirror = (function() { }, coordsChar: function(coords) { - var off = this.display.lineSpace.getBoundingClientRect(); + var off = getRect(this.display.lineSpace); var scrollY = window.pageYOffset || (document.documentElement || document.body).scrollTop; var scrollX = window.pageXOffset || (document.documentElement || document.body).scrollLeft; return coordsChar(this, coords.left - off.left - scrollX, coords.top - off.top - scrollY); @@ -4878,6 +4878,11 @@ window.CodeMirror = (function() { } else e.textContent = str; } + function getRect(node) { + return node.getBoundingClientRect(); + } + CodeMirror.replaceGetRect = function(f) { getRect = f; }; + // FEATURE DETECTION // Detect drag-and-drop From e0186cdf976015469a596b4f0ee7938e9bc5d567 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Feb 2013 11:04:57 +0100 Subject: [PATCH 0196/5273] Add two missing addons to compression helper --- doc/compress.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/compress.html b/doc/compress.html index f2e7634c9f..1bec338058 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -152,6 +152,8 @@

    { } CodeMi + + From 3ae0106197c6866a822e818e841b650164cff33f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Feb 2013 14:01:08 +0100 Subject: [PATCH 0197/5273] Fix problem where the gutter won't span to bottom of horizontally scrollable document --- lib/codemirror.css | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codemirror.css b/lib/codemirror.css index 1ceb0800dc..6e34d15578 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -148,6 +148,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} .CodeMirror-gutters { position: absolute; left: 0; top: 0; height: 100%; + padding-bottom: 30px; z-index: 3; } .CodeMirror-gutter { From 77fbf4abec6b9e568393a70726a9a637064545ca Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Feb 2013 14:01:55 +0100 Subject: [PATCH 0198/5273] Use a less weird construct in createObj helper --- lib/codemirror.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 96b71fc0e4..c0e19c1b4f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4813,9 +4813,9 @@ window.CodeMirror = (function() { } function createObj(base, props) { - if (!base) return; - createObj.prototype = base; - var inst = new createObj(); + function Obj() {} + Obj.prototype = base; + var inst = new Obj(); if (props) copyObj(props, inst); return inst; } From 7b16cbcd8ba4ed5dbefe7d987b1114f278b6784e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Feb 2013 14:10:35 +0100 Subject: [PATCH 0199/5273] Change key handling prototol to allow returning Pass, rather than throwing it This to make dev tools show useful backtraces when an error is raised inside a key handler. Once we've caught it, the backtrace is truncated. --- addon/edit/closetag.js | 10 +++++----- demo/xmlcomplete.html | 2 +- doc/manual.html | 10 ++++++---- lib/codemirror.js | 12 ++++-------- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index 44bbca7c6f..46a5f4c76c 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -27,9 +27,9 @@ if (val && (old == CodeMirror.Init || !old)) { var map = {name: "autoCloseTags"}; if (typeof val != "object" || val.whenClosing) - map["'/'"] = function(cm) { autoCloseTag(cm, '/'); }; + map["'/'"] = function(cm) { return autoCloseTag(cm, '/'); }; if (typeof val != "object" || val.whenOpening) - map["'>'"] = function(cm) { autoCloseTag(cm, '>'); }; + map["'>'"] = function(cm) { return autoCloseTag(cm, '>'); }; cm.addKeyMap(map); } else if (!val && (old != CodeMirror.Init && old)) { cm.removeKeyMap("autoCloseTags"); @@ -44,7 +44,7 @@ function autoCloseTag(cm, ch) { var pos = cm.getCursor(), tok = cm.getTokenAt(pos); var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; - if (inner.mode.name != "xml") throw CodeMirror.Pass; + if (inner.mode.name != "xml") return CodeMirror.Pass; var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html"; var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); @@ -58,7 +58,7 @@ if (tok.type == "tag" && state.type == "closeTag" || /\/\s*$/.test(tok.string) || dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1) - throw CodeMirror.Pass; + return CodeMirror.Pass; var doIndent = indentTags && indexOf(indentTags, lowerTagName) > -1; var curPos = doIndent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1); @@ -74,7 +74,7 @@ if (tagName) cm.replaceSelection("/" + tagName + ">", "end"); return; } - throw CodeMirror.Pass; + return CodeMirror.Pass; } function indexOf(collection, elt) { diff --git a/demo/xmlcomplete.html b/demo/xmlcomplete.html index 34a1b0152f..28a50638f7 100644 --- a/demo/xmlcomplete.html +++ b/demo/xmlcomplete.html @@ -62,7 +62,7 @@

    CodeMirror: XML Autocomplete demo

    } function passAndHint(cm) { setTimeout(function() {cm.execCommand("autocomplete");}, 100); - throw CodeMirror.Pass; + return CodeMirror.Pass; } var editor = CodeMirror.fromTextArea(document.getElementById("code"), { diff --git a/doc/manual.html b/doc/manual.html index c3e4181df9..a7039d3b98 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -481,7 +481,7 @@

    Keymaps

    common commands that are used by the default keybindings, and maps them to functions. If the property is set to false, CodeMirror leaves handling of the key up to the browser. A key - handler function may throw CodeMirror.Pass to indicate + handler function may return CodeMirror.Pass to indicate that it has decided not to handle the key, and other handlers (or the default behavior) should be given a turn.

    @@ -1595,8 +1595,8 @@

    Writing CodeMirror Modes

    If you want your mode to provide smart indentation (through the indentLine method and the indentAuto - and newlineAndIndent commands, which keys can be - bound to), you must define + and newlineAndIndent commands, to which keys can be + bound), you must define an indent(state, textAfter) method on your mode object.

    @@ -1605,7 +1605,9 @@

    Writing CodeMirror Modes

    the text on the line that is being indented, and return an integer, the amount of spaces to indent. It should usually take the indentUnit - option into account.

    + option into account. An indentation method may + return CodeMirror.Pass to indicate that it + could not come up with a precise indentation.

    Finally, a mode may define an electricChars property, which should hold a string diff --git a/lib/codemirror.js b/lib/codemirror.js index c0e19c1b4f..beb1d99832 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1838,16 +1838,16 @@ window.CodeMirror = (function() { // Ensure previous input has been read, so that the handler sees a // consistent view of the document if (cm.display.pollingFast && readInput(cm)) cm.display.pollingFast = false; - var doc = cm.doc, prevShift = doc.sel.shift; + var doc = cm.doc, prevShift = doc.sel.shift, done = false; try { if (isReadOnly(cm)) cm.state.suppressEdits = true; if (dropShift) doc.sel.shift = false; - bound(cm); + done = bound(cm) != Pass; } finally { doc.sel.shift = prevShift; cm.state.suppressEdits = false; } - return true; + return done; } function allKeyMaps(cm) { @@ -3097,11 +3097,7 @@ window.CodeMirror = (function() { map = getKeyMap(map); var found = map[name]; if (found === false) return "stop"; - if (found != null) { - try { var done = handle(found); } - catch (e) { if (e != Pass) throw e; } - if (done) return true; - } + if (found != null && handle(found)) return true; if (map.nofallthrough) return "stop"; var fallthrough = map.fallthrough; From 72ca55233967e1d92ee54fb792d548b651be54a6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Feb 2013 15:47:21 +0100 Subject: [PATCH 0200/5273] [variableheight demo] Fix inconsistent text/markup --- demo/variableheight.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/variableheight.html b/demo/variableheight.html index 8523027368..b00f7e4542 100644 --- a/demo/variableheight.html +++ b/demo/variableheight.html @@ -18,7 +18,7 @@

    CodeMirror: Variable Height Demo

    -

    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.

    +

    MIME types defined: text/html (redefined, only takes effect if you load this parser after the XML parser).

    From 5f528b5928286a95d5e60d498ecd4f75ff85075e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 10:30:26 +0100 Subject: [PATCH 0211/5273] Add Mongo MapReduce WebBrowser to real-world uses --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 60db83ac74..118ce10b6a 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -62,6 +62,7 @@

    { } CodeMi
  • Light Table (experimental IDE)
  • Mergely (interactive diffing)
  • MIHTool (iOS web-app debugging tool)
  • +
  • Mongo MapReduce WebBrowser
  • My2ndGeneration (social coding)
  • NoTex (rST authoring)
  • ORG (z80 assembly IDE)
  • From 1ff3c7ea500bc8b8f9e2f6ed5ae262c484023b11 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 11:11:26 +0100 Subject: [PATCH 0212/5273] Make sure operation ids aren't reused between editors Issue #1249 --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 32f2ac7d08..4d360aca68 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -60,7 +60,6 @@ window.CodeMirror = (function() { draggingText: false, highlight: new Delayed()}; - this.nextOpId = 0; themeChanged(this); if (options.lineWrapping) this.display.wrapper.className += " CodeMirror-wrap"; @@ -1201,6 +1200,7 @@ window.CodeMirror = (function() { // be awkward, slow, and error-prone), but instead updates are // batched and then all combined and executed at once. + var nextOpId = 0; function startOperation(cm) { cm.curOp = { // An array of ranges of lines that have to be updated. See @@ -1212,7 +1212,7 @@ window.CodeMirror = (function() { selectionChanged: false, updateMaxLine: false, updateScrollPos: false, - id: ++cm.nextOpId + id: ++nextOpId }; if (!delayedCallbackDepth++) delayedCallbacks = []; } From 15328c7adb8bebd957b228cf80959fa285e715e6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 11:24:32 +0100 Subject: [PATCH 0213/5273] [htmlmixed mode] Fix bug in matching of script types Closes #1248 --- mode/htmlmixed/htmlmixed.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/htmlmixed/htmlmixed.js b/mode/htmlmixed/htmlmixed.js index 05c2e8ac7e..f8a0d5d18a 100644 --- a/mode/htmlmixed/htmlmixed.js +++ b/mode/htmlmixed/htmlmixed.js @@ -19,6 +19,7 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) { // Script block: mode to change to depends on type attribute var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i); scriptType = scriptType ? scriptType[1] : ""; + if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1); for (var i = 0; i < scriptTypes.length; ++i) { var tp = scriptTypes[i]; if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) { From f7c3944acd608bc2e6a7ffa673d4658dc08119ed Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 12:18:01 +0100 Subject: [PATCH 0214/5273] Factor findPosH into an exported interface. Add tests. --- doc/manual.html | 14 ++++++++++++++ lib/codemirror.js | 33 ++++++++++++++++++++++++--------- test/test.js | 21 +++++++++++++++++++++ 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index c154942014..23ef10abac 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -736,6 +736,20 @@

    Cursor and selection methods

    the shift key, in that it will cause cursor movement and calls to extendSelection to leave the selection anchor in place.

    + +
    cm.findPosH(start, amount, unit, visually) → object
    +
    Used to find the target position for horizontal cursor + motion. start is a {line, ch} + object, amount an integer (may be negative), + and unit one of the + string "char", "column", + or "word". Will return a position that is produced + by moving amount times the distance specified + by unit. When visually is true, motion + in right-to-left text will be visual rather than logical. When + the motion was clipped by hitting the end or start of the + document, the returned value will have a hitSide + property set to true.

    Configuration methods

    diff --git a/lib/codemirror.js b/lib/codemirror.js index 4d360aca68..5030fb70f8 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2440,12 +2440,13 @@ window.CodeMirror = (function() { return line; } - function findPosH(doc, dir, unit, visually) { - var end = doc.sel.head, line = end.line, ch = end.ch; + function findPosH(doc, pos, dir, unit, visually) { + var line = pos.line, ch = pos.ch; var lineObj = getLine(doc, line); + var possible = true; function findNextLine() { var l = line + dir; - if (l < doc.first || l >= doc.first + doc.size) return false; + if (l < doc.first || l >= doc.first + doc.size) return (possible = false); line = l; return lineObj = getLine(doc, l); } @@ -2455,10 +2456,11 @@ window.CodeMirror = (function() { if (!boundToLine && findNextLine()) { if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); else ch = dir < 0 ? lineObj.text.length : 0; - } else return false; + } else return (possible = false); } else ch = next; return true; } + if (unit == "char") moveOnce(); else if (unit == "column") moveOnce(true); else if (unit == "word") { @@ -2470,7 +2472,9 @@ window.CodeMirror = (function() { if (dir > 0) if (!moveOnce()) break; } } - return skipAtomic(doc, Pos(line, ch), dir, true); + var result = skipAtomic(doc, Pos(line, ch), dir, true); + if (!possible) result.hitSide = true; + return result; } function findWordAt(line, pos) { @@ -2708,18 +2712,29 @@ window.CodeMirror = (function() { execCommand: function(cmd) {return commands[cmd](this);}, - // Stuff used by commands, probably not much use to outside code. + findPosH: function(from, amount, unit, visually) { + 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; + } + return cur; + }, + moveH: operation(null, function(dir, unit) { - var sel = this.doc.sel, pos = dir < 0 ? sel.from : sel.to; + var sel = this.doc.sel, pos; if (sel.shift || sel.extend || posEq(sel.from, sel.to)) - pos = findPosH(this.doc, dir, unit, this.options.rtlMoveVisually); + pos = findPosH(this.doc, sel.head, dir, unit, this.options.rtlMoveVisually); + else + pos = dir < 0 ? sel.from : sel.to; extendSelection(this.doc, pos, pos, dir); }), deleteH: operation(null, function(dir, unit) { var sel = this.doc.sel; if (!posEq(sel.from, sel.to)) replaceRange(this.doc, "", sel.from, sel.to, "+delete"); - else replaceRange(this.doc, "", sel.from, findPosH(this.doc, dir, unit, false), "+delete"); + else replaceRange(this.doc, "", sel.from, findPosH(this.doc, sel.head, dir, unit, false), "+delete"); this.curOp.userSelChange = true; }), diff --git a/test/test.js b/test/test.js index 3a3dfac2d7..871c095d7d 100644 --- a/test/test.js +++ b/test/test.js @@ -1273,3 +1273,24 @@ testCM("addKeyMap", function(cm) { sendKey(39); eqPos(cm.getCursor(), Pos(0, 3)); }, {value: "abc"}); + +testCM("findPosH", function(cm) { + forEach([{from: Pos(0, 0), to: Pos(0, 1), by: 1}, + {from: Pos(0, 0), to: Pos(0, 0), by: -1, hitSide: true}, + {from: Pos(0, 0), to: Pos(0, 4), by: 1, unit: "word"}, + {from: Pos(0, 0), to: Pos(0, 8), by: 2, unit: "word"}, + {from: Pos(0, 0), to: Pos(2, 0), by: 20, unit: "word", hitSide: true}, + {from: Pos(0, 7), to: Pos(0, 5), by: -1, unit: "word"}, + {from: Pos(0, 4), to: Pos(0, 8), by: 1, unit: "word"}, + {from: Pos(1, 0), to: Pos(1, 18), by: 3, unit: "word"}, + {from: Pos(1, 22), to: Pos(1, 5), by: -3, unit: "word"}, + {from: Pos(1, 15), to: Pos(1, 10), by: -5}, + {from: Pos(1, 15), to: Pos(1, 10), by: -5, unit: "column"}, + {from: Pos(1, 15), to: Pos(1, 0), by: -50, unit: "column", hitSide: true}, + {from: Pos(1, 15), to: Pos(1, 24), by: 50, unit: "column", hitSide: true}, + {from: Pos(1, 15), to: Pos(2, 0), by: 50, hitSide: true}], function(t) { + var r = cm.findPosH(t.from, t.by, t.unit || "char"); + eqPos(r, t.to); + eq(!!r.hitSide, !!t.hitSide); + }); +}, {value: "line one\nline two.something.other\n"}); From 6638d16c0e44b238df42b780d4f967f4af62afa7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 12:53:46 +0100 Subject: [PATCH 0215/5273] Export and document findPosV Issue #1235 --- doc/manual.html | 6 ++++++ lib/codemirror.js | 53 +++++++++++++++++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 23ef10abac..04cadcb37b 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -750,6 +750,12 @@

    Cursor and selection methods

    the motion was clipped by hitting the end or start of the document, the returned value will have a hitSide property set to true. +
    cm.findPosV(start, amount, unit) → object
    +
    Similar to findPosH, + but used for vertical motion. unit may + be "line" or "page". The other + arguments and the returned value have the same interpretation as + they have in findPosH.

    Configuration methods

    diff --git a/lib/codemirror.js b/lib/codemirror.js index 5030fb70f8..3dfad34da0 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2477,6 +2477,23 @@ window.CodeMirror = (function() { return result; } + function findPosV(cm, pos, dir, unit) { + var doc = cm.doc, possible = true, 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; + } else if (unit == "line") { + 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; + } + return target; + } + function findWordAt(line, pos) { var start = pos.ch, end = pos.ch; if (line) { @@ -2738,25 +2755,29 @@ window.CodeMirror = (function() { this.curOp.userSelChange = true; }), - moveV: operation(null, function(dir, unit) { - var doc = this.doc, display = this.display; - var cur = doc.sel.head, pos = cursorCoords(this, cur, "div"); - var x = pos.left, y; - if (doc.sel.goalColumn != null) x = doc.sel.goalColumn; - if (unit == "page") { - var pageSize = Math.min(display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); - y = pos.top + dir * pageSize; - } else if (unit == "line") { - y = dir > 0 ? pos.bottom + 3 : pos.top - 3; + findPosV: function(from, amount, unit) { + var dir = 1, x = null; + 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; } - do { - var target = coordsChar(this, x, y); - y += dir * 5; - } while (target.outside && (dir < 0 ? y > 0 : y < doc.height)); + return cur; + }, + + moveV: operation(null, function(dir, unit) { + var sel = this.doc.sel; + var pos = cursorCoords(this, sel.head, "div"); + if (sel.goalColumn != null) pos.left = sel.goalColumn; + var target = findPosV(this, pos, dir, unit); - if (unit == "page") display.scrollbarV.scrollTop += charCoords(this, target, "div").top - pos.top; + if (unit == "page") + this.display.scrollbarV.scrollTop += charCoords(this, target, "div").top - pos.top; extendSelection(this.doc, target, target, dir); - doc.sel.goalColumn = x; + sel.goalColumn = pos.left; }), toggleOverwrite: function() { From f3d0bbbeac9d12d876ecace7fa5d2c640e904d54 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 13:00:41 +0100 Subject: [PATCH 0216/5273] Use Pos constructor for all internal positions --- lib/codemirror.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 3dfad34da0..2544846320 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1103,11 +1103,17 @@ window.CodeMirror = (function() { return main; } + function PosMaybeOutside(line, ch, outside) { + var pos = new Pos(line, ch); + if (outside) pos.outside = true; + return pos; + } + // Coords must be lineSpace-local function coordsChar(cm, x, y) { var doc = cm.doc; y += cm.display.viewOffset; - if (y < 0) return {line: doc.first, ch: 0, outside: true}; + if (y < 0) return PosMaybeOutside(doc.first, 0, true); var lineNo = lineAtHeight(doc, y), last = doc.first + doc.size - 1; if (lineNo > last) return Pos(doc.size - 1, getLine(doc, last).text.length); @@ -1144,13 +1150,15 @@ window.CodeMirror = (function() { var from = lineLeft(lineObj), to = lineRight(lineObj); var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; - if (x > toX) return {line: lineNo, ch: to, outside: toOutside}; + if (x > toX) return PosMaybeOutside(lineNo, to, toOutside); // Do a binary search between these bounds. for (;;) { if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { var after = x - fromX < toX - x, ch = after ? from : to; while (isExtendingChar.test(lineObj.text.charAt(ch))) ++ch; - return {line: lineNo, ch: ch, after: after, outside: after ? fromOutside : toOutside}; + var pos = PosMaybeOutside(lineNo, ch, after ? fromOutside : toOutside); + pos.after = after; + return pos; } var step = Math.ceil(dist / 2), middle = from + step; if (bidi) { @@ -2478,7 +2486,7 @@ window.CodeMirror = (function() { } function findPosV(cm, pos, dir, unit) { - var doc = cm.doc, possible = true, 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); y = pos.top + dir * pageSize; From bdb776e154f8a12e22063aab8d8fd15df918d1f1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 13:03:03 +0100 Subject: [PATCH 0217/5273] [manual] Make description of getCursor less confusing --- doc/manual.html | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 04cadcb37b..79ca16f681 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -701,15 +701,14 @@

    Cursor and selection methods

    Replace the selection with the given string.
    doc.getCursor(start) → object
    -
    start is a boolean indicating whether the start - or the end of the selection must be retrieved. If it is not - given, the current cursor pos, i.e. the side of the selection - that would move if you pressed an arrow key, is chosen. - Alternatively, you can pass one of the - strings "start", "end", "head" - (same as not passing anything), or "anchor" (the - opposite). A {line, ch} object will be - returned.
    +
    start is a an optional string indicating which + end of the selection to return. It may + be "start", "end", "head" + (the side of the selection that moves when you press + shift+arrow), or "anchor" (the fixed side of the + selection). Omitting the argument is the same as + passing "head". A {line, ch} object + will be returned.
    doc.somethingSelected() → boolean
    Return true if any text is selected.
    doc.setCursor(pos)
    From 5a26cb068559360082e324cd94af30d6113500bd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 13:35:21 +0100 Subject: [PATCH 0218/5273] Add beforeChange event Issue #1244 --- doc/manual.html | 24 ++++++++++++++++++++++++ lib/codemirror.js | 27 +++++++++++++++++++++++++++ test/test.js | 18 ++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/doc/manual.html b/doc/manual.html index 79ca16f681..a40143e4f6 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -365,6 +365,26 @@

    Events

    a next property pointing to another change object (which may point to another, etc). +
    "beforeChange" (instance, change)
    +
    This event is fired before a change is applied, and its + handler may choose to modify or cancel the change. + The change object + has from, to, and text + properties, as with + the "change" event, but + never a next property, since this is fired for each + individual change, and not batched per operation. It also + has update(from, to, text) + and cancel() methods, which may be used to modify + or cancel the change. All three arguments to update + are optional, and can be left off to leave the existing value + for that field intact. Note: you may not do + anything from a "beforeChange" handler that would + cause changes to the document or its visualization. Doing so + will, since this handler is called directly from the bowels of + the CodeMirror implementation, probably cause the editor to + become corrupted.
    +
    "cursorActivity" (instance)
    Will be fired when the cursor or selection moves, or any change is made to the editor content.
    @@ -410,6 +430,10 @@

    Events

    document change events are not batched (whereas editor change events are). +
    "beforeChange" (doc, change)
    +
    See the description of the + same event on editor instances.
    +
    "cursorActivity" (doc)
    Fired whenever the cursor or selection in this document changes.
    diff --git a/lib/codemirror.js b/lib/codemirror.js index 2544846320..a95d6f4bff 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2055,6 +2055,28 @@ window.CodeMirror = (function() { return {anchor: adjustPos(sel.anchor), head: adjustPos(sel.head)}; } + function filterChange(doc, change) { + var obj = { + canceled: false, + from: change.from, + to: change.to, + text: change.text, + origin: change.origin, + 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; + }, + cancel: function() { this.canceled = true; } + }; + 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}; + } + // Replace the range from from to to by the strings in replacement. // change is a {from, to, text [, origin]} object function makeChange(doc, change, selUpdate, ignoreReadOnly) { @@ -2063,6 +2085,11 @@ window.CodeMirror = (function() { if (doc.cm.state.suppressEdits) return; } + if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { + change = filterChange(doc, change); + 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); diff --git a/test/test.js b/test/test.js index 871c095d7d..79e8a9bca1 100644 --- a/test/test.js +++ b/test/test.js @@ -1294,3 +1294,21 @@ testCM("findPosH", function(cm) { eq(!!r.hitSide, !!t.hitSide); }); }, {value: "line one\nline two.something.other\n"}); + +testCM("beforeChange", function(cm) { + cm.on("beforeChange", function(cm, change) { + var text = []; + for (var i = 0; i < change.text.length; ++i) + text.push(change.text[i].replace(/\s/g, "_")); + change.update(null, null, text); + }); + cm.setValue("hello, i am a\nnew document\n"); + eq(cm.getValue(), "hello,_i_am_a\nnew_document\n"); + CodeMirror.on(cm.getDoc(), "beforeChange", function(doc, change) { + if (change.from.line == 0) change.cancel(); + }); + cm.setValue("oops"); // Canceled + eq(cm.getValue(), "hello,_i_am_a\nnew_document\n"); + cm.replaceRange("hey hey hey", Pos(1, 0), Pos(2, 0)); + eq(cm.getValue(), "hello,_i_am_a\nhey_hey_hey"); +}, {value: "abcdefghijk"}); From b1df9d5efaa9aab345df1d0e5a4ccefba32a1954 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 13:55:07 +0100 Subject: [PATCH 0219/5273] Properly set 'outside' property when fetching a position below the document --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index a95d6f4bff..d480f40168 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1116,7 +1116,7 @@ window.CodeMirror = (function() { if (y < 0) return PosMaybeOutside(doc.first, 0, true); var lineNo = lineAtHeight(doc, y), last = doc.first + doc.size - 1; if (lineNo > last) - return Pos(doc.size - 1, getLine(doc, last).text.length); + return PosMaybeOutside(doc.size - 1, getLine(doc, last).text.length, true); if (x < 0) x = 0; for (;;) { From c430dec1f0ddbda6d9344d06dbaf52389968cec2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 13:56:54 +0100 Subject: [PATCH 0220/5273] Allow passing in a goalColumn to findPosV --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index d480f40168..c42b2c2983 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2790,8 +2790,8 @@ window.CodeMirror = (function() { this.curOp.userSelChange = true; }), - findPosV: function(from, amount, unit) { - var dir = 1, x = null; + findPosV: function(from, amount, unit, goalColumn) { + 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"); From 1ccc8a088fd640dc277f48b6f076eef77361e69c Mon Sep 17 00:00:00 2001 From: "angelo.zerr@gmail.com" Date: Fri, 15 Feb 2013 14:33:35 +0100 Subject: [PATCH 0221/5273] Close Bracket Feature. --- addon/edit/closebracket.js | 39 ++++++++++++++++++++++++++++++++++++++ demo/closebracket.html | 31 ++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 addon/edit/closebracket.js create mode 100644 demo/closebracket.html diff --git a/addon/edit/closebracket.js b/addon/edit/closebracket.js new file mode 100644 index 0000000000..bd29f12792 --- /dev/null +++ b/addon/edit/closebracket.js @@ -0,0 +1,39 @@ +(function() { + var DEFAULT_BRACKETS = [ "()", "[]", "{}", "''", "\"\"" ]; + CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { + if (val && (old == CodeMirror.Init || !old)) { + var map = { + name : "autoCloseBrackets" + }; + var brackets = val.brackets || val.brackets || DEFAULT_BRACKETS; + for ( var i = 0; i < brackets.length; i++) { + var bracket = brackets[i]; + var startBracket = bracket.charAt(0); + var endBracket = bracket.substring(1, bracket.length); + attachAutoCloseBracket(startBracket, endBracket, map) + } + cm.addKeyMap(map); + } else if (!val && (old != CodeMirror.Init && old)) { + cm.removeKeyMap("autoCloseBrackets"); + } + }); + + function attachAutoCloseBracket(startBracket, endBracket, map) { + map["'" + startBracket + "'"] = function(cm) { + autoCloseBracket(cm, startBracket, endBracket); + }; + }; + + function autoCloseBracket(cm, startBracket, endBracket) { + +// if (cm.somethingSelected()) { +// alert('e'); +// //cm.replaceSelection("[#{cm.getSelection()}]") +// //CodeMirror.commands["goCharRight"](cm) +// } else { + cm.replaceRange(endBracket, cm.getCursor(false)) + CodeMirror.commands["goCharLeft"](cm) + //} + throw CodeMirror.Pass; + } +})(); diff --git a/demo/closebracket.html b/demo/closebracket.html new file mode 100644 index 0000000000..59b9144593 --- /dev/null +++ b/demo/closebracket.html @@ -0,0 +1,31 @@ + + + + + CodeMirror: Close-Tag Demo + + + + + + + + + +

    Close-Bracket Demo

    +
      +
    • Type a bracket like '[', '(', '{', '"', or ''' and it will close the bracket and set the cursor on the middle.
    • +
    + +
    + + + + From 085ab5180bdbcb154f903928996e04283aecc338 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 16:21:55 +0100 Subject: [PATCH 0222/5273] [closebrackets addon] Clean up and integrate --- addon/edit/closebracket.js | 39 ------------------------ addon/edit/closebrackets.js | 29 ++++++++++++++++++ demo/closebracket.html | 31 ------------------- demo/closebrackets.html | 59 +++++++++++++++++++++++++++++++++++++ doc/compress.html | 1 + doc/manual.html | 7 +++++ 6 files changed, 96 insertions(+), 70 deletions(-) delete mode 100644 addon/edit/closebracket.js create mode 100644 addon/edit/closebrackets.js delete mode 100644 demo/closebracket.html create mode 100644 demo/closebrackets.html diff --git a/addon/edit/closebracket.js b/addon/edit/closebracket.js deleted file mode 100644 index bd29f12792..0000000000 --- a/addon/edit/closebracket.js +++ /dev/null @@ -1,39 +0,0 @@ -(function() { - var DEFAULT_BRACKETS = [ "()", "[]", "{}", "''", "\"\"" ]; - CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { - if (val && (old == CodeMirror.Init || !old)) { - var map = { - name : "autoCloseBrackets" - }; - var brackets = val.brackets || val.brackets || DEFAULT_BRACKETS; - for ( var i = 0; i < brackets.length; i++) { - var bracket = brackets[i]; - var startBracket = bracket.charAt(0); - var endBracket = bracket.substring(1, bracket.length); - attachAutoCloseBracket(startBracket, endBracket, map) - } - cm.addKeyMap(map); - } else if (!val && (old != CodeMirror.Init && old)) { - cm.removeKeyMap("autoCloseBrackets"); - } - }); - - function attachAutoCloseBracket(startBracket, endBracket, map) { - map["'" + startBracket + "'"] = function(cm) { - autoCloseBracket(cm, startBracket, endBracket); - }; - }; - - function autoCloseBracket(cm, startBracket, endBracket) { - -// if (cm.somethingSelected()) { -// alert('e'); -// //cm.replaceSelection("[#{cm.getSelection()}]") -// //CodeMirror.commands["goCharRight"](cm) -// } else { - cm.replaceRange(endBracket, cm.getCursor(false)) - CodeMirror.commands["goCharLeft"](cm) - //} - throw CodeMirror.Pass; - } -})(); diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js new file mode 100644 index 0000000000..09dc7de3aa --- /dev/null +++ b/addon/edit/closebrackets.js @@ -0,0 +1,29 @@ +(function() { + var DEFAULT_BRACKETS = "()[]{}''\"\""; + + CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { + var wasOn = old && old != CodeMirror.Init; + if (val && !wasOn) + cm.addKeyMap(buildKeymap(typeof val == "string" ? val : DEFAULT_BRACKETS)); + else if (!val && wasOn) + cm.removeKeyMap("autoCloseBrackets"); + }); + + function buildKeymap(pairs) { + var map = {name : "autoCloseBrackets"}; + for (var i = 0; i < pairs.length; i += 2) (function(left, right) { + function maybeOverwrite(cm) { + var cur = cm.getCursor(), ahead = cm.getRange(cur, CodeMirror.Pos(cur.line, cur.ch + 1)); + if (ahead != right) return CodeMirror.Pass; + else cm.execCommand("goCharRight"); + } + map["'" + left + "'"] = function(cm) { + if (left == right && maybeOverwrite(cm) != CodeMirror.Pass) return; + var cur = cm.getCursor(), ahead = CodeMirror.Pos(cur.line, cur.ch + 1); + cm.replaceSelection(left + right, {head: ahead, anchor: ahead}); + }; + if (left != right) map["'" + right + "'"] = maybeOverwrite; + })(pairs.charAt(i), pairs.charAt(i + 1)); + return map; + } +})(); diff --git a/demo/closebracket.html b/demo/closebracket.html deleted file mode 100644 index 59b9144593..0000000000 --- a/demo/closebracket.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - CodeMirror: Close-Tag Demo - - - - - - - - - -

    Close-Bracket Demo

    -
      -
    • Type a bracket like '[', '(', '{', '"', or ''' and it will close the bracket and set the cursor on the middle.
    • -
    - -
    - - - - diff --git a/demo/closebrackets.html b/demo/closebrackets.html new file mode 100644 index 0000000000..58ba0330a1 --- /dev/null +++ b/demo/closebrackets.html @@ -0,0 +1,59 @@ + + + + + CodeMirror: Closebrackets Demo + + + + + + + + + +

    CodeMirror: Closebrackets Demo

    + +

    Type a bracket like '[', '(', '{', '"', or ''' + and the addon + will auto-close it. Type the closing variant when directly in + front of a matching character and it will overwrite it.

    + +
    + + + + diff --git a/doc/compress.html b/doc/compress.html index 1bec338058..b06062abf0 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -134,6 +134,7 @@

    { } CodeMi + diff --git a/doc/manual.html b/doc/manual.html index a40143e4f6..d7a3e87d05 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1389,6 +1389,13 @@

    Add-ons

    once, and a method findMatchingBracket that can be used to run the bracket-finding algorithm that this uses internally. +
    closebrackets.js
    +
    Defines an option autoCloseBrackets that will + auto-close brackets and quotes when typed. By default, it'll + auto-close ()[]{}''"", but you can pass it a + string similar to that (containing pairs of matching characters) + to customize it. Demo + here.
    foldcode.js
    Helps with code folding. See the demo for an example. From 3eae20a249335fd13c7db7feacf7140893c01dd8 Mon Sep 17 00:00:00 2001 From: Metatheos Date: Mon, 11 Feb 2013 16:56:06 +0100 Subject: [PATCH 0223/5273] [vim mode] Added gj/gk, :noh, defineEx(). Better :{num}, <{Key}> handling - gj/gk for moveByDisplayLines motion, allows vertical movement within wrapped lines - :noh[lsearch] is now an ex-command - new ex-commands can be defined through api, using CodeMirror.Vim.defineEx() - :{number} should now move to line with {number} on the gutter - parseKeyString now also accepts keys like (in addition to ) --- keymap/vim.js | 127 +++++++++++++++++++++++++++++++---------------- test/vim_test.js | 59 ++++++++++++++++++++-- 2 files changed, 139 insertions(+), 47 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index f8fe5ab4bf..e0e18cc5b4 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -3,6 +3,7 @@ * * Motion: * h, j, k, l + * gj, gk * e, E, w, W, b, B, ge, gE * f, F, t, T * $, ^, 0 @@ -90,6 +91,12 @@ { keys: ['k'], type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, linewise: true }}, + { keys: ['g','j'], type: 'motion', + motion: 'moveByDisplayLines', + motionArgs: { forward: true, linewise: true }}, + { keys: ['g','k'], type: 'motion', + motion: 'moveByDisplayLines', + motionArgs: { forward: false, linewise: true }}, { keys: ['w'], type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false }}, @@ -212,7 +219,6 @@ { keys: ['Ctrl-r'], type: 'action', action: 'redo' }, { keys: ['m', 'character'], type: 'action', action: 'setMark' }, { keys: ['\"', 'character'], type: 'action', action: 'setRegister' }, - { keys: [',', '/'], type: 'action', action: 'clearSearchHighlight' }, { keys: ['z', 'z'], type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }}, { keys: ['z', '.'], type: 'action', action: 'scrollToCursor', @@ -275,7 +281,7 @@ return alphabetRegex.test(k); } function isLine(cm, line) { - return line >= 0 && line < cm.lineCount(); + return line >= cm.firstLine() && line <= cm.lastLine(); } function isLowerCase(k) { return (/^[a-z]$/).test(k); @@ -335,6 +341,8 @@ // cursor should go back to its horizontal position on the longer // line if it can. This is to keep track of the horizontal position. lastHPos: -1, + // Doing the same with screen-position for gj/gk + lastHSPos: -1, // The last motion command run. Cleared if a non-motion command gets // executed in between. lastMotion: null, @@ -364,6 +372,12 @@ // Add user defined key bindings. exCommandDispatcher.map(lhs, rhs); }, + defineEx: function(name, prefix, func){ + if (name.indexOf(prefix) === 0) { + exCommands[name]=func; + exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'}; + }else throw new Error("(Vim.defineEx) \""+prefix+"\" is not a prefix of \""+name+"\", command not registered"); + }, // Initializes vim state variable on the CodeMirror object. Should only be // called lazily by handleKey or for testing. maybeInitState: function(cm) { @@ -916,7 +930,8 @@ return { line: cur.line, ch: ch }; }, moveByLines: function(cm, motionArgs, vim) { - var endCh = cm.getCursor().ch; + var cur = cm.getCursor(); + var endCh = cur.ch; // Depending what our last motion was, we may want to do different // things. If our last motion was moving vertically, we want to // preserve the HPos from our last horizontal move. If our last motion @@ -924,6 +939,7 @@ // the end of the line, etc. switch (vim.lastMotion) { case this.moveByLines: + case this.moveByDisplayLines: case this.moveToColumn: case this.moveToEol: endCh = vim.lastHPos; @@ -931,14 +947,31 @@ default: vim.lastHPos = endCh; } - var cur = cm.getCursor(); var repeat = motionArgs.repeat; var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat; - if (line < 0 || line > cm.lineCount() - 1) { + if (line < cm.firstLine() || line > cm.lastLine() ) { return null; } + vim.lastHSPos = cm.charCoords({line:line, ch:endCh},"div").left; return { line: line, ch: endCh }; }, + moveByDisplayLines: function(cm, motionArgs, vim) { + var cur = cm.getCursor(); + switch (vim.lastMotion) { + case this.moveByDisplayLines: + case this.moveByLines: + case this.moveToColumn: + case this.moveToEol: + break; + default: + vim.lastHSPos = cm.charCoords(cur,"div").left; + } + var repeat = motionArgs.repeat; + var res=cm.findPosV(cur,(motionArgs.forward ? repeat : -repeat),"line",vim.lastHSPos); + if(res.hitSide)return null; + vim.lastHPos = res.ch; + return res; + }, moveByPage: function(cm, motionArgs) { // CodeMirror only exposes functions that move the cursor page down, so // doing this bad hack to move the cursor and move it back. evalInput @@ -955,12 +988,12 @@ var repeat = motionArgs.repeat; var inc = motionArgs.forward ? 1 : -1; for (var i = 0; i < repeat; i++) { - if ((!motionArgs.forward && line === 0) || - (motionArgs.forward && line == cm.lineCount() - 1)) { + if ((!motionArgs.forward && line === cm.firstLine() ) || + (motionArgs.forward && line == cm.lastLine())) { break; } line += inc; - while (line !== 0 && line != cm.lineCount - 1 && cm.getLine(line)) { + while (line !== cm.firstLine() && line != cm.lastLine() && cm.getLine(line)) { line += inc; } } @@ -987,12 +1020,17 @@ var repeat = motionArgs.repeat; // repeat is equivalent to which column we want to move to! vim.lastHPos = repeat - 1; + vim.lastHSPos = cm.charCoords(cm.getCursor(),"div").left; return moveToColumn(cm, repeat); }, moveToEol: function(cm, motionArgs, vim) { var cur = cm.getCursor(); vim.lastHPos = Infinity; - return { line: cur.line + motionArgs.repeat - 1, ch: Infinity }; + var retval={ line: cur.line + motionArgs.repeat - 1, ch: Infinity } + var end=cm.clipPos(retval); + end.ch--; + vim.lastHSPos = cm.charCoords(end,"div").left; + return retval; }, moveToFirstNonWhiteSpaceCharacter: function(cm) { // Go to the start of the line where the text begins, or the end for @@ -1016,9 +1054,9 @@ return { line: cursor.line, ch: 0 }; }, moveToLineOrEdgeOfDocument: function(cm, motionArgs) { - var lineNum = motionArgs.forward ? cm.lineCount() - 1 : 0; + var lineNum = motionArgs.forward ? cm.lastLine() : cm.firstLine(); if (motionArgs.repeatIsExplicit) { - lineNum = motionArgs.repeat - 1; + lineNum = motionArgs.repeat - cm.getOption('firstLineNumber'); } return { line: lineNum, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum)) }; @@ -1117,7 +1155,6 @@ }; var actions = { - clearSearchHighlight: clearSearchHighlight, scrollToCursor: function(cm, actionArgs) { var lineNum = cm.getCursor().line; var heightProp = window.getComputedStyle(cm.getScrollerElement()). @@ -1234,10 +1271,10 @@ }, newLineAndEnterInsertMode: function(cm, actionArgs) { var insertAt = cm.getCursor(); - if (insertAt.line === 0 && !actionArgs.after) { + if (insertAt.line === cm.firstLine() && !actionArgs.after) { // Special case for inserting newline before start of document. - cm.replaceRange('\n', { line: 0, ch: 0 }); - cm.setCursor(0, 0); + cm.replaceRange('\n', { line: cm.firstLine(), ch: 0 }); + cm.setCursor(cm.firstLine(), 0); } else { insertAt.line = (actionArgs.after) ? insertAt.line : insertAt.line - 1; @@ -1357,14 +1394,11 @@ */ /** - * Clips cursor to ensure that: - * 0 <= cur.ch < lineLength - * AND - * 0 <= cur.line < lineCount + * Clips cursor to ensure that line is within the buffer's range * If includeLineBreak is true, then allow cur.ch == lineLength. */ function clipCursorToContent(cm, cur, includeLineBreak) { - var line = Math.min(Math.max(0, cur.line), cm.lineCount() - 1); + var line = Math.min(Math.max(cm.firstLine(), cur.line), cm.lastLine() ); var maxCh = lineLength(cm, line) - 1; maxCh = (includeLineBreak) ? maxCh + 1 : maxCh; var ch = Math.min(Math.max(0, cur.ch), maxCh); @@ -2091,7 +2125,7 @@ // SearchCursor may have returned null because it hit EOF, wrap // around and try again. cursor = cm.getSearchCursor(query, - (prev) ? { line: cm.lineCount() - 1} : {line: 0, ch: 0} ); + (prev) ? { line: cm.lastLine() } : {line: cm.firstLine(), ch: 0} ); if (!cursor.find(prev)) { return; } @@ -2156,7 +2190,8 @@ { name: 'write', shortName: 'w', type: 'builtIn' }, { name: 'undo', shortName: 'u', type: 'builtIn' }, { name: 'redo', shortName: 'red', type: 'builtIn' }, - { name: 'substitute', shortName: 's', type: 'builtIn'} + { name: 'substitute', shortName: 's', type: 'builtIn'}, + { name: 'nohlsearch', shortName: 'noh', type: 'builtIn'} ]; Vim.ExCommandDispatcher = function() { this.buildCommandMap_(); @@ -2206,8 +2241,8 @@ inputStream.eatWhile(':'); // Parse range. if (inputStream.eat('%')) { - result.line = 0; - result.lineEnd = cm.lineCount() - 1; + result.line = cm.firstLine(); + result.lineEnd = cm.lastLine(); } else { result.line = this.parseLineSpec_(cm, inputStream); if (result.line !== undefined && inputStream.eat(',')) { @@ -2234,7 +2269,7 @@ case '.': return cm.getCursor().line; case '$': - return cm.lineCount() - 1; + return cm.lastLine(); case '\'': var mark = getVimState(cm).marks[inputStream.next()]; if (mark && mark.find()) { @@ -2337,25 +2372,28 @@ var vimKeyNotationStart = ++idx; while (str.charAt(idx++) != '>') {} var vimKeyNotation = str.substring(vimKeyNotationStart, idx - 1); + var mod=''; var match = (/^C-(.+)$/).exec(vimKeyNotation); if (match) { - var key; - switch (match[1]) { - case 'BS': - key = 'Backspace'; - break; - case 'CR': - key = 'Enter'; - break; - case 'Del': - key = 'Delete'; - break; - default: - key = match[1]; - break; - } - keys.push('Ctrl-' + key); + mod='Ctrl-'; + vimKeyNotation=match[1]; + } + var key; + switch (vimKeyNotation) { + case 'BS': + key = 'Backspace'; + break; + case 'CR': + key = 'Enter'; + break; + case 'Del': + key = 'Delete'; + break; + default: + key = vimKeyNotation; + break; } + keys.push(mod + key); } return keys; } @@ -2375,7 +2413,7 @@ commandDispatcher.processMotion(cm, getVimState(cm), { motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, - linewise: true, repeat: params.line }}); + linewise: true, repeat: params.line+1 }}); }, substitute: function(cm, params) { var argString = params.argString; @@ -2410,7 +2448,7 @@ } var state = getSearchState(cm); var query = state.getQuery(); - var lineStart = params.line || 0; + var lineStart = params.line || cm.firstLine(); var lineEnd = params.lineEnd || lineStart; if (count) { lineStart = lineEnd; @@ -2447,6 +2485,9 @@ // Saves to text area if no save command is defined. cm.save(); } + }, + nohlsearch: function(cm) { + clearSearchHighlight(cm); } }; diff --git a/test/vim_test.js b/test/vim_test.js index d91abe5ad0..52d9ea3909 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -87,7 +87,6 @@ function copyCursor(cur) { function testVim(name, run, opts, expectedFail) { var vimOpts = { lineNumbers: true, - mode: 'text/x-csrc', keyMap: 'vim', showCursorWhenSelecting: true, value: code @@ -266,6 +265,41 @@ testVim('Changing lines after Eol operation', function(cm, vim, helpers) { // same place we were at on line 1 helpers.assertCursorAt({ line: 5, ch: lines[2].length - 2 }); }); +//making sure gj and gk recover from clipping +testVim('gj_gk_clipping', function(cm,vim,helpers){ + cm.setCursor(0, 1); + helpers.doKeys('g','j','g','j'); + helpers.assertCursorAt(2, 1); + helpers.doKeys('g','k','g','k'); + helpers.assertCursorAt(0, 1); +},{value: 'line 1\n\nline 2'}); +//testing a mix of j/k and gj/gk +testVim('j_k_and_gj_gk', function(cm,vim,helpers){ + cm.setSize(120); + cm.setCursor(0, 0); + //go to the last character on the first line + helpers.doKeys('$'); + //move up/down on the column within the wrapped line + //side-effect: cursor is not locked to eol anymore + helpers.doKeys('g','k'); + var cur=cm.getCursor(); + eq(cur.line,0); + is((cur.ch<176),'gk didn\'t move cursor back (1)'); + helpers.doKeys('g','j'); + helpers.assertCursorAt(0, 176); + //should move to character 177 on line 2 (j/k preserve character index within line) + helpers.doKeys('j'); + //due to different line wrapping, the cursor can be on a different screen-x now + //gj and gk preserve screen-x on movement, much like moveV + helpers.doKeys('3','g','k'); + cur=cm.getCursor(); + eq(cur.line,1); + is((cur.ch<176),'gk didn\'t move cursor back (2)'); + helpers.doKeys('g','j','2','g','j'); + //should return to the same character-index + helpers.doKeys('k'); + helpers.assertCursorAt(0, 176); +},{ lineWrapping:true, value: 'This line is intentially long to test movement of gj and gk over wrapped lines. I will start on the end of this line, then make a step up and back to set the origin for j and k.\nThis line is supposed to be even longer than the previous. I will jump here and make another wiggle with gj and gk, before I jump back to the line above. Both wiggles should not change my cursor\'s target character but both j/k and gj/gk change each other\'s reference position.'}); testVim('}', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('}'); @@ -827,11 +861,14 @@ testVim('? and n/N', function(cm, vim, helpers) { helpers.doKeys('2', '?'); helpers.assertCursorAt(0, 11); }, { value: 'match nope match \n nope Match' }); -testVim(',/ clearSearchHighlight', function(cm, vim, helpers) { +//:noh should clear highlighting of search-results but allow to resume search through n +testVim('noh_clearSearchHighlight', function(cm, vim, helpers) { cm.openDialog = helpers.fakeOpenDialog('match'); helpers.doKeys('?'); - helpers.doKeys(',', '/', 'n'); - helpers.assertCursorAt(0, 11); + helpers.doEx('noh'); + eq(vim.searchState_.getOverlay(),null,'match-highlighting wasn\'t cleared'); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 11,'can\'t resume search after clearing highlighting'); }, { value: 'match nope match \n nope Match' }); testVim('*', function(cm, vim, helpers) { cm.setCursor(0, 9); @@ -987,6 +1024,20 @@ testVim('ex_map_key2ex', function(cm, vim, helpers) { eq(written, true); eq(actualCm, cm); }); +// Testing registration of functions as ex-commands and mapping to -keys +testVim('ex_api_test', function(cm, vim, helpers) { + var res=false; + var val='from'; + CodeMirror.Vim.defineEx('extest','ext',function(cm,params){ + if(params.args)val=params.args[0]; + else res=true; + }); + helpers.doEx(':ext to'); + eq(val,'to','Defining ex-command failed'); + CodeMirror.Vim.map('',':ext'); + helpers.doKeys('Ctrl-Enter','Space'); + is(res,'Mapping to key failed'); +}); // For now, this test needs to be last because it messes up : for future tests. testVim('ex_map_key2key_from_colon', function(cm, vim, helpers) { helpers.doEx('map : x'); From c3b97cb59684cf8af012bb6b6eb19139bdf45e01 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 16:38:35 +0100 Subject: [PATCH 0224/5273] [closebrackets addon] Fix bug in cursor placement --- 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 09dc7de3aa..9ca4ce1f5c 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -19,7 +19,7 @@ } map["'" + left + "'"] = function(cm) { if (left == right && maybeOverwrite(cm) != CodeMirror.Pass) return; - var cur = cm.getCursor(), ahead = CodeMirror.Pos(cur.line, cur.ch + 1); + var cur = cm.getCursor("start"), ahead = CodeMirror.Pos(cur.line, cur.ch + 1); cm.replaceSelection(left + right, {head: ahead, anchor: ahead}); }; if (left != right) map["'" + right + "'"] = maybeOverwrite; From f1c4978de0deb562329ef9f53ee556fe72a9891f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 17:17:33 +0100 Subject: [PATCH 0225/5273] Take care that selection updates in changes don't create invalid selections --- lib/codemirror.js | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index c42b2c2983..0b5ac78e67 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2034,9 +2034,28 @@ window.CodeMirror = (function() { lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); } + // Make sure a position will be valid after the given change. + function clipPostChange(doc, change, pos) { + if (!posLess(change.from, pos)) return clipPos(doc, pos); + var diff = (change.text.length - 1) - (change.to.line - change.from.line); + if (pos.line > change.to.line + diff) { + var preLine = pos.line - diff, lastLine = doc.first + doc.size - 1; + if (preLine > lastLine) return Pos(lastLine, getLine(doc, lastLine).text.length); + return clipToLen(pos, getLine(doc, preLine).text.length); + } + if (pos.line == change.to.line + diff) + return clipToLen(pos, lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0) + + getLine(doc, change.to.line).text.length - change.to.ch); + var inside = pos.line - change.from.line; + return clipToLen(pos, change.text[inside].length + (inside ? 0 : change.from.ch)); + } + // Hint can be null|"end"|"start"|"around"|{anchor,head} - function computeSelAfterChange(sel, change, hint) { - if (hint && typeof hint == "object") return hint; // Assumed to be {from, to} object + function computeSelAfterChange(doc, change, hint) { + if (hint && typeof hint == "object") // Assumed to be {anchor, head} object + return {anchor: clipPostChange(doc, change, hint.anchor), + head: clipPostChange(doc, change, hint.head)}; + if (hint == "start") return {anchor: change.from, head: change.from}; var end = changeEnd(change); @@ -2052,7 +2071,7 @@ window.CodeMirror = (function() { if (pos.line == change.to.line) ch += end.ch - change.to.ch; return Pos(line, ch); }; - return {anchor: adjustPos(sel.anchor), head: adjustPos(sel.head)}; + return {anchor: adjustPos(doc.sel.anchor), head: adjustPos(doc.sel.head)}; } function filterChange(doc, change) { @@ -2104,7 +2123,7 @@ window.CodeMirror = (function() { } function makeChangeNoReadonly(doc, change, selUpdate) { - var selAfter = computeSelAfterChange(doc.sel, change, selUpdate); + var selAfter = computeSelAfterChange(doc, change, selUpdate); addToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); @@ -2134,7 +2153,7 @@ window.CodeMirror = (function() { change.origin = type; anti.changes.push(historyChangeFromChange(doc, change)); - var after = i ? computeSelAfterChange(doc.sel, change, null) + var after = i ? computeSelAfterChange(doc, change, null) : {anchor: event.anchorBefore, head: event.headBefore}; makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); var rebased = []; @@ -2180,7 +2199,7 @@ window.CodeMirror = (function() { text: [change.text[0]], origin: change.origin}; } - if (!selAfter) selAfter = computeSelAfterChange(doc.sel, change, null); + if (!selAfter) selAfter = computeSelAfterChange(doc, change, null); if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans, selAfter); else updateDoc(doc, change, spans, selAfter); } @@ -2256,7 +2275,10 @@ window.CodeMirror = (function() { 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); - var ch = pos.ch, linelen = getLine(doc, pos.line).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; From 6bbcad10ed4c7f9d04372bfaa2bbfc43c8cdcf07 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 17:22:51 +0100 Subject: [PATCH 0226/5273] Remove e_prop hack I don't think anyone is using it anymore, and it was a kludge to begin with. --- lib/codemirror.js | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 0b5ac78e67..731920c614 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1446,7 +1446,7 @@ window.CodeMirror = (function() { on(d.input, "keyup", operation(cm, function(e) { if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; - if (e_prop(e, "keyCode") == 16) cm.doc.sel.shift = false; + if (e.keyCode == 16) cm.doc.sel.shift = false; })); on(d.input, "input", bind(fastPoll, cm)); on(d.input, "keydown", operation(cm, onKeyDown)); @@ -1517,7 +1517,7 @@ window.CodeMirror = (function() { var lastClick, lastDoubleClick; function onMouseDown(e) { var cm = this, display = cm.display, doc = cm.doc, sel = doc.sel; - sel.shift = e_prop(e, "shiftKey"); + sel.shift = e.shiftKey; if (eventInWidget(display, e)) { if (!webkit) { @@ -1886,7 +1886,7 @@ window.CodeMirror = (function() { if (!name) return false; var keymaps = allKeyMaps(cm); - if (e_prop(e, "shiftKey")) { + if (e.shiftKey) { // 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-'. @@ -1923,15 +1923,15 @@ window.CodeMirror = (function() { if (!cm.state.focused) onFocus(cm); if (ie && e.keyCode == 27) { e.returnValue = false; } if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; - var code = e_prop(e, "keyCode"); + var code = e.keyCode; // IE does strange things with escape. - cm.doc.sel.shift = code == 16 || e_prop(e, "shiftKey"); + cm.doc.sel.shift = code == 16 || e.shiftKey; // First give onKeyEvent option a chance to handle this. var handled = handleKeyBinding(cm, e); if (opera) { lastStoppedKey = handled ? code : null; // Opera has no cut event... we try to at least catch the key combo - if (!handled && code == 88 && !hasCopyEvent && e_prop(e, mac ? "metaKey" : "ctrlKey")) + if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) cm.replaceSelection(""); } } @@ -1939,7 +1939,7 @@ window.CodeMirror = (function() { function onKeyPress(e) { var cm = this; if (cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; - var keyCode = e_prop(e, "keyCode"), charCode = e_prop(e, "charCode"); + var keyCode = e.keyCode, charCode = e.charCode; if (opera && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} if (((opera && (!e.which || e.which < 10)) || khtml) && handleKeyBinding(cm, e)) return; var ch = String.fromCharCode(charCode == null ? keyCode : charCode); @@ -3219,16 +3219,16 @@ window.CodeMirror = (function() { } } function isModifierKey(event) { - var name = keyNames[e_prop(event, "keyCode")]; + var name = keyNames[event.keyCode]; return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; } function keyName(event, noShift) { - var name = keyNames[e_prop(event, "keyCode")]; + var name = keyNames[event.keyCode]; if (name == null || event.altGraphKey) return false; - if (e_prop(event, "altKey")) name = "Alt-" + name; - if (e_prop(event, flipCtrlCmd ? "metaKey" : "ctrlKey")) name = "Ctrl-" + name; - if (e_prop(event, flipCtrlCmd ? "ctrlKey" : "metaKey")) name = "Cmd-" + name; - if (!noShift && e_prop(event, "shiftKey")) name = "Shift-" + name; + if (event.altKey) name = "Alt-" + name; + if (flipCtrlCmd ? event.metaKey : event.ctrlKey) name = "Ctrl-" + name; + if (flipCtrlCmd ? event.ctrlKey : event.metaKey) name = "Cmd-" + name; + if (!noShift && event.shiftKey) name = "Shift-" + name; return name; } CodeMirror.lookupKey = lookupKey; @@ -4799,13 +4799,6 @@ window.CodeMirror = (function() { return b; } - // Allow 3rd-party code to override event properties by adding an override - // object to an event object. - function e_prop(e, prop) { - var overridden = e.override && e.override.hasOwnProperty(prop); - return overridden ? e.override[prop] : e[prop]; - } - // EVENT HANDLING function on(emitter, type, f) { From fa7d0e90eb6dd770a39535e63803397b66b9bd43 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Feb 2013 21:24:15 +0100 Subject: [PATCH 0227/5273] Fix typo in beforeChange event implementation --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 731920c614..a0f900a7b9 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2083,7 +2083,7 @@ window.CodeMirror = (function() { origin: change.origin, update: function(from, to, text, origin) { if (from) this.from = clipPos(doc, from); - if (to) this.to = clipPos(doc.to); + if (to) this.to = clipPos(doc, to); if (text) this.text = text; if (origin !== undefined) this.origin = origin; }, From b76d6989db6adb72370f2fafbab8f1742d684bac Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 18 Feb 2013 09:06:50 +0100 Subject: [PATCH 0228/5273] Fix ignorance about doc.first in coordsChar Closes #1254 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index a0f900a7b9..fbfefde622 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1116,7 +1116,7 @@ window.CodeMirror = (function() { if (y < 0) return PosMaybeOutside(doc.first, 0, true); var lineNo = lineAtHeight(doc, y), last = doc.first + doc.size - 1; if (lineNo > last) - return PosMaybeOutside(doc.size - 1, getLine(doc, last).text.length, true); + return PosMaybeOutside(doc.first + doc.size - 1, getLine(doc, last).text.length, true); if (x < 0) x = 0; for (;;) { From e12fbcbda5026a2e42d63b1076698c422bd8775c Mon Sep 17 00:00:00 2001 From: Charles Skelton Date: Mon, 18 Feb 2013 09:13:30 +0100 Subject: [PATCH 0229/5273] Add a Q mode --- doc/compress.html | 1 + doc/modes.html | 1 + mode/q/index.html | 131 ++++++++++++++++++++++++++++++++++++++++++++++ mode/q/q.js | 124 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 257 insertions(+) create mode 100644 mode/q/index.html create mode 100644 mode/q/q.js diff --git a/doc/compress.html b/doc/compress.html index b06062abf0..0f5926fe60 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -100,6 +100,7 @@

    { } CodeMi + diff --git a/doc/modes.html b/doc/modes.html index 8132770cfa..7d273cbb75 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -55,6 +55,7 @@

    { } CodeMi
  • Pig Latin
  • Properties files
  • Python
  • +
  • Q
  • R
  • RPM spec and changelog
  • reStructuredText
  • diff --git a/mode/q/index.html b/mode/q/index.html new file mode 100644 index 0000000000..303ec1d3ad --- /dev/null +++ b/mode/q/index.html @@ -0,0 +1,131 @@ + + + + + CodeMirror: Q mode + + + + + + + + +

    CodeMirror: Q mode

    + +
    + + + +

    MIME type defined: text/x-q.

    + + diff --git a/mode/q/q.js b/mode/q/q.js new file mode 100644 index 0000000000..8f339bc3c6 --- /dev/null +++ b/mode/q/q.js @@ -0,0 +1,124 @@ +CodeMirror.defineMode("q",function(config){ + var indentUnit=config.indentUnit, + curPunc, + keywords=buildRE(["abs","acos","aj","aj0","all","and","any","asc","asin","asof","atan","attr","avg","avgs","bin","by","ceiling","cols","cor","cos","count","cov","cross","csv","cut","delete","deltas","desc","dev","differ","distinct","div","do","each","ej","enlist","eval","except","exec","exit","exp","fby","fills","first","fkeys","flip","floor","from","get","getenv","group","gtime","hclose","hcount","hdel","hopen","hsym","iasc","idesc","if","ij","in","insert","inter","inv","key","keys","last","like","list","lj","load","log","lower","lsq","ltime","ltrim","mavg","max","maxs","mcount","md5","mdev","med","meta","min","mins","mmax","mmin","mmu","mod","msum","neg","next","not","null","or","over","parse","peach","pj","plist","prd","prds","prev","prior","rand","rank","ratios","raze","read0","read1","reciprocal","reverse","rload","rotate","rsave","rtrim","save","scan","select","set","setenv","show","signum","sin","sqrt","ss","ssr","string","sublist","sum","sums","sv","system","tables","tan","til","trim","txf","type","uj","ungroup","union","update","upper","upsert","value","var","view","views","vs","wavg","where","where","while","within","wj","wj1","wsum","xasc","xbar","xcol","xcols","xdesc","xexp","xgroup","xkey","xlog","xprev","xrank"]), + E=/[|/&^!+:\\\-*%$=~#;@><,?_\'\"\[\(\]\)\s{}]/; + function buildRE(w){return new RegExp("^("+w.join("|")+")$");} + function tokenBase(stream,state){ + var sol=stream.sol(),c=stream.next(); + curPunc=null; + if(sol) + if(c=="/") + return(state.tokenize=tokenLineComment)(stream,state); + else if(c=="\\"){ + if(stream.eol()||/\s/.test(stream.peek())) + return stream.skipToEnd(),/^\\\s*$/.test(stream.current())?(state.tokenize=tokenCommentToEOF)(stream, state):state.tokenize=tokenBase,"comment"; + else + return state.tokenize=tokenBase,"builtin"; + } + if(/\s/.test(c)) + return stream.peek()=="/"?(stream.skipToEnd(),"comment"):"whitespace"; + if(c=='"') + return(state.tokenize=tokenString)(stream,state); + if(c=='`') + return stream.eatWhile(/[A-Z|a-z|\d|_|:|\/|\.]/),"symbol"; + if(("."==c&&/\d/.test(stream.peek()))||/\d/.test(c)){ + var t=null; + stream.backUp(1); + if(stream.match(/^\d{4}\.\d{2}(m|\.\d{2}([D|T](\d{2}(:\d{2}(:\d{2}(\.\d{1,9})?)?)?)?)?)/) + || stream.match(/^\d+D(\d{2}(:\d{2}(:\d{2}(\.\d{1,9})?)?)?)/) + || stream.match(/^\d{2}:\d{2}(:\d{2}(\.\d{1,9})?)?/) + || stream.match(/^\d+[ptuv]{1}/)) + t="temporal"; + else if(stream.match(/^0[NwW]{1}/) + || stream.match(/^0x[\d|a-f|A-F]*/) + || stream.match(/^[0|1]+[b]{1}/) + || stream.match(/^\d+[chijn]{1}/) + || stream.match(/-?\d*(\.\d*)?(e[+\-]?\d+)?(e|f)?/)) + t="number"; + return(t&&(!(c=stream.peek())||E.test(c)))?t:(stream.next(),"error"); + } + if(/[A-Z|a-z]|\./.test(c)) + return stream.eatWhile(/[A-Z|a-z|\.|_|\d]/),keywords.test(stream.current())?"keyword":"variable"; + if(/[|/&^!+:\\\-*%$=~#;@><\.,?_\']/.test(c)) + return null; + if(/[{}\(\[\]\)]/.test(c)) + return null; + return"error"; + } + function tokenLineComment(stream,state){ + return stream.skipToEnd(),/\/\s*$/.test(stream.current())?(state.tokenize=tokenBlockComment)(stream,state):(state.tokenize=tokenBase),"comment"; + } + function tokenBlockComment(stream,state){ + var f=stream.sol()&&stream.peek()=="\\"; + stream.skipToEnd(); + if(f&&/^\\\s*$/.test(stream.current())) + state.tokenize=tokenBase; + return"comment"; + } + function tokenCommentToEOF(stream,state){return stream.skipToEnd(),"comment";} + function tokenString(stream,state){ + var escaped=false,next,end=false; + while((next=stream.next())){ + if(next=="\""&&!escaped){end=true;break;} + escaped=!escaped&&next=="\\"; + } + if(end)state.tokenize=tokenBase; + return"string"; + } + function pushContext(state,type,col){state.context={prev:state.context,indent:state.indent,col:col,type:type};} + function popContext(state){state.indent=state.context.indent;state.context=state.context.prev;} + return{ + startState:function(base){ + return{tokenize:tokenBase, + context:null, + indent:0, + col:0}; + }, + token:function(stream,state){ + if(stream.sol()){ + if(state.context&&state.context.align==null) + state.context.align=false; + state.indent=stream.indentation(); + } + //if (stream.eatSpace()) return null; + var style=state.tokenize(stream,state); + if(style!="comment"&&state.context&&state.context.align==null&&state.context.type!="pattern"){ + state.context.align=true; + } + if(curPunc=="(")pushContext(state,")",stream.column()); + else if(curPunc=="[")pushContext(state,"]",stream.column()); + else if(curPunc=="{")pushContext(state,"}",stream.column()); + else if(/[\]\}\)]/.test(curPunc)){ + while(state.context&&state.context.type=="pattern")popContext(state); + if(state.context&&curPunc==state.context.type)popContext(state); + } + else if(curPunc=="."&&state.context&&state.context.type=="pattern")popContext(state); + else if(/atom|string|variable/.test(style)&&state.context){ + if(/[\}\]]/.test(state.context.type)) + pushContext(state,"pattern",stream.column()); + else if(state.context.type=="pattern"&&!state.context.align){ + state.context.align=true; + state.context.col=stream.column(); + } + } + return style; + }, + indent:function(state,textAfter){ + var firstChar=textAfter&&textAfter.charAt(0); + var context=state.context; + if(/[\]\}]/.test(firstChar)) + while (context&&context.type=="pattern")context=context.prev; + var closing=context&&firstChar==context.type; + if(!context) + return 0; + else if(context.type=="pattern") + return context.col; + else if(context.align) + return context.col+(closing?0:1); + else + return context.indent+(closing?0:indentUnit); + } + }; +}); +CodeMirror.defineMIME("text/x-q","q"); From 853093b7743f3435bf3dd18dab276114bb981682 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 18 Feb 2013 09:33:33 +0100 Subject: [PATCH 0230/5273] Fix bug in document iteration over subviews Closes #1252 --- lib/codemirror.js | 2 +- test/doc_test.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index fbfefde622..60d1da2d8a 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4283,7 +4283,7 @@ window.CodeMirror = (function() { Doc.prototype = createObj(BranchChunk.prototype, { iter: function(from, to, op) { - if (op) this.iterN(from - this.first, to - (from - this.first), op); + if (op) this.iterN(from - this.first, to - from, op); else this.iterN(this.first, this.first + this.size, from); }, diff --git a/test/doc_test.js b/test/doc_test.js index bebdfb091f..3e04e155b3 100644 --- a/test/doc_test.js +++ b/test/doc_test.js @@ -319,4 +319,11 @@ eq(mark.find(), null); eq(cleared, 1); }); + + testDoc("undoInSubview", "A='line 0\nline 1\nline 2\nline 3\nline 4' B Date: Mon, 18 Feb 2013 10:18:01 +0100 Subject: [PATCH 0231/5273] Reduce intact ranges, rather than extending change ranges, for collapsed spans This way, we don't have to shuffle coordinate systems. Closes #1255 --- lib/codemirror.js | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 60d1da2d8a..fe2cdd605a 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -430,18 +430,6 @@ window.CodeMirror = (function() { var gutterW = display.sizer.style.marginLeft = display.gutters.offsetWidth + "px"; display.scrollbarH.style.left = cm.options.fixedGutter ? gutterW : "0"; - // When merged lines are present, the line that needs to be - // redrawn might not be the one that was changed. - if (sawCollapsedSpans) - for (var i = 0; i < changes.length; ++i) { - var ch = changes[i], merged; - while (merged = collapsedSpanAtStart(getLine(doc, ch.from))) { - var from = merged.find().from.line; - if (ch.diff) ch.diff -= ch.from - from; - ch.from = from; - } - } - // Used to determine which lines need their line numbers updated var positionsChangedFrom = Infinity; if (cm.options.lineNumbers) @@ -460,7 +448,22 @@ window.CodeMirror = (function() { // Create a range of theoretically intact lines, and punch holes // in that using the change info. - var intact = computeIntact([{from: display.showingFrom, to: display.showingTo}], changes); + var intact = [{from: Math.max(display.showingFrom, doc.first), + to: Math.min(display.showingTo, end)}]; + if (intact[0].from >= intact[0].to) intact = []; + else intact = computeIntact(intact, changes); + // When merged lines are present, we might have to reduce the + // intact ranges because changes in continued fragments of the + // intact lines do require the lines to be redrawn. + if (sawCollapsedSpans) + for (var i = 0; i < intact.length; ++i) { + var range = intact[i], merged; + while (merged = collapsedSpanAtEnd(getLine(doc, range.to - 1))) { + var newTo = merged.find().from.line; + if (newTo > range.from) range.to = newTo; + else { intact.splice(i--, 1); break; } + } + } // Clip off the parts that won't be visible var intactLines = 0; @@ -512,7 +515,7 @@ window.CodeMirror = (function() { } updateViewOffset(cm); - if (visibleLines(display, doc, viewPort).to >= to) + if (visibleLines(display, doc, viewPort).to > to) updateDisplayInner(cm, [], viewPort); return true; } From f2e3f3c525c30f92200ee86ccee9e0a6e8095fe0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 18 Feb 2013 10:27:02 +0100 Subject: [PATCH 0232/5273] [q mode] Remove unused variables --- mode/q/q.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/q/q.js b/mode/q/q.js index 8f339bc3c6..6fc4e65a9c 100644 --- a/mode/q/q.js +++ b/mode/q/q.js @@ -56,7 +56,7 @@ CodeMirror.defineMode("q",function(config){ state.tokenize=tokenBase; return"comment"; } - function tokenCommentToEOF(stream,state){return stream.skipToEnd(),"comment";} + function tokenCommentToEOF(stream){return stream.skipToEnd(),"comment";} function tokenString(stream,state){ var escaped=false,next,end=false; while((next=stream.next())){ @@ -69,7 +69,7 @@ CodeMirror.defineMode("q",function(config){ function pushContext(state,type,col){state.context={prev:state.context,indent:state.indent,col:col,type:type};} function popContext(state){state.indent=state.context.indent;state.context=state.context.prev;} return{ - startState:function(base){ + startState:function(){ return{tokenize:tokenBase, context:null, indent:0, From 8a2d4668bfbcc1f00495cc1bb369d550686dcfc6 Mon Sep 17 00:00:00 2001 From: Narciso Jaramillo Date: Mon, 11 Feb 2013 17:30:37 -0800 Subject: [PATCH 0233/5273] Avoid scrolling to cursor position in a non-visible editor --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index fe2cdd605a..6a8ab07cfd 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1244,7 +1244,7 @@ window.CodeMirror = (function() { var newScrollPos, updated; if (op.updateScrollPos) { newScrollPos = op.updateScrollPos; - } else if (op.selectionChanged) { + } else if (op.selectionChanged && display.scroller.clientHeight) { // don't rescroll if not visible var coords = cursorCoords(cm, doc.sel.head); newScrollPos = calculateScrollPos(cm, coords.left, coords.top, coords.left, coords.bottom); } From 1605b5557b37d5b1ef38df313904045f61af37b9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 18 Feb 2013 10:39:54 +0100 Subject: [PATCH 0234/5273] Demote formatting.js to non-supported module status --- demo/formatting.html | 7 +++++++ doc/manual.html | 5 ----- index.html | 1 - 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/demo/formatting.html b/demo/formatting.html index e2dec35548..6a05794b20 100644 --- a/demo/formatting.html +++ b/demo/formatting.html @@ -24,6 +24,13 @@

    CodeMirror: Formatting demo

    +

    Note: The formatting addon receives a fair + amount of bug requests. I (the maintainer of CodeMirror) do not + intend to spend time on improving it. Pull requests (if clean and + intelligent) are welcome, but you should see this code as a + proof-of-concept (using CodeMirror's mode tokenizers to help + format code), not a finished, robust module.

    +
    + + +

    This demo runs JSHint over the code +in the editor and use CodeMirror Lint to display the warnings that JSHint comes up with.

    + + diff --git a/demo/jsonlint.html b/demo/jsonlint.html new file mode 100644 index 0000000000..39e90b266a --- /dev/null +++ b/demo/jsonlint.html @@ -0,0 +1,75 @@ + + + + + CodeMirror: JSON Lint Demo + + + + + + + + + + + + + + + +

    CodeMirror: JSON Lint Demo

    + + + + +

    This demo runs JSONLint over the code +in the editor and use CodeMirror Lint to display the warnings that JSONLint comes up with.

    + + diff --git a/lib/codemirror-lint.css b/lib/codemirror-lint.css new file mode 100644 index 0000000000..c251c973ed --- /dev/null +++ b/lib/codemirror-lint.css @@ -0,0 +1,85 @@ +.annotationRange { + background-position: left bottom; + background-repeat: repeat-x; +} + +.annotationRange.error { + background-image: + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") + ; +} + +.annotationRange.warning { + /* images/squiggly_warning.png */ + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); +} + +.annotationHTML { + background-position: center center; + background-repeat: no-repeat; + cursor: pointer; + display: inline-block; + height: 16px; + vertical-align: middle; + width: 16px; +} + +.annotationHTML.error { + background-image: + url("data:image/gif;base64,R0lGODlhEAAQANUAAPVvcvWHiPVucvRuc+ttcfV6f91KVN5LU99PV/FZY/JhaM4oN84pONE4Rd1ATfJLWutVYPRgbdxpcsgWKMgZKs4lNfE/UvE/U+artcpdSc5uXveimslHPuBhW/eJhfV5efaCgO2CgP+/v+PExP///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAQABAAAAZ+wJJwSCwaScgkySgkjTQZTkYzWhadnE5oE+pwqkSshwQqkzxfa4kkQXxEpA9J9EFI1KQGQQBAigYCBA14ExEWF0gXihETeA0QD3AkD5QQg0NsDnAJmwkOd5gYFSQKpXAFDBhqaxgLBwQBBAapq00YEg0UDRKqTGtKSL7Cw8JBADs=") + ; +} + +.annotationHTML.warning { + /* images/warning.gif */ + background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAP7bc//egf/ij/7ijv/jl/7kl//mnv7lnv/uwf7CTP7DTf7DT/7IW//Na/7Na//NbP7QdP/dmbltAIJNAF03AMSAJMSCLKqASa2DS6uBSquCSrGHTq6ETbCHT7WKUrKIUcCVXL+UXMOYX8GWXsSZYMiib6+ETbOIUcOXX86uhd3Muf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACsALAAAAAAQABAAAAZowJVwSCwaj0ihikRSJYcoBEL0XKlGkcjImQQhJBREKFnyICoThKeE/AAW6AXgdPyUAgrLJBEo0YsbAQyDhAEdRRwDDw8OaA4NDQImRBgFEJdglxAEGEQZKQcHBqOkKRpFF6mqq1WtrUEAOw=="); +} + +/* Styles for the overview ruler */ +.annotationOverview { + cursor: pointer; + border-radius: 2px; + left: 2px; + width: 8px; +} +.annotationOverview.error { + background-color: lightcoral; + border: 1px solid darkred; +} +.annotationOverview.warning { + background-color: Gold; + border: 1px solid black; +} + +.annotationHTML.overlay { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEAQvB2JVdrAAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAD1JREFUCNdtjkESADAEAzemf69f66HMqGlOIhYiFRFRtSQBWAY7mzx+EDTL6sSgb1jTk7Q87rxyqe37fXsAa78gLyZnRgEAAAAASUVORK5CYII="); + background-position: right bottom; + position: relative; + top: -16px; +} + +.CodeMirror-lints { + width: 16px; +} + +.textviewTooltip { + background-color: infobackground; + border: 1px solid black; + border-radius: 4px 4px 4px 4px; + color: infotext; + font-family: monospace; + font-size: 10pt; + overflow: hidden; + padding: 2px; + position: fixed; + white-space: pre; + z-index: 100; +} + +#ttcont { + //display: block; + //padding: 2px 12px 3px 7px; + margin-left: 5px; +// background: #666; +// color: #fff; +} \ No newline at end of file From 50ab187f4ea611f32d396ada23fc680a26cafb0e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 18 Feb 2013 11:13:52 +0100 Subject: [PATCH 0236/5273] [lint addon] Start integrating - Link to external jsonlint.js (don't want dependencies in repo if I can help it) - Use a single demo file (prevent demo/ from becoming a huge mess) - Make whitespace and newlines conform to other files, fix linter errors --- addon/lint/javascript-lint.js | 267 ++++++----- addon/lint/json-lint.js | 34 +- addon/lint/jsonlint.js | 432 ------------------ addon/lint/lint.css | 81 ++++ addon/lint/lint.js | 565 ++++++++++++------------ demo/jsonlint.html | 75 ---- demo/{javascriptlint.html => lint.html} | 64 ++- doc/compress.html | 3 + lib/codemirror-lint.css | 85 ---- 9 files changed, 563 insertions(+), 1043 deletions(-) delete mode 100644 addon/lint/jsonlint.js create mode 100644 addon/lint/lint.css delete mode 100644 demo/jsonlint.html rename demo/{javascriptlint.html => lint.html} (60%) delete mode 100644 lib/codemirror-lint.css diff --git a/addon/lint/javascript-lint.js b/addon/lint/javascript-lint.js index cc108fa4d7..e3f84b857a 100644 --- a/addon/lint/javascript-lint.js +++ b/addon/lint/javascript-lint.js @@ -1,144 +1,137 @@ (function() { - var localConfig, defaults, defaultIndent, bogus, warnings, errors; - - localConfig = {}; - - defaults = [ "undef", "newcap", "smarttabs" ]; - defaultIndent = 3; - - bogus = [ "Dangerous comment" ]; - - warnings = [ [ "Expected '{'", - "Statement body should be inside '{ }' braces." ] ]; - - errors = [ "Missing semicolon", "Extra comma", "Missing property name", - "Unmatched ", " and instead saw", " is not defined", - "Unclosed string", "Stopping, unable to continue" ]; - - CodeMirror.javascriptValidator = function(contents, collector, cm) { - var positionalAdjustment = 1; - var result = jshint(contents); - var errors = result.errors; - if (errors) { - parseErrors(errors, positionalAdjustment, collector); - } - }; - - function jshint(contents) { - JSHINT(contents/* , localConfig.options, localConfig.options.predef */); - return JSHINT.data(); - } - - function cleanup(error) { - // All problems are warnings by default - fixWith(error, warnings, "warning", true); - fixWith(error, errors, "error"); - - return isBogus(error) ? null : error; - } - - function fixWith(error, fixes, severity, force) { - var description, fix, find, replace, found; - - 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]); - found = description.indexOf(find) !== -1; - - if (force || found) { - error.severity = severity; - } - if (found && replace) { - error.description = replace; - } - } + var bogus = [ "Dangerous comment" ]; + + var warnings = [ [ "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" ]; + + CodeMirror.javascriptValidator = function(contents, collector) { + var positionalAdjustment = 1; + var result = jshint(contents); + var errors = result.errors; + if (errors) { + parseErrors(errors, positionalAdjustment, collector); + } + }; + + function jshint(contents) { + JSHINT(contents/* , localConfig.options, localConfig.options.predef */); + return JSHINT.data(); + } + + function cleanup(error) { + // All problems are warnings by default + fixWith(error, warnings, "warning", true); + fixWith(error, errors, "error"); + + return isBogus(error) ? null : error; + } + + function fixWith(error, fixes, severity, force) { + var description, fix, find, replace, found; + + 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]); + found = description.indexOf(find) !== -1; + + if (force || found) { + error.severity = severity; + } + if (found && replace) { + error.description = replace; + } + } + } + + 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, positionalAdjustment, collector) { + for ( var i = 0; i < errors.length; i++) { + var error = errors[i]; + if (error) { + var linetabpositions, index; + + linetabpositions = []; + + // This next block is to fix a problem in jshint. Jshint + // replaces + // all tabs with spaces then performs some checks. The error + // positions (character/space) are then reported incorrectly, + // not taking the replacement step into account. Here we look + // at the evidence line and try to adjust the character position + // to the correct value. + if (error.evidence) { + // Tab positions are computed once per line and cached + var tabpositions = linetabpositions[error.line]; + if (!tabpositions) { + var evidence = error.evidence; + tabpositions = []; + // ugggh phantomjs does not like this + // forEachChar(evidence, function(item, index) { + Array.prototype.forEach.call(evidence, function(item, + index) { + if (item === '\t') { + // First col is 1 (not 0) to match error + // positions + tabpositions.push(index + 1); + } + }); + linetabpositions[error.line] = tabpositions; + } + if (tabpositions.length > 0) { + var pos = error.character; + tabpositions.forEach(function(tabposition) { + if (pos > tabposition) { + pos -= positionalAdjustment; + } + }); + error.character = pos; + } } - 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; + var start = error.character - 1, end = start + 1; + if (error.evidence) { + index = error.evidence.substring(start).search(/.\b/); + if (index > -1) { + end += index; + } } - function parseErrors(errors, positionalAdjustment, collector) { - for ( var i = 0; i < errors.length; i++) { - error = errors[i]; - if (error) { - var linetabpositions, index; - - linetabpositions = []; - - // This next block is to fix a problem in jshint. Jshint - // replaces - // all tabs with spaces then performs some checks. The error - // positions (character/space) are then reported incorrectly, - // not taking the replacement step into account. Here we look - // at the evidence line and try to adjust the character position - // to the correct value. - if (error.evidence) { - // Tab positions are computed once per line and cached - var tabpositions = linetabpositions[error.line]; - if (!tabpositions) { - var evidence = error.evidence; - tabpositions = []; - // ugggh phantomjs does not like this - // forEachChar(evidence, function(item, index) { - Array.prototype.forEach.call(evidence, function(item, - index) { - if (item === '\t') { - // First col is 1 (not 0) to match error - // positions - tabpositions.push(index + 1); - } - }); - linetabpositions[error.line] = tabpositions; - } - if (tabpositions.length > 0) { - var pos = error.character; - tabpositions.forEach(function(tabposition) { - if (pos > tabposition) { - pos -= positionalAdjustment; - } - }); - error.character = pos; - } - } - - var start = error.character - 1, end = start + 1; - if (error.evidence) { - index = error.evidence.substring(start).search(/.\b/); - if (index > -1) { - end += index; - } - } - - // Convert to format expected by validation service - error.description = error.reason;// + "(jshint)"; - error.start = error.character; - error.end = end; - error = cleanup(error); - - if (error) { - var severity = error.severity; - var lineStart = error.line - 1; - var charStart = start; - var lineEnd = error.line - 1; - var charEnd = end; - var description = error.description; - - collector.addAnnotation(severity, lineStart, charStart, - lineEnd, charEnd, description); - - } - } - } + // Convert to format expected by validation service + error.description = error.reason;// + "(jshint)"; + error.start = error.character; + error.end = end; + error = cleanup(error); + + if (error) { + var severity = error.severity; + var lineStart = error.line - 1; + var charStart = start; + var lineEnd = error.line - 1; + var charEnd = end; + var description = error.description; + + collector.addAnnotation(severity, lineStart, charStart, + lineEnd, charEnd, description); + } -})(); \ No newline at end of file + } + } + } +})(); diff --git a/addon/lint/json-lint.js b/addon/lint/json-lint.js index 2aebcdc7b9..d3c4c756ee 100644 --- a/addon/lint/json-lint.js +++ b/addon/lint/json-lint.js @@ -1,24 +1,20 @@ (function() { - CodeMirror.jsonValidator = function(contents, collector, cm) { - try { - jsonlint.parseError = function(str, hash) { + CodeMirror.jsonValidator = function(contents, collector) { + jsonlint.parseError = function(str, hash) { + var severity = 'error'; + var loc = hash.loc; + var lineStart = loc.first_line - 1; + var lineEnd = hash.line;// loc.last_line - 1; + var charStart = loc.first_column; + var charEnd = loc.last_column; - var severity = 'error'; - var loc = hash.loc; - var lineStart = loc.first_line - 1; - var lineEnd = hash.line;// loc.last_line - 1; - var charStart = loc.first_column - var charEnd = loc.last_column; + collector.addAnnotation(severity, lineStart, charStart, + lineEnd, charEnd, str); - collector.addAnnotation(severity, lineStart, charStart, - lineEnd, charEnd, str); + }; + try { jsonlint.parse(contents); } + catch(e) {} + }; - }; - jsonlint.parse(contents); - } catch (parseException) { - //alert(parseException); - } - }; - -})(); \ No newline at end of file +})(); diff --git a/addon/lint/jsonlint.js b/addon/lint/jsonlint.js deleted file mode 100644 index d72145473c..0000000000 --- a/addon/lint/jsonlint.js +++ /dev/null @@ -1,432 +0,0 @@ -/* Jison generated parser */ -var jsonlint = (function(){ -var parser = {trace: function trace() { }, -yy: {}, -symbols_: {"error":2,"JSONString":3,"STRING":4,"JSONNumber":5,"NUMBER":6,"JSONNullLiteral":7,"NULL":8,"JSONBooleanLiteral":9,"TRUE":10,"FALSE":11,"JSONText":12,"JSONValue":13,"EOF":14,"JSONObject":15,"JSONArray":16,"{":17,"}":18,"JSONMemberList":19,"JSONMember":20,":":21,",":22,"[":23,"]":24,"JSONElementList":25,"$accept":0,"$end":1}, -terminals_: {2:"error",4:"STRING",6:"NUMBER",8:"NULL",10:"TRUE",11:"FALSE",14:"EOF",17:"{",18:"}",21:":",22:",",23:"[",24:"]"}, -productions_: [0,[3,1],[5,1],[7,1],[9,1],[9,1],[12,2],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[15,2],[15,3],[20,3],[19,1],[19,3],[16,2],[16,3],[25,1],[25,3]], -performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) { - -var $0 = $$.length - 1; -switch (yystate) { -case 1: // replace escaped characters with actual character - this.$ = yytext.replace(/\\(\\|")/g, "$"+"1") - .replace(/\\n/g,'\n') - .replace(/\\r/g,'\r') - .replace(/\\t/g,'\t') - .replace(/\\v/g,'\v') - .replace(/\\f/g,'\f') - .replace(/\\b/g,'\b'); - -break; -case 2:this.$ = Number(yytext); -break; -case 3:this.$ = null; -break; -case 4:this.$ = true; -break; -case 5:this.$ = false; -break; -case 6:return this.$ = $$[$0-1]; -break; -case 13:this.$ = {}; -break; -case 14:this.$ = $$[$0-1]; -break; -case 15:this.$ = [$$[$0-2], $$[$0]]; -break; -case 16:this.$ = {}; this.$[$$[$0][0]] = $$[$0][1]; -break; -case 17:this.$ = $$[$0-2]; $$[$0-2][$$[$0][0]] = $$[$0][1]; -break; -case 18:this.$ = []; -break; -case 19:this.$ = $$[$0-1]; -break; -case 20:this.$ = [$$[$0]]; -break; -case 21:this.$ = $$[$0-2]; $$[$0-2].push($$[$0]); -break; -} -}, -table: [{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],12:1,13:2,15:7,16:8,17:[1,14],23:[1,15]},{1:[3]},{14:[1,16]},{14:[2,7],18:[2,7],22:[2,7],24:[2,7]},{14:[2,8],18:[2,8],22:[2,8],24:[2,8]},{14:[2,9],18:[2,9],22:[2,9],24:[2,9]},{14:[2,10],18:[2,10],22:[2,10],24:[2,10]},{14:[2,11],18:[2,11],22:[2,11],24:[2,11]},{14:[2,12],18:[2,12],22:[2,12],24:[2,12]},{14:[2,3],18:[2,3],22:[2,3],24:[2,3]},{14:[2,4],18:[2,4],22:[2,4],24:[2,4]},{14:[2,5],18:[2,5],22:[2,5],24:[2,5]},{14:[2,1],18:[2,1],21:[2,1],22:[2,1],24:[2,1]},{14:[2,2],18:[2,2],22:[2,2],24:[2,2]},{3:20,4:[1,12],18:[1,17],19:18,20:19},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:23,15:7,16:8,17:[1,14],23:[1,15],24:[1,21],25:22},{1:[2,6]},{14:[2,13],18:[2,13],22:[2,13],24:[2,13]},{18:[1,24],22:[1,25]},{18:[2,16],22:[2,16]},{21:[1,26]},{14:[2,18],18:[2,18],22:[2,18],24:[2,18]},{22:[1,28],24:[1,27]},{22:[2,20],24:[2,20]},{14:[2,14],18:[2,14],22:[2,14],24:[2,14]},{3:20,4:[1,12],20:29},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:30,15:7,16:8,17:[1,14],23:[1,15]},{14:[2,19],18:[2,19],22:[2,19],24:[2,19]},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:31,15:7,16:8,17:[1,14],23:[1,15]},{18:[2,17],22:[2,17]},{18:[2,15],22:[2,15]},{22:[2,21],24:[2,21]}], -defaultActions: {16:[2,6]}, -parseError: function parseError(str, hash) { - throw new Error(str); -}, -parse: function parse(input) { - var self = this, - stack = [0], - vstack = [null], // semantic value stack - lstack = [], // location stack - table = this.table, - yytext = '', - yylineno = 0, - yyleng = 0, - recovering = 0, - TERROR = 2, - EOF = 1; - - //this.reductionCount = this.shiftCount = 0; - - this.lexer.setInput(input); - this.lexer.yy = this.yy; - this.yy.lexer = this.lexer; - if (typeof this.lexer.yylloc == 'undefined') - this.lexer.yylloc = {}; - var yyloc = this.lexer.yylloc; - lstack.push(yyloc); - - if (typeof this.yy.parseError === 'function') - this.parseError = this.yy.parseError; - - function popStack (n) { - stack.length = stack.length - 2*n; - vstack.length = vstack.length - n; - lstack.length = lstack.length - n; - } - - function lex() { - var token; - token = self.lexer.lex() || 1; // $end = 1 - // if token isn't its numeric value, convert - if (typeof token !== 'number') { - token = self.symbols_[token] || token; - } - return token; - } - - var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected; - while (true) { - // retreive state number from top of stack - state = stack[stack.length-1]; - - // use default actions if available - if (this.defaultActions[state]) { - action = this.defaultActions[state]; - } else { - if (symbol == null) - symbol = lex(); - // read action for current state and first input - action = table[state] && table[state][symbol]; - } - - // handle parse error - _handle_error: - if (typeof action === 'undefined' || !action.length || !action[0]) { - - if (!recovering) { - // Report error - expected = []; - for (p in table[state]) if (this.terminals_[p] && p > 2) { - expected.push("'"+this.terminals_[p]+"'"); - } - var errStr = ''; - if (this.lexer.showPosition) { - errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'"; - } else { - errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " + - (symbol == 1 /*EOF*/ ? "end of input" : - ("'"+(this.terminals_[symbol] || symbol)+"'")); - } - this.parseError(errStr, - {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); - } - - // just recovered from another error - if (recovering == 3) { - if (symbol == EOF) { - throw new Error(errStr || 'Parsing halted.'); - } - - // discard current lookahead and grab another - yyleng = this.lexer.yyleng; - yytext = this.lexer.yytext; - yylineno = this.lexer.yylineno; - yyloc = this.lexer.yylloc; - symbol = lex(); - } - - // try to recover from error - while (1) { - // check for error recovery rule in this state - if ((TERROR.toString()) in table[state]) { - break; - } - if (state == 0) { - throw new Error(errStr || 'Parsing halted.'); - } - popStack(1); - state = stack[stack.length-1]; - } - - preErrorSymbol = symbol; // save the lookahead token - symbol = TERROR; // insert generic error symbol as new lookahead - state = stack[stack.length-1]; - action = table[state] && table[state][TERROR]; - recovering = 3; // allow 3 real symbols to be shifted before reporting a new error - } - - // this shouldn't happen, unless resolve defaults are off - if (action[0] instanceof Array && action.length > 1) { - throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol); - } - - switch (action[0]) { - - case 1: // shift - //this.shiftCount++; - - stack.push(symbol); - vstack.push(this.lexer.yytext); - lstack.push(this.lexer.yylloc); - stack.push(action[1]); // push state - symbol = null; - if (!preErrorSymbol) { // normal execution/no error - yyleng = this.lexer.yyleng; - yytext = this.lexer.yytext; - yylineno = this.lexer.yylineno; - yyloc = this.lexer.yylloc; - if (recovering > 0) - recovering--; - } else { // error just occurred, resume old lookahead f/ before error - symbol = preErrorSymbol; - preErrorSymbol = null; - } - break; - - case 2: // reduce - //this.reductionCount++; - - len = this.productions_[action[1]][1]; - - // perform semantic action - yyval.$ = vstack[vstack.length-len]; // default to $$ = $1 - // default location, uses first token for firsts, last for lasts - yyval._$ = { - first_line: lstack[lstack.length-(len||1)].first_line, - last_line: lstack[lstack.length-1].last_line, - first_column: lstack[lstack.length-(len||1)].first_column, - last_column: lstack[lstack.length-1].last_column - }; - r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); - - if (typeof r !== 'undefined') { - return r; - } - - // pop off stack - if (len) { - stack = stack.slice(0,-1*len*2); - vstack = vstack.slice(0, -1*len); - lstack = lstack.slice(0, -1*len); - } - - stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce) - vstack.push(yyval.$); - lstack.push(yyval._$); - // goto new state = table[STATE][NONTERMINAL] - newState = table[stack[stack.length-2]][stack[stack.length-1]]; - stack.push(newState); - break; - - case 3: // accept - return true; - } - - } - - return true; -}}; -/* Jison generated lexer */ -var lexer = (function(){ -var lexer = ({EOF:1, -parseError:function parseError(str, hash) { - if (this.yy.parseError) { - this.yy.parseError(str, hash); - } else { - throw new Error(str); - } - }, -setInput:function (input) { - this._input = input; - this._more = this._less = this.done = false; - this.yylineno = this.yyleng = 0; - this.yytext = this.matched = this.match = ''; - this.conditionStack = ['INITIAL']; - this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0}; - return this; - }, -input:function () { - var ch = this._input[0]; - this.yytext+=ch; - this.yyleng++; - this.match+=ch; - this.matched+=ch; - var lines = ch.match(/\n/); - if (lines) this.yylineno++; - this._input = this._input.slice(1); - return ch; - }, -unput:function (ch) { - this._input = ch + this._input; - return this; - }, -more:function () { - this._more = true; - return this; - }, -less:function (n) { - this._input = this.match.slice(n) + this._input; - }, -pastInput:function () { - var past = this.matched.substr(0, this.matched.length - this.match.length); - return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); - }, -upcomingInput:function () { - var next = this.match; - if (next.length < 20) { - next += this._input.substr(0, 20-next.length); - } - return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, ""); - }, -showPosition:function () { - var pre = this.pastInput(); - var c = new Array(pre.length + 1).join("-"); - return pre + this.upcomingInput() + "\n" + c+"^"; - }, -next:function () { - if (this.done) { - return this.EOF; - } - if (!this._input) this.done = true; - - var token, - match, - tempMatch, - index, - col, - lines; - if (!this._more) { - this.yytext = ''; - this.match = ''; - } - var rules = this._currentRules(); - for (var i=0;i < rules.length; i++) { - tempMatch = this._input.match(this.rules[rules[i]]); - if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { - match = tempMatch; - index = i; - if (!this.options.flex) break; - } - } - if (match) { - lines = match[0].match(/\n.*/g); - if (lines) this.yylineno += lines.length; - this.yylloc = {first_line: this.yylloc.last_line, - last_line: this.yylineno+1, - first_column: this.yylloc.last_column, - last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length} - this.yytext += match[0]; - this.match += match[0]; - this.yyleng = this.yytext.length; - this._more = false; - this._input = this._input.slice(match[0].length); - this.matched += match[0]; - token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]); - if (this.done && this._input) this.done = false; - if (token) return token; - else return; - } - if (this._input === "") { - return this.EOF; - } else { - this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), - {text: "", token: null, line: this.yylineno}); - } - }, -lex:function lex() { - var r = this.next(); - if (typeof r !== 'undefined') { - return r; - } else { - return this.lex(); - } - }, -begin:function begin(condition) { - this.conditionStack.push(condition); - }, -popState:function popState() { - return this.conditionStack.pop(); - }, -_currentRules:function _currentRules() { - return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules; - }, -topState:function () { - return this.conditionStack[this.conditionStack.length-2]; - }, -pushState:function begin(condition) { - this.begin(condition); - }}); -lexer.options = {}; -lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { - -var YYSTATE=YY_START -switch($avoiding_name_collisions) { -case 0:/* skip whitespace */ -break; -case 1:return 6 -break; -case 2:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 4 -break; -case 3:return 17 -break; -case 4:return 18 -break; -case 5:return 23 -break; -case 6:return 24 -break; -case 7:return 22 -break; -case 8:return 21 -break; -case 9:return 10 -break; -case 10:return 11 -break; -case 11:return 8 -break; -case 12:return 14 -break; -case 13:return 'INVALID' -break; -} -}; -lexer.rules = [/^(?:\s+)/,/^(?:(-?([0-9]|[1-9][0-9]+))(\.[0-9]+)?([eE][-+]?[0-9]+)?\b)/,/^(?:"(?:\\[\\"bfnrt/]|\\u[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*")/,/^(?:\{)/,/^(?:\})/,/^(?:\[)/,/^(?:\])/,/^(?:,)/,/^(?::)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:$)/,/^(?:.)/]; -lexer.conditions = {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"inclusive":true}}; - - -; -return lexer;})() -parser.lexer = lexer; -return parser; -})(); -if (typeof require !== 'undefined' && typeof exports !== 'undefined') { -exports.parser = jsonlint; -exports.parse = function () { return jsonlint.parse.apply(jsonlint, arguments); } -exports.main = function commonjsMain(args) { - if (!args[1]) - throw new Error('Usage: '+args[0]+' FILE'); - if (typeof process !== 'undefined') { - var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8"); - } else { - var cwd = require("file").path(require("file").cwd()); - var source = cwd.join(args[1]).read({charset: "utf-8"}); - } - return exports.parser.parse(source); -} -if (typeof module !== 'undefined' && require.main === module) { - exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args); -} -} \ No newline at end of file diff --git a/addon/lint/lint.css b/addon/lint/lint.css new file mode 100644 index 0000000000..98e883266f --- /dev/null +++ b/addon/lint/lint.css @@ -0,0 +1,81 @@ +.annotationRange { + background-position: left bottom; + background-repeat: repeat-x; +} + +.annotationRange.error { + background-image: + url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") + ; +} + +.annotationRange.warning { + /* images/squiggly_warning.png */ + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); +} + +.annotationHTML { + background-position: center center; + background-repeat: no-repeat; + cursor: pointer; + display: inline-block; + height: 16px; + vertical-align: middle; + width: 16px; +} + +.annotationHTML.error { + background-image: + url("data:image/gif;base64,R0lGODlhEAAQANUAAPVvcvWHiPVucvRuc+ttcfV6f91KVN5LU99PV/FZY/JhaM4oN84pONE4Rd1ATfJLWutVYPRgbdxpcsgWKMgZKs4lNfE/UvE/U+artcpdSc5uXveimslHPuBhW/eJhfV5efaCgO2CgP+/v+PExP///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAQABAAAAZ+wJJwSCwaScgkySgkjTQZTkYzWhadnE5oE+pwqkSshwQqkzxfa4kkQXxEpA9J9EFI1KQGQQBAigYCBA14ExEWF0gXihETeA0QD3AkD5QQg0NsDnAJmwkOd5gYFSQKpXAFDBhqaxgLBwQBBAapq00YEg0UDRKqTGtKSL7Cw8JBADs=") + ; +} + +.annotationHTML.warning { + /* images/warning.gif */ + background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAP7bc//egf/ij/7ijv/jl/7kl//mnv7lnv/uwf7CTP7DTf7DT/7IW//Na/7Na//NbP7QdP/dmbltAIJNAF03AMSAJMSCLKqASa2DS6uBSquCSrGHTq6ETbCHT7WKUrKIUcCVXL+UXMOYX8GWXsSZYMiib6+ETbOIUcOXX86uhd3Muf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACsALAAAAAAQABAAAAZowJVwSCwaj0ihikRSJYcoBEL0XKlGkcjImQQhJBREKFnyICoThKeE/AAW6AXgdPyUAgrLJBEo0YsbAQyDhAEdRRwDDw8OaA4NDQImRBgFEJdglxAEGEQZKQcHBqOkKRpFF6mqq1WtrUEAOw=="); +} + +/* Styles for the overview ruler */ +.annotationOverview { + cursor: pointer; + border-radius: 2px; + left: 2px; + width: 8px; +} +.annotationOverview.error { + background-color: lightcoral; + border: 1px solid darkred; +} +.annotationOverview.warning { + background-color: Gold; + border: 1px solid black; +} + +.annotationHTML.overlay { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEAQvB2JVdrAAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAD1JREFUCNdtjkESADAEAzemf69f66HMqGlOIhYiFRFRtSQBWAY7mzx+EDTL6sSgb1jTk7Q87rxyqe37fXsAa78gLyZnRgEAAAAASUVORK5CYII="); + background-position: right bottom; + position: relative; + top: -16px; +} + +.CodeMirror-lints { + width: 16px; +} + +.textviewTooltip { + background-color: infobackground; + border: 1px solid black; + border-radius: 4px 4px 4px 4px; + color: infotext; + font-family: monospace; + font-size: 10pt; + overflow: hidden; + padding: 2px; + position: fixed; + white-space: pre; + z-index: 100; +} + +#ttcont { + margin-left: 5px; +} diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 82adebdd36..a2713efcce 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -1,283 +1,282 @@ -CodeMirror.validate = function(cm, collectAnnotations, options) { - if (!options) - options = {}; - - var GUTTER_ID = "CodeMirror-lints"; - - // see - // http://sixrevisions.com/tutorials/javascript_tutorial/create_lightweight_javascript_tooltip/ - var tooltip = function() { - var id = 'tt'; - var top = 3; - var left = 3; - var maxw = 600; - var speed = 10; - var timer = 20; - var endalpha = 95; - var alpha = 0; - //var tt, t, c, b, h; - var tt, c, h; - var ie = document.all ? true : false; - return { - show : function(v, w, severity) { - if (tt == null) { - tt = document.createElement('div'); - tt.setAttribute('id', id); - tt.className = 'textviewTooltip'; - //t = document.createElement('div'); - //t.setAttribute('id', id + 'top'); - c = document.createElement('div'); - c.setAttribute('id', id + 'cont'); - //b = document.createElement('div'); - //b.setAttribute('id', id + 'bot'); - //tt.appendChild(t); - tt.appendChild(c); - //tt.appendChild(b); - document.body.appendChild(tt); - tt.style.opacity = 0; - tt.style.filter = 'alpha(opacity=0)'; - document.onmousemove = this.pos; - } - tt.style.display = 'block'; - c.innerHTML = v; - tt.style.width = w ? w + 'px' : 'auto'; - if (!w && ie) { - //t.style.display = 'none'; - //b.style.display = 'none'; - tt.style.width = tt.offsetWidth; - //t.style.display = 'block'; - //b.style.display = 'block'; - } - if (tt.offsetWidth > maxw) { - tt.style.width = maxw + 'px' - } - h = parseInt(tt.offsetHeight) + top; - clearInterval(tt.timer); - tt.timer = setInterval(function() { - tooltip.fade(1) - }, timer); - }, - pos : function(e) { - var u = ie ? event.clientY + document.documentElement.scrollTop - : e.pageY; - var l = ie ? event.clientX - + document.documentElement.scrollLeft : e.pageX; - tt.style.top = (u - h) + 'px'; - tt.style.left = (l + left) + 'px'; - }, - fade : function(d) { - var a = alpha; - if ((a != endalpha && d == 1) || (a != 0 && d == -1)) { - var i = speed; - if (endalpha - a < speed && d == 1) { - i = endalpha - a; - } else if (alpha < speed && d == -1) { - i = a; - } - alpha = a + (i * d); - tt.style.opacity = alpha * .01; - tt.style.filter = 'alpha(opacity=' + alpha + ')'; - } else { - clearInterval(tt.timer); - if (d == -1) { - tt.style.display = 'none' - } else if (d == 1) { - tt.style.opacity = 1; - tt.style.filter = 'alpha(opacity=100)'; - } - } - }, - hide : function() { - clearInterval(tt.timer); - tt.timer = setInterval(function() { - tooltip.fade(-1) - }, timer); - } - }; - }(); - - function SyntaxErrorHighlightState() { - this.marked = []; - } - function getSyntaxErrorHighlightState(cm) { - return cm._syntaxErrorHighlightState - || (cm._syntaxErrorHighlightState = new SyntaxErrorHighlightState()); - } - - function clearMarks(cm, gutterID) { - cm.clearGutter(gutterID); - var state = getSyntaxErrorHighlightState(cm); - for ( var i = 0; i < state.marked.length; ++i) - state.marked[i].clear(); - state.marked = []; - } - - function makeMarker(tooltipLabel, maxSeverity, multiple) { - - var marker = document.createElement("div"); - marker.onmouseover = function() { - tooltip.show(tooltipLabel, null, maxSeverity); - }; - marker.onmouseout = function() { - tooltip.hide(); - }; - marker.className = 'annotation ' + maxSeverity; - - var markerHTML= document.createElement("div"); - markerHTML.className = 'annotationHTML ' + maxSeverity; - marker.appendChild(markerHTML); - - if (multiple) { - var markerHTML= document.createElement("div"); - markerHTML.className = 'annotationHTML overlay'; - marker.appendChild(markerHTML); - } - - return marker; - } - - var AnnotationsCollector = function() { - this.linesNumber = []; - this.linesAnnotations = []; - }; - - AnnotationsCollector.prototype.addAnnotation = function(severity, - lineStart, charStart, lineEnd, charEnd, description) { - - var annotation = { - "severity" : severity, - "lineStart" : lineStart, - "charStart" : charStart, - "lineEnd" : lineEnd, - "charEnd" : charEnd, - "description" : description - } - var annotations = this.linesAnnotations[lineStart]; - if (!annotations) { - annotations = []; - this.linesAnnotations[lineStart] = annotations; - this.linesNumber.push(lineStart); - } - annotations.push(annotation); - }; - - function getMaxSeverity(severity1, severity2) { - // TODO : should be improved to extend severity (today just error and - // warning are managed) - if (severity1 == 'error') { - return severity1; - } - return severity2; - } - - function getTooltipLabel(content, multiple) { - var label = '
    '; - if (multiple) { - label += '
    Multiple Annotations
    '; - } - label += '
    '; - label += content; - label += '
    '; - label += '
    '; - return label; - } - - function getTooltipAnnotationLabel(description, severity) { - var label = '
    '; - label += '
    '; - label += '
    '; - label += ' '; - label += description; - label += ''; - label += '
    '; - return label; - } - - function makeMarkText(severity, lineStart, charStart, lineEnd, charEnd, annotationLabel) { - var markClass = 'annotationRange ' + severity; - var mark = cm.markText({ - line : lineStart, - ch : charStart - }, { - line : lineEnd, - ch : charEnd - }, { - className : markClass, - readOnly : false - }); - - // save mark text in an array which is used to clean mark - var state = getSyntaxErrorHighlightState(cm); - state.marked.push(mark); - - var tooltipLabel = getTooltipLabel(annotationLabel, false); - // TODO : add tooltip for mark text. How to manage that??? - // I would like do like this - /*mark.onmouseover = function() { - tooltip.show(tooltipLabel, null, severity); - }; - mark.onmouseout = function() { - tooltip.hide(); - };*/ - } - - function markDocument() { - var gutterID = GUTTER_ID; - clearMarks(cm, gutterID); - - var collector = new AnnotationsCollector(); - - var contents = (options.getContents ? options.getContents() : cm - .getValue()); - collectAnnotations(contents, collector, cm); - - var linesNumber = collector.linesNumber; - // Loop for each lines number which contains problems - for ( var i = 0; i < linesNumber.length; i++) { - var line = linesNumber[i]; - var annotations = collector.linesAnnotations[line]; - - // loop for each annotations for the current line to - // - create a markText for each annotations - // - create a tooltip with the list of annotations - - var maxSeverity = null; - var markerTooltipLabel = ''; - var multiple = annotations.length > 1; - - // create a markText for each annotations - for ( var j = 0; j < annotations.length; j++) { - var annotation = annotations[j]; - if (options.formatAnnotation) { - annotation = options.formatAnnotation(annotation); - } - - // Create mark text - - var severity = annotation.severity; - var lineStart = annotation.lineStart; - var charStart = annotation.charStart; - var lineEnd = annotation.lineEnd; - var charEnd = annotation.charEnd; - var description = annotation.description; - - var annotationLabel = getTooltipAnnotationLabel(description, severity); - makeMarkText(severity, lineStart, charStart, lineEnd, charEnd, annotationLabel); - - markerTooltipLabel+=annotationLabel; - maxSeverity = getMaxSeverity(maxSeverity, severity); - } - markerTooltipLabel = getTooltipLabel(markerTooltipLabel, multiple); - - - // create a tooltip with the list of annotations - var marker = makeMarker(markerTooltipLabel, maxSeverity, multiple); - - var info = cm.lineInfo(line); - cm.setGutterMarker(line, gutterID, info.gutterMarkers ? null - : marker); - } - } - - return markDocument(); -}; +CodeMirror.validate = function(cm, collectAnnotations, options) { + if (!options) + options = {}; + + var GUTTER_ID = "CodeMirror-lints"; + + // see + // http://sixrevisions.com/tutorials/javascript_tutorial/create_lightweight_javascript_tooltip/ + var tooltip = function() { + var id = 'tt'; + var top = 3; + var left = 3; + var maxw = 600; + var speed = 10; + var timer = 20; + var endalpha = 95; + var alpha = 0; + var tt, c, h; + var ie = document.all ? true : false; + return { + show : function(v, w) { + if (tt == null) { + tt = document.createElement('div'); + tt.setAttribute('id', id); + tt.className = 'textviewTooltip'; + //t = document.createElement('div'); + //t.setAttribute('id', id + 'top'); + c = document.createElement('div'); + c.setAttribute('id', id + 'cont'); + //b = document.createElement('div'); + //b.setAttribute('id', id + 'bot'); + //tt.appendChild(t); + tt.appendChild(c); + //tt.appendChild(b); + document.body.appendChild(tt); + tt.style.opacity = 0; + tt.style.filter = 'alpha(opacity=0)'; + document.onmousemove = this.pos; + } + tt.style.display = 'block'; + c.innerHTML = v; + tt.style.width = w ? w + 'px' : 'auto'; + if (!w && ie) { + //t.style.display = 'none'; + //b.style.display = 'none'; + tt.style.width = tt.offsetWidth; + //t.style.display = 'block'; + //b.style.display = 'block'; + } + if (tt.offsetWidth > maxw) { + tt.style.width = maxw + 'px'; + } + h = parseInt(tt.offsetHeight) + top; + clearInterval(tt.timer); + tt.timer = setInterval(function() { + tooltip.fade(1); + }, timer); + }, + pos : function(e) { + var u = ie ? event.clientY + document.documentElement.scrollTop + : e.pageY; + var l = ie ? event.clientX + + document.documentElement.scrollLeft : e.pageX; + tt.style.top = (u - h) + 'px'; + tt.style.left = (l + left) + 'px'; + }, + fade : function(d) { + var a = alpha; + if ((a != endalpha && d == 1) || (a != 0 && d == -1)) { + var i = speed; + if (endalpha - a < speed && d == 1) { + i = endalpha - a; + } else if (alpha < speed && d == -1) { + i = a; + } + alpha = a + (i * d); + tt.style.opacity = alpha * .01; + tt.style.filter = 'alpha(opacity=' + alpha + ')'; + } else { + clearInterval(tt.timer); + if (d == -1) { + tt.style.display = 'none'; + } else if (d == 1) { + tt.style.opacity = 1; + tt.style.filter = 'alpha(opacity=100)'; + } + } + }, + hide : function() { + clearInterval(tt.timer); + tt.timer = setInterval(function() { + tooltip.fade(-1); + }, timer); + } + }; + }(); + + function SyntaxErrorHighlightState() { + this.marked = []; + } + function getSyntaxErrorHighlightState(cm) { + return cm._syntaxErrorHighlightState + || (cm._syntaxErrorHighlightState = new SyntaxErrorHighlightState()); + } + + function clearMarks(cm, gutterID) { + cm.clearGutter(gutterID); + var state = getSyntaxErrorHighlightState(cm); + for ( var i = 0; i < state.marked.length; ++i) + state.marked[i].clear(); + state.marked = []; + } + + function makeMarker(tooltipLabel, maxSeverity, multiple) { + + var marker = document.createElement("div"); + marker.onmouseover = function() { + tooltip.show(tooltipLabel, null, maxSeverity); + }; + marker.onmouseout = function() { + tooltip.hide(); + }; + marker.className = 'annotation ' + maxSeverity; + + var markerHTML= document.createElement("div"); + markerHTML.className = 'annotationHTML ' + maxSeverity; + marker.appendChild(markerHTML); + + if (multiple) { + var markerHTML= document.createElement("div"); + markerHTML.className = 'annotationHTML overlay'; + marker.appendChild(markerHTML); + } + + return marker; + } + + var AnnotationsCollector = function() { + this.linesNumber = []; + this.linesAnnotations = []; + }; + + AnnotationsCollector.prototype.addAnnotation = function(severity, + lineStart, charStart, lineEnd, charEnd, description) { + + var annotation = { + "severity" : severity, + "lineStart" : lineStart, + "charStart" : charStart, + "lineEnd" : lineEnd, + "charEnd" : charEnd, + "description" : description + }; + var annotations = this.linesAnnotations[lineStart]; + if (!annotations) { + annotations = []; + this.linesAnnotations[lineStart] = annotations; + this.linesNumber.push(lineStart); + } + annotations.push(annotation); + }; + + function getMaxSeverity(severity1, severity2) { + // TODO : should be improved to extend severity (today just error and + // warning are managed) + if (severity1 == 'error') { + return severity1; + } + return severity2; + } + + function getTooltipLabel(content, multiple) { + var label = '
    '; + if (multiple) { + label += '
    Multiple Annotations
    '; + } + label += '
    '; + label += content; + label += '
    '; + label += '
    '; + return label; + } + + function getTooltipAnnotationLabel(description, severity) { + var label = '
    '; + label += '
    '; + label += '
    '; + label += ' '; + label += description; + label += ''; + label += '
    '; + return label; + } + + function makeMarkText(severity, lineStart, charStart, lineEnd, charEnd, annotationLabel) { + var markClass = 'annotationRange ' + severity; + var mark = cm.markText({ + line : lineStart, + ch : charStart + }, { + line : lineEnd, + ch : charEnd + }, { + className : markClass, + readOnly : false + }); + + // save mark text in an array which is used to clean mark + var state = getSyntaxErrorHighlightState(cm); + state.marked.push(mark); + + var _tooltipLabel = getTooltipLabel(annotationLabel, false); + // TODO : add tooltip for mark text. How to manage that??? + // I would like do like this + /*mark.onmouseover = function() { + tooltip.show(tooltipLabel, null, severity); + }; + mark.onmouseout = function() { + tooltip.hide(); + };*/ + } + + function markDocument() { + var gutterID = GUTTER_ID; + clearMarks(cm, gutterID); + + var collector = new AnnotationsCollector(); + + var contents = (options.getContents ? options.getContents() : cm + .getValue()); + collectAnnotations(contents, collector, cm); + + var linesNumber = collector.linesNumber; + // Loop for each lines number which contains problems + for ( var i = 0; i < linesNumber.length; i++) { + var line = linesNumber[i]; + var annotations = collector.linesAnnotations[line]; + + // loop for each annotations for the current line to + // - create a markText for each annotations + // - create a tooltip with the list of annotations + + var maxSeverity = null; + var markerTooltipLabel = ''; + var multiple = annotations.length > 1; + + // create a markText for each annotations + for ( var j = 0; j < annotations.length; j++) { + var annotation = annotations[j]; + if (options.formatAnnotation) { + annotation = options.formatAnnotation(annotation); + } + + // Create mark text + + var severity = annotation.severity; + var lineStart = annotation.lineStart; + var charStart = annotation.charStart; + var lineEnd = annotation.lineEnd; + var charEnd = annotation.charEnd; + var description = annotation.description; + + var annotationLabel = getTooltipAnnotationLabel(description, severity); + makeMarkText(severity, lineStart, charStart, lineEnd, charEnd, annotationLabel); + + markerTooltipLabel+=annotationLabel; + maxSeverity = getMaxSeverity(maxSeverity, severity); + } + markerTooltipLabel = getTooltipLabel(markerTooltipLabel, multiple); + + + // create a tooltip with the list of annotations + var marker = makeMarker(markerTooltipLabel, maxSeverity, multiple); + + var info = cm.lineInfo(line); + cm.setGutterMarker(line, gutterID, info.gutterMarkers ? null + : marker); + } + } + + return markDocument(); +}; diff --git a/demo/jsonlint.html b/demo/jsonlint.html deleted file mode 100644 index 39e90b266a..0000000000 --- a/demo/jsonlint.html +++ /dev/null @@ -1,75 +0,0 @@ - - - - - CodeMirror: JSON Lint Demo - - - - - - - - - - - - - - - -

    CodeMirror: JSON Lint Demo

    - - - - -

    This demo runs JSONLint over the code -in the editor and use CodeMirror Lint to display the warnings that JSONLint comes up with.

    - - diff --git a/demo/javascriptlint.html b/demo/lint.html similarity index 60% rename from demo/javascriptlint.html rename to demo/lint.html index de89fbb465..35f2156623 100644 --- a/demo/javascriptlint.html +++ b/demo/lint.html @@ -2,25 +2,26 @@ - CodeMirror: Javascript Lint Demo + CodeMirror: Linter Demo + - - - - + + + + -

    CodeMirror: Javascript Lint Demo

    +

    CodeMirror: Linter Demo

    - +

    + +

    -

    This demo runs JSHint over the code -in the editor and use CodeMirror Lint to display the warnings that JSHint comes up with.

    + diff --git a/doc/compress.html b/doc/compress.html index 0f5926fe60..521e6e865a 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -156,6 +156,9 @@

    { } CodeMi + + + diff --git a/lib/codemirror-lint.css b/lib/codemirror-lint.css deleted file mode 100644 index c251c973ed..0000000000 --- a/lib/codemirror-lint.css +++ /dev/null @@ -1,85 +0,0 @@ -.annotationRange { - background-position: left bottom; - background-repeat: repeat-x; -} - -.annotationRange.error { - background-image: - url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") - ; -} - -.annotationRange.warning { - /* images/squiggly_warning.png */ - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); -} - -.annotationHTML { - background-position: center center; - background-repeat: no-repeat; - cursor: pointer; - display: inline-block; - height: 16px; - vertical-align: middle; - width: 16px; -} - -.annotationHTML.error { - background-image: - url("data:image/gif;base64,R0lGODlhEAAQANUAAPVvcvWHiPVucvRuc+ttcfV6f91KVN5LU99PV/FZY/JhaM4oN84pONE4Rd1ATfJLWutVYPRgbdxpcsgWKMgZKs4lNfE/UvE/U+artcpdSc5uXveimslHPuBhW/eJhfV5efaCgO2CgP+/v+PExP///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAQABAAAAZ+wJJwSCwaScgkySgkjTQZTkYzWhadnE5oE+pwqkSshwQqkzxfa4kkQXxEpA9J9EFI1KQGQQBAigYCBA14ExEWF0gXihETeA0QD3AkD5QQg0NsDnAJmwkOd5gYFSQKpXAFDBhqaxgLBwQBBAapq00YEg0UDRKqTGtKSL7Cw8JBADs=") - ; -} - -.annotationHTML.warning { - /* images/warning.gif */ - background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAP7bc//egf/ij/7ijv/jl/7kl//mnv7lnv/uwf7CTP7DTf7DT/7IW//Na/7Na//NbP7QdP/dmbltAIJNAF03AMSAJMSCLKqASa2DS6uBSquCSrGHTq6ETbCHT7WKUrKIUcCVXL+UXMOYX8GWXsSZYMiib6+ETbOIUcOXX86uhd3Muf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACsALAAAAAAQABAAAAZowJVwSCwaj0ihikRSJYcoBEL0XKlGkcjImQQhJBREKFnyICoThKeE/AAW6AXgdPyUAgrLJBEo0YsbAQyDhAEdRRwDDw8OaA4NDQImRBgFEJdglxAEGEQZKQcHBqOkKRpFF6mqq1WtrUEAOw=="); -} - -/* Styles for the overview ruler */ -.annotationOverview { - cursor: pointer; - border-radius: 2px; - left: 2px; - width: 8px; -} -.annotationOverview.error { - background-color: lightcoral; - border: 1px solid darkred; -} -.annotationOverview.warning { - background-color: Gold; - border: 1px solid black; -} - -.annotationHTML.overlay { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEAQvB2JVdrAAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAD1JREFUCNdtjkESADAEAzemf69f66HMqGlOIhYiFRFRtSQBWAY7mzx+EDTL6sSgb1jTk7Q87rxyqe37fXsAa78gLyZnRgEAAAAASUVORK5CYII="); - background-position: right bottom; - position: relative; - top: -16px; -} - -.CodeMirror-lints { - width: 16px; -} - -.textviewTooltip { - background-color: infobackground; - border: 1px solid black; - border-radius: 4px 4px 4px 4px; - color: infotext; - font-family: monospace; - font-size: 10pt; - overflow: hidden; - padding: 2px; - position: fixed; - white-space: pre; - z-index: 100; -} - -#ttcont { - //display: block; - //padding: 2px 12px 3px 7px; - margin-left: 5px; -// background: #666; -// color: #fff; -} \ No newline at end of file From 0bcee7c52d7813f2f53c87ee8ece004ec2f1de34 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 18 Feb 2013 12:25:37 +0100 Subject: [PATCH 0237/5273] WIP --- addon/lint/json-lint.js | 32 ++-- addon/lint/lint.css | 71 ++++----- addon/lint/lint.js | 319 ++++++++++------------------------------ demo/lint.html | 8 +- 4 files changed, 133 insertions(+), 297 deletions(-) diff --git a/addon/lint/json-lint.js b/addon/lint/json-lint.js index d3c4c756ee..bbab508e98 100644 --- a/addon/lint/json-lint.js +++ b/addon/lint/json-lint.js @@ -1,20 +1,14 @@ -(function() { - - CodeMirror.jsonValidator = function(contents, collector) { - jsonlint.parseError = function(str, hash) { - var severity = 'error'; - var loc = hash.loc; - var lineStart = loc.first_line - 1; - var lineEnd = hash.line;// loc.last_line - 1; - var charStart = loc.first_column; - var charEnd = loc.last_column; - - collector.addAnnotation(severity, lineStart, charStart, - lineEnd, charEnd, str); - - }; - try { jsonlint.parse(contents); } - catch(e) {} +// Depends on jsonlint.js from https://github.com/zaach/jsonlint + +CodeMirror.jsonValidator = function(cm) { + var found = []; + jsonlint.parseError = function(str, hash) { + var loc = hash.loc; + found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column), + to: CodeMirror.Pos(loc.last_line - 1, loc.last_column), + message: str}); }; - -})(); + try { jsonlint.parse(cm.getValue()); } + catch(e) {} + return found; +}; diff --git a/addon/lint/lint.css b/addon/lint/lint.css index 98e883266f..d508f5cb78 100644 --- a/addon/lint/lint.css +++ b/addon/lint/lint.css @@ -1,41 +1,63 @@ -.annotationRange { +/* The lint marker gutter */ +.CodeMirror-lint-markers { + width: 16px; +} + +.CodeMirror-lint-tooltip { + background-color: infobackground; + border: 1px solid black; + border-radius: 4px 4px 4px 4px; + color: infotext; + font-family: monospace; + font-size: 10pt; + overflow: hidden; + padding: 2px 5px; + position: fixed; + white-space: pre; + z-index: 100; + max-width: 600px; + opacity: 0; + transition: opacity .4s; + -moz-transition: opacity .4s; + -webkit-transition: opacity .4s; + -o-transition: opacity .4s; + -ms-transition: opacity .4s; +} + +.CodeMirror-lint { background-position: left bottom; background-repeat: repeat-x; } -.annotationRange.error { +.CodeMirror-lint-error { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") ; } -.annotationRange.warning { +.CodeMirror-lint-warning { /* images/squiggly_warning.png */ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); } -.annotationHTML { +.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { background-position: center center; background-repeat: no-repeat; cursor: pointer; display: inline-block; height: 16px; - vertical-align: middle; width: 16px; + vertical-align: middle; } -.annotationHTML.error { - background-image: - url("data:image/gif;base64,R0lGODlhEAAQANUAAPVvcvWHiPVucvRuc+ttcfV6f91KVN5LU99PV/FZY/JhaM4oN84pONE4Rd1ATfJLWutVYPRgbdxpcsgWKMgZKs4lNfE/UvE/U+artcpdSc5uXveimslHPuBhW/eJhfV5efaCgO2CgP+/v+PExP///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAQABAAAAZ+wJJwSCwaScgkySgkjTQZTkYzWhadnE5oE+pwqkSshwQqkzxfa4kkQXxEpA9J9EFI1KQGQQBAigYCBA14ExEWF0gXihETeA0QD3AkD5QQg0NsDnAJmwkOd5gYFSQKpXAFDBhqaxgLBwQBBAapq00YEg0UDRKqTGtKSL7Cw8JBADs=") - ; +.CodeMirror-lint-marker-error { + background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAPVvcvWHiPVucvRuc+ttcfV6f91KVN5LU99PV/FZY/JhaM4oN84pONE4Rd1ATfJLWutVYPRgbdxpcsgWKMgZKs4lNfE/UvE/U+artcpdSc5uXveimslHPuBhW/eJhfV5efaCgO2CgP+/v+PExP///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAQABAAAAZ+wJJwSCwaScgkySgkjTQZTkYzWhadnE5oE+pwqkSshwQqkzxfa4kkQXxEpA9J9EFI1KQGQQBAigYCBA14ExEWF0gXihETeA0QD3AkD5QQg0NsDnAJmwkOd5gYFSQKpXAFDBhqaxgLBwQBBAapq00YEg0UDRKqTGtKSL7Cw8JBADs="); } -.annotationHTML.warning { - /* images/warning.gif */ +.CodeMirror-lint-marker-warning { background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAP7bc//egf/ij/7ijv/jl/7kl//mnv7lnv/uwf7CTP7DTf7DT/7IW//Na/7Na//NbP7QdP/dmbltAIJNAF03AMSAJMSCLKqASa2DS6uBSquCSrGHTq6ETbCHT7WKUrKIUcCVXL+UXMOYX8GWXsSZYMiib6+ETbOIUcOXX86uhd3Muf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACsALAAAAAAQABAAAAZowJVwSCwaj0ihikRSJYcoBEL0XKlGkcjImQQhJBREKFnyICoThKeE/AAW6AXgdPyUAgrLJBEo0YsbAQyDhAEdRRwDDw8OaA4NDQImRBgFEJdglxAEGEQZKQcHBqOkKRpFF6mqq1WtrUEAOw=="); } - -/* Styles for the overview ruler */ +/* Styles for the overview ruler .annotationOverview { cursor: pointer; border-radius: 2px; @@ -57,25 +79,4 @@ position: relative; top: -16px; } - -.CodeMirror-lints { - width: 16px; -} - -.textviewTooltip { - background-color: infobackground; - border: 1px solid black; - border-radius: 4px 4px 4px 4px; - color: infotext; - font-family: monospace; - font-size: 10pt; - overflow: hidden; - padding: 2px; - position: fixed; - white-space: pre; - z-index: 100; -} - -#ttcont { - margin-left: 5px; -} +*/ \ No newline at end of file diff --git a/addon/lint/lint.js b/addon/lint/lint.js index a2713efcce..8db5d4624b 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -1,282 +1,123 @@ -CodeMirror.validate = function(cm, collectAnnotations, options) { +CodeMirror.validate = function(cm, getAnnotations, options) { if (!options) options = {}; - var GUTTER_ID = "CodeMirror-lints"; + var GUTTER_ID = "CodeMirror-lint-markers"; + var SEVERITIES = /^(?:error|warning)$/; - // see - // http://sixrevisions.com/tutorials/javascript_tutorial/create_lightweight_javascript_tooltip/ var tooltip = function() { - var id = 'tt'; - var top = 3; - var left = 3; - var maxw = 600; - var speed = 10; - var timer = 20; - var endalpha = 95; - var alpha = 0; - var tt, c, h; - var ie = document.all ? true : false; + var tt; return { - show : function(v, w) { + show: function(nodes, e) { if (tt == null) { - tt = document.createElement('div'); - tt.setAttribute('id', id); - tt.className = 'textviewTooltip'; - //t = document.createElement('div'); - //t.setAttribute('id', id + 'top'); - c = document.createElement('div'); - c.setAttribute('id', id + 'cont'); - //b = document.createElement('div'); - //b.setAttribute('id', id + 'bot'); - //tt.appendChild(t); - tt.appendChild(c); - //tt.appendChild(b); + tt = document.createElement("div"); + tt.className = "CodeMirror-lint-tooltip"; document.body.appendChild(tt); - tt.style.opacity = 0; - tt.style.filter = 'alpha(opacity=0)'; - document.onmousemove = this.pos; + CodeMirror.on(document, "mousemove", this.pos); + this.pos(e); } - tt.style.display = 'block'; - c.innerHTML = v; - tt.style.width = w ? w + 'px' : 'auto'; - if (!w && ie) { - //t.style.display = 'none'; - //b.style.display = 'none'; - tt.style.width = tt.offsetWidth; - //t.style.display = 'block'; - //b.style.display = 'block'; - } - if (tt.offsetWidth > maxw) { - tt.style.width = maxw + 'px'; - } - h = parseInt(tt.offsetHeight) + top; - clearInterval(tt.timer); - tt.timer = setInterval(function() { - tooltip.fade(1); - }, timer); + tt.style.display = "block"; + tt.appendChild(nodes); + this.fade(true); }, - pos : function(e) { - var u = ie ? event.clientY + document.documentElement.scrollTop - : e.pageY; - var l = ie ? event.clientX - + document.documentElement.scrollLeft : e.pageX; - tt.style.top = (u - h) + 'px'; - tt.style.left = (l + left) + 'px'; + pos: function(e) { + if (tt.style.display == "none") return; + + var u = event.pageY, l = event.pageX; + if (u == null) { + u = event.clientY + document.documentElement.scrollTop; + l = event.clientX + document.documentElement.scrollLeft; + } + tt.style.top = (u - tt.offsetHeight - 5) + "px"; + tt.style.left = (l + 5) + "px"; }, - fade : function(d) { - var a = alpha; - if ((a != endalpha && d == 1) || (a != 0 && d == -1)) { - var i = speed; - if (endalpha - a < speed && d == 1) { - i = endalpha - a; - } else if (alpha < speed && d == -1) { - i = a; - } - alpha = a + (i * d); - tt.style.opacity = alpha * .01; - tt.style.filter = 'alpha(opacity=' + alpha + ')'; - } else { - clearInterval(tt.timer); - if (d == -1) { - tt.style.display = 'none'; - } else if (d == 1) { - tt.style.opacity = 1; - tt.style.filter = 'alpha(opacity=100)'; - } - } + fade: function(show) { + if (!show) setTimeout(function() { + if (tt.style.opacity == "0") tt.style.display = "none"; + }, 600); + else tt.style.display = ""; + tt.style.opacity = show ? 1 : 0; }, - hide : function() { - clearInterval(tt.timer); - tt.timer = setInterval(function() { - tooltip.fade(-1); - }, timer); - } + hide: function() { this.fade(false); } }; }(); - function SyntaxErrorHighlightState() { + function LintState() { this.marked = []; } - function getSyntaxErrorHighlightState(cm) { - return cm._syntaxErrorHighlightState - || (cm._syntaxErrorHighlightState = new SyntaxErrorHighlightState()); + function getLintState(cm) { + return cm._lintState || (cm._lintState = new LintState()); } - function clearMarks(cm, gutterID) { - cm.clearGutter(gutterID); - var state = getSyntaxErrorHighlightState(cm); - for ( var i = 0; i < state.marked.length; ++i) + function clearMarks(cm, state) { + if (options.gutterMarkers) cm.clearGutter(GUTTER_ID); + for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear(); - state.marked = []; + state.marked.length = 0; } - function makeMarker(tooltipLabel, maxSeverity, multiple) { - + function makeMarker(labels, severity) { var marker = document.createElement("div"); - marker.onmouseover = function() { - tooltip.show(tooltipLabel, null, maxSeverity); - }; - marker.onmouseout = function() { + marker.className = "CodeMirror-lint-marker-" + severity; + + CodeMirror.on(marker, "mouseover", function(e) { + tooltip.show(labels, e); + }); + CodeMirror.on(marker, "mouseout", function(e) { tooltip.hide(); - }; - marker.className = 'annotation ' + maxSeverity; - - var markerHTML= document.createElement("div"); - markerHTML.className = 'annotationHTML ' + maxSeverity; - marker.appendChild(markerHTML); - - if (multiple) { - var markerHTML= document.createElement("div"); - markerHTML.className = 'annotationHTML overlay'; - marker.appendChild(markerHTML); - } - + }); + return marker; } - var AnnotationsCollector = function() { - this.linesNumber = []; - this.linesAnnotations = []; - }; - - AnnotationsCollector.prototype.addAnnotation = function(severity, - lineStart, charStart, lineEnd, charEnd, description) { - - var annotation = { - "severity" : severity, - "lineStart" : lineStart, - "charStart" : charStart, - "lineEnd" : lineEnd, - "charEnd" : charEnd, - "description" : description - }; - var annotations = this.linesAnnotations[lineStart]; - if (!annotations) { - annotations = []; - this.linesAnnotations[lineStart] = annotations; - this.linesNumber.push(lineStart); - } - annotations.push(annotation); - }; - - function getMaxSeverity(severity1, severity2) { - // TODO : should be improved to extend severity (today just error and - // warning are managed) - if (severity1 == 'error') { - return severity1; - } - return severity2; + function getMaxSeverity(a, b) { + if (a == "error") return a; + else return b; } - - function getTooltipLabel(content, multiple) { - var label = '
    '; - if (multiple) { - label += '
    Multiple Annotations
    '; + + function groupByLine(annotations) { + var lines = []; + for (var i = 0; i < annotations.length; ++i) { + var ann = annotations[i], line = ann.from.line; + (lines[line] || (lines[line] = [])).push(ann); } - label += '
    '; - label += content; - label += '
    '; - label += '
    '; - return label; - } - - function getTooltipAnnotationLabel(description, severity) { - var label = '
    '; - label += '
    '; - label += '
    '; - label += ' '; - label += description; - label += ''; - label += '
    '; - return label; - } - - function makeMarkText(severity, lineStart, charStart, lineEnd, charEnd, annotationLabel) { - var markClass = 'annotationRange ' + severity; - var mark = cm.markText({ - line : lineStart, - ch : charStart - }, { - line : lineEnd, - ch : charEnd - }, { - className : markClass, - readOnly : false - }); - - // save mark text in an array which is used to clean mark - var state = getSyntaxErrorHighlightState(cm); - state.marked.push(mark); - - var _tooltipLabel = getTooltipLabel(annotationLabel, false); - // TODO : add tooltip for mark text. How to manage that??? - // I would like do like this - /*mark.onmouseover = function() { - tooltip.show(tooltipLabel, null, severity); - }; - mark.onmouseout = function() { - tooltip.hide(); - };*/ + return lines; } - function markDocument() { - var gutterID = GUTTER_ID; - clearMarks(cm, gutterID); + function markDocument(cm) { + var state = getLintState(cm); + clearMarks(cm, state); - var collector = new AnnotationsCollector(); + var annotations = groupByLine(getAnnotations(cm)); - var contents = (options.getContents ? options.getContents() : cm - .getValue()); - collectAnnotations(contents, collector, cm); + for (var line = 0; line < annotations.length; ++line) { + var anns = annotations[line]; + if (!anns) continue; - var linesNumber = collector.linesNumber; - // Loop for each lines number which contains problems - for ( var i = 0; i < linesNumber.length; i++) { - var line = linesNumber[i]; - var annotations = collector.linesAnnotations[line]; - - // loop for each annotations for the current line to - // - create a markText for each annotations - // - create a tooltip with the list of annotations + var maxSeverity = null, tipLabel = document.createDocumentFragment(); - var maxSeverity = null; - var markerTooltipLabel = ''; - var multiple = annotations.length > 1; - - // create a markText for each annotations - for ( var j = 0; j < annotations.length; j++) { - var annotation = annotations[j]; - if (options.formatAnnotation) { - annotation = options.formatAnnotation(annotation); - } + for (var i = 0; i < anns.length; ++i) { + var ann = anns[i]; + var severity = ann.severity; + if (!SEVERITIES.test(severity)) severity = "error"; + maxSeverity = getMaxSeverity(maxSeverity, severity); - // Create mark text - - var severity = annotation.severity; - var lineStart = annotation.lineStart; - var charStart = annotation.charStart; - var lineEnd = annotation.lineEnd; - var charEnd = annotation.charEnd; - var description = annotation.description; + if (options.formatAnnotation) ann = options.formatAnnotation(ann); - var annotationLabel = getTooltipAnnotationLabel(description, severity); - makeMarkText(severity, lineStart, charStart, lineEnd, charEnd, annotationLabel); - - markerTooltipLabel+=annotationLabel; - maxSeverity = getMaxSeverity(maxSeverity, severity); - } - markerTooltipLabel = getTooltipLabel(markerTooltipLabel, multiple); + var label = document.createElement("div"); + label.className = "CodeMirror-hint-message-" + severity; + label.appendChild(document.createTextNode(ann.message)); + tipLabel.appendChild(label); - - // create a tooltip with the list of annotations - var marker = makeMarker(markerTooltipLabel, maxSeverity, multiple); + if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { + className: "CodeMirror-lint CodeMirror-lint-" + severity + })); + } - var info = cm.lineInfo(line); - cm.setGutterMarker(line, gutterID, info.gutterMarkers ? null - : marker); + if (options.gutterMarkers !== false) + cm.setGutterMarker(i, GUTTER_ID, makeMarker(tipLabel, maxSeverity)); } } - return markDocument(); + return markDocument(cm); }; diff --git a/demo/lint.html b/demo/lint.html index 35f2156623..1b66c7f468 100644 --- a/demo/lint.html +++ b/demo/lint.html @@ -77,9 +77,9 @@

    CodeMirror: Linter Demo

    var editor = CodeMirror.fromTextArea(document.getElementById("code-js"), { lineNumbers: true, mode: "javascript", - gutters: ["CodeMirror-lints"] + gutters: ["CodeMirror-lint-markers"] }); - +/* var validate = function() { CodeMirror.validate(editor, CodeMirror.javascriptValidator); }; @@ -89,13 +89,13 @@

    CodeMirror: Linter Demo

    waiting = setTimeout(validate, 500); }); - setTimeout(validate, 100); + setTimeout(validate, 100);*/ var editor2 = CodeMirror.fromTextArea(document.getElementById("code-json"), { lineNumbers: true, mode: "application/json", - gutters: ["CodeMirror-lints"] + gutters: ["CodeMirror-lint-markers"] }); var validate2 = function() { From 5a5d7c570008a8b18cc95b5ad3096bba46f4ade0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 18 Feb 2013 14:18:59 +0100 Subject: [PATCH 0238/5273] [linter addon] Rewrite. Make tooltips on text work --- addon/lint/javascript-lint.js | 40 +++---- addon/lint/lint.css | 26 +++-- addon/lint/lint.js | 189 +++++++++++++++++++++------------- demo/lint.html | 39 ++----- 4 files changed, 158 insertions(+), 136 deletions(-) diff --git a/addon/lint/javascript-lint.js b/addon/lint/javascript-lint.js index e3f84b857a..2200bba3e4 100644 --- a/addon/lint/javascript-lint.js +++ b/addon/lint/javascript-lint.js @@ -9,20 +9,13 @@ "Unmatched ", " and instead saw", " is not defined", "Unclosed string", "Stopping, unable to continue" ]; - CodeMirror.javascriptValidator = function(contents, collector) { - var positionalAdjustment = 1; - var result = jshint(contents); - var errors = result.errors; - if (errors) { - parseErrors(errors, positionalAdjustment, collector); - } + CodeMirror.javascriptValidator = function(cm) { + JSHINT(cm.getValue()); + var errors = JSHINT.data().errors, result = []; + if (errors) parseErrors(errors, result); + return result; }; - function jshint(contents) { - JSHINT(contents/* , localConfig.options, localConfig.options.predef */); - return JSHINT.data(); - } - function cleanup(error) { // All problems are warnings by default fixWith(error, warnings, "warning", true); @@ -61,7 +54,7 @@ return false; } - function parseErrors(errors, positionalAdjustment, collector) { + function parseErrors(errors, output) { for ( var i = 0; i < errors.length; i++) { var error = errors[i]; if (error) { @@ -97,9 +90,7 @@ if (tabpositions.length > 0) { var pos = error.character; tabpositions.forEach(function(tabposition) { - if (pos > tabposition) { - pos -= positionalAdjustment; - } + if (pos > tabposition) pos -= 1; }); error.character = pos; } @@ -119,18 +110,11 @@ error.end = end; error = cleanup(error); - if (error) { - var severity = error.severity; - var lineStart = error.line - 1; - var charStart = start; - var lineEnd = error.line - 1; - var charEnd = end; - var description = error.description; - - collector.addAnnotation(severity, lineStart, charStart, - lineEnd, charEnd, description); - - } + if (error) + output.push({message: error.description, + severity: error.severity, + from: CodeMirror.Pos(error.line - 1, start), + to: CodeMirror.Pos(error.line - 1, end)}); } } } diff --git a/addon/lint/lint.css b/addon/lint/lint.css index d508f5cb78..4fd72e774a 100644 --- a/addon/lint/lint.css +++ b/addon/lint/lint.css @@ -24,19 +24,18 @@ -ms-transition: opacity .4s; } -.CodeMirror-lint { +.CodeMirror-lint-span-error, .CodeMirror-lint-span-warning { background-position: left bottom; background-repeat: repeat-x; } -.CodeMirror-lint-error { +.CodeMirror-lint-span-error { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") ; } -.CodeMirror-lint-warning { - /* images/squiggly_warning.png */ +.CodeMirror-lint-span-warning { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); } @@ -48,15 +47,30 @@ height: 16px; width: 16px; vertical-align: middle; + position: relative; } -.CodeMirror-lint-marker-error { +.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { + padding-left: 18px; + background-position: top left; + background-repeat: no-repeat; +} + +.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAPVvcvWHiPVucvRuc+ttcfV6f91KVN5LU99PV/FZY/JhaM4oN84pONE4Rd1ATfJLWutVYPRgbdxpcsgWKMgZKs4lNfE/UvE/U+artcpdSc5uXveimslHPuBhW/eJhfV5efaCgO2CgP+/v+PExP///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAQABAAAAZ+wJJwSCwaScgkySgkjTQZTkYzWhadnE5oE+pwqkSshwQqkzxfa4kkQXxEpA9J9EFI1KQGQQBAigYCBA14ExEWF0gXihETeA0QD3AkD5QQg0NsDnAJmwkOd5gYFSQKpXAFDBhqaxgLBwQBBAapq00YEg0UDRKqTGtKSL7Cw8JBADs="); } -.CodeMirror-lint-marker-warning { +.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAP7bc//egf/ij/7ijv/jl/7kl//mnv7lnv/uwf7CTP7DTf7DT/7IW//Na/7Na//NbP7QdP/dmbltAIJNAF03AMSAJMSCLKqASa2DS6uBSquCSrGHTq6ETbCHT7WKUrKIUcCVXL+UXMOYX8GWXsSZYMiib6+ETbOIUcOXX86uhd3Muf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACsALAAAAAAQABAAAAZowJVwSCwaj0ihikRSJYcoBEL0XKlGkcjImQQhJBREKFnyICoThKeE/AAW6AXgdPyUAgrLJBEo0YsbAQyDhAEdRRwDDw8OaA4NDQImRBgFEJdglxAEGEQZKQcHBqOkKRpFF6mqq1WtrUEAOw=="); } + +.CodeMirror-lint-marker-multiple { + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEAQvB2JVdrAAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAD1JREFUCNdtjkESADAEAzemf69f66HMqGlOIhYiFRFRtSQBWAY7mzx+EDTL6sSgb1jTk7Q87rxyqe37fXsAa78gLyZnRgEAAAAASUVORK5CYII="); + background-repeat: no-repeat; + background-position: right bottom; + width: 100%; height: 100%; +} + /* Styles for the overview ruler .annotationOverview { cursor: pointer; diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 8db5d4624b..d59478aab0 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -1,71 +1,66 @@ -CodeMirror.validate = function(cm, getAnnotations, options) { - if (!options) - options = {}; - +CodeMirror.validate = (function() { var GUTTER_ID = "CodeMirror-lint-markers"; var SEVERITIES = /^(?:error|warning)$/; - var tooltip = function() { - var tt; - return { - show: function(nodes, e) { - if (tt == null) { - tt = document.createElement("div"); - tt.className = "CodeMirror-lint-tooltip"; - document.body.appendChild(tt); - CodeMirror.on(document, "mousemove", this.pos); - this.pos(e); - } - tt.style.display = "block"; - tt.appendChild(nodes); - this.fade(true); - }, - pos: function(e) { - if (tt.style.display == "none") return; - - var u = event.pageY, l = event.pageX; - if (u == null) { - u = event.clientY + document.documentElement.scrollTop; - l = event.clientX + document.documentElement.scrollLeft; - } - tt.style.top = (u - tt.offsetHeight - 5) + "px"; - tt.style.left = (l + 5) + "px"; - }, - fade: function(show) { - if (!show) setTimeout(function() { - if (tt.style.opacity == "0") tt.style.display = "none"; - }, 600); - else tt.style.display = ""; - tt.style.opacity = show ? 1 : 0; - }, - hide: function() { this.fade(false); } - }; - }(); - - function LintState() { + function showTooltip(e, content) { + var tt = document.createElement("div"); + tt.className = "CodeMirror-lint-tooltip"; + tt.appendChild(content.cloneNode(true)); + document.body.appendChild(tt); + + function position(e) { + if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); + tt.style.top = (e.clientY - tt.offsetHeight - 5) + "px"; + tt.style.left = (e.clientX + 5) + "px"; + } + CodeMirror.on(document, "mousemove", position); + position(e); + tt.style.opacity = 1; + return tt; + } + function rm(elt) { + if (elt.parentNode) elt.parentNode.removeChild(elt); + } + function hideTooltip(tt) { + if (!tt.parentNode) return; + if (tt.style.opacity == null) rm(tt); + tt.style.opacity = 0; + setTimeout(function() { rm(tt); }, 600); + } + + function LintState(cm, options, hasGutter) { this.marked = []; + this.options = options; + this.timeout = null; + this.hasGutter = hasGutter; + this.onMouseOver = function(e) { onMouseOver(cm, e); }; } - function getLintState(cm) { - return cm._lintState || (cm._lintState = new LintState()); + + function parseOptions(options) { + if (options instanceof Function) return {getAnnotations: options}; + else if (!options || !options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)"); + return options; } - function clearMarks(cm, state) { - if (options.gutterMarkers) cm.clearGutter(GUTTER_ID); + function clearMarks(cm) { + var state = cm._lintState; + if (state.hasGutter) cm.clearGutter(GUTTER_ID); for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear(); state.marked.length = 0; } - function makeMarker(labels, severity) { - var marker = document.createElement("div"); + function makeMarker(labels, severity, multiple) { + var marker = document.createElement("div"), inner = marker; marker.className = "CodeMirror-lint-marker-" + severity; + if (multiple) { + inner = marker.appendChild(document.createElement("div")); + inner.className = "CodeMirror-lint-marker-multiple"; + } - CodeMirror.on(marker, "mouseover", function(e) { - tooltip.show(labels, e); - }); - CodeMirror.on(marker, "mouseout", function(e) { - tooltip.hide(); - }); + var tooltip; + CodeMirror.on(inner, "mouseover", function(e) { tooltip = showTooltip(e, labels); }); + CodeMirror.on(inner, "mouseout", function() { if (tooltip) hideTooltip(tooltip); }); return marker; } @@ -84,17 +79,27 @@ CodeMirror.validate = function(cm, getAnnotations, options) { return lines; } - function markDocument(cm) { - var state = getLintState(cm); - clearMarks(cm, state); + function annotationTooltip(ann) { + var severity = ann.severity; + if (!SEVERITIES.test(severity)) severity = "error"; + var tip = document.createElement("div"); + tip.className = "CodeMirror-lint-message-" + severity; + tip.appendChild(document.createTextNode(ann.message)); + return tip; + } + + function updateLinting(cm) { + clearMarks(cm); + var state = cm._lintState, options = state.options; - var annotations = groupByLine(getAnnotations(cm)); + var annotations = groupByLine(options.getAnnotations(cm)); for (var line = 0; line < annotations.length; ++line) { var anns = annotations[line]; if (!anns) continue; - var maxSeverity = null, tipLabel = document.createDocumentFragment(); + var maxSeverity = null; + var tipLabel = state.hasGutter && document.createDocumentFragment(); for (var i = 0; i < anns.length; ++i) { var ann = anns[i]; @@ -103,21 +108,67 @@ CodeMirror.validate = function(cm, getAnnotations, options) { maxSeverity = getMaxSeverity(maxSeverity, severity); if (options.formatAnnotation) ann = options.formatAnnotation(ann); - - var label = document.createElement("div"); - label.className = "CodeMirror-hint-message-" + severity; - label.appendChild(document.createTextNode(ann.message)); - tipLabel.appendChild(label); + if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { - className: "CodeMirror-lint CodeMirror-lint-" + severity + className: "CodeMirror-lint-span-" + severity, + __annotation: ann })); } - if (options.gutterMarkers !== false) - cm.setGutterMarker(i, GUTTER_ID, makeMarker(tipLabel, maxSeverity)); + if (state.hasGutter) + cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1)); } } - return markDocument(cm); -}; + function onChange(cm) { + var state = cm._lintState; + clearTimeout(state.timeout); + state.timeout = setTimeout(function(){updateLinting(cm);}, state.options.delay || 500); + } + + function popupSpanTooltip(ann, e) { + var tooltip = showTooltip(e, annotationTooltip(ann)); + var target = e.target || e.srcElement; + CodeMirror.on(target, "mouseout", hide); + function hide() { + CodeMirror.off(target, "mouseout", hide); + hideTooltip(tooltip); + } + } + + // When the mouseover fires, the cursor might not actually be over + // the character itself yet. These pairs of x,y offsets are used to + // probe a few nearby points when no suitable marked range is found. + var nearby = [0, 0, 0, 5, 0, -5, 5, 0, -5, 0]; + + function onMouseOver(cm, e) { + if (!/\bCodeMirror-lint-span-/.test((e.target || e.srcElement).className)) return; + for (var i = 0; i < nearby.length; i += 2) { + var spans = cm.findMarksAt(cm.coordsChar({left: e.clientX + nearby[i], + top: e.clientY + nearby[i + 1]})); + for (var j = 0; j < spans.length; ++j) { + var span = spans[j], ann = span.__annotation; + if (ann) return popupSpanTooltip(ann, e); + } + } + } + + CodeMirror.defineOption("lintWith", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + clearMarks(cm); + cm.off("change", onChange); + CodeMirror.off(cm.getWrapperElement(), "mouseover", cm._lintState.onMouseOver); + delete cm._lintState; + } + + if (val) { + var gutters = cm.getOption("gutters"), hasLintGutter = false; + for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; + var state = cm._lintState = new LintState(cm, parseOptions(val), hasLintGutter); + cm.on("change", onChange); + CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); + updateLinting(cm); + } + }); +})(); diff --git a/demo/lint.html b/demo/lint.html index 1b66c7f468..ece8b1cef7 100644 --- a/demo/lint.html +++ b/demo/lint.html @@ -50,8 +50,7 @@

    CodeMirror: Linter Demo

    From 85893eca60510784d8122824c8e1152fe5546118 Mon Sep 17 00:00:00 2001 From: Matthias BUSSONNIER Date: Sun, 17 Feb 2013 12:36:07 +0100 Subject: [PATCH 0239/5273] [python mode] Make tokenizer regexps configurable --- mode/python/index.html | 11 +++++++++++ mode/python/python.js | 14 +++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/mode/python/index.html b/mode/python/index.html index c1df119485..4244c6fc5a 100644 --- a/mode/python/index.html +++ b/mode/python/index.html @@ -118,6 +118,17 @@

    Configuration Options:

  • version - 2/3 - The version of Python to recognize. Default is 2.
  • singleLineStringErrors - true/false - If you have a single-line string that is not terminated at the end of the line, this will show subsequent lines as errors if true, otherwise it will consider the newline as the end of the string. Default is false.
  • +

    Advanced Configuration Options:

    +

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

    +
      +
    • singleOperators - RegEx - Regular Expression for single operator matching, default :
      ^[\\+\\-\\*/%&|\\^~<>!]
    • +
    • singleDelimiters - RegEx - Regular Expression for single delimiter matching, default :
      ^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]
    • +
    • doubleOperators - RegEx - Regular Expression for double operators matching, default :
      ^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))
    • +
    • doubleDelimiters - RegEx - Regular Expressoin for double delimiters matching, default :
      ^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))
    • +
    • tripleDelimiters - RegEx - Regular Expression for triple delimiters matching, default :
      ^((//=)|(>>=)|(<<=)|(\\*\\*=))
    • +
    • identifiers - RegEx - Regular Expression for identifier, default :
      ^[_A-Za-z][_A-Za-z0-9]*
    • +
    +

    MIME types defined: text/x-python.

    diff --git a/mode/python/python.js b/mode/python/python.js index a12e326dc8..951aaf8197 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -1,16 +1,16 @@ CodeMirror.defineMode("python", function(conf, parserConf) { var ERRORCLASS = 'error'; - + function wordRegexp(words) { return new RegExp("^((" + words.join(")|(") + "))\\b"); } - var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]"); - var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]'); - var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"); - var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"); - var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))"); - var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*"); + var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!]"); + var singleDelimiters = parserConf.singleDelimiters || new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]'); + var doubleOperators = parserConf.doubleOperators || new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"); + var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"); + var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))"); + var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9]*"); var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']); var commonkeywords = ['as', 'assert', 'break', 'class', 'continue', From f92ea27a83e048e63bfa8045c1c9711d09fb4ad0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 18 Feb 2013 16:08:30 +0100 Subject: [PATCH 0240/5273] [lint addon] Pass code instead of editor instance to lint providers --- addon/lint/javascript-lint.js | 4 ++-- addon/lint/json-lint.js | 4 ++-- addon/lint/lint.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/addon/lint/javascript-lint.js b/addon/lint/javascript-lint.js index 2200bba3e4..0d8ec32ed0 100644 --- a/addon/lint/javascript-lint.js +++ b/addon/lint/javascript-lint.js @@ -9,8 +9,8 @@ "Unmatched ", " and instead saw", " is not defined", "Unclosed string", "Stopping, unable to continue" ]; - CodeMirror.javascriptValidator = function(cm) { - JSHINT(cm.getValue()); + CodeMirror.javascriptValidator = function(text) { + JSHINT(text); var errors = JSHINT.data().errors, result = []; if (errors) parseErrors(errors, result); return result; diff --git a/addon/lint/json-lint.js b/addon/lint/json-lint.js index bbab508e98..42b36abb39 100644 --- a/addon/lint/json-lint.js +++ b/addon/lint/json-lint.js @@ -1,6 +1,6 @@ // Depends on jsonlint.js from https://github.com/zaach/jsonlint -CodeMirror.jsonValidator = function(cm) { +CodeMirror.jsonValidator = function(text) { var found = []; jsonlint.parseError = function(str, hash) { var loc = hash.loc; @@ -8,7 +8,7 @@ CodeMirror.jsonValidator = function(cm) { to: CodeMirror.Pos(loc.last_line - 1, loc.last_column), message: str}); }; - try { jsonlint.parse(cm.getValue()); } + try { jsonlint.parse(text); } catch(e) {} return found; }; diff --git a/addon/lint/lint.js b/addon/lint/lint.js index d59478aab0..39aee495d6 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -92,7 +92,7 @@ CodeMirror.validate = (function() { clearMarks(cm); var state = cm._lintState, options = state.options; - var annotations = groupByLine(options.getAnnotations(cm)); + var annotations = groupByLine(options.getAnnotations(cm.getValue())); for (var line = 0; line < annotations.length; ++line) { var anns = annotations[line]; From a3d7282704e9adda2e317291a8067211f553d9c7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 19 Feb 2013 09:53:43 +0100 Subject: [PATCH 0241/5273] [real-world uses] Update Farabi's description --- doc/realworld.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/realworld.html b/doc/realworld.html index 118ce10b6a..6388a4034e 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -43,7 +43,7 @@

    { } CodeMi
  • Elm language examples
  • Eloquent JavaScript (book)
  • Fastfig (online computation/math tool)
  • -
  • Farabi (Perl editor)
  • +
  • Farabi (modern Perl IDE)
  • FathomJS integration (slides with editors, again)
  • Go language tour
  • GitHub's Android app
  • From 017805885ede3df22140ad270679201a4cc0d5c0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 19 Feb 2013 12:38:12 +0100 Subject: [PATCH 0242/5273] [javascript mode] Add 'property' style to string/number propnames in object literals --- mode/javascript/javascript.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index c734555047..d41536f77a 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -302,6 +302,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function objprop(type) { if (type == "variable") cx.marked = "property"; + else if (type == "number" || type == "string") cx.marked = type + " property"; if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression); } function commasep(what, end) { From 21c2450d0b85eec83e52788e73ce5b3e84a626ed Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Feb 2013 13:50:02 +0100 Subject: [PATCH 0243/5273] Fix unclosed tag on front page Closes #1265 --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 3e9725083e..073e577ba2 100644 --- a/index.html +++ b/index.html @@ -95,7 +95,7 @@

    Usage demos:

  • Code folding
  • Bi-directional text
  • Line widgets (via JSHint)
  • -
  • Split view
  • +
  • Split view
  • Mode overlays
  • Mode multiplexer
  • HTML editor with preview
  • From 0560bdf780638ac956bf9a6cf8af49648861bfb0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Feb 2013 13:59:17 +0100 Subject: [PATCH 0244/5273] [show-hint addon] Make hint window behave halfway proper when scrolling the editor Closes #1264 --- addon/hint/show-hint.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index ccc062b2d7..1d581e5291 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -31,8 +31,9 @@ CodeMirror.showHint = function(cm, getHints, options) { elt.hintId = i; } var pos = cm.cursorCoords(options.alignWithWord !== false ? data.from : null); - hints.style.left = pos.left + "px"; - hints.style.top = pos.bottom + "px"; + var left = pos.left, top = pos.bottom; + hints.style.left = left + "px"; + hints.style.top = top + "px"; document.body.appendChild(hints); // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. @@ -45,7 +46,7 @@ CodeMirror.showHint = function(cm, getHints, options) { hints.style.width = (winW - 5) + "px"; overlapX -= (box.right - box.left) - winW; } - hints.style.left = (pos.left - overlapX) + "px"; + hints.style.left = (left = pos.left - overlapX) + "px"; } if (overlapY > 0) { var height = box.bottom - box.top; @@ -55,7 +56,7 @@ CodeMirror.showHint = function(cm, getHints, options) { hints.style.height = (winH - 5) + "px"; overlapY -= height - winH; } - hints.style.top = (pos.bottom - overlapY) + "px"; + hints.style.top = (top = pos.bottom - overlapY) + "px"; } function changeActive(i) { @@ -93,7 +94,18 @@ CodeMirror.showHint = function(cm, getHints, options) { cm.addKeyMap(ourMap); cm.on("cursorActivity", cursorActivity); - cm.on("blur", close); + var closingOnBlur; + function onBlur(){ closingOnBlur = setTimeout(close, 100); }; + function onFocus(){ clearTimeout(closingOnBlur); }; + cm.on("blur", onBlur); + cm.on("focus", onFocus); + var startScroll = cm.getScrollInfo(); + function onScroll() { + var curScroll = cm.getScrollInfo(); + hints.style.top = (top + startScroll.top - curScroll.top) + "px"; + hints.style.left = (left + startScroll.left - curScroll.left) + "px"; + } + cm.on("scroll", onScroll); CodeMirror.on(hints, "dblclick", function(e) { var t = e.target || e.srcElement; if (t.hintId != null) {selectedHint = t.hintId; pick();} @@ -113,7 +125,9 @@ CodeMirror.showHint = function(cm, getHints, options) { hints.parentNode.removeChild(hints); cm.removeKeyMap(ourMap); cm.off("cursorActivity", cursorActivity); - cm.off("blur", close); + cm.off("blur", onBlur); + cm.off("focus", onFocus); + cm.off("scroll", onScroll); } function pick() { cm.replaceRange(completions[selectedHint], data.from, data.to); From 1eb6cc12decc227d8b8ea7767b14153986b816bd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Feb 2013 17:19:44 +0100 Subject: [PATCH 0245/5273] Fix selection drawing in non-left-aligned text --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 6a8ab07cfd..706f7980ed 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -930,7 +930,7 @@ window.CodeMirror = (function() { function paddingTop(display) {return display.lineSpace.offsetTop;} function paddingLeft(display) { - var e = removeChildrenAndAdd(display.measure, elt("pre")).appendChild(elt("span", "x")); + var e = removeChildrenAndAdd(display.measure, elt("pre", null, null, "text-align: left")).appendChild(elt("span", "x")); return e.offsetLeft; } From 16bd84ef120ba1632cc0b630d09f3ad4900cf501 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Feb 2013 17:30:02 +0100 Subject: [PATCH 0246/5273] Add a getAllMarks method --- doc/manual.html | 2 ++ lib/codemirror.js | 9 +++++++++ test/test.js | 12 ++++++++++++ 3 files changed, 23 insertions(+) diff --git a/doc/manual.html b/doc/manual.html index 56f822bba1..0abaedabd9 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1025,6 +1025,8 @@

    Text-marking methods

    doc.findMarksAt(pos) → array
    Returns an array of all the bookmarks and marked ranges present at the given position.
    +
    doc.getAllMarks() → array
    +
    Returns an array containing all marked ranges in the document.

    Widget, gutter, and decoration methods

    diff --git a/lib/codemirror.js b/lib/codemirror.js index 706f7980ed..fb589c9090 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4411,6 +4411,15 @@ window.CodeMirror = (function() { } return markers; }, + getAllMarks: function() { + var markers = []; + this.iter(function(line) { + 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; + }, posFromIndex: function(off) { var ch, lineNo = this.first; diff --git a/test/test.js b/test/test.js index 79e8a9bca1..11d5c3f5fb 100644 --- a/test/test.js +++ b/test/test.js @@ -477,6 +477,18 @@ testCM("bookmarkInsertLeft", function(cm) { eqPos(bl.find(), Pos(0, 1)); }, {value: "abcdef"}); +testCM("getAllMarks", function(cm) { + addDoc(cm, 10, 10); + var m1 = cm.setBookmark(Pos(0, 2)); + var m2 = cm.markText(Pos(0, 2), Pos(3, 2)); + var m3 = cm.markText(Pos(1, 2), Pos(1, 8)); + var m4 = cm.markText(Pos(8, 0), Pos(9, 0)); + eq(cm.getAllMarks().length, 4); + m1.clear(); + m3.clear(); + eq(cm.getAllMarks().length, 2); +}); + testCM("bug577", function(cm) { cm.setValue("a\nb"); cm.clearHistory(); From 25ad8f62cf8b4f6b6b9de04fe95385f9af05f971 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Feb 2013 17:57:24 +0100 Subject: [PATCH 0247/5273] Make marker widgets inline blocks --- lib/codemirror.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/codemirror.css b/lib/codemirror.css index 6e34d15578..8de0b1908e 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -200,6 +200,10 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} overflow: auto; } +.CodeMirror-widget { + display: inline-block; +} + .CodeMirror-wrap .CodeMirror-scroll { overflow-x: hidden; } From 33f92ebec2993f750d55ba5159bcf1fcc01eeacf Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Feb 2013 17:58:55 +0100 Subject: [PATCH 0248/5273] Add null/plain text mode to mode/meta.js Closes #1267 --- mode/meta.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/meta.js b/mode/meta.js index d6296c332f..5d2ee0ffe9 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -38,6 +38,7 @@ CodeMirror.modeInfo = [ {name: 'PHP', mime: 'text/x-php', mode: 'php'}, {name: 'PHP(HTML)', mime: 'application/x-httpd-php', mode: 'php'}, {name: 'Pig', mime: 'text/x-pig', mode: 'pig'}, + {name: 'Plain Text', mime: 'text/plain', mode: 'null'}, {name: 'Properties files', mime: 'text/x-properties', mode: 'clike'}, {name: 'Python', mime: 'text/x-python', mode: 'python'}, {name: 'R', mime: 'text/x-rsrc', mode: 'r'}, From a65e98fbc80a23db584e23e323acfc5a5d934632 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Feb 2013 12:26:06 +0100 Subject: [PATCH 0249/5273] Add beforeSelectionChange event Issue #1262 --- doc/manual.html | 17 +++++++++++++++++ lib/codemirror.js | 14 ++++++++++++++ test/test.js | 19 +++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/doc/manual.html b/doc/manual.html index 0abaedabd9..3ef0456184 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -389,6 +389,18 @@

    Events

    Will be fired when the cursor or selection moves, or any change is made to the editor content.
    +
    "beforeSelectionChange" (instance, selection)
    +
    This event is fired before the selection is moved. Its + handler may modify the resulting selection head and anchor. + The selection parameter is an object + with head and anchor properties + holding {line, ch} objects, which the handler can + read and update. Handlers for this event have the same + restriction + as "beforeChange" + handlers — they should not do anything to directly update the + state of the editor.
    +
    "viewportChange" (instance, from, to)
    Fires whenever the view port of the editor changes (due to scrolling, editing, or any other @@ -437,6 +449,11 @@

    Events

    "cursorActivity" (doc)
    Fired whenever the cursor or selection in this document changes.
    + +
    "beforeSelectionChange" (doc, selection)
    +
    Equivalent to + the event by the same + name as fired on editor instances.

    Line handles (as returned by, for diff --git a/lib/codemirror.js b/lib/codemirror.js index fb589c9090..328b2c14d7 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2309,10 +2309,24 @@ window.CodeMirror = (function() { if (doc.cm) doc.cm.curOp.userSelChange = true; } + function filterSelectionChange(doc, anchor, head) { + var obj = {anchor: anchor, head: head}; + signal(doc, "beforeSelectionChange", doc, obj); + if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); + obj.anchor = clipPos(doc, obj.anchor); obj.head = clipPos(doc, obj.head); + return obj; + } + // Update the selection. Last two args are only used by // updateDoc, since they have to be expressed in the line // numbers before the update. function setSelection(doc, anchor, head, bias, checkAtomic) { + if (!checkAtomic && hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) { + var filtered = filterSelectionChange(doc, anchor, head); + head = filtered.head; + anchor = filtered.anchor; + } + var sel = doc.sel; sel.goalColumn = null; // Skip over atomic spans. diff --git a/test/test.js b/test/test.js index 11d5c3f5fb..4dbbf2a758 100644 --- a/test/test.js +++ b/test/test.js @@ -1324,3 +1324,22 @@ testCM("beforeChange", function(cm) { cm.replaceRange("hey hey hey", Pos(1, 0), Pos(2, 0)); eq(cm.getValue(), "hello,_i_am_a\nhey_hey_hey"); }, {value: "abcdefghijk"}); + +testCM("beforeSelectionChange", function(cm) { + function notAtEnd(cm, pos) { + var len = cm.getLine(pos.line).length; + if (!len || pos.ch == len) return Pos(pos.line, pos.ch - 1); + return pos; + } + cm.on("beforeSelectionChange", function(cm, sel) { + sel.head = notAtEnd(cm, sel.head); + sel.anchor = notAtEnd(cm, sel.anchor); + }); + + addDoc(cm, 10, 10); + cm.execCommand("goLineEnd"); + eqPos(cm.getCursor(), Pos(0, 9)); + cm.execCommand("selectAll"); + eqPos(cm.getCursor("start"), Pos(0, 0)); + eqPos(cm.getCursor("end"), Pos(9, 9)); +}); \ No newline at end of file From c69ce2ee8ad52bb5e9ddab6f4b2be76466e39b1f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Feb 2013 13:09:31 +0100 Subject: [PATCH 0250/5273] [htmlmixed mode] Make detection of opening script/style tags more robust Closes #1271 --- mode/htmlmixed/htmlmixed.js | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/mode/htmlmixed/htmlmixed.js b/mode/htmlmixed/htmlmixed.js index f8a0d5d18a..ec0c21d24a 100644 --- a/mode/htmlmixed/htmlmixed.js +++ b/mode/htmlmixed/htmlmixed.js @@ -13,29 +13,28 @@ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) { mode: CodeMirror.getMode(config, "text/plain")}); function html(stream, state) { + var tagName = state.htmlState.tagName; var style = htmlMode.token(stream, state.htmlState); - if (/(?:^|\s)tag(?:\s|$)/.test(style) && stream.current() == ">" && state.htmlState.context) { - if (/^script$/i.test(state.htmlState.context.tagName)) { - // Script block: mode to change to depends on type attribute - var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i); - scriptType = scriptType ? scriptType[1] : ""; - if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1); - for (var i = 0; i < scriptTypes.length; ++i) { - var tp = scriptTypes[i]; - if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) { - if (tp.mode) { - state.token = script; - state.localMode = tp.mode; - state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, "")); - } - break; + if (tagName == "script" && /\btag\b/.test(style) && stream.current() == ">") { + // Script block: mode to change to depends on type attribute + var scriptType = stream.string.slice(Math.max(0, stream.pos - 100), stream.pos).match(/\btype\s*=\s*("[^"]+"|'[^']+'|\S+)[^<]*$/i); + scriptType = scriptType ? scriptType[1] : ""; + if (scriptType && /[\"\']/.test(scriptType.charAt(0))) scriptType = scriptType.slice(1, scriptType.length - 1); + for (var i = 0; i < scriptTypes.length; ++i) { + var tp = scriptTypes[i]; + if (typeof tp.matches == "string" ? scriptType == tp.matches : tp.matches.test(scriptType)) { + if (tp.mode) { + state.token = script; + state.localMode = tp.mode; + state.localState = tp.mode.startState && tp.mode.startState(htmlMode.indent(state.htmlState, "")); } + break; } - } else if (/^style$/i.test(state.htmlState.context.tagName)) { - state.token = css; - state.localMode = cssMode; - state.localState = cssMode.startState(htmlMode.indent(state.htmlState, "")); } + } else if (tagName == "style" && /\btag\b/.test(style) && stream.current() == ">") { + state.token = css; + state.localMode = cssMode; + state.localState = cssMode.startState(htmlMode.indent(state.htmlState, "")); } return style; } From 7ce264fdfe78a70694b999c45d1b4a06df3469e8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Feb 2013 13:18:10 +0100 Subject: [PATCH 0251/5273] [show-hint addon] Close hinting popup when scrolled out of view --- addon/hint/show-hint.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 1d581e5291..2eb206d1fd 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -31,7 +31,7 @@ CodeMirror.showHint = function(cm, getHints, options) { elt.hintId = i; } var pos = cm.cursorCoords(options.alignWithWord !== false ? data.from : null); - var left = pos.left, top = pos.bottom; + var left = pos.left, top = pos.bottom, below = true; hints.style.left = left + "px"; hints.style.top = top + "px"; document.body.appendChild(hints); @@ -52,6 +52,7 @@ CodeMirror.showHint = function(cm, getHints, options) { var height = box.bottom - box.top; if (box.top - (pos.bottom - pos.top) - height > 0) { overlapY = height + (pos.bottom - pos.top); + below = false; } else if (height > winH) { hints.style.height = (winH - 5) + "px"; overlapY -= height - winH; @@ -101,8 +102,11 @@ CodeMirror.showHint = function(cm, getHints, options) { cm.on("focus", onFocus); var startScroll = cm.getScrollInfo(); function onScroll() { - var curScroll = cm.getScrollInfo(); - hints.style.top = (top + startScroll.top - curScroll.top) + "px"; + var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); + var newTop = top + startScroll.top - curScroll.top, point = newTop; + if (!below) point += hints.offsetHeight; + if (point <= editor.top || point >= editor.bottom) return close(); + hints.style.top = newTop + "px"; hints.style.left = (left + startScroll.left - curScroll.left) + "px"; } cm.on("scroll", onScroll); From 7db06ab9f635946f32977406597d6593e3b708e7 Mon Sep 17 00:00:00 2001 From: "angelo.zerr@gmail.com" Date: Thu, 21 Feb 2013 11:57:32 +0100 Subject: [PATCH 0252/5273] [lint addon] Add an option run an asynchronous linter --- addon/lint/lint.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 39aee495d6..f8aa3365df 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -88,11 +88,19 @@ CodeMirror.validate = (function() { return tip; } - function updateLinting(cm) { + function startLinting(cm) { + var state = cm._lintState, options = state.options; + if (options.async) + options.getAnnotations(cm, updateLinting, options); + else + updateLinting(cm, options.getAnnotations(cm.getValue())); + } + + function updateLinting(cm, annotationsNotSorted) { clearMarks(cm); var state = cm._lintState, options = state.options; - var annotations = groupByLine(options.getAnnotations(cm.getValue())); + var annotations = groupByLine(annotationsNotSorted); for (var line = 0; line < annotations.length; ++line) { var anns = annotations[line]; @@ -124,7 +132,7 @@ CodeMirror.validate = (function() { function onChange(cm) { var state = cm._lintState; clearTimeout(state.timeout); - state.timeout = setTimeout(function(){updateLinting(cm);}, state.options.delay || 500); + state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); } function popupSpanTooltip(ann, e) { @@ -168,7 +176,7 @@ CodeMirror.validate = (function() { var state = cm._lintState = new LintState(cm, parseOptions(val), hasLintGutter); cm.on("change", onChange); CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); - updateLinting(cm); + startLinting(cm); } }); })(); From 9e5599dd6bfae3ebed670cffbd523838a75264ed Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Feb 2013 14:54:55 +0100 Subject: [PATCH 0253/5273] Add a kludge to work around poor dimension measurements in bidi text in IE Closes #1129 --- lib/codemirror.js | 26 +++++++++++++++++++++----- test/test.js | 2 +- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 328b2c14d7..3fb5ed9f73 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1022,7 +1022,9 @@ window.CodeMirror = (function() { } } if (j == vranges.length) vranges.push(top, bot); - data[i] = {left: size.left - outer.left, right: size.right - outer.left, top: j}; + var right = size.right; + if (cur.measureRight) right = getRect(cur.measureRight).left; + data[i] = {left: size.left - outer.left, right: right - outer.left, top: j}; } for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) { var vr = cur.top; @@ -1085,10 +1087,9 @@ window.CodeMirror = (function() { if (part.from < ch && part.to > ch) return get(ch, rtl); var left = rtl ? part.to : part.from, right = rtl ? part.from : part.to; if (left == ch) { - // Opera and IE return bogus offsets and widths for edges - // where the direction flips, but only for the side with the - // lower level. So we try to use the side with the higher - // level. + // IE returns bogus offsets and widths for edges where the + // direction flips, but only for the side with the lower + // level. So we try to use the side with the higher level. if (i && part.level < (nb = order[i-1]).level) here = get(nb.level % 2 ? nb.from : nb.to - 1, true); else here = get(rtl && part.from != part.to ? ch - 1 : ch); if (rtl == linedir) main = here; else other = here; @@ -3971,6 +3972,21 @@ window.CodeMirror = (function() { if (!builder.pre.firstChild && !lineIsHidden(cm.doc, realLine)) builder.pre.appendChild(document.createTextNode("\u00a0")); + var order; + // Work around problem with the reported dimensions of single-char + // direction spans on IE (issue #1129). See also the comment in + // cursorCoords. + if (measure && ie && (order = getOrder(line))) { + var l = order.length - 1; + if (order[l].from == order[l].to) --l; + var last = order[l], prev = order[l - 1]; + if (last.from + 1 == last.to && prev && last.level < prev.level) { + var span = measure[builder.pos - 1]; + if (span) span.parentNode.insertBefore(span.measureRight = zeroWidthElement(cm.display.measure), + span.nextSibling); + } + } + return builder.pre; } diff --git a/test/test.js b/test/test.js index 4dbbf2a758..80770ef422 100644 --- a/test/test.js +++ b/test/test.js @@ -984,7 +984,7 @@ testCM("verticalMovementCommandsWrapping", function(cm) { testCM("rtlMovement", function(cm) { forEach(["خحج", "خحabcخحج", "abخحخحجcd", "abخde", "abخح2342خ1حج", "خ1ح2خح3حxج", - "خحcd", "1خحcd", "abcdeح1ج", "خمرحبها مها!"], function(line) { + "خحcd", "1خحcd", "abcdeح1ج", "خمرحبها مها!", "foobarر"], function(line) { var inv = line.charAt(0) == "خ"; cm.setValue(line + "\n"); cm.execCommand(inv ? "goLineEnd" : "goLineStart"); var cursor = byClassName(cm.getWrapperElement(), "CodeMirror-cursor")[0]; From 69fa5fd886cb6cc77ff5df40bc15c194996cc215 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Feb 2013 15:09:38 +0100 Subject: [PATCH 0254/5273] Clean up documentation for addons, mention lint addon --- doc/manual.html | 63 +++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 3ef0456184..0071d39a4f 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1357,14 +1357,14 @@

    Add-ons

    functionality. In brief, they are:

    -
    dialog.js
    +
    dialog/dialog.js
    Provides a very simple way to query users for text input. Adds an openDialog method to CodeMirror instances, which can be called with an HTML fragment that provides the prompt (should include an input tag), and a callback function that is called when text has been entered. Depends on addon/dialog/dialog.css.
    -
    searchcursor.js
    +
    search/searchcursor.js
    Adds the getSearchCursor(query, start, caseFold) → cursor method to CodeMirror instances, which can be used to implement search/replace functionality. query @@ -1393,14 +1393,14 @@

    Add-ons

    replacement.

    - +
    Implements the search commands. CodeMirror has keys bound to these by default, but will not do anything with them unless an implementation is provided. Depends on searchcursor.js, and will make use of openDialog when available to make prompting for search queries less ugly.
    -
    matchbrackets.js
    +
    edit/matchbrackets.js
    Defines an option matchBrackets which, when set to true, causes matching brackets to be highlighted whenever the cursor is next to them. It also adds a @@ -1408,14 +1408,14 @@

    Add-ons

    once, and a method findMatchingBracket that can be used to run the bracket-finding algorithm that this uses internally.
    -
    closebrackets.js
    +
    edit/closebrackets.js
    Defines an option autoCloseBrackets that will auto-close brackets and quotes when typed. By default, it'll auto-close ()[]{}''"", but you can pass it a string similar to that (containing pairs of matching characters) to customize it. Demo here.
    -
    foldcode.js
    +
    fold/foldcode.js
    Helps with code folding. See the demo for an example. Call CodeMirror.newFoldFunction with a range-finder @@ -1431,12 +1431,12 @@

    Add-ons

    where indentation determines block structure (Python, Haskell), and CodeMirror.tagRangeFinder, for XML-style languages.
    -
    collapserange.js
    +
    fold/collapserange.js
    Another approach to folding. See demo. Allows the user to select a range to fold by clicking in the gutter.
    -
    runmode.js
    +
    runmode/runmode.js
    Can be used to run a CodeMirror mode over text without actually opening an editor instance. See the demo for an example. @@ -1445,7 +1445,7 @@

    Add-ons

    (without including all of CodeMirror) and for running under node.js.
    -
    overlay.js
    +
    mode/overlay.js
    Mode combinator that can be used to extend a mode with an 'overlay' — a secondary mode is run over the stream, along with the base mode, and can color specific pieces of text without @@ -1453,7 +1453,7 @@

    Add-ons

    Defines CodeMirror.overlayMode, which is used to create such a mode. See this demo for a detailed example.
    -
    multiplex.js
    +
    mode/multiplex.js
    Mode combinator that can be used to easily 'multiplex' between several modes. Defines CodeMirror.multiplexingMode which, when @@ -1472,7 +1472,7 @@

    Add-ons

    see the content between the delimiters. See this demo for an example.
    -
    show-hint.js
    +
    hint/show-hint.js
    Provides a framework for showing autocompletion hints. Defines CodeMirror.showHint, which takes a CodeMirror instance and a hinting function, and pops up a widget @@ -1482,44 +1482,41 @@

    Add-ons

    is an array of strings (the completions), and from and to give the start and end of the token that is being completed. Depends - on addon/hint/show-hint.css. - See the demo for an + on addon/hint/show-hint.css. See the other files in + the addon/hint for + hint sources for various languages. Check + out the demo for an example.
    -
    simple-hint.js
    -
    Defines CodeMirror.simpleHint, which is - compatible with showHint. Deprecated, - use showHint instead. Depends - on addon/hint/simple-hint.css.
    -
    javascript-hint.js
    -
    Defines CodeMirror.javascriptHint - and CodeMirror.coffeescriptHint, which are simple - hinting functions for the JavaScript and CoffeeScript - modes.
    -
    xml-hint.js
    -
    Defines CodeMirror.xmlHint, a hinting function - for XML (which requires a schema to be defined).
    -
    python-hint.js
    -
    Defines CodeMirror.pythonHint, a hinter for Python code.
    match-highlighter.js
    Adds a highlightSelectionMatches option that can be enabled to highlight all instances of a currently selected word. Demo here.
    -
    mark-selection.js
    +
    lint/lint.js
    +
    Defines an interface component for showing linting warnings, + with pluggable warning sources + (see json-lint.js + and javascript-lint.js + in the same directory). Defines a lintWith option + that can be set to a warning source (for + example CodeMirror.javascriptValidator). Depends + on addon/lint/lint.css. A demo can be + found here.
    +
    selection/mark-selection.js
    Causes the selected text to be marked with the CSS class CodeMirror-selectedtext when the styleSelectedText option is enabled. Useful to change the colour of the selection (in addition to the background), like in this demo.
    -
    active-line.js
    +
    selection/active-line.js
    Defines a styleActiveLine option that, when enabled, gives the wrapper of the active line the class CodeMirror-activeline, and adds a background with the class CodeMirror-activeline-background. is enabled. See the demo.
    -
    closetag.js
    +
    edit/closetag.js
    Provides utility functions for adding automatic tag closing to XML modes. See the demo.
    -
    loadmode.js
    +
    mode/loadmode.js
    Defines a CodeMirror.requireMode(modename, callback) function that will try to load a given mode and call the callback when it succeeded. You'll have to @@ -1531,7 +1528,7 @@

    Add-ons

    which will ensure the given mode is loaded and cause the given editor instance to refresh its mode when the loading succeeded. See the demo.
    -
    continuecomment.js
    +
    edit/continuecomment.js
    Adds a command called newlineAndIndentContinueComment that you can bind Enter to in order to have the editor prefix From 545aeb74f6800dcaf6acead1bfc14c4eef99c9eb Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 21 Feb 2013 15:39:07 +0100 Subject: [PATCH 0255/5273] Mark release 3.1 --- doc/compress.html | 1 + doc/oldrelease.html | 37 ++++++++++++++++++++++ index.html | 76 ++++++++++++++++++++++----------------------- lib/codemirror.js | 2 +- package.json | 2 +- 5 files changed, 78 insertions(+), 40 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 521e6e865a..7f3bc7f7ab 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -30,6 +30,7 @@

    { } CodeMi

    Version: From d597e278cd4dade42095d82ebb0f2023c4bc8337 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 28 Feb 2013 09:42:06 +0100 Subject: [PATCH 0282/5273] Try to make page-up + page-down place the cursor back in its old place Closes #1291 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index ac43d0b97f..30fbce9670 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2591,7 +2591,7 @@ window.CodeMirror = (function() { 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 - textHeight(cm.display)); + y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); } else if (unit == "line") { y = dir > 0 ? pos.bottom + 3 : pos.top - 3; } From 9b17e93f7a71abdb569cceabd8d942d5ef6b7183 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 28 Feb 2013 09:56:59 +0100 Subject: [PATCH 0283/5273] Add leaveSubmitMethodAlone option to disable form submit hack --- lib/codemirror.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 30fbce9670..3137d231c4 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3306,17 +3306,19 @@ window.CodeMirror = (function() { function save() {textarea.value = cm.getValue();} if (textarea.form) { - // Deplorable hack to make the submit method do the right thing. on(textarea.form, "submit", save); - var form = textarea.form, realSubmit = form.submit; - try { - var wrappedSubmit = form.submit = function() { - save(); - form.submit = realSubmit; - form.submit(); - form.submit = wrappedSubmit; - }; - } catch(e) {} + // Deplorable hack to make the submit method do the right thing. + if (!options.leaveSubmitMethodAlone) { + var form = textarea.form, realSubmit = form.submit; + try { + var wrappedSubmit = form.submit = function() { + save(); + form.submit = realSubmit; + form.submit(); + form.submit = wrappedSubmit; + }; + } catch(e) {} + } } textarea.style.display = "none"; From 1344052d63dafe5cdefc36206e5325ed21ebc988 Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Thu, 28 Feb 2013 12:32:18 -0500 Subject: [PATCH 0284/5273] [gfm] Add support for task lists. Closes #1165. --- mode/gfm/gfm.js | 1 + mode/gfm/index.html | 5 +++++ mode/gfm/test.js | 28 ++++++++++++++++++++++++++++ mode/markdown/markdown.js | 26 ++++++++++++++++++++++++++ mode/markdown/test.js | 11 +++++++++++ 5 files changed, 71 insertions(+) diff --git a/mode/gfm/gfm.js b/mode/gfm/gfm.js index 1aec9f8c43..1179b53dc6 100644 --- a/mode/gfm/gfm.js +++ b/mode/gfm/gfm.js @@ -89,6 +89,7 @@ CodeMirror.defineMode("gfm", function(config) { CodeMirror.defineMIME("gfmBase", { name: "markdown", underscoresBreakWords: false, + taskLists: true, fencedCodeBlocks: true }); return CodeMirror.overlayMode(CodeMirror.getMode(config, "gfmBase"), gfmOverlay); diff --git a/mode/gfm/index.html b/mode/gfm/index.html index f413db19ef..826a96d2de 100644 --- a/mode/gfm/index.html +++ b/mode/gfm/index.html @@ -40,6 +40,11 @@

    CodeMirror: GFM mode

    } ``` +## Task Lists + +- [ ] Incomplete task list item +- [x] **Completed** task list item + ## A bit of GitHub spice * SHA: be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2 diff --git a/mode/gfm/test.js b/mode/gfm/test.js index de29f5889a..3ccaec5010 100644 --- a/mode/gfm/test.js +++ b/mode/gfm/test.js @@ -25,6 +25,34 @@ "[comment ```]", "bar"); + MT("taskListAsterisk", + "[variable-2 * []] foo]", // Invalid; must have space or x between [] + "[variable-2 * [ ]]bar]", // Invalid; must have space after ] + "[variable-2 * [x]]hello]", // Invalid; must have space after ] + "[variable-2 * ][meta [ ]]][variable-2 [world]]]", // Valid; tests reference style links + " [variable-3 * ][property [x]]][variable-3 foo]"); // Valid; can be nested + + MT("taskListPlus", + "[variable-2 + []] foo]", // Invalid; must have space or x between [] + "[variable-2 + [ ]]bar]", // Invalid; must have space after ] + "[variable-2 + [x]]hello]", // Invalid; must have space after ] + "[variable-2 + ][meta [ ]]][variable-2 [world]]]", // Valid; tests reference style links + " [variable-3 + ][property [x]]][variable-3 foo]"); // Valid; can be nested + + MT("taskListDash", + "[variable-2 - []] foo]", // Invalid; must have space or x between [] + "[variable-2 - [ ]]bar]", // Invalid; must have space after ] + "[variable-2 - [x]]hello]", // Invalid; must have space after ] + "[variable-2 - ][meta [ ]]][variable-2 [world]]]", // Valid; tests reference style links + " [variable-3 - ][property [x]]][variable-3 foo]"); // Valid; can be nested + + MT("taskListNumber", + "[variable-2 1. []] foo]", // Invalid; must have space or x between [] + "[variable-2 2. [ ]]bar]", // Invalid; must have space after ] + "[variable-2 3. [x]]hello]", // Invalid; must have space after ] + "[variable-2 4. ][meta [ ]]][variable-2 [world]]]", // Valid; tests reference style links + " [variable-3 1. ][property [x]]][variable-3 foo]"); // Valid; can be nested + MT("SHA", "foo [link be6a8cc1c1ecfe9489fb51e4869af15a13fc2cd2] bar"); diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index ba6d4d7fc4..2de56ca739 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -49,6 +49,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { // Turn on fenced code blocks? ("```" to start/end) if (modeCfg.fencedCodeBlocks === undefined) modeCfg.fencedCodeBlocks = false; + // Turn on task lists? ("- [ ] " and "- [x] ") + if (modeCfg.taskLists === undefined) modeCfg.taskLists = false; + var codeDepth = 0; var prevLineHasContent = false , thisLineHasContent = false; @@ -72,6 +75,7 @@ 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 , headerRE = /^(?:\={1,}|-{1,})$/ , textRE = /^[^!\[\]*_\\<>` "'(]+/; @@ -144,6 +148,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.indentation += 4; state.list = true; state.listDepth++; + if (modeCfg.taskLists && stream.match(taskListRE, false)) { + state.taskList = true; + } } else if (modeCfg.fencedCodeBlocks && stream.match(/^```([\w+#]*)/, true)) { // try switching mode state.localMode = getMode(RegExp.$1); @@ -187,6 +194,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { function getType(state) { var styles = []; + if (state.taskOpen) { return "meta"; } + if (state.taskClosed) { return "property"; } + if (state.strong) { styles.push(strong); } if (state.em) { styles.push(em); } @@ -227,6 +237,17 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return getType(state); } + if (state.taskList) { + var taskOpen = stream.match(taskListRE, true)[1] !== "x"; + if (taskOpen) state.taskOpen = true; + else state.taskClosed = true; + state.taskList = false; + return getType(state); + } + + state.taskOpen = false; + state.taskClosed = false; + var ch = stream.next(); if (ch === '\\') { @@ -428,6 +449,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { em: false, strong: false, header: false, + taskList: false, list: false, listDepth: 0, quote: 0 @@ -451,6 +473,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { em: s.em, strong: s.strong, header: s.header, + taskList: s.taskList, list: s.list, listDepth: s.listDepth, quote: s.quote, @@ -474,6 +497,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { // Reset state.header state.header = false; + // Reset state.taskList + state.taskList = false; + // Reset state.code state.code = false; diff --git a/mode/markdown/test.js b/mode/markdown/test.js index e527354e45..835f6cf6db 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -610,4 +610,15 @@ MT("doubleEscapeHash", "\\\\# foo"); + + + // Tests to make sure GFM-specific things aren't getting through + + MT("taskList", + "[variable-2 * [ ]] bar]"); + + MT("fencedCodeBlocks", + "[comment ```]", + "foo", + "[comment ```]"); })(); From 66fee2cc00a81db9eff5cddf816475fa25090311 Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Thu, 28 Feb 2013 13:02:20 -0500 Subject: [PATCH 0285/5273] [markdown] Fix list highlighting. Previously, lists following other content weren't always highlighted. --- mode/markdown/markdown.js | 25 +++++++++++++------------ mode/markdown/test.js | 12 ++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 2de56ca739..be43082280 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -53,8 +53,6 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { if (modeCfg.taskLists === undefined) modeCfg.taskLists = false; var codeDepth = 0; - var prevLineHasContent = false - , thisLineHasContent = false; var header = 'header' , code = 'comment' @@ -105,6 +103,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.f = inlineNormal; state.block = blockNormal; } + // Mark this line as blank + state.thisLineHasContent = false; return null; } @@ -130,7 +130,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return code; } else if (stream.eatSpace()) { return null; - } else if (stream.peek() === '#' || (prevLineHasContent && stream.match(headerRE)) ) { + } else if (stream.peek() === '#' || (state.prevLineHasContent && stream.match(headerRE)) ) { state.header = true; } else if (stream.eat('>')) { state.indentation++; @@ -144,7 +144,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return switchInline(stream, state, footnoteLink); } else if (stream.match(hrRE, true)) { return hr; - } else if ((!prevLineHasContent || prevLineIsList) && (stream.match(ulRE, true) || stream.match(olRE, true))) { + } else if ((!state.prevLineHasContent || prevLineIsList) && (stream.match(ulRE, true) || stream.match(olRE, true))) { state.indentation += 4; state.list = true; state.listDepth++; @@ -432,11 +432,12 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return { startState: function() { - prevLineHasContent = false; - thisLineHasContent = false; return { f: blockNormal, + prevLineHasContent: false, + thisLineHasContent: false, + block: blockNormal, htmlState: CodeMirror.startState(htmlMode), indentation: 0, @@ -460,6 +461,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return { f: s.f, + prevLineHasContent: s.prevLineHasContent, + thisLineHasContent: s.thisLineHasContent, + block: s.block, htmlState: CodeMirror.copyState(htmlMode, s.htmlState), indentation: s.indentation, @@ -484,14 +488,11 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { token: function(stream, state) { if (stream.sol()) { if (stream.match(/^\s*$/, true)) { - prevLineHasContent = false; + state.prevLineHasContent = false; return blankLine(state); } else { - if(thisLineHasContent){ - prevLineHasContent = true; - thisLineHasContent = false; - } - thisLineHasContent = true; + state.prevLineHasContent = state.thisLineHasContent; + state.thisLineHasContent = true; } // Reset state.header diff --git a/mode/markdown/test.js b/mode/markdown/test.js index 835f6cf6db..cfc229bc3f 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -174,18 +174,30 @@ // Check list types MT("listAsterisk", + "foo", + "bar", + "", "[variable-2 * foo]", "[variable-2 * bar]"); MT("listPlus", + "foo", + "bar", + "", "[variable-2 + foo]", "[variable-2 + bar]"); MT("listDash", + "foo", + "bar", + "", "[variable-2 - foo]", "[variable-2 - bar]"); MT("listNumber", + "foo", + "bar", + "", "[variable-2 1. foo]", "[variable-2 2. bar]"); From b444f799e1db2eb0d38bdf82af1071e452fc1a22 Mon Sep 17 00:00:00 2001 From: Ford_Lawnmower Date: Wed, 27 Feb 2013 11:55:42 -0500 Subject: [PATCH 0286/5273] Mode tcl added. --- mode/tcl/index.html | 130 +++++++++++++++++++++++++++++++++++++++++++ mode/tcl/tcl.js | 131 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 261 insertions(+) create mode 100644 mode/tcl/index.html create mode 100644 mode/tcl/tcl.js diff --git a/mode/tcl/index.html b/mode/tcl/index.html new file mode 100644 index 0000000000..ea72331269 --- /dev/null +++ b/mode/tcl/index.html @@ -0,0 +1,130 @@ + + + + + CodeMirror: tcl mode + + + + + + + + +

    CodeMirror: tcl mode

    +
    + + +

    MIME types defined: text/tcl.

    + + + diff --git a/mode/tcl/tcl.js b/mode/tcl/tcl.js new file mode 100644 index 0000000000..4defa8d8c5 --- /dev/null +++ b/mode/tcl/tcl.js @@ -0,0 +1,131 @@ +//tcl mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara +CodeMirror.defineMode("tcl", function() { + function parseWords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + var keywords = parseWords("Tcl safe after append array auto_execok auto_import auto_load " + + "auto_mkindex auto_mkindex_old auto_qualify auto_reset bgerror " + + "binary break catch cd close concat continue dde eof encoding error " + + "eval exec exit expr fblocked fconfigure fcopy file fileevent filename " + + "filename flush for foreach format gets glob global history http if " + + "incr info interp join lappend lindex linsert list llength load lrange " + + "lreplace lsearch lset lsort memory msgcat namespace open package parray " + + "pid pkg::create pkg_mkIndex proc puts pwd re_syntax read regex regexp " + + "registry regsub rename resource return scan seek set socket source split " + + "string subst switch tcl_endOfWord tcl_findLibrary tcl_startOfNextWord " + + "tcl_wordBreakAfter tcl_startOfPreviousWord tcl_wordBreakBefore tcltest " + + "tclvars tell time trace unknown unset update uplevel upvar variable " + + "vwait"); + var functions = parseWords("if elseif else and not or eq ne in ni for foreach while switch"); + var isOperatorChar = /[+\-*&%=<>!?^\/\|]/; + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + function tokenBase(stream, state) { + var beforeParams = state.beforeParams; + state.beforeParams = false; + var ch = stream.next(); + if ((ch == '"' || ch == "'") && state.inParams) + return chain(stream, state, tokenString(ch)); + else if (/[\[\]{}\(\),;\.]/.test(ch)) { + if (ch == "(" && beforeParams) state.inParams = true; + else if (ch == ")") state.inParams = false; + return null; + } + else if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + else if (ch == "#" && stream.eat("*")) { + return chain(stream, state, tokenComment); + } + else if (ch == "#" && stream.match(/ *\[ *\[/)) { + return chain(stream, state, tokenUnparsed); + } + else if (ch == "#" && stream.eat("#")) { + stream.skipToEnd(); + return "comment"; + } + else if (ch == '"') { + stream.skipTo(/"/) + return "comment"; + } + else if (ch == "$") { + stream.eatWhile(/[$_a-z0-9A-Z\.{:]/); + stream.eatWhile(/}/) + state.beforeParams = true; + return "builtin"; + } + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "comment"; + } + else { + stream.eatWhile(/[\w\$_{}]/); + var word = stream.current().toLowerCase(); + if (keywords && keywords.propertyIsEnumerable(word)) + return "keyword"; + if (functions && functions.propertyIsEnumerable(word)) { + state.beforeParams = true; + return "keyword"; + } + return null; + } + } + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) { + end = true; + break; + } + escaped = !escaped && next == "\\"; + } + if (end) state.tokenize = tokenBase; + return "string"; + }; + } + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "#" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + function tokenUnparsed(stream, state) { + var maybeEnd = 0, ch; + while (ch = stream.next()) { + if (ch == "#" && maybeEnd == 2) { + state.tokenize = tokenBase; + break; + } + if (ch == "]") + maybeEnd++; + else if (ch != " ") + maybeEnd = 0; + } + return "meta"; + } + return { + startState: function() { + return { + tokenize: tokenBase, + beforeParams: false, + inParams: false + }; + }, + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + } + }; +}); +CodeMirror.defineMIME("text/tcl", "tcl"); From d5e9746db834fa2478dfa0d4a73ea8087e5e02d5 Mon Sep 17 00:00:00 2001 From: Ford_Lawnmower Date: Wed, 27 Feb 2013 12:29:06 -0500 Subject: [PATCH 0287/5273] Added mirc mode. --- mode/mirc/index.html | 149 +++++++++++++++++++++++++++++++++ mode/mirc/mirc.js | 191 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 340 insertions(+) create mode 100644 mode/mirc/index.html create mode 100644 mode/mirc/mirc.js diff --git a/mode/mirc/index.html b/mode/mirc/index.html new file mode 100644 index 0000000000..8784374fe4 --- /dev/null +++ b/mode/mirc/index.html @@ -0,0 +1,149 @@ + + + + + CodeMirror: mIRC mode + + + + + + + + +

    CodeMirror: mIRC mode

    +
    + + +

    MIME types defined: text/mirc.

    + + + diff --git a/mode/mirc/mirc.js b/mode/mirc/mirc.js new file mode 100644 index 0000000000..632e8a3076 --- /dev/null +++ b/mode/mirc/mirc.js @@ -0,0 +1,191 @@ +//mIRC mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara +CodeMirror.defineMIME("text/mirc", "mirc"); +CodeMirror.defineMode("mirc", function() { + function parseWords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + var specials = parseWords("$! $$ $& $? $+ $abook $abs $active $activecid " + + "$activewid $address $addtok $agent $agentname $agentstat $agentver " + + "$alias $and $anick $ansi2mirc $aop $appactive $appstate $asc $asctime " + + "$asin $atan $avoice $away $awaymsg $awaytime $banmask $base $bfind " + + "$binoff $biton $bnick $bvar $bytes $calc $cb $cd $ceil $chan $chanmodes " + + "$chantypes $chat $chr $cid $clevel $click $cmdbox $cmdline $cnick $color " + + "$com $comcall $comchan $comerr $compact $compress $comval $cos $count " + + "$cr $crc $creq $crlf $ctime $ctimer $ctrlenter $date $day $daylight " + + "$dbuh $dbuw $dccignore $dccport $dde $ddename $debug $decode $decompress " + + "$deltok $devent $dialog $did $didreg $didtok $didwm $disk $dlevel $dll " + + "$dllcall $dname $dns $duration $ebeeps $editbox $emailaddr $encode $error " + + "$eval $event $exist $feof $ferr $fgetc $file $filename $filtered $finddir " + + "$finddirn $findfile $findfilen $findtok $fline $floor $fopen $fread $fserve " + + "$fulladdress $fulldate $fullname $fullscreen $get $getdir $getdot $gettok $gmt " + + "$group $halted $hash $height $hfind $hget $highlight $hnick $hotline " + + "$hotlinepos $ial $ialchan $ibl $idle $iel $ifmatch $ignore $iif $iil " + + "$inelipse $ini $inmidi $inpaste $inpoly $input $inrect $inroundrect " + + "$insong $instok $int $inwave $ip $isalias $isbit $isdde $isdir $isfile " + + "$isid $islower $istok $isupper $keychar $keyrpt $keyval $knick $lactive " + + "$lactivecid $lactivewid $left $len $level $lf $line $lines $link $lock " + + "$lock $locked $log $logstamp $logstampfmt $longfn $longip $lower $ltimer " + + "$maddress $mask $matchkey $matchtok $md5 $me $menu $menubar $menucontext " + + "$menutype $mid $middir $mircdir $mircexe $mircini $mklogfn $mnick $mode " + + "$modefirst $modelast $modespl $mouse $msfile $network $newnick $nick $nofile " + + "$nopath $noqt $not $notags $notify $null $numeric $numok $oline $onpoly " + + "$opnick $or $ord $os $passivedcc $pic $play $pnick $port $portable $portfree " + + "$pos $prefix $prop $protect $puttok $qt $query $rand $r $rawmsg $read $readomo " + + "$readn $regex $regml $regsub $regsubex $remove $remtok $replace $replacex " + + "$reptok $result $rgb $right $round $scid $scon $script $scriptdir $scriptline " + + "$sdir $send $server $serverip $sfile $sha1 $shortfn $show $signal $sin " + + "$site $sline $snick $snicks $snotify $sock $sockbr $sockerr $sockname " + + "$sorttok $sound $sqrt $ssl $sreq $sslready $status $strip $str $stripped " + + "$syle $submenu $switchbar $tan $target $ticks $time $timer $timestamp " + + "$timestampfmt $timezone $tip $titlebar $toolbar $treebar $trust $ulevel " + + "$ulist $upper $uptime $url $usermode $v1 $v2 $var $vcmd $vcmdstat $vcmdver " + + "$version $vnick $vol $wid $width $wildsite $wildtok $window $wrap $xor"); + var keywords = parseWords("abook ajinvite alias aline ame amsg anick aop auser autojoin avoice " + + "away background ban bcopy beep bread break breplace bset btrunc bunset bwrite " + + "channel clear clearall cline clipboard close cnick color comclose comopen " + + "comreg continue copy creq ctcpreply ctcps dcc dccserver dde ddeserver " + + "debug dec describe dialog did didtok disable disconnect dlevel dline dll " + + "dns dqwindow drawcopy drawdot drawfill drawline drawpic drawrect drawreplace " + + "drawrot drawsave drawscroll drawtext ebeeps echo editbox emailaddr enable " + + "events exit fclose filter findtext finger firewall flash flist flood flush " + + "flushini font fopen fseek fsend fserve fullname fwrite ghide gload gmove " + + "gopts goto gplay gpoint gqreq groups gshow gsize gstop gtalk gunload hadd " + + "halt haltdef hdec hdel help hfree hinc hload hmake hop hsave ial ialclear " + + "ialmark identd if ignore iline inc invite iuser join kick linesep links list " + + "load loadbuf localinfo log mdi me menubar mkdir mnick mode msg nick noop notice " + + "notify omsg onotice part partall pdcc perform play playctrl pop protect pvoice " + + "qme qmsg query queryn quit raw reload remini remote remove rename renwin " + + "reseterror resetidle return rlevel rline rmdir run ruser save savebuf saveini " + + "say scid scon server set showmirc signam sline sockaccept sockclose socklist " + + "socklisten sockmark sockopen sockpause sockread sockrename sockudp sockwrite " + + "sound speak splay sreq strip switchbar timer timestamp titlebar tnick tokenize " + + "toolbar topic tray treebar ulist unload unset unsetall updatenl url uwho " + + "var vcadd vcmd vcrem vol while whois window winhelp write writeint if isalnum " + + "isalpha isaop isavoice isban ischan ishop isignore isin isincs isletter islower " + + "isnotify isnum ison isop isprotect isreg isupper isvoice iswm iswmcs " + + "elseif else goto menu nicklist status title icon size option text edit " + + "button check radio box scroll list combo link tab item"); + var functions = parseWords("if elseif else and not or eq ne in ni for foreach while switch"); + var isOperatorChar = /[+\-*&%=<>!?^\/\|]/; + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + function tokenBase(stream, state) { + var beforeParams = state.beforeParams; + state.beforeParams = false; + var ch = stream.next(); + if (/[\[\]{}\(\),\.]/.test(ch)) { + if (ch == "(" && beforeParams) state.inParams = true; + else if (ch == ")") state.inParams = false; + return null; + } + else if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + else if (ch == "\\") { + stream.eat("\\"); + stream.eat(/./) + return "number" + } + else if (ch == "/" && stream.eat("*")) { + return chain(stream, state, tokenComment); + } + else if (ch == ";" && stream.match(/ *\( *\(/)) { + return chain(stream, state, tokenUnparsed); + } + else if (ch == ";" && !state.inParams) { + stream.skipToEnd(); + return "comment"; + } + else if (ch == '"') { + stream.eat(/"/); + return "keyword"; + } + else if (ch == "$") { + stream.eatWhile(/[$_a-z0-9A-Z\.:]/); + if (specials && specials.propertyIsEnumerable(stream.current().toLowerCase())) { + return "keyword" + } + else { + state.beforeParams = true; + return "builtin"; + } + } + else if (ch == "%") { + stream.eatWhile(/[^,^\s^\(^\)]/); + state.beforeParams = true; + return "string"; + } + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + else { + stream.eatWhile(/[\w\$_{}]/); + var word = stream.current().toLowerCase(); + if (keywords && keywords.propertyIsEnumerable(word)) + return "keyword"; + if (functions && functions.propertyIsEnumerable(word)) { + state.beforeParams = true; + return "keyword"; + } + return null; + } + } + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) { + end = true; + break; + } + escaped = !escaped && next == "\\"; + } + if (end) state.tokenize = tokenBase; + return "string"; + }; + } + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + function tokenUnparsed(stream, state) { + var maybeEnd = 0, ch; + while (ch = stream.next()) { + if (ch == ";" && maybeEnd == 2) { + state.tokenize = tokenBase; + break; + } + if (ch == ")") + maybeEnd++; + else if (ch != " ") + maybeEnd = 0; + } + return "meta"; + } + return { + startState: function() { + return { + tokenize: tokenBase, + beforeParams: false, + inParams: false + }; + }, + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + } + }; +}); From 90092d10eb03609d1401f1efe87a36b571c35fb1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 1 Mar 2013 09:27:24 +0100 Subject: [PATCH 0288/5273] [mirc mode] Integrate. --- doc/compress.html | 1 + doc/modes.html | 1 + mode/meta.js | 1 + mode/mirc/index.html | 24 ++-- mode/mirc/mirc.js | 324 +++++++++++++++++++++---------------------- 5 files changed, 170 insertions(+), 181 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 7f3bc7f7ab..d9e0843686 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -91,6 +91,7 @@

    { } CodeMi + diff --git a/doc/modes.html b/doc/modes.html index 7d273cbb75..642c7c1d7d 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -47,6 +47,7 @@

    { } CodeMi
  • LESS
  • Lua
  • Markdown (GitHub-flavour)
  • +
  • mIRC
  • NTriples
  • OCaml
  • Pascal
  • diff --git a/mode/meta.js b/mode/meta.js index 5d2ee0ffe9..99586bc30b 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -31,6 +31,7 @@ CodeMirror.modeInfo = [ {name: 'LESS', mime: 'text/x-less', mode: 'less'}, {name: 'Lua', mime: 'text/x-lua', mode: 'lua'}, {name: 'Markdown (GitHub-flavour)', mime: 'text/x-markdown', mode: 'markdown'}, + {name: 'mIRC', mime: 'text/mirc', mode: 'mirc'}, {name: 'NTriples', mime: 'text/n-triples', mode: 'ntriples'}, {name: 'OCaml', mime: 'text/x-ocaml', mode: 'ocaml'}, {name: 'Pascal', mime: 'text/x-pascal', mode: 'pascal'}, diff --git a/mode/mirc/index.html b/mode/mirc/index.html index 8784374fe4..0ff5ec9a20 100644 --- a/mode/mirc/index.html +++ b/mode/mirc/index.html @@ -5,7 +5,7 @@ CodeMirror: mIRC mode - + @@ -48,7 +48,7 @@

    CodeMirror: mIRC mode

    } else { hadd -m NickNames $2 $+(~,$1,~,$iif($3,$+($3,~))) - } + } } alias -l Fix.All.MindUser { var %Fix.Count = $hfind(NickNames,/[^~]+[0-9]{4}~/,0,r).data @@ -77,10 +77,10 @@

    CodeMirror: mIRC mode

    } menu status,channel { - - .AKA + .AKA ..AKA Search Dialog:dialog $iif($dialog(AKA_Search),-v,-m) AKA_Search AKA_Search - ..Clean All Records:Fix.All.Minduser - - + ..Clean All Records:Fix.All.Minduser + - } dialog AKA_Search { title "AKA Search Engine" @@ -105,7 +105,7 @@

    CodeMirror: mIRC mode

    did -a $dname 6 $hfind(NickNames,%search,%matches,w). [ $+ [ %type ] ] dec %matches } - did -c $dname 6 1 + did -c $dname 6 1 } elseif ($did == 7) && ($did($dname,6).seltext) { echo -ga $AKALogo 07 $mid($replace($hget(NickNames,$v1),$chr(126),$chr(44)),2,-1) } elseif ($did == 9) && ($did($dname,6).seltext) { clipboard $mid($v1,$pos($v1,*,1)) } @@ -114,20 +114,20 @@

    CodeMirror: mIRC mode

    if (!$hget(NickNames)) { hmake NickNames 10 } if ($isfile(NickNames.hsh)) { hload NickNames NickNames.hsh } } -On *:Exit: { if ($hget(NickNames)) { hsave NickNames NickNames.hsh } } +On *:Exit: { if ($hget(NickNames)) { hsave NickNames NickNames.hsh } } On *:Disconnect: { if ($hget(NickNames)) { hsave NickNames NickNames.hsh } } On *:Unload: { hfree NickNames } alias -l ialupdateCheck { inc -z $+(%,ialupdateCheck,$network) $calc($nick($1,0) / 4) - ;If your ial is already being updated on join .who $1 out. + ;If your ial is already being updated on join .who $1 out. ;If you are using /names to update ial you will still need this line. .who $1 } -Raw 352:*: { - if ($($+(%,ialupdateCheck,$network),2)) haltdef - NickNamesAdd $6 $+($network,$address($6,2)) +Raw 352:*: { + if ($($+(%,ialupdateCheck,$network),2)) haltdef + NickNamesAdd $6 $+($network,$address($6,2)) } -Raw 315:*: { +Raw 315:*: { if ($($+(%,ialupdateCheck,$network),2)) haltdef } diff --git a/mode/mirc/mirc.js b/mode/mirc/mirc.js index 632e8a3076..f76f782764 100644 --- a/mode/mirc/mirc.js +++ b/mode/mirc/mirc.js @@ -7,185 +7,171 @@ CodeMirror.defineMode("mirc", function() { return obj; } var specials = parseWords("$! $$ $& $? $+ $abook $abs $active $activecid " + - "$activewid $address $addtok $agent $agentname $agentstat $agentver " + - "$alias $and $anick $ansi2mirc $aop $appactive $appstate $asc $asctime " + - "$asin $atan $avoice $away $awaymsg $awaytime $banmask $base $bfind " + - "$binoff $biton $bnick $bvar $bytes $calc $cb $cd $ceil $chan $chanmodes " + - "$chantypes $chat $chr $cid $clevel $click $cmdbox $cmdline $cnick $color " + - "$com $comcall $comchan $comerr $compact $compress $comval $cos $count " + - "$cr $crc $creq $crlf $ctime $ctimer $ctrlenter $date $day $daylight " + - "$dbuh $dbuw $dccignore $dccport $dde $ddename $debug $decode $decompress " + - "$deltok $devent $dialog $did $didreg $didtok $didwm $disk $dlevel $dll " + - "$dllcall $dname $dns $duration $ebeeps $editbox $emailaddr $encode $error " + - "$eval $event $exist $feof $ferr $fgetc $file $filename $filtered $finddir " + - "$finddirn $findfile $findfilen $findtok $fline $floor $fopen $fread $fserve " + - "$fulladdress $fulldate $fullname $fullscreen $get $getdir $getdot $gettok $gmt " + - "$group $halted $hash $height $hfind $hget $highlight $hnick $hotline " + - "$hotlinepos $ial $ialchan $ibl $idle $iel $ifmatch $ignore $iif $iil " + - "$inelipse $ini $inmidi $inpaste $inpoly $input $inrect $inroundrect " + - "$insong $instok $int $inwave $ip $isalias $isbit $isdde $isdir $isfile " + - "$isid $islower $istok $isupper $keychar $keyrpt $keyval $knick $lactive " + - "$lactivecid $lactivewid $left $len $level $lf $line $lines $link $lock " + - "$lock $locked $log $logstamp $logstampfmt $longfn $longip $lower $ltimer " + - "$maddress $mask $matchkey $matchtok $md5 $me $menu $menubar $menucontext " + - "$menutype $mid $middir $mircdir $mircexe $mircini $mklogfn $mnick $mode " + - "$modefirst $modelast $modespl $mouse $msfile $network $newnick $nick $nofile " + - "$nopath $noqt $not $notags $notify $null $numeric $numok $oline $onpoly " + - "$opnick $or $ord $os $passivedcc $pic $play $pnick $port $portable $portfree " + - "$pos $prefix $prop $protect $puttok $qt $query $rand $r $rawmsg $read $readomo " + - "$readn $regex $regml $regsub $regsubex $remove $remtok $replace $replacex " + - "$reptok $result $rgb $right $round $scid $scon $script $scriptdir $scriptline " + - "$sdir $send $server $serverip $sfile $sha1 $shortfn $show $signal $sin " + - "$site $sline $snick $snicks $snotify $sock $sockbr $sockerr $sockname " + - "$sorttok $sound $sqrt $ssl $sreq $sslready $status $strip $str $stripped " + - "$syle $submenu $switchbar $tan $target $ticks $time $timer $timestamp " + - "$timestampfmt $timezone $tip $titlebar $toolbar $treebar $trust $ulevel " + - "$ulist $upper $uptime $url $usermode $v1 $v2 $var $vcmd $vcmdstat $vcmdver " + - "$version $vnick $vol $wid $width $wildsite $wildtok $window $wrap $xor"); + "$activewid $address $addtok $agent $agentname $agentstat $agentver " + + "$alias $and $anick $ansi2mirc $aop $appactive $appstate $asc $asctime " + + "$asin $atan $avoice $away $awaymsg $awaytime $banmask $base $bfind " + + "$binoff $biton $bnick $bvar $bytes $calc $cb $cd $ceil $chan $chanmodes " + + "$chantypes $chat $chr $cid $clevel $click $cmdbox $cmdline $cnick $color " + + "$com $comcall $comchan $comerr $compact $compress $comval $cos $count " + + "$cr $crc $creq $crlf $ctime $ctimer $ctrlenter $date $day $daylight " + + "$dbuh $dbuw $dccignore $dccport $dde $ddename $debug $decode $decompress " + + "$deltok $devent $dialog $did $didreg $didtok $didwm $disk $dlevel $dll " + + "$dllcall $dname $dns $duration $ebeeps $editbox $emailaddr $encode $error " + + "$eval $event $exist $feof $ferr $fgetc $file $filename $filtered $finddir " + + "$finddirn $findfile $findfilen $findtok $fline $floor $fopen $fread $fserve " + + "$fulladdress $fulldate $fullname $fullscreen $get $getdir $getdot $gettok $gmt " + + "$group $halted $hash $height $hfind $hget $highlight $hnick $hotline " + + "$hotlinepos $ial $ialchan $ibl $idle $iel $ifmatch $ignore $iif $iil " + + "$inelipse $ini $inmidi $inpaste $inpoly $input $inrect $inroundrect " + + "$insong $instok $int $inwave $ip $isalias $isbit $isdde $isdir $isfile " + + "$isid $islower $istok $isupper $keychar $keyrpt $keyval $knick $lactive " + + "$lactivecid $lactivewid $left $len $level $lf $line $lines $link $lock " + + "$lock $locked $log $logstamp $logstampfmt $longfn $longip $lower $ltimer " + + "$maddress $mask $matchkey $matchtok $md5 $me $menu $menubar $menucontext " + + "$menutype $mid $middir $mircdir $mircexe $mircini $mklogfn $mnick $mode " + + "$modefirst $modelast $modespl $mouse $msfile $network $newnick $nick $nofile " + + "$nopath $noqt $not $notags $notify $null $numeric $numok $oline $onpoly " + + "$opnick $or $ord $os $passivedcc $pic $play $pnick $port $portable $portfree " + + "$pos $prefix $prop $protect $puttok $qt $query $rand $r $rawmsg $read $readomo " + + "$readn $regex $regml $regsub $regsubex $remove $remtok $replace $replacex " + + "$reptok $result $rgb $right $round $scid $scon $script $scriptdir $scriptline " + + "$sdir $send $server $serverip $sfile $sha1 $shortfn $show $signal $sin " + + "$site $sline $snick $snicks $snotify $sock $sockbr $sockerr $sockname " + + "$sorttok $sound $sqrt $ssl $sreq $sslready $status $strip $str $stripped " + + "$syle $submenu $switchbar $tan $target $ticks $time $timer $timestamp " + + "$timestampfmt $timezone $tip $titlebar $toolbar $treebar $trust $ulevel " + + "$ulist $upper $uptime $url $usermode $v1 $v2 $var $vcmd $vcmdstat $vcmdver " + + "$version $vnick $vol $wid $width $wildsite $wildtok $window $wrap $xor"); var keywords = parseWords("abook ajinvite alias aline ame amsg anick aop auser autojoin avoice " + - "away background ban bcopy beep bread break breplace bset btrunc bunset bwrite " + - "channel clear clearall cline clipboard close cnick color comclose comopen " + - "comreg continue copy creq ctcpreply ctcps dcc dccserver dde ddeserver " + - "debug dec describe dialog did didtok disable disconnect dlevel dline dll " + - "dns dqwindow drawcopy drawdot drawfill drawline drawpic drawrect drawreplace " + - "drawrot drawsave drawscroll drawtext ebeeps echo editbox emailaddr enable " + - "events exit fclose filter findtext finger firewall flash flist flood flush " + - "flushini font fopen fseek fsend fserve fullname fwrite ghide gload gmove " + - "gopts goto gplay gpoint gqreq groups gshow gsize gstop gtalk gunload hadd " + - "halt haltdef hdec hdel help hfree hinc hload hmake hop hsave ial ialclear " + - "ialmark identd if ignore iline inc invite iuser join kick linesep links list " + - "load loadbuf localinfo log mdi me menubar mkdir mnick mode msg nick noop notice " + - "notify omsg onotice part partall pdcc perform play playctrl pop protect pvoice " + - "qme qmsg query queryn quit raw reload remini remote remove rename renwin " + - "reseterror resetidle return rlevel rline rmdir run ruser save savebuf saveini " + - "say scid scon server set showmirc signam sline sockaccept sockclose socklist " + - "socklisten sockmark sockopen sockpause sockread sockrename sockudp sockwrite " + - "sound speak splay sreq strip switchbar timer timestamp titlebar tnick tokenize " + - "toolbar topic tray treebar ulist unload unset unsetall updatenl url uwho " + - "var vcadd vcmd vcrem vol while whois window winhelp write writeint if isalnum " + - "isalpha isaop isavoice isban ischan ishop isignore isin isincs isletter islower " + - "isnotify isnum ison isop isprotect isreg isupper isvoice iswm iswmcs " + - "elseif else goto menu nicklist status title icon size option text edit " + - "button check radio box scroll list combo link tab item"); - var functions = parseWords("if elseif else and not or eq ne in ni for foreach while switch"); - var isOperatorChar = /[+\-*&%=<>!?^\/\|]/; - function chain(stream, state, f) { - state.tokenize = f; - return f(stream, state); + "away background ban bcopy beep bread break breplace bset btrunc bunset bwrite " + + "channel clear clearall cline clipboard close cnick color comclose comopen " + + "comreg continue copy creq ctcpreply ctcps dcc dccserver dde ddeserver " + + "debug dec describe dialog did didtok disable disconnect dlevel dline dll " + + "dns dqwindow drawcopy drawdot drawfill drawline drawpic drawrect drawreplace " + + "drawrot drawsave drawscroll drawtext ebeeps echo editbox emailaddr enable " + + "events exit fclose filter findtext finger firewall flash flist flood flush " + + "flushini font fopen fseek fsend fserve fullname fwrite ghide gload gmove " + + "gopts goto gplay gpoint gqreq groups gshow gsize gstop gtalk gunload hadd " + + "halt haltdef hdec hdel help hfree hinc hload hmake hop hsave ial ialclear " + + "ialmark identd if ignore iline inc invite iuser join kick linesep links list " + + "load loadbuf localinfo log mdi me menubar mkdir mnick mode msg nick noop notice " + + "notify omsg onotice part partall pdcc perform play playctrl pop protect pvoice " + + "qme qmsg query queryn quit raw reload remini remote remove rename renwin " + + "reseterror resetidle return rlevel rline rmdir run ruser save savebuf saveini " + + "say scid scon server set showmirc signam sline sockaccept sockclose socklist " + + "socklisten sockmark sockopen sockpause sockread sockrename sockudp sockwrite " + + "sound speak splay sreq strip switchbar timer timestamp titlebar tnick tokenize " + + "toolbar topic tray treebar ulist unload unset unsetall updatenl url uwho " + + "var vcadd vcmd vcrem vol while whois window winhelp write writeint if isalnum " + + "isalpha isaop isavoice isban ischan ishop isignore isin isincs isletter islower " + + "isnotify isnum ison isop isprotect isreg isupper isvoice iswm iswmcs " + + "elseif else goto menu nicklist status title icon size option text edit " + + "button check radio box scroll list combo link tab item"); + var functions = parseWords("if elseif else and not or eq ne in ni for foreach while switch"); + var isOperatorChar = /[+\-*&%=<>!?^\/\|]/; + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + function tokenBase(stream, state) { + var beforeParams = state.beforeParams; + state.beforeParams = false; + var ch = stream.next(); + if (/[\[\]{}\(\),\.]/.test(ch)) { + if (ch == "(" && beforeParams) state.inParams = true; + else if (ch == ")") state.inParams = false; + return null; } - function tokenBase(stream, state) { - var beforeParams = state.beforeParams; - state.beforeParams = false; - var ch = stream.next(); - if (/[\[\]{}\(\),\.]/.test(ch)) { - if (ch == "(" && beforeParams) state.inParams = true; - else if (ch == ")") state.inParams = false; - return null; - } - else if (/\d/.test(ch)) { - stream.eatWhile(/[\w\.]/); - return "number"; - } - else if (ch == "\\") { - stream.eat("\\"); - stream.eat(/./) - return "number" - } - else if (ch == "/" && stream.eat("*")) { - return chain(stream, state, tokenComment); - } - else if (ch == ";" && stream.match(/ *\( *\(/)) { - return chain(stream, state, tokenUnparsed); - } - else if (ch == ";" && !state.inParams) { - stream.skipToEnd(); - return "comment"; - } - else if (ch == '"') { - stream.eat(/"/); - return "keyword"; - } - else if (ch == "$") { - stream.eatWhile(/[$_a-z0-9A-Z\.:]/); - if (specials && specials.propertyIsEnumerable(stream.current().toLowerCase())) { - return "keyword" - } - else { - state.beforeParams = true; - return "builtin"; - } - } - else if (ch == "%") { - stream.eatWhile(/[^,^\s^\(^\)]/); - state.beforeParams = true; - return "string"; - } - else if (isOperatorChar.test(ch)) { - stream.eatWhile(isOperatorChar); - return "operator"; + else if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + else if (ch == "\\") { + stream.eat("\\"); + stream.eat(/./); + return "number"; + } + else if (ch == "/" && stream.eat("*")) { + return chain(stream, state, tokenComment); + } + else if (ch == ";" && stream.match(/ *\( *\(/)) { + return chain(stream, state, tokenUnparsed); + } + else if (ch == ";" && !state.inParams) { + stream.skipToEnd(); + return "comment"; + } + else if (ch == '"') { + stream.eat(/"/); + return "keyword"; + } + else if (ch == "$") { + stream.eatWhile(/[$_a-z0-9A-Z\.:]/); + if (specials && specials.propertyIsEnumerable(stream.current().toLowerCase())) { + return "keyword"; } else { - stream.eatWhile(/[\w\$_{}]/); - var word = stream.current().toLowerCase(); - if (keywords && keywords.propertyIsEnumerable(word)) - return "keyword"; - if (functions && functions.propertyIsEnumerable(word)) { - state.beforeParams = true; - return "keyword"; - } - return null; + state.beforeParams = true; + return "builtin"; } } - function tokenString(quote) { - return function(stream, state) { - var escaped = false, next, end = false; - while ((next = stream.next()) != null) { - if (next == quote && !escaped) { - end = true; - break; - } - escaped = !escaped && next == "\\"; - } - if (end) state.tokenize = tokenBase; - return "string"; - }; + else if (ch == "%") { + stream.eatWhile(/[^,^\s^\(^\)]/); + state.beforeParams = true; + return "string"; + } + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; } - function tokenComment(stream, state) { - var maybeEnd = false, ch; - while (ch = stream.next()) { - if (ch == "/" && maybeEnd) { - state.tokenize = tokenBase; - break; - } - maybeEnd = (ch == "*"); + else { + stream.eatWhile(/[\w\$_{}]/); + var word = stream.current().toLowerCase(); + if (keywords && keywords.propertyIsEnumerable(word)) + return "keyword"; + if (functions && functions.propertyIsEnumerable(word)) { + state.beforeParams = true; + return "keyword"; } - return "comment"; + return null; } - function tokenUnparsed(stream, state) { - var maybeEnd = 0, ch; - while (ch = stream.next()) { - if (ch == ";" && maybeEnd == 2) { - state.tokenize = tokenBase; - break; - } - if (ch == ")") - maybeEnd++; - else if (ch != " ") - maybeEnd = 0; + } + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = tokenBase; + break; } - return "meta"; + maybeEnd = (ch == "*"); } - return { - startState: function() { - return { - tokenize: tokenBase, - beforeParams: false, - inParams: false - }; - }, - token: function(stream, state) { - if (stream.eatSpace()) return null; - return state.tokenize(stream, state); + return "comment"; + } + function tokenUnparsed(stream, state) { + var maybeEnd = 0, ch; + while (ch = stream.next()) { + if (ch == ";" && maybeEnd == 2) { + state.tokenize = tokenBase; + break; } - }; + if (ch == ")") + maybeEnd++; + else if (ch != " ") + maybeEnd = 0; + } + return "meta"; + } + return { + startState: function() { + return { + tokenize: tokenBase, + beforeParams: false, + inParams: false + }; + }, + token: function(stream, state) { + if (stream.eatSpace()) return null; + return state.tokenize(stream, state); + } + }; }); From 6ff549aa5aae0b1598fa88e984ac793d33e5f69b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 1 Mar 2013 09:32:24 +0100 Subject: [PATCH 0289/5273] [tcl mode] Integrate --- doc/compress.html | 1 + doc/modes.html | 1 + index.html | 1 + mode/meta.js | 1 + mode/tcl/index.html | 17 ++++++++--------- mode/tcl/tcl.js | 32 ++++++++++++++++---------------- 6 files changed, 28 insertions(+), 25 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index d9e0843686..a92f36396c 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -119,6 +119,7 @@

    { } CodeMi + diff --git a/doc/modes.html b/doc/modes.html index 642c7c1d7d..927ef27dca 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -72,6 +72,7 @@

    { } CodeMi
  • SQL (several dialects)
  • SPARQL
  • sTeX, LaTeX
  • +
  • Tcl
  • Tiddlywiki
  • Tiki wiki
  • Turtle
  • diff --git a/index.html b/index.html index a853e2ce11..59ebc87b70 100644 --- a/index.html +++ b/index.html @@ -75,6 +75,7 @@

    Supported modes:

  • SQL (several dialects)
  • SPARQL
  • sTeX, LaTeX
  • +
  • Tcl
  • VB.NET
  • VBScript
  • Velocity
  • diff --git a/mode/meta.js b/mode/meta.js index 99586bc30b..7ac3f181d0 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -59,6 +59,7 @@ CodeMirror.modeInfo = [ {name: 'PL/SQL', mime: 'text/x-plsql', mode: 'sql'}, {name: 'sTeX', mime: 'text/x-stex', mode: 'stex'}, {name: 'LaTeX', mime: 'text/x-latex', mode: 'stex'}, + {name: 'Tcl', mime: 'text/x-tcl', mode: 'tcl'}, {name: 'TiddlyWiki ', mime: 'text/x-tiddlywiki', mode: 'tiddlywiki'}, {name: 'Tiki wiki', mime: 'text/tiki', mode: 'tiki'}, {name: 'VB.NET', mime: 'text/x-vb', mode: 'vb'}, diff --git a/mode/tcl/index.html b/mode/tcl/index.html index ea72331269..e2e42a04be 100644 --- a/mode/tcl/index.html +++ b/mode/tcl/index.html @@ -2,16 +2,15 @@ - CodeMirror: tcl mode + CodeMirror: Tcl mode - -

    CodeMirror: tcl mode

    +

    CodeMirror: Tcl mode

    -

    MIME types defined: text/tcl.

    +

    MIME types defined: text/x-tcl.

    diff --git a/mode/tcl/tcl.js b/mode/tcl/tcl.js index 4defa8d8c5..58ca709e4c 100644 --- a/mode/tcl/tcl.js +++ b/mode/tcl/tcl.js @@ -6,17 +6,17 @@ CodeMirror.defineMode("tcl", function() { return obj; } var keywords = parseWords("Tcl safe after append array auto_execok auto_import auto_load " + - "auto_mkindex auto_mkindex_old auto_qualify auto_reset bgerror " + - "binary break catch cd close concat continue dde eof encoding error " + - "eval exec exit expr fblocked fconfigure fcopy file fileevent filename " + - "filename flush for foreach format gets glob global history http if " + - "incr info interp join lappend lindex linsert list llength load lrange " + - "lreplace lsearch lset lsort memory msgcat namespace open package parray " + - "pid pkg::create pkg_mkIndex proc puts pwd re_syntax read regex regexp " + - "registry regsub rename resource return scan seek set socket source split " + - "string subst switch tcl_endOfWord tcl_findLibrary tcl_startOfNextWord " + - "tcl_wordBreakAfter tcl_startOfPreviousWord tcl_wordBreakBefore tcltest " + - "tclvars tell time trace unknown unset update uplevel upvar variable " + + "auto_mkindex auto_mkindex_old auto_qualify auto_reset bgerror " + + "binary break catch cd close concat continue dde eof encoding error " + + "eval exec exit expr fblocked fconfigure fcopy file fileevent filename " + + "filename flush for foreach format gets glob global history http if " + + "incr info interp join lappend lindex linsert list llength load lrange " + + "lreplace lsearch lset lsort memory msgcat namespace open package parray " + + "pid pkg::create pkg_mkIndex proc puts pwd re_syntax read regex regexp " + + "registry regsub rename resource return scan seek set socket source split " + + "string subst switch tcl_endOfWord tcl_findLibrary tcl_startOfNextWord " + + "tcl_wordBreakAfter tcl_startOfPreviousWord tcl_wordBreakBefore tcltest " + + "tclvars tell time trace unknown unset update uplevel upvar variable " + "vwait"); var functions = parseWords("if elseif else and not or eq ne in ni for foreach while switch"); var isOperatorChar = /[+\-*&%=<>!?^\/\|]/; @@ -50,13 +50,13 @@ CodeMirror.defineMode("tcl", function() { return "comment"; } else if (ch == '"') { - stream.skipTo(/"/) - return "comment"; + stream.skipTo(/"/); + return "comment"; } else if (ch == "$") { stream.eatWhile(/[$_a-z0-9A-Z\.{:]/); - stream.eatWhile(/}/) - state.beforeParams = true; + stream.eatWhile(/}/); + state.beforeParams = true; return "builtin"; } else if (isOperatorChar.test(ch)) { @@ -128,4 +128,4 @@ CodeMirror.defineMode("tcl", function() { } }; }); -CodeMirror.defineMIME("text/tcl", "tcl"); +CodeMirror.defineMIME("text/x-tcl", "tcl"); From 73e32fea5729a9f461ebfccfa0d3f8a122bb8bb7 Mon Sep 17 00:00:00 2001 From: John Connor Date: Thu, 28 Feb 2013 19:59:47 -0500 Subject: [PATCH 0290/5273] Added delmarks command to vim key bindings. Functionality and error messages match the latest vim 7.0 release. --- keymap/vim.js | 64 ++++++++++++++++++++++++++++- test/vim_test.js | 104 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 1 deletion(-) diff --git a/keymap/vim.js b/keymap/vim.js index 38bfa1d482..57e90e09df 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2236,7 +2236,8 @@ { name: 'undo', shortName: 'u', type: 'builtIn' }, { name: 'redo', shortName: 'red', type: 'builtIn' }, { name: 'substitute', shortName: 's', type: 'builtIn'}, - { name: 'nohlsearch', shortName: 'noh', type: 'builtIn'} + { name: 'nohlsearch', shortName: 'noh', type: 'builtIn'}, + { name: 'delmarks', shortName: 'delm', type: 'builtin'} ]; Vim.ExCommandDispatcher = function() { this.buildCommandMap_(); @@ -2533,6 +2534,67 @@ }, nohlsearch: function(cm) { clearSearchHighlight(cm); + }, + delmarks: function(cm, params) { + if (!params.argString || !params.argString.trim()) { + showConfirm(cm, 'Argument required'); + return; + } + + var state = getVimState(cm); + var stream = new CodeMirror.StringStream(params.argString.trim()); + while (!stream.eol()) { + stream.eatSpace(); + + // Record the streams position at the beginning of the loop for use + // in error messages. + var count = stream.pos; + + if (!stream.match(/[a-zA-Z]/, false)) { + showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); + return; + } + + var sym = stream.next(); + // Check if this symbol is part of a range + if (stream.match('-', true)) { + // This symbol is part of a range. + + // The range must terminate at an alphabetic character. + if (!stream.match(/[a-zA-Z]/, false)) { + showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); + return; + } + + var startMark = sym; + var finishMark = stream.next(); + // The range must terminate at an alphabetic character which + // shares the same case as the start of the range. + if (isLowerCase(startMark) && isLowerCase(finishMark) || + isUpperCase(startMark) && isUpperCase(finishMark)) { + var start = startMark.charCodeAt(0); + var finish = finishMark.charCodeAt(0); + if (start >= finish) { + showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count)); + return; + } + + // Because marks are always ASCII values, and we have + // determined that they are the same case, we can use + // their char codes to iterate through the defined range. + for (var j = 0; j <= finish - start; j++) { + var mark = String.fromCharCode(start + j); + delete state.marks[mark]; + } + } else { + showConfirm(cm, 'Invalid argument: ' + startMark + "-"); + return; + } + } else { + // This symbol is a valid mark, and is not part of a range. + delete state.marks[sym]; + } + } } }; diff --git a/test/vim_test.js b/test/vim_test.js index b9827e1f07..00638b570d 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -812,6 +812,110 @@ testVim('mark', function(cm, vim, helpers) { helpers.doKeys('`', 't'); helpers.assertCursorAt(2, 2); }); +testVim('delmark_single', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('m', 't'); + helpers.doEx('delmarks t'); + cm.setCursor(0, 0); + helpers.doKeys('`', 't'); + helpers.assertCursorAt(0, 0); +}); +testVim('delmark_range', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 2); + helpers.doKeys('m', 'b'); + cm.setCursor(3, 2); + helpers.doKeys('m', 'c'); + cm.setCursor(4, 2); + helpers.doKeys('m', 'd'); + cm.setCursor(5, 2); + helpers.doKeys('m', 'e'); + helpers.doEx('delmarks b-d'); + cm.setCursor(0, 0); + helpers.doKeys('`', 'a'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'b'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'c'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'd'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'e'); + helpers.assertCursorAt(5, 2); +}); +testVim('delmark_multi', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 2); + helpers.doKeys('m', 'b'); + cm.setCursor(3, 2); + helpers.doKeys('m', 'c'); + cm.setCursor(4, 2); + helpers.doKeys('m', 'd'); + cm.setCursor(5, 2); + helpers.doKeys('m', 'e'); + helpers.doEx('delmarks bcd'); + cm.setCursor(0, 0); + helpers.doKeys('`', 'a'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'b'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'c'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'd'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'e'); + helpers.assertCursorAt(5, 2); +}); +testVim('delmark_multi_space', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 2); + helpers.doKeys('m', 'b'); + cm.setCursor(3, 2); + helpers.doKeys('m', 'c'); + cm.setCursor(4, 2); + helpers.doKeys('m', 'd'); + cm.setCursor(5, 2); + helpers.doKeys('m', 'e'); + helpers.doEx('delmarks b c d'); + cm.setCursor(0, 0); + helpers.doKeys('`', 'a'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'b'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'c'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'd'); + helpers.assertCursorAt(1, 2); + helpers.doKeys('`', 'e'); + helpers.assertCursorAt(5, 2); +}); +testVim('delmark_all', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 2); + helpers.doKeys('m', 'b'); + cm.setCursor(3, 2); + helpers.doKeys('m', 'c'); + cm.setCursor(4, 2); + helpers.doKeys('m', 'd'); + cm.setCursor(5, 2); + helpers.doKeys('m', 'e'); + helpers.doEx('delmarks a b-de'); + cm.setCursor(0, 0); + helpers.doKeys('`', 'a'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('`', 'b'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('`', 'c'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('`', 'd'); + helpers.assertCursorAt(0, 0); + helpers.doKeys('`', 'e'); + helpers.assertCursorAt(0, 0); +}); testVim('visual', function(cm, vim, helpers) { helpers.doKeys('l', 'v', 'l', 'l'); helpers.assertCursorAt(0, 3); From a3ff09d80ad536f6ebd6b2b284158f9603bad57d Mon Sep 17 00:00:00 2001 From: David Pathakjee Date: Thu, 28 Feb 2013 22:44:12 -0600 Subject: [PATCH 0291/5273] Replaced builtins with updated list for 1.4. Generated by: (->> 'clojure.core ns-publics (map first) sort (clojure.string/join " ")) --- mode/clojure/clojure.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/clojure/clojure.js b/mode/clojure/clojure.js index 5d90edb8a5..5dcb489d38 100644 --- a/mode/clojure/clojure.js +++ b/mode/clojure/clojure.js @@ -19,7 +19,7 @@ CodeMirror.defineMode("clojure", function () { "defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle"); var builtins = makeKeywords( - "* *1 *2 *3 *agent* *allow-unresolved-vars* *assert *clojure-version* *command-line-args* *compile-files* *compile-path* *e *err* *file* *flush-on-newline* *in* *macro-meta* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *use-context-classloader* *warn-on-reflection* + - / < <= = == > >= accessor aclone agent agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* butlast byte byte-array bytes case cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec decimal? declare definline defmacro defmethod defmulti defn defn- defonce defstruct delay delay? deliver deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall doc dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq eval even? every? extend extend-protocol extend-type extends? extenders false? ffirst file-seq filter find find-doc find-ns find-var first float float-array float? floats flush fn fn? fnext for force format future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator hash hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map? mapcat max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod name namespace neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext num number? odd? or parents partial partition pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-doc print-dup print-method print-namespace-doc print-simple print-special-doc print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string reify reduce ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure release-pending-sends rem remove remove-method remove-ns repeat repeatedly replace replicate require reset! reset-meta! resolve rest resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? seque sequence sequential? set set-validator! set? short short-array shorts shutdown-agents slurp some sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-form-anchor special-symbol? split-at split-with str stream? string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync syntax-symbol-anchor take take-last take-nth take-while test the-ns time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-dec unchecked-divide unchecked-inc unchecked-multiply unchecked-negate unchecked-remainder unchecked-subtract underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision xml-seq"); + "* *' *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* *command-line-args* *compile-files* *compile-path* *compiler-options* *data-readers* *e *err* *file* *flush-on-newline* *fn-loader* *in* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *unchecked-math* *use-context-classloader* *verbose-defrecords* *warn-on-reflection* + +' - -' -> ->> ->ArrayChunk ->Vec ->VecNode ->VecSeq -cache-protocol-fn -reset-methods .. / < <= = == > >= EMPTY-NODE accessor aclone add-classpath add-watch agent agent-error agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint biginteger binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* bound? butlast byte byte-array bytes case cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec dec' decimal? declare default-data-readers definline definterface defmacro defmethod defmulti defn defn- defonce defprotocol defrecord defstruct deftype delay delay? deliver denominator deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq error-handler error-mode eval even? every-pred every? ex-data ex-info extend extend-protocol extend-type extenders extends? false? ffirst file-seq filter filterv find find-keyword find-ns find-protocol-impl find-protocol-method find-var first flatten float float-array float? floats flush fn fn? fnext fnil for force format frequencies future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator group-by hash hash-combine hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc inc' init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt keep keep-indexed key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map-indexed map? mapcat mapv max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod munge name namespace namespace-munge neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext nthrest num number? numerator object-array odd? or parents partial partition partition-all partition-by pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-dup print-method print-simple print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int rand-nth range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string realized? reduce reduce-kv reductions ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure reify release-pending-sends rem remove remove-all-methods remove-method remove-ns remove-watch repeat repeatedly replace replicate require reset! reset-meta! resolve rest restart-agent resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? seque sequence sequential? set set-error-handler! set-error-mode! set-validator! set? short short-array shorts shuffle shutdown-agents slurp some some-fn sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-symbol? spit split-at split-with str string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync take take-last take-nth take-while test the-ns thread-bound? time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-add-int unchecked-byte unchecked-char unchecked-dec unchecked-dec-int unchecked-divide-int unchecked-double unchecked-float unchecked-inc unchecked-inc-int unchecked-int unchecked-long unchecked-multiply unchecked-multiply-int unchecked-negate unchecked-negate-int unchecked-remainder-int unchecked-short unchecked-subtract unchecked-subtract-int underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector-of vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision with-redefs with-redefs-fn xml-seq zero? zipmap"); var indentKeys = makeKeywords( // Built-ins From 3e3f3939c8992af4be7f6009eb2646652ff2ab7c Mon Sep 17 00:00:00 2001 From: Joseph Pecoraro Date: Fri, 1 Mar 2013 12:04:24 -0800 Subject: [PATCH 0292/5273] Improve performance of StringStream with long lines Fixes Issue #1301 StringStreams.prototype.column was always calculating the column offset for a position by walking from index 0 in the string to the current start position. That is factorial in performance and gets noticeably slower with long lines. StringStreams only ever advance forward. So when determining the column we can cache the value for a previous position on the line. Then the next time column is called, we only need to update the cache for the small portion that the Stream advanced. This way we only ever walk the stream once. --- lib/codemirror.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 3137d231c4..8c429c6b87 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3350,6 +3350,7 @@ window.CodeMirror = (function() { this.pos = this.start = 0; this.string = string; this.tabSize = tabSize || 8; + this.lastColumnPos = this.lastColumnValue = 0; } StringStream.prototype = { @@ -3382,7 +3383,13 @@ window.CodeMirror = (function() { if (found > -1) {this.pos = found; return true;} }, backUp: function(n) {this.pos -= n;}, - column: function() {return countColumn(this.string, this.start, this.tabSize);}, + column: function() { + if (this.lastColumnPos < this.start) { + this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); + this.lastColumnPos = this.start; + } + return this.lastColumnValue; + }, indentation: function() {return countColumn(this.string, null, this.tabSize);}, match: function(pattern, consume, caseInsensitive) { if (typeof pattern == "string") { @@ -4960,12 +4967,12 @@ window.CodeMirror = (function() { // Counts the column offset in a string, taking tabs into account. // Used mostly to find indentation. - function countColumn(string, end, tabSize) { + function countColumn(string, end, tabSize, startIndex, startValue) { if (end == null) { end = string.search(/[^\s\u00a0]/); if (end == -1) end = string.length; } - for (var i = 0, n = 0; i < end; ++i) { + for (var i = startIndex || 0, n = startValue || 0; i < end; ++i) { if (string.charAt(i) == "\t") n += tabSize - (n % tabSize); else ++n; } From f97e5a6e30cda984d2e4e97205895c487eb69c9c Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Fri, 1 Mar 2013 12:38:50 -0500 Subject: [PATCH 0293/5273] Fix typo in manual. --- doc/manual.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index 5812b48b1b..8a5f8f4723 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1210,7 +1210,7 @@

    Sizing, scrolling and positioning methods

    Mode, state, and token-related methods

    When writing language-aware functionality, it can often be - useful to hook into the knowledge thate the CodeMirror language + useful to hook into the knowledge that the CodeMirror language mode has. See the section on modes for a more detailed description of how these work.

    From c3f655b5311ba5e54af9198cd2bcde3e16e65817 Mon Sep 17 00:00:00 2001 From: Joseph Pecoraro Date: Fri, 1 Mar 2013 13:23:19 -0800 Subject: [PATCH 0294/5273] Improve performance of StringStream with long lines (match) StringString.prototype.match() may do a lot of unnecessary work: - If it is caseInsensitive it was calling toLowerCase on the entire string. - It did an indexOf search through the string for a pattern, but only cared if the string started with that pattern. Because a string pattern has a fixed length, we only need to run toLowerCase on a small substring of the stream, and we only compare this small substring to the pattern. --- lib/codemirror.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 8c429c6b87..23be905deb 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3394,7 +3394,8 @@ window.CodeMirror = (function() { match: function(pattern, consume, caseInsensitive) { if (typeof pattern == "string") { var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; - if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) { + var substr = this.string.substr(this.pos, pattern.length); + if (cased(substr) == cased(pattern)) { if (consume !== false) this.pos += pattern.length; return true; } From 136265718e5c96abd5c6db306f3c4c236688ad41 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Sat, 2 Mar 2013 11:16:08 -0500 Subject: [PATCH 0295/5273] [vim] Clean up v2 references --- keymap/vim.js | 72 +++++++++------------------------------------------ 1 file changed, 12 insertions(+), 60 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 57e90e09df..358814292d 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1945,10 +1945,7 @@ } // Search functions - function SearchState() { - // Highlighted text that match the query. - this.marked = null; - } + function SearchState() {} SearchState.prototype = { getQuery: function() { return getVimGlobalState().query; @@ -1956,12 +1953,6 @@ setQuery: function(query) { getVimGlobalState().query = query; }, - getMarked: function() { - return this.marked; - }, - setMarked: function(marked) { - this.marked = marked; - }, getOverlay: function() { return this.searchOverlay; }, @@ -2094,7 +2085,6 @@ if (regexEqual(query, state.getQuery())) { return; } - clearSearchHighlight(cm); highlightSearchMatches(cm, query); state.setQuery(query); }); @@ -2124,28 +2114,14 @@ }; } function highlightSearchMatches(cm, query) { - if (cm.addOverlay) { - var overlay = getSearchState(cm).getOverlay(); - if (!overlay || query != overlay.query) { - if (overlay) { - cm.removeOverlay(overlay); - } - overlay = searchOverlay(query); - cm.addOverlay(overlay); - getSearchState(cm).setOverlay(overlay); - } - } else { - // TODO: Highlight only text inside the viewport. Highlighting everything - // is inefficient and expensive. - if (cm.lineCount() < 2000) { // This is too expensive on big documents. - var marked = []; - for (var cursor = cm.getSearchCursor(query); - cursor.findNext();) { - marked.push(cm.markText(cursor.from(), cursor.to(), - { className: 'cm-searching' })); - } - getSearchState(cm).setMarked(marked); + var overlay = getSearchState(cm).getOverlay(); + if (!overlay || query != overlay.query) { + if (overlay) { + cm.removeOverlay(overlay); } + overlay = searchOverlay(query); + cm.addOverlay(overlay); + getSearchState(cm).setOverlay(overlay); } } function findNext(cm, prev, repeat) { @@ -2155,9 +2131,7 @@ if (!query) { return; } - if (!state.getMarked()) { - highlightSearchMatches(cm, query); - } + highlightSearchMatches(cm, query); var pos = cm.getCursor(); // If search is initiated with ? instead of /, negate direction. prev = (state.isReversed()) ? !prev : prev; @@ -2179,25 +2153,8 @@ return cursor.from(); });} function clearSearchHighlight(cm) { - if (cm.addOverlay) { - cm.removeOverlay(getSearchState(cm).getOverlay()); - getSearchState(cm).setOverlay(null); - } else { - cm.operation(function() { - var state = getSearchState(cm); - if (!state.getQuery()) { - return; - } - var marked = state.getMarked(); - if (!marked) { - return; - } - for (var i = 0; i < marked.length; ++i) { - marked[i].clear(); - } - state.setMarked(null); - }); - } + cm.removeOverlay(getSearchState(cm).getOverlay()); + getSearchState(cm).setOverlay(null); } /** * Check if pos is in the specified range, INCLUSIVE. @@ -2514,12 +2471,7 @@ exitVisualMode(cm, vim); } } - if (cm.compoundChange) { - // Only exists in v2 - cm.compoundChange(doReplace); - } else { - cm.operation(doReplace); - } + cm.operation(doReplace); }, redo: CodeMirror.commands.redo, undo: CodeMirror.commands.undo, From 8a2068fdc69c0fdb4f4343ea8cacfbc4fa9e515e Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Sat, 2 Mar 2013 14:33:55 -0500 Subject: [PATCH 0296/5273] [vim] Incremental search --- addon/dialog/dialog.js | 4 +++ keymap/vim.js | 82 ++++++++++++++++++++++++++++-------------- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/addon/dialog/dialog.js b/addon/dialog/dialog.js index e113f7c9b4..51fdc6443f 100644 --- a/addon/dialog/dialog.js +++ b/addon/dialog/dialog.js @@ -25,6 +25,7 @@ var inp = dialog.getElementsByTagName("input")[0], button; if (inp) { CodeMirror.on(inp, "keydown", function(e) { + if (options && options.onKeyDown && options.onKeyDown(e, inp.value)) { return; } if (e.keyCode == 13 || e.keyCode == 27) { CodeMirror.e_stop(e); close(); @@ -32,6 +33,9 @@ if (e.keyCode == 13) callback(inp.value); } }); + if (options && options.onKeyUp) { + CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value);}); + } if (options && options.value) inp.value = options.value; inp.focus(); CodeMirror.on(inp, "blur", close); diff --git a/keymap/vim.js b/keymap/vim.js index 358814292d..2f230db8e1 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -182,8 +182,10 @@ { keys: ['<'], type: 'operator', operator: 'indent', operatorArgs: { indentRight: false }}, { keys: ['g', '~'], type: 'operator', operator: 'swapcase' }, - { keys: ['n'], type: 'motion', motion: 'findNext' }, - { keys: ['N'], type: 'motion', motion: 'findPrev' }, + { keys: ['n'], type: 'motion', motion: 'findNext', + motionArgs: { forward: true }}, + { keys: ['N'], type: 'motion', motion: 'findNext', + motionArgs: { forward: false }}, // Operator-Motion dual commands { keys: ['x'], type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: true }, @@ -727,19 +729,45 @@ var forward = command.searchArgs.forward; getSearchState(cm).setReversed(!forward); var promptPrefix = (forward) ? '/' : '?'; + var originalQuery = getSearchState(cm).getQuery(); + var originalPos = cm.getCursor(); function handleQuery(query, ignoreCase, smartCase) { updateSearchQuery(cm, query, ignoreCase, smartCase); commandDispatcher.processMotion(cm, vim, { type: 'motion', - motion: 'findNext' + motion: 'findNext', + motionArgs: { forward: true } }); } function onPromptClose(query) { + cm.scrollIntoView(originalPos); handleQuery(query, true /** ignoreCase */, true /** smartCase */); } + function onPromptKeyUp(e, query) { + if (query) { + updateSearchQuery(cm, query, true /** ignoreCase */, true /** smartCase */); + cm.scrollIntoView(findNext(cm, forward, query)); + } else { + clearSearchHighlight(cm); + cm.scrollIntoView(originalPos); + } + } + function onPromptKeyDown(e, query) { + if (CodeMirror.keyName(e) == 'Esc') { + updateSearchQuery(cm, originalQuery); + clearSearchHighlight(cm); + cm.scrollIntoView(originalPos); + } + } switch (command.searchArgs.querySrc) { case 'prompt': - showPrompt(cm, onPromptClose, promptPrefix, searchPromptDesc); + showPrompt(cm, { + onClose: onPromptClose, + prefix: promptPrefix, + desc: searchPromptDesc, + onKeyUp: onPromptKeyUp, + onKeyDown: onPromptKeyDown + }); break; case 'wordUnderCursor': var word = expandWordUnderCursor(cm, false /** inclusive */, @@ -776,9 +804,9 @@ exCommandDispatcher.processCommand(cm, command.exArgs.input); } else { if (vim.visualMode) { - showPrompt(cm, onPromptClose, ':', undefined, '\'<,\'>'); + showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>' }); } else { - showPrompt(cm, onPromptClose, ':'); + showPrompt(cm, { onClose: onPromptClose, prefix: ':' }); } } }, @@ -932,10 +960,16 @@ return { line: cur.line + motionArgs.repeat - 1, ch: Infinity }; }, findNext: function(cm, motionArgs, vim) { - return findNext(cm, false /** prev */, motionArgs.repeat); - }, - findPrev: function(cm, motionArgs, vim) { - return findNext(cm, true /** prev */, motionArgs.repeat); + var state = getSearchState(cm); + var query = state.getQuery(); + if (!query) { + return; + } + var prev = !motionArgs.forward; + // If search is initiated with ? instead of /, negate direction. + prev = (state.isReversed()) ? !prev : prev; + highlightSearchMatches(cm, query); + return findNext(cm, prev/** prev */, query, motionArgs.repeat); }, goToMark: function(cm, motionArgs, vim) { var mark = vim.marks[motionArgs.selectedCharacter]; @@ -1970,9 +2004,10 @@ var vim = getVimState(cm); return vim.searchState_ || (vim.searchState_ = new SearchState()); } - function dialog(cm, text, shortText, callback, initialValue) { + function dialog(cm, template, shortText, onClose, options) { if (cm.openDialog) { - cm.openDialog(text, callback, { bottom: true, value: initialValue }); + cm.openDialog(template, onClose, { bottom: true, value: options.value, + onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp }); } else { callback(prompt(shortText, "")); @@ -2001,6 +2036,8 @@ * through to the Regex object. */ function parseQuery(cm, query, ignoreCase, smartCase) { + // Check if the query is already a regex. + if (query instanceof RegExp) { return query; } // First try to extract regex + flags from the input. If no flags found, // extract just the regex. IE does not accept flags directly defined in // the regex string in the form /regex/flags @@ -2054,10 +2091,10 @@ return raw; } var searchPromptDesc = '(Javascript regexp)'; - function showPrompt(cm, onPromptClose, prefix, desc, initialValue) { - var shortText = (prefix || '') + ' ' + (desc || ''); - dialog(cm, makePrompt(prefix, desc), shortText, onPromptClose, - initialValue); + function showPrompt(cm, options) { + var shortText = (options.prefix || '') + ' ' + (options.desc || ''); + var prompt = makePrompt(options.prefix, options.desc); + dialog(cm, prompt, shortText, options.onClose, options); } function regexEqual(r1, r2) { if (r1 instanceof RegExp && r2 instanceof RegExp) { @@ -2082,10 +2119,10 @@ if (!query) { return; } + highlightSearchMatches(cm, query); if (regexEqual(query, state.getQuery())) { return; } - highlightSearchMatches(cm, query); state.setQuery(query); }); } @@ -2124,17 +2161,10 @@ getSearchState(cm).setOverlay(overlay); } } - function findNext(cm, prev, repeat) { + function findNext(cm, prev, query, repeat) { + if (repeat === undefined) { repeat = 1; } return cm.operation(function() { - var state = getSearchState(cm); - var query = state.getQuery(); - if (!query) { - return; - } - highlightSearchMatches(cm, query); var pos = cm.getCursor(); - // If search is initiated with ? instead of /, negate direction. - prev = (state.isReversed()) ? !prev : prev; if (!prev) { pos.ch += 1; } From f4fcea92fa4375189bb6f66ccb3359729cca24aa Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Sat, 2 Mar 2013 14:45:59 -0500 Subject: [PATCH 0297/5273] [vim] Ctrl-C and Ctrl-[ exit dialog --- addon/dialog/dialog.js | 4 ++-- keymap/vim.js | 23 +++++++++++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/addon/dialog/dialog.js b/addon/dialog/dialog.js index 51fdc6443f..71e2287447 100644 --- a/addon/dialog/dialog.js +++ b/addon/dialog/dialog.js @@ -25,7 +25,7 @@ var inp = dialog.getElementsByTagName("input")[0], button; if (inp) { CodeMirror.on(inp, "keydown", function(e) { - if (options && options.onKeyDown && options.onKeyDown(e, inp.value)) { return; } + if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } if (e.keyCode == 13 || e.keyCode == 27) { CodeMirror.e_stop(e); close(); @@ -34,7 +34,7 @@ } }); if (options && options.onKeyUp) { - CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value);}); + CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);}); } if (options && options.value) inp.value = options.value; inp.focus(); diff --git a/keymap/vim.js b/keymap/vim.js index 2f230db8e1..a04f4d3fef 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -752,11 +752,16 @@ cm.scrollIntoView(originalPos); } } - function onPromptKeyDown(e, query) { - if (CodeMirror.keyName(e) == 'Esc') { + function onPromptKeyDown(e, query, close) { + var keyName = CodeMirror.keyName(e); + if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') { updateSearchQuery(cm, originalQuery); clearSearchHighlight(cm); cm.scrollIntoView(originalPos); + + CodeMirror.e_stop(e); + close(); + cm.focus(); } } switch (command.searchArgs.querySrc) { @@ -799,14 +804,24 @@ function onPromptClose(input) { exCommandDispatcher.processCommand(cm, input); } + function onPromptKeyDown(e, input, close) { + var keyName = CodeMirror.keyName(e); + if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') { + CodeMirror.e_stop(e); + close(); + cm.focus(); + } + } if (command.type == 'keyToEx') { // Handle user defined Ex to Ex mappings exCommandDispatcher.processCommand(cm, command.exArgs.input); } else { if (vim.visualMode) { - showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>' }); + showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\'<,\'>', + onKeyDown: onPromptKeyDown}); } else { - showPrompt(cm, { onClose: onPromptClose, prefix: ':' }); + showPrompt(cm, { onClose: onPromptClose, prefix: ':', + onKeyDown: onPromptKeyDown}); } } }, From 6db15190fee156acf5428a44563f901cba8ec21f Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Sat, 2 Mar 2013 12:40:23 -0500 Subject: [PATCH 0298/5273] [vim] Initial implementation of . --- keymap/vim.js | 43 +++++++++++++++++++++++++++++++------------ test/vim_test.js | 35 +++++++++++++++++++++++++---------- 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index a04f4d3fef..b7006d850c 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -245,6 +245,7 @@ { keys: ['z', 'b'], type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, + { keys: ['.'], type: 'action', action: 'repeatLastEdit' }, // Text object motions { keys: ['a', 'character'], type: 'motion', motion: 'textObjectManipulation' }, @@ -401,7 +402,7 @@ var vim = getVimState(cm); if (key == 'Esc') { // Clear input state and get back to normal mode. - vim.inputState.reset(); + vim.inputState = new InputState(); if (vim.visualMode) { exitVisualMode(cm, vim); } @@ -441,9 +442,6 @@ // Represents the current input state. function InputState() { - this.reset(); - } - InputState.prototype.reset = function() { this.prefixRepeat = []; this.motionRepeat = []; @@ -453,7 +451,7 @@ this.motionArgs = null; this.keyBuffer = []; // For matching multi-key commands. this.registerName = null; // Defaults to the unamed register. - }; + } InputState.prototype.pushRepeatDigit = function(n) { if (!this.operator) { this.prefixRepeat = this.prefixRepeat.concat(n); @@ -631,6 +629,7 @@ return null; }, processCommand: function(cm, vim, command) { + vim.inputState.repeatOverride = command.repeatOverride; switch (command.type) { case 'motion': this.processMotion(cm, vim, command); @@ -672,7 +671,7 @@ return; } else { // 2 different operators in a row doesn't make sense. - inputState.reset(); + vim.inputState = new InputState(); } } inputState.operator = command.operator; @@ -717,7 +716,7 @@ actionArgs.repeat = repeat || 1; actionArgs.repeatIsExplicit = repeatIsExplicit; actionArgs.registerName = inputState.registerName; - inputState.reset(); + vim.inputState = new InputState(); vim.lastMotion = null, actions[command.action](cm, actionArgs, vim); }, @@ -842,10 +841,13 @@ var curOriginal = copyCursor(curStart); var curEnd; var repeat; - if (motionArgs.repeat !== undefined) { - // If motionArgs specifies a repeat, that takes precedence over the + if (operator) { + this.recordLastEdit(cm, vim, inputState); + } + if (inputState.repeatOverride !== undefined) { + // If repeatOverride is specified, that takes precedence over the // input state's repeat. Used by Ex mode and can be user defined. - repeat = inputState.motionArgs.repeat; + repeat = inputState.repeatOverride; } else { repeat = inputState.getRepeat(); } @@ -862,7 +864,7 @@ inputState.selectedCharacter; } motionArgs.repeat = repeat; - inputState.reset(); + vim.inputState = new InputState(); if (motion) { var motionResult = motions[motion](cm, motionArgs, vim); vim.lastMotion = motions[motion]; @@ -959,6 +961,9 @@ actions.enterInsertMode(cm); } } + }, + recordLastEdit: function(cm, vim, inputState) { + vim.lastEdit = inputState; } }; @@ -1450,6 +1455,19 @@ cm.setCursor(offsetCursor(curEnd, 0, -1)); } } + }, + repeatLastEdit: function(cm, actionArgs, vim) { + // TODO: Make this repeat insert mode changes. + var lastEdit = vim.lastEdit; + if (lastEdit) { + if (actionArgs.repeat && actionArgs.repeatIsExplicit) { + vim.lastEdit.repeatOverride = actionArgs.repeat; + } + var currentInputState = vim.inputState; + vim.inputState = vim.lastEdit; + commandDispatcher.evalInput(cm, vim); + vim.inputState = currentInputState; + } } }; @@ -2461,7 +2479,8 @@ commandDispatcher.processMotion(cm, getVimState(cm), { motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, - linewise: true, repeat: params.line+1 }}); + linewise: true }, + repeatOverride: params.line+1}); }, substitute: function(cm, params) { var argString = params.argString; diff --git a/test/vim_test.js b/test/vim_test.js index 00638b570d..4764c639b5 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -54,7 +54,8 @@ var bigWord3 = { var bigWord4 = { start: { line: bigWordLine.line, ch: bigWord1.end.ch + 3 }, end: { line: bigWordLine.line, ch: bigWord1.end.ch + 7 } -} +}; + var oChars = [ { line: charLine.line, ch: 1 }, { line: charLine.line, ch: 3 }, { line: charLine.line, ch: 7 } ]; @@ -971,15 +972,6 @@ testVim('? and n/N', function(cm, vim, helpers) { helpers.doKeys('2', '?'); helpers.assertCursorAt(0, 11); }, { value: 'match nope match \n nope Match' }); -//:noh should clear highlighting of search-results but allow to resume search through n -testVim('noh_clearSearchHighlight', function(cm, vim, helpers) { - cm.openDialog = helpers.fakeOpenDialog('match'); - helpers.doKeys('?'); - helpers.doEx('noh'); - eq(vim.searchState_.getOverlay(),null,'match-highlighting wasn\'t cleared'); - helpers.doKeys('n'); - helpers.assertCursorAt(0, 11,'can\'t resume search after clearing highlighting'); -}, { value: 'match nope match \n nope Match' }); testVim('*', function(cm, vim, helpers) { cm.setCursor(0, 9); helpers.doKeys('*'); @@ -1020,6 +1012,20 @@ testVim('#', function(cm, vim, helpers) { helpers.doKeys('#'); helpers.assertCursorAt(1, 8); }, { value: ' := match nomatch match \nnomatch Match' }); +testVim('.', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('2', 'd', 'w'); + helpers.doKeys('.'); + eq('5 6', cm.getValue()); +}, { value: '1 2 3 4 5 6'}); +testVim('._repeat', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('2', 'd', 'w'); + helpers.doKeys('3', '.'); + eq('6', cm.getValue()); +}, { value: '1 2 3 4 5 6'}); + +// Ex mode tests testVim('ex_write', function(cm, vim, helpers) { var tmp = CodeMirror.commands.save; var written; @@ -1084,6 +1090,15 @@ testVim('ex_substitute_count_with_range', function(cm, vim, helpers) { helpers.doEx('1,3s/\\d/0/ 3'); eq('1\n2\n0\n0', cm.getValue()); }, { value: '1\n2\n3\n4' }); +//:noh should clear highlighting of search-results but allow to resume search through n +testVim('ex_noh_clearSearchHighlight', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('match'); + helpers.doKeys('?'); + helpers.doEx('noh'); + eq(vim.searchState_.getOverlay(),null,'match-highlighting wasn\'t cleared'); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 11,'can\'t resume search after clearing highlighting'); +}, { value: 'match nope match \n nope Match' }); // TODO: Reset key maps after each test. testVim('ex_map_key2key', function(cm, vim, helpers) { helpers.doEx('map a x'); From 6e250cef478e35f9e27a7f09987d20a699013643 Mon Sep 17 00:00:00 2001 From: David Pathakjee Date: Sat, 2 Mar 2013 14:58:46 -0600 Subject: [PATCH 0299/5273] Update for release of Clojure 1.5.0. --- mode/clojure/clojure.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/clojure/clojure.js b/mode/clojure/clojure.js index 5dcb489d38..8b9614cc20 100644 --- a/mode/clojure/clojure.js +++ b/mode/clojure/clojure.js @@ -19,7 +19,7 @@ CodeMirror.defineMode("clojure", function () { "defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle"); var builtins = makeKeywords( - "* *' *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* *command-line-args* *compile-files* *compile-path* *compiler-options* *data-readers* *e *err* *file* *flush-on-newline* *fn-loader* *in* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *unchecked-math* *use-context-classloader* *verbose-defrecords* *warn-on-reflection* + +' - -' -> ->> ->ArrayChunk ->Vec ->VecNode ->VecSeq -cache-protocol-fn -reset-methods .. / < <= = == > >= EMPTY-NODE accessor aclone add-classpath add-watch agent agent-error agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint biginteger binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* bound? butlast byte byte-array bytes case cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec dec' decimal? declare default-data-readers definline definterface defmacro defmethod defmulti defn defn- defonce defprotocol defrecord defstruct deftype delay delay? deliver denominator deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq error-handler error-mode eval even? every-pred every? ex-data ex-info extend extend-protocol extend-type extenders extends? false? ffirst file-seq filter filterv find find-keyword find-ns find-protocol-impl find-protocol-method find-var first flatten float float-array float? floats flush fn fn? fnext fnil for force format frequencies future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator group-by hash hash-combine hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc inc' init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt keep keep-indexed key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map-indexed map? mapcat mapv max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod munge name namespace namespace-munge neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext nthrest num number? numerator object-array odd? or parents partial partition partition-all partition-by pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-dup print-method print-simple print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int rand-nth range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string realized? reduce reduce-kv reductions ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure reify release-pending-sends rem remove remove-all-methods remove-method remove-ns remove-watch repeat repeatedly replace replicate require reset! reset-meta! resolve rest restart-agent resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? seque sequence sequential? set set-error-handler! set-error-mode! set-validator! set? short short-array shorts shuffle shutdown-agents slurp some some-fn sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-symbol? spit split-at split-with str string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync take take-last take-nth take-while test the-ns thread-bound? time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-add-int unchecked-byte unchecked-char unchecked-dec unchecked-dec-int unchecked-divide-int unchecked-double unchecked-float unchecked-inc unchecked-inc-int unchecked-int unchecked-long unchecked-multiply unchecked-multiply-int unchecked-negate unchecked-negate-int unchecked-remainder-int unchecked-short unchecked-subtract unchecked-subtract-int underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector-of vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision with-redefs with-redefs-fn xml-seq zero? zipmap"); + "* *' *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* *command-line-args* *compile-files* *compile-path* *compiler-options* *data-readers* *e *err* *file* *flush-on-newline* *fn-loader* *in* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *unchecked-math* *use-context-classloader* *verbose-defrecords* *warn-on-reflection* + +' - -' -> ->> ->ArrayChunk ->Vec ->VecNode ->VecSeq -cache-protocol-fn -reset-methods .. / < <= = == > >= EMPTY-NODE accessor aclone add-classpath add-watch agent agent-error agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint biginteger binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* bound? butlast byte byte-array bytes case cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec dec' decimal? declare default-data-readers definline definterface defmacro defmethod defmulti defn defn- defonce defprotocol defrecord defstruct deftype delay delay? deliver denominator deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq error-handler error-mode eval even? every-pred every? ex-data ex-info extend extend-protocol extend-type extenders extends? false? ffirst file-seq filter filterv find find-keyword find-ns find-protocol-impl find-protocol-method find-var first flatten float float-array float? floats flush fn fn? fnext fnil for force format frequencies future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator group-by hash hash-combine hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc inc' init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt keep keep-indexed key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map-indexed map? mapcat mapv max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod munge name namespace namespace-munge neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext nthrest num number? numerator object-array odd? or parents partial partition partition-all partition-by pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-dup print-method print-simple print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int rand-nth range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string realized? reduce reduce-kv reductions ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure reify release-pending-sends rem remove remove-all-methods remove-method remove-ns remove-watch repeat repeatedly replace replicate require reset! reset-meta! resolve rest restart-agent resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? seque sequence sequential? set set-error-handler! set-error-mode! set-validator! set? short short-array shorts shuffle shutdown-agents slurp some some-fn sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-symbol? spit split-at split-with str string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync take take-last take-nth take-while test the-ns thread-bound? time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-add-int unchecked-byte unchecked-char unchecked-dec unchecked-dec-int unchecked-divide-int unchecked-double unchecked-float unchecked-inc unchecked-inc-int unchecked-int unchecked-long unchecked-multiply unchecked-multiply-int unchecked-negate unchecked-negate-int unchecked-remainder-int unchecked-short unchecked-subtract unchecked-subtract-int underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector-of vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision with-redefs with-redefs-fn xml-seq zero? zipmap *default-data-reader-fn* as-> cond-> cond->> reduced reduced? send-via set-agent-send-executor! set-agent-send-off-executor! some-> some->>"); var indentKeys = makeKeywords( // Built-ins From 0442d11707009e1f1cc9cba3a321a237bf1b6e10 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 3 Mar 2013 21:40:38 +0100 Subject: [PATCH 0300/5273] Clip updated scroll positions to a sane range --- lib/codemirror.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 23be905deb..0b8382749c 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2496,8 +2496,9 @@ window.CodeMirror = (function() { function addToScrollPos(cm, left, top) { var pos = cm.curOp.updateScrollPos || (cm.curOp.updateScrollPos = {scrollLeft: cm.doc.scrollLeft, scrollTop: cm.doc.scrollTop}); - pos.scrollTop += top; - pos.scrollLeft += left; + var scroll = cm.display.scroller; + pos.scrollTop = Math.max(0, Math.min(scroll.scrollHeight - scroll.clientHeight, pos.scrollTop + top)); + pos.scrollLeft = Math.max(0, Math.min(scroll.scrollWidth - scroll.clientWidth, pos.scrollLeft + left)); } // API UTILITIES From 6bb8b11860d294782d7c08849dd71b5b9615539a Mon Sep 17 00:00:00 2001 From: Joseph Pecoraro Date: Sat, 2 Mar 2013 17:51:47 -0800 Subject: [PATCH 0301/5273] [javascript mode] Recognize bitwise operators '~' and '^' This was causing "1^2" to tokenize as: (number, "1"), (variable, "^2). By tokenizing these bitwise operators as operators CodeMirror can correctly syntax highlight the 2 as a number. Likewise the number in "~0". --- 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 d41536f77a..b6d4e6b451 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -52,7 +52,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return jsKeywords; }(); - var isOperatorChar = /[+\-*&%=<>!?|]/; + var isOperatorChar = /[+\-*&%=<>!?|~^]/; function chain(stream, state, f) { state.tokenize = f; From 8ce322a1afb0d2fea153e78ed396341fe2966030 Mon Sep 17 00:00:00 2001 From: Thaddee Tyl Date: Sun, 3 Mar 2013 00:16:32 +0100 Subject: [PATCH 0302/5273] Give example of the extraKeys option. Issues #988, #742, #612, etc. show that CodeMirror users tend to: 1. Not find how to make the Tab key insert spaces instead of a tab, 2. Miss how to use extraKeys to easily solve the issue. Adding an example helps them find a solution immediately. --- doc/manual.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/manual.html b/doc/manual.html index 8a5f8f4723..1739b741e4 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -523,6 +523,17 @@

    Keymaps

    for example, Shift-Ctrl-Space would be a valid key identifier.

    +

    Common example: map the Tab key to insert spaces instead of a tab + character.

    + +
    +{
    +  Tab: function(cm) {
    +    var spaces = Array(cm.getOption("indentUnit") + 1).join(" ");
    +    cm.replaceSelection(spaces, "end", "+input");
    +  }
    +}
    +

    Alternatively, a character can be specified directly by surrounding it in single quotes, for example '$' or 'q'. Due to limitations in the way browsers fire From b06dbb217e39cb065752b99b4004a4ec47496538 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 4 Mar 2013 11:58:59 +0100 Subject: [PATCH 0303/5273] Give heightForcer a width to make sure it actually forces height --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 0b8382749c..8fc2dabb13 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -118,7 +118,7 @@ window.CodeMirror = (function() { // Set to the height of the text, causes scrolling d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); // D is needed because behavior of elts with overflow: auto and padding is inconsistent across browsers - d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerCutOff + "px"); + d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerCutOff + "px; width: 1px;"); // Will contain the gutters, if any d.gutters = elt("div", null, "CodeMirror-gutters"); d.lineGutter = null; From 4b53a77c2a54baa1887e0edb80afaa048491328e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 5 Mar 2013 10:23:22 +0100 Subject: [PATCH 0304/5273] Add the soft-hyphen character to the list of non-printing chars Closes #1310 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 8fc2dabb13..442ba8a62f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4034,7 +4034,7 @@ window.CodeMirror = (function() { return builder.pre; } - var tokenSpecialChars = /[\t\u0000-\u0019\u200b\u2028\u2029\uFEFF]/g; + var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g; function buildToken(builder, text, style, startStyle, endStyle) { if (!text) return; if (!tokenSpecialChars.test(text)) { From 9565019853ed6d2b90ffb160a5f0e848fcbcc2f7 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Mon, 4 Mar 2013 21:14:14 -0500 Subject: [PATCH 0305/5273] [vim] Fix handling of invalid search regexps. --- keymap/vim.js | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index b7006d850c..5a3469453e 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -731,7 +731,12 @@ var originalQuery = getSearchState(cm).getQuery(); var originalPos = cm.getCursor(); function handleQuery(query, ignoreCase, smartCase) { - updateSearchQuery(cm, query, ignoreCase, smartCase); + try { + updateSearchQuery(cm, query, ignoreCase, smartCase); + } catch (e) { + showConfirm(cm, 'Invalid regex: ' + regexPart); + return; + } commandDispatcher.processMotion(cm, vim, { type: 'motion', motion: 'findNext', @@ -744,8 +749,13 @@ } function onPromptKeyUp(e, query) { if (query) { - updateSearchQuery(cm, query, true /** ignoreCase */, true /** smartCase */); - cm.scrollIntoView(findNext(cm, forward, query)); + try { + updateSearchQuery(cm, query, true /** ignoreCase */, + true /** smartCase */); + cm.scrollIntoView(findNext(cm, forward, query)); + } catch (e) { + // Swallow bad regexes for incremental search. + } } else { clearSearchHighlight(cm); cm.scrollIntoView(originalPos); @@ -2092,13 +2102,9 @@ if (smartCase) { ignoreCase = (/^[^A-Z]*$/).test(regexPart); } - try { - var regexp = new RegExp(regexPart, - (ignoreCase || forceIgnoreCase) ? 'i' : undefined); - return regexp; - } catch (e) { - showConfirm(cm, 'Invalid regex: ' + regexPart); - } + var regexp = new RegExp(regexPart, + (ignoreCase || forceIgnoreCase) ? 'i' : undefined); + return regexp; } function showConfirm(cm, text) { if (cm.openConfirm) { @@ -2510,8 +2516,13 @@ if (regexPart) { // If regex part is empty, then use the previous query. Otherwise use // the regex part as the new query. - updateSearchQuery(cm, regexPart, true /** ignoreCase */, - true /** smartCase */); + try { + updateSearchQuery(cm, regexPart, true /** ignoreCase */, + true /** smartCase */); + } catch (e) { + showConfirm(cm, 'Invalid regex: ' + regexPart); + return; + } } var state = getSearchState(cm); var query = state.getQuery(); @@ -2586,7 +2597,7 @@ var finishMark = stream.next(); // The range must terminate at an alphabetic character which // shares the same case as the start of the range. - if (isLowerCase(startMark) && isLowerCase(finishMark) || + if (isLowerCase(startMark) && isLowerCase(finishMark) || isUpperCase(startMark) && isUpperCase(finishMark)) { var start = startMark.charCodeAt(0); var finish = finishMark.charCodeAt(0); @@ -2599,7 +2610,7 @@ // determined that they are the same case, we can use // their char codes to iterate through the defined range. for (var j = 0; j <= finish - start; j++) { - var mark = String.fromCharCode(start + j); + var mark = String.fromCharCode(start + j); delete state.marks[mark]; } } else { From 1171acb083d681a6d657c67058341c3e9b483ae7 Mon Sep 17 00:00:00 2001 From: "Daniel, Dao Quang Minh" Date: Tue, 5 Mar 2013 02:49:58 +0800 Subject: [PATCH 0306/5273] Make CSS mode configurable, use it to implement SCSS mode. --- mode/css/css.js | 575 +++++++++++++++++++++++++----------------- mode/css/scss.html | 142 +++++++++++ mode/css/scss_test.js | 77 ++++++ mode/css/test.js | 5 +- test/index.html | 1 + 5 files changed, 562 insertions(+), 238 deletions(-) create mode 100644 mode/css/scss.html create mode 100644 mode/css/scss_test.js diff --git a/mode/css/css.js b/mode/css/css.js index 37ef76c941..7cdd18b3fc 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -1,204 +1,25 @@ -CodeMirror.defineMode("css", function(config) { - var indentUnit = config.indentUnit, type; - - var atMediaTypes = keySet([ - "all", "aural", "braille", "handheld", "print", "projection", "screen", - "tty", "tv", "embossed" - ]); - - var atMediaFeatures = keySet([ - "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 = keySet([ - "align-content", "align-items", "align-self", "alignment-adjust", - "alignment-baseline", "anchor-point", "animation", "animation-delay", - "animation-direction", "animation-duration", "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", "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-cell", "grid-column", "grid-column-align", - "grid-column-sizing", "grid-column-span", "grid-columns", "grid-flow", - "grid-row", "grid-row-align", "grid-row-sizing", "grid-row-span", - "grid-rows", "grid-template", "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", "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", "rendering-intent", - "resize", "rest", "rest-after", "rest-before", "richness", "right", - "rotation", "rotation-point", "ruby-align", "ruby-overhang", - "ruby-position", "ruby-span", "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-shadow", - "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" - ]); - - var colorKeywords = keySet([ - "black", "silver", "gray", "white", "maroon", "red", "purple", "fuchsia", - "green", "lime", "olive", "yellow", "navy", "blue", "teal", "aqua" - ]); - - var valueKeywords = keySet([ - "above", "absolute", "activeborder", "activecaption", "afar", - "after-white-space", "ahead", "alias", "all", "all-scroll", "alternate", - "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", - "arabic-indic", "armenian", "asterisks", "auto", "avoid", "background", - "backwards", "baseline", "below", "bidi-override", "binary", "bengali", - "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", - "both", "bottom", "break-all", "break-word", "button", "button-bevel", - "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian", - "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", - "cell", "center", "checkbox", "circle", "cjk-earthly-branch", - "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", - "col-resize", "collapse", "compact", "condensed", "contain", "content", - "content-box", "context-menu", "continuous", "copy", "cover", "crop", - "cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal", - "decimal-leading-zero", "default", "default-button", "destination-atop", - "destination-in", "destination-out", "destination-over", "devanagari", - "disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted", - "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", - "element", "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", "ew-resize", "expanded", "extra-condensed", - "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "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-table", "inset", "inside", "intrinsic", "invert", - "italic", "justify", "kannada", "katakana", "katakana-iroha", "khmer", - "landscape", "lao", "large", "larger", "left", "level", "lighter", - "line-through", "linear", "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", - "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", "navy", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", - "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", - "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", - "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", - "outside", "overlay", "overline", "padding", "padding-box", "painted", - "paused", "persian", "plus-darker", "plus-lighter", "pointer", "portrait", - "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button", - "radio", "read-only", "read-write", "read-write-plaintext-only", "relative", - "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba", - "ridge", "right", "round", "row-resize", "rtl", "run-in", "running", - "s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield", - "searchfield-cancel-button", "searchfield-decoration", - "searchfield-results-button", "searchfield-results-decoration", - "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", - "single", "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", "square", - "square-button", "start", "static", "status-bar", "stretch", "stroke", - "sub", "subpixel-antialiased", "super", "sw-resize", "table", - "table-caption", "table-cell", "table-column", "table-column-group", - "table-footer-group", "table-header-group", "table-row", "table-row-group", - "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", - "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", - "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", - "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", - "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", - "visibleStroke", "visual", "w-resize", "wait", "wave", "white", "wider", - "window", "windowframe", "windowtext", "x-large", "x-small", "xor", - "xx-large", "xx-small", "yellow" - ]); +CodeMirror.defineMode("css", function(config, parserConfig) { + "use strict"; + var indentUnit = config.indentUnit, + hooks = parserConfig.hooks || {}, + atMediaTypes = parserConfig.atMediaTypes || {}, + atMediaFeatures = parserConfig.atMediaFeatures || {}, + propertyKeywords = parserConfig.propertyKeywords || {}, + colorKeywords = parserConfig.colorKeywords || {}, + valueKeywords = parserConfig.valueKeywords || {}, + allowNested = !!parserConfig.allowNested, + type = null; - function keySet(array) { var keys = {}; for (var i = 0; i < array.length; ++i) keys[array[i]] = true; return keys; } - function ret(style, tp) {type = tp; return style;} + function ret(style, tp) { type = tp; return style; } function tokenBase(stream, state) { var ch = stream.next(); - if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());} - else if (ch == "/" && stream.eat("*")) { - state.tokenize = tokenCComment; - return tokenCComment(stream, state); - } - else if (ch == "<" && stream.eat("!")) { - state.tokenize = tokenSGMLComment; - return tokenSGMLComment(stream, state); + if (hooks[ch]) { + // result[0] is style and result[1] is type + var result = hooks[ch](stream, state); + if (result !== false) return ret(result[0], result[1]); } + if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());} else if (ch == "=") ret(null, "compare"); else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare"); else if (ch == "\"" || ch == "'") { @@ -248,30 +69,6 @@ CodeMirror.defineMode("css", function(config) { } } - function tokenCComment(stream, state) { - var maybeEnd = false, ch; - while ((ch = stream.next()) != null) { - if (maybeEnd && ch == "/") { - state.tokenize = tokenBase; - break; - } - maybeEnd = (ch == "*"); - } - return ret("comment", "comment"); - } - - function tokenSGMLComment(stream, state) { - var dashes = 0, ch; - while ((ch = stream.next()) != null) { - if (dashes >= 2 && ch == ">") { - state.tokenize = tokenBase; - break; - } - dashes = (ch == "-") ? dashes + 1 : 0; - } - return ret("comment", "comment"); - } - function tokenString(quote, nonInclusive) { return function(stream, state) { var escaped = false, ch; @@ -305,59 +102,63 @@ CodeMirror.defineMode("css", function(config) { }, token: function(stream, state) { - + // Use these terms when applicable (see http://www.xanthir.com/blog/b4E50) - // + // // rule** or **ruleset: // A selector + braces combo, or an at-rule. - // + // // declaration block: // A sequence of declarations. - // + // // declaration: // A property + colon + value combo. - // + // // property value: // The entire value of a property. - // + // // component value: // A single piece of a property value. Like the 5px in // text-shadow: 0 0 5px blue;. Can also refer to things that are // multiple terms, like the 1-4 terms that make up the background-size // portion of the background shorthand. - // + // // term: // The basic unit of author-facing CSS, like a single number (5), // dimension (5px), string ("foo"), or function. Officially defined // by the CSS 2.1 grammar (look for the 'term' production) - // - // + // + // // simple selector: // A single atomic selector, like a type selector, an attr selector, a // class selector, etc. - // + // // compound selector: // One or more simple selectors without a combinator. div.example is // compound, div > .example is not. - // + // // complex selector: // One or more compound selectors chained with combinators. - // + // // combinator: // The parts of selectors that express relationships. There are four // currently - the space (descendant combinator), the greater-than // bracket (child combinator), the plus sign (next sibling combinator), // and the tilda (following sibling combinator). - // + // // sequence of selectors: // One or more of the named type of selector chained with commas. + state.tokenize = state.tokenize || tokenBase; if (state.tokenize == tokenBase && stream.eatSpace()) return null; var style = state.tokenize(stream, state); // Changing style returned based on context var context = state.stack[state.stack.length-1]; - if (style == "property") { + if (style == "variable") { + if (type == "variable-definition") state.stack.push("propertyValue"); + return "variable-2"; + } else if (style == "property") { if (context == "propertyValue"){ if (valueKeywords[stream.current()]) { style = "string-2"; @@ -370,6 +171,18 @@ CodeMirror.defineMode("css", function(config) { if (!propertyKeywords[stream.current()]) { style += " error"; } + } else if (context == "block") { + // if a value is present in both property, value, or color, the order + // of preference is property -> color -> value + if (propertyKeywords[stream.current()]) { + style = "property"; + } else if (colorKeywords[stream.current()]) { + style = "keyword"; + } else if (valueKeywords[stream.current()]) { + style = "string-2"; + } else { + style = "tag"; + } } else if (!context || context == "@media{") { style = "tag"; } else if (context == "@media") { @@ -434,19 +247,25 @@ CodeMirror.defineMode("css", function(config) { state.stack.pop(); state.stack[state.stack.length-1] = "@media{"; } - else state.stack.push("rule"); + else { + var newContext = allowNested ? "block" : "rule"; + state.stack.push(newContext); + } } else if (type == "}") { + var lastState = state.stack[state.stack.length - 1]; + if (lastState == "interpolation") style = "operator"; state.stack.pop(); if (context == "propertyValue") state.stack.pop(); } + else if (type == "interpolation") state.stack.push("interpolation"); else if (type == "@media") state.stack.push("@media"); else if (context == "@media" && /\b(keyword|attribute)\b/.test(style)) state.stack.push("@mediaType"); else if (context == "@mediaType" && stream.current() == ",") state.stack.pop(); else if (context == "@mediaType" && type == "(") state.stack.push("@mediaType("); else if (context == "@mediaType(" && type == ")") state.stack.pop(); - else if (context == "rule" && type == ":") state.stack.push("propertyValue"); + else if ((context == "rule" || context == "block") && type == ":") state.stack.push("propertyValue"); else if (context == "propertyValue" && type == ";") state.stack.pop(); return style; }, @@ -462,4 +281,286 @@ CodeMirror.defineMode("css", function(config) { }; }); -CodeMirror.defineMIME("text/css", "css"); +(function() { + function mimes(ms, mode) { + for (var i = 0; i < ms.length; ++i) { + CodeMirror.defineMIME(ms[i], mode); + } + } + + function keySet(array) { + var keys = {}; + for (var i = 0; i < array.length; ++i) { + keys[array[i]] = true; + } + return keys; + } + + var atMediaTypes = [ + "all", "aural", "braille", "handheld", "print", "projection", "screen", + "tty", "tv", "embossed" + ]; + + var atMediaFeatures = [ + "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-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", "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-cell", "grid-column", "grid-column-align", + "grid-column-sizing", "grid-column-span", "grid-columns", "grid-flow", + "grid-row", "grid-row-align", "grid-row-sizing", "grid-row-span", + "grid-rows", "grid-template", "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", "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", "rendering-intent", + "resize", "rest", "rest-after", "rest-before", "richness", "right", + "rotation", "rotation-point", "ruby-align", "ruby-overhang", + "ruby-position", "ruby-span", "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-shadow", + "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" + ]; + + var colorKeywords = [ + "black", "silver", "gray", "white", "maroon", "red", "purple", "fuchsia", + "green", "lime", "olive", "yellow", "navy", "blue", "teal", "aqua" + ]; + + var valueKeywords = [ + "above", "absolute", "activeborder", "activecaption", "afar", + "after-white-space", "ahead", "alias", "all", "all-scroll", "alternate", + "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", + "arabic-indic", "armenian", "asterisks", "auto", "avoid", "background", + "backwards", "baseline", "below", "bidi-override", "binary", "bengali", + "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", + "both", "bottom", "break-all", "break-word", "button", "button-bevel", + "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian", + "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", + "cell", "center", "checkbox", "circle", "cjk-earthly-branch", + "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", + "col-resize", "collapse", "compact", "condensed", "contain", "content", + "content-box", "context-menu", "continuous", "copy", "cover", "crop", + "cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal", + "decimal-leading-zero", "default", "default-button", "destination-atop", + "destination-in", "destination-out", "destination-over", "devanagari", + "disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted", + "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", + "element", "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", "ew-resize", "expanded", "extra-condensed", + "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "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-table", "inset", "inside", "intrinsic", "invert", + "italic", "justify", "kannada", "katakana", "katakana-iroha", "khmer", + "landscape", "lao", "large", "larger", "left", "level", "lighter", + "line-through", "linear", "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", + "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", "navy", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", + "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", + "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", + "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", + "outside", "overlay", "overline", "padding", "padding-box", "painted", + "paused", "persian", "plus-darker", "plus-lighter", "pointer", "portrait", + "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button", + "radio", "read-only", "read-write", "read-write-plaintext-only", "relative", + "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba", + "ridge", "right", "round", "row-resize", "rtl", "run-in", "running", + "s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield", + "searchfield-cancel-button", "searchfield-decoration", + "searchfield-results-button", "searchfield-results-decoration", + "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", + "single", "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", "square", + "square-button", "start", "static", "status-bar", "stretch", "stroke", + "sub", "subpixel-antialiased", "super", "sw-resize", "table", + "table-caption", "table-cell", "table-column", "table-column-group", + "table-footer-group", "table-header-group", "table-row", "table-row-group", + "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", + "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", + "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", + "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", + "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", + "visibleStroke", "visual", "w-resize", "wait", "wave", "white", "wider", + "window", "windowframe", "windowtext", "x-large", "x-small", "xor", + "xx-large", "xx-small", "yellow" + ]; + + function tokenCComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "/") { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return ["comment", "comment"]; + } + + mimes(['text/css', 'css'], { + atMediaTypes: keySet(atMediaTypes), + atMediaFeatures: keySet(atMediaFeatures), + propertyKeywords: keySet(propertyKeywords), + colorKeywords: keySet(colorKeywords), + valueKeywords: keySet(valueKeywords), + hooks: { + "<": function(stream, state) { + function tokenSGMLComment(stream, state) { + var dashes = 0, ch; + while ((ch = stream.next()) != null) { + if (dashes >= 2 && ch == ">") { + state.tokenize = null; + break; + } + dashes = (ch == "-") ? dashes + 1 : 0; + } + return ["comment", "comment"]; + } + if (stream.eat("!")) { + state.tokenize = tokenSGMLComment; + return tokenSGMLComment(stream, state); + } + }, + '/': function(stream, state) { + if (stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + } + }, + name: "css" + }); + + mimes(['text/x-scss', 'scss'], { + atMediaTypes: keySet(atMediaTypes), + atMediaFeatures: keySet(atMediaFeatures), + propertyKeywords: keySet(propertyKeywords), + colorKeywords: keySet(colorKeywords), + valueKeywords: keySet(valueKeywords), + allowNested: true, + hooks: { + "$": function(stream) { + stream.match(/^[\w-]+/); + if (stream.peek() == ':') { + return ["variable", "variable-definition"]; + } + return ["variable", "variable"]; + }, + '/': function(stream, state) { + if (stream.eat('/')) { + stream.skipToEnd(); + return ['comment', 'comment']; + } else if (stream.eat('*')) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } else { + return ["operator", "operator"]; + } + }, + '#': function(stream) { + if (stream.eat('{')) { + return ["operator", "interpolation"]; + } else { + stream.eatWhile(/[\w\\\-]/); + return ["atom", "hash"]; + } + } + }, + name: "css" + }); +})(); diff --git a/mode/css/scss.html b/mode/css/scss.html new file mode 100644 index 0000000000..b67d7ff28a --- /dev/null +++ b/mode/css/scss.html @@ -0,0 +1,142 @@ + + + + + CodeMirror: SCSS mode + + + + + + + +

    CodeMirror: SCSS mode

    +
    + + +

    MIME types defined: text/scss.

    + +

    Parsing/Highlighting Tests: normal, verbose.

    + + + diff --git a/mode/css/scss_test.js b/mode/css/scss_test.js new file mode 100644 index 0000000000..a296e56fe6 --- /dev/null +++ b/mode/css/scss_test.js @@ -0,0 +1,77 @@ +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "text/x-scss"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + MT('url_with_quotation', + "[tag foo] { [property background][operator :][string-2 url]([string test.jpg]) }"); + + MT('url_with_double_quotes', + "[tag foo] { [property background][operator :][string-2 url]([string \"test.jpg\"]) }"); + + MT('url_with_single_quotes', + "[tag foo] { [property background][operator :][string-2 url]([string \'test.jpg\']) }"); + + MT('string', + "[def @import] [string \"compass/css3\"]"); + + MT('important_keyword', + "[tag foo] { [property background][operator :][string-2 url]([string \'test.jpg\']) [keyword !important] }"); + + MT('variable', + "[variable-2 $blue][operator :][atom #333]"); + + MT('variable_as_attribute', + "[tag foo] { [property color][operator :][variable-2 $blue] }"); + + MT('numbers', + "[tag foo] { [property padding][operator :][number 10px] [number 10] [number 10em] [number 8in] }"); + + MT('number_percentage', + "[tag foo] { [property width][operator :][number 80%] }"); + + MT('selector', + "[builtin #hello][qualifier .world]{}"); + + MT('singleline_comment', + "[comment // this is a comment]"); + + MT('multiline_comment', + "[comment /*foobar*/]"); + + MT('attribute_with_hyphen', + "[tag foo] { [property font-size][operator :][number 10px] }"); + + MT('string_after_attribute', + "[tag foo] { [property content][operator :][string \"::\"] }"); + + MT('directives', + "[def @include] [qualifier .mixin]"); + + MT('basic_structure', + "[tag p] { [property background][operator :][keyword red]; }"); + + MT('nested_structure', + "[tag p] { [tag a] { [property color][operator :][keyword red]; } }"); + + MT('mixin', + "[def @mixin] [tag table-base] {}"); + + MT('number_without_semicolon', + "[tag p] {[property width][operator :][number 12]}", + "[tag a] {[property color][operator :][keyword red];}"); + + MT('atom_in_nested_block', + "[tag p] { [tag a] { [property color][operator :][atom #000]; } }"); + + MT('interpolation_in_property', + "[tag foo] { [operator #{][variable-2 $hello][operator }:][atom #000]; }"); + + MT('interpolation_in_selector', + "[tag foo][operator #{][variable-2 $hello][operator }] { [property color][operator :][atom #000]; }"); + + MT('interpolation_error', + "[tag foo][operator #{][error foo][operator }] { [property color][operator :][atom #000]; }"); + + MT("divide_operator", + "[tag foo] { [property width][operator :][number 4] [operator /] [number 2] }"); +})(); diff --git a/mode/css/test.js b/mode/css/test.js index 4336ddabdf..0f68deb1c4 100644 --- a/mode/css/test.js +++ b/mode/css/test.js @@ -1,6 +1,6 @@ (function() { var mode = CodeMirror.getMode({tabSize: 4}, "css"); - function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 2)); } + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } // Requires at least one media query MT("atMediaEmpty", @@ -103,4 +103,7 @@ MT("tagTwoProperties", "[tag foo] { [property margin][operator :] [number 0]; [property padding][operator :] [number 0]; }"); + + MT("commentSGML", + "[comment ]"); })(); diff --git a/test/index.html b/test/index.html index 24bdf999d8..0a0da5bd87 100644 --- a/test/index.html +++ b/test/index.html @@ -56,6 +56,7 @@

    CodeMirror: Test Suite

    + From eb13244c5afdc86cd3803c6f83619bda5f53d287 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 5 Mar 2013 10:56:56 +0100 Subject: [PATCH 0307/5273] [scss mode] Integrate --- doc/modes.html | 1 + mode/css/css.js | 78 +++++++++++++++++++++---------------------- mode/css/scss_test.js | 2 +- mode/meta.js | 1 + test/mode_test.js | 4 +-- 5 files changed, 44 insertions(+), 42 deletions(-) diff --git a/doc/modes.html b/doc/modes.html index 927ef27dca..c3d16059ac 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -65,6 +65,7 @@

    { } CodeMi
  • Sass
  • Scala
  • Scheme
  • +
  • SCSS
  • Shell
  • Sieve
  • Smalltalk
  • diff --git a/mode/css/css.js b/mode/css/css.js index 7cdd18b3fc..058ae42036 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -1,5 +1,10 @@ -CodeMirror.defineMode("css", function(config, parserConfig) { +CodeMirror.defineMode("css", function(config) { + return CodeMirror.getMode(config, "text/css"); +}); + +CodeMirror.defineMode("css-base", function(config, parserConfig) { "use strict"; + var indentUnit = config.indentUnit, hooks = parserConfig.hooks || {}, atMediaTypes = parserConfig.atMediaTypes || {}, @@ -282,12 +287,6 @@ CodeMirror.defineMode("css", function(config, parserConfig) { }); (function() { - function mimes(ms, mode) { - for (var i = 0; i < ms.length; ++i) { - CodeMirror.defineMIME(ms[i], mode); - } - } - function keySet(array) { var keys = {}; for (var i = 0; i < array.length; ++i) { @@ -296,12 +295,12 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return keys; } - var atMediaTypes = [ + var atMediaTypes = keySet([ "all", "aural", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "embossed" - ]; + ]); - var atMediaFeatures = [ + var atMediaFeatures = keySet([ "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", @@ -310,9 +309,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "max-color", "color-index", "min-color-index", "max-color-index", "monochrome", "min-monochrome", "max-monochrome", "resolution", "min-resolution", "max-resolution", "scan", "grid" - ]; + ]); - var propertyKeywords = [ + var propertyKeywords = keySet([ "align-content", "align-items", "align-self", "alignment-adjust", "alignment-baseline", "anchor-point", "animation", "animation-delay", "animation-direction", "animation-duration", "animation-iteration-count", @@ -388,14 +387,14 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "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" - ]; + ]); - var colorKeywords = [ + var colorKeywords = keySet([ "black", "silver", "gray", "white", "maroon", "red", "purple", "fuchsia", "green", "lime", "olive", "yellow", "navy", "blue", "teal", "aqua" - ]; + ]); - var valueKeywords = [ + var valueKeywords = keySet([ "above", "absolute", "activeborder", "activecaption", "afar", "after-white-space", "ahead", "alias", "all", "all-scroll", "alternate", "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", @@ -478,7 +477,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "visibleStroke", "visual", "w-resize", "wait", "wave", "white", "wider", "window", "windowframe", "windowtext", "x-large", "x-small", "xor", "xx-large", "xx-small", "yellow" - ]; + ]); function tokenCComment(stream, state) { var maybeEnd = false, ch; @@ -492,12 +491,12 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return ["comment", "comment"]; } - mimes(['text/css', 'css'], { - atMediaTypes: keySet(atMediaTypes), - atMediaFeatures: keySet(atMediaFeatures), - propertyKeywords: keySet(propertyKeywords), - colorKeywords: keySet(colorKeywords), - valueKeywords: keySet(valueKeywords), + CodeMirror.defineMIME("text/css", { + atMediaTypes: atMediaTypes, + atMediaFeatures: atMediaFeatures, + propertyKeywords: propertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, hooks: { "<": function(stream, state) { function tokenSGMLComment(stream, state) { @@ -516,44 +515,45 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return tokenSGMLComment(stream, state); } }, - '/': function(stream, state) { + "/": function(stream, state) { if (stream.eat("*")) { state.tokenize = tokenCComment; return tokenCComment(stream, state); } + return false; } }, - name: "css" + name: "css-base" }); - mimes(['text/x-scss', 'scss'], { - atMediaTypes: keySet(atMediaTypes), - atMediaFeatures: keySet(atMediaFeatures), - propertyKeywords: keySet(propertyKeywords), - colorKeywords: keySet(colorKeywords), - valueKeywords: keySet(valueKeywords), + CodeMirror.defineMIME("text/x-scss", { + atMediaTypes: atMediaTypes, + atMediaFeatures: atMediaFeatures, + propertyKeywords: propertyKeywords, + colorKeywords: colorKeywords, + valueKeywords: valueKeywords, allowNested: true, hooks: { "$": function(stream) { stream.match(/^[\w-]+/); - if (stream.peek() == ':') { + if (stream.peek() == ":") { return ["variable", "variable-definition"]; } return ["variable", "variable"]; }, - '/': function(stream, state) { - if (stream.eat('/')) { + "/": function(stream, state) { + if (stream.eat("/")) { stream.skipToEnd(); - return ['comment', 'comment']; - } else if (stream.eat('*')) { + return ["comment", "comment"]; + } else if (stream.eat("*")) { state.tokenize = tokenCComment; return tokenCComment(stream, state); } else { return ["operator", "operator"]; } }, - '#': function(stream) { - if (stream.eat('{')) { + "#": function(stream) { + if (stream.eat("{")) { return ["operator", "interpolation"]; } else { stream.eatWhile(/[\w\\\-]/); @@ -561,6 +561,6 @@ CodeMirror.defineMode("css", function(config, parserConfig) { } } }, - name: "css" + name: "css-base" }); })(); diff --git a/mode/css/scss_test.js b/mode/css/scss_test.js index a296e56fe6..330b0a6a5b 100644 --- a/mode/css/scss_test.js +++ b/mode/css/scss_test.js @@ -1,6 +1,6 @@ (function() { var mode = CodeMirror.getMode({tabSize: 4}, "text/x-scss"); - function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); } MT('url_with_quotation', "[tag foo] { [property background][operator :][string-2 url]([string test.jpg]) }"); diff --git a/mode/meta.js b/mode/meta.js index 7ac3f181d0..cf8a7ec3ea 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -48,6 +48,7 @@ CodeMirror.modeInfo = [ {name: 'Rust', mime: 'text/x-rustsrc', mode: 'rust'}, {name: 'Sass', mime: 'text/x-sass', mode: 'sass'}, {name: 'Scheme', mime: 'text/x-scheme', mode: 'scheme'}, + {name: 'SCSS', mime: 'text/x-scss', mode: 'css'}, {name: 'Shell', mime: 'text/x-sh', mode: 'shell'}, {name: 'Sieve', mime: 'application/sieve', mode: 'sieve'}, {name: 'Smalltalk', mime: 'text/x-stsrc', mode: 'smalltalk'}, diff --git a/test/mode_test.js b/test/mode_test.js index 51e51b9525..79a7752492 100644 --- a/test/mode_test.js +++ b/test/mode_test.js @@ -59,9 +59,9 @@ return {tokens: tokens, plain: plain}; } - test.mode = function(name, mode, tokens) { + test.mode = function(name, mode, tokens, modeName) { var data = parseTokens(tokens); - return test(mode.name + "_" + name, function() { + return test((modeName || mode.name) + "_" + name, function() { return compare(data.plain, data.tokens, mode); }); }; From bfea2717d18bca74944b36d08d8984177a05b9c4 Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Tue, 5 Mar 2013 22:04:55 -0500 Subject: [PATCH 0308/5273] Correct path of package from codemirror.js to lib/codemirror.js Ran into this when trying to include CodeMirror from Browserify - the path of `codemirror.js` doesn't point to the necessary `lib/codemirror.js` file. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2799b0a5e3..eb8f2ba07d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "codemirror", "version":"3.10.01", - "main": "codemirror.js", + "main": "lib/codemirror.js", "description": "In-browser code editing made bearable", "licenses": [{"type": "MIT", "url": "http://codemirror.net/LICENSE"}], From c65ee3ed62c60cedcd02a314187619587caf0881 Mon Sep 17 00:00:00 2001 From: flack Date: Tue, 5 Mar 2013 15:56:31 +0100 Subject: [PATCH 0309/5273] Fix 1-2 pixel jumps when brackets are highlighted With the eclipse theme, if you move your cursor on a bracket and have the matching bracket option enabled, spans with borders are inserted. They push the rest of the line to the right by the amount of the border width, which looks very crappy. Using outline instead of border fixes this --- theme/eclipse.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/eclipse.css b/theme/eclipse.css index 47d66a012e..4807e45156 100644 --- a/theme/eclipse.css +++ b/theme/eclipse.css @@ -20,6 +20,6 @@ .cm-s-eclipse span.cm-link {color: #219;} .cm-s-eclipse .CodeMirror-matchingbracket { - border:1px solid grey; + outline:1px solid grey; color:black !important;; } From ec8438df11c0207dd3fed27817fc934803f88d1f Mon Sep 17 00:00:00 2001 From: Chris Coyier Date: Fri, 1 Mar 2013 08:36:28 -0800 Subject: [PATCH 0310/5273] iOS keyboard opening fix --- lib/codemirror.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 442ba8a62f..801ddb07c3 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -91,10 +91,14 @@ window.CodeMirror = (function() { function makeDisplay(place, docStart) { var d = {}; + var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none;"); if (webkit) input.style.width = "1000px"; else input.setAttribute("wrap", "off"); + // if border: 0; -- iOS fails to open keyboard (issue #1287) + if (ios) input.style.border = "1px solid black"; input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off"); + // Wraps and hides input textarea d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); // The actual fake scrollbars. From d07f7a9c8340a9e2a4943e947fb483733c90c87b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Mar 2013 08:26:39 +0100 Subject: [PATCH 0311/5273] M-x delete-trailing-whitespace (lib/codemirror.js) --- lib/codemirror.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 801ddb07c3..10888bac1f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -39,7 +39,7 @@ window.CodeMirror = (function() { function CodeMirror(place, options) { if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); - + this.options = options = options || {}; // Determine effective options based on given values and defaults. for (var opt in defaults) if (!options.hasOwnProperty(opt) && defaults.hasOwnProperty(opt)) @@ -183,7 +183,7 @@ window.CodeMirror = (function() { // Used for measuring wheel scrolling granularity d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; - + return d; } @@ -328,7 +328,7 @@ window.CodeMirror = (function() { if (needsV) { d.scrollbarV.style.display = "block"; d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0"; - d.scrollbarV.firstChild.style.height = + d.scrollbarV.firstChild.style.height = (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + "px"; } else d.scrollbarV.style.display = ""; if (needsH) { @@ -638,7 +638,7 @@ window.CodeMirror = (function() { // Lines with gutter elements, widgets or a background class need // to be wrapped again, and have the extra elements added to the // wrapper div - + if (reuse) { reuse.alignable = null; var isOk = true, widgetsSeen = 0; @@ -931,7 +931,7 @@ window.CodeMirror = (function() { } // POSITION MEASUREMENT - + function paddingTop(display) {return display.lineSpace.offsetTop;} function paddingLeft(display) { var e = removeChildrenAndAdd(display.measure, elt("pre", null, null, "text-align: left")).appendChild(elt("span", "x")); @@ -941,7 +941,7 @@ window.CodeMirror = (function() { function measureChar(cm, line, ch, data) { var dir = -1; data = data || measureLine(cm, line); - + for (var pos = ch;; pos += dir) { var r = data[pos]; if (r) break; @@ -1385,7 +1385,7 @@ window.CodeMirror = (function() { var updateInput = cm.curOp.updateInput; makeChange(cm.doc, {from: from, to: to, text: splitLines(text.slice(same)), origin: cm.state.pasteIncoming ? "paste" : "+input"}, "end"); - + cm.curOp.updateInput = updateInput; if (text.length > 1000) input.value = cm.display.prevInput = ""; else cm.display.prevInput = text; @@ -1465,7 +1465,7 @@ window.CodeMirror = (function() { for (var p = d.wrapper.parentNode; p && p != document.body; p = p.parentNode) {} if (p) setTimeout(unregister, 5000); else off(window, "resize", onResize); - } + } setTimeout(unregister, 5000); on(d.input, "keyup", operation(cm, function(e) { @@ -1490,7 +1490,7 @@ window.CodeMirror = (function() { } on(d.scroller, "paste", function(e){ if (eventInWidget(d, e)) return; - focusInput(cm); + focusInput(cm); fastPoll(cm); }); on(d.input, "paste", function() { @@ -1748,7 +1748,7 @@ window.CodeMirror = (function() { function onDragStart(cm, e) { if (eventInWidget(cm.display, e)) return; - + var txt = cm.getSelection(); e.dataTransfer.setData("Text", txt); @@ -2032,7 +2032,7 @@ window.CodeMirror = (function() { if (ie_lt9) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos; slowPoll(cm); - // Try to detect the user choosing select-all + // Try to detect the user choosing select-all if (display.input.selectionStart != null && (!ie || ie_lt9)) { clearTimeout(detectingSelectAll); var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" : display.input.value), i = 0; @@ -2090,7 +2090,7 @@ window.CodeMirror = (function() { head: clipPostChange(doc, change, hint.head)}; if (hint == "start") return {anchor: change.from, head: change.from}; - + var end = changeEnd(change); if (hint == "around") return {anchor: change.from, head: end}; if (hint == "end") return {anchor: end, head: end}; @@ -3018,7 +3018,7 @@ window.CodeMirror = (function() { option("firstLineNumber", 1, guttersChanged, true); option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true); option("showCursorWhenSelecting", false, updateSelection, true); - + option("readOnly", false, function(cm, val) { if (val == "nocursor") {onBlur(cm); cm.display.input.blur();} else if (!val) resetInput(cm, true); @@ -4353,7 +4353,7 @@ window.CodeMirror = (function() { var Doc = CodeMirror.Doc = function(text, mode, firstLine) { if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); if (firstLine == null) firstLine = 0; - + BranchChunk.call(this, [new LeafChunk([makeLine("", null)])]); this.first = firstLine; this.scrollTop = this.scrollLeft = 0; @@ -4465,7 +4465,7 @@ window.CodeMirror = (function() { this.history.lastOp = this.history.lastOrigin = null; }, isClean: function () {return this.history.dirtyCounter == 0;}, - + getHistory: function() { return {done: copyHistoryArray(this.history.done), undone: copyHistoryArray(this.history.undone)}; @@ -4760,7 +4760,7 @@ window.CodeMirror = (function() { while (hist.done.length > hist.undoDepth) hist.done.shift(); if (hist.dirtyCounter < 0) - // The user has made a change after undoing past the last clean state. + // The user has made a change after undoing past the last clean state. // We can never get back to a clean state now until markClean() is called. hist.dirtyCounter = NaN; else From f60fb21c0ede7d44cbd4050305a9ee770e8e632a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 6 Mar 2013 08:33:04 +0100 Subject: [PATCH 0312/5273] Make cursor sit above text, give fat cursor a specific z-index to sit behind it Issue #1317 --- lib/codemirror.css | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index 9359cd2996..e36fbeb88f 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -41,6 +41,7 @@ .CodeMirror div.CodeMirror-cursor { border-left: 1px solid black; + z-index: 3; } /* Shown when moving in bi-directional text */ .CodeMirror div.CodeMirror-secondarycursor { @@ -49,13 +50,8 @@ .CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor { width: auto; border: 0; - background: transparent; - background: rgba(0, 200, 0, .4); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800); -} -/* Kludge to turn off filter in ie9+, which also accepts rgba */ -.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor:not(#nonsense_id) { - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + background: #7e7; + z-index: 1; } /* Can style cursor different in overwrite (non-insert) mode */ .CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {} From d57f4cdcad4c2056d5a41bdc41de6caf0f24b9e8 Mon Sep 17 00:00:00 2001 From: Miguel Castillo Date: Wed, 6 Mar 2013 09:03:24 -0500 Subject: [PATCH 0313/5273] [javascript mode] Make 'this' a keyword --- mode/javascript/javascript.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index b6d4e6b451..8c25070408 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -19,7 +19,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { "function": kw("function"), "catch": kw("catch"), "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), "in": operator, "typeof": operator, "instanceof": operator, - "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom + "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom, + "this": kw("this") }; // Extend the 'normal' keywords with the TypeScript language extensions From 6ad9552d0aa1cfccd12a458af7b3ff40ec7af676 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 7 Mar 2013 09:01:02 +0100 Subject: [PATCH 0314/5273] [javascript mode] Make parser aware of 'this' keyword --- 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 8c25070408..fcb9ffc22c 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -149,7 +149,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { // Parser - var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true}; + var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true}; function JSLexical(indented, column, type, align, prev, info) { this.indented = indented; From 55fc0ac71e820418a75d52238c2bab3533dddbbb Mon Sep 17 00:00:00 2001 From: edsharp Date: Wed, 6 Mar 2013 10:01:34 +0000 Subject: [PATCH 0315/5273] [xml-hint addon] Recognize multi-line tags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows correct hinting even when the tag is multi-line by achieving a dot matches all effect by using [\s\S] instead. --- addon/hint/xml-hint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/hint/xml-hint.js b/addon/hint/xml-hint.js index 1609aafd40..42eab6f3b7 100644 --- a/addon/hint/xml-hint.js +++ b/addon/hint/xml-hint.js @@ -50,7 +50,7 @@ if(text.length >= 0) { - var regex = new RegExp('<([^!?][^\\s/>]*).*?>', 'g'); + var regex = new RegExp('<([^!?][^\\s/>]*)[\\s\\S]*?>', 'g'); var matches = []; var match; From 3a359da33aeed970f2621823fa3a5a80db025d98 Mon Sep 17 00:00:00 2001 From: Hasan Karahan Date: Wed, 6 Mar 2013 17:43:41 +0500 Subject: [PATCH 0316/5273] Fixed minor bug: HTTP path with commas now properly highlighted --- mode/rst/rst.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/rst/rst.js b/mode/rst/rst.js index abbd79a93b..5fed967a67 100644 --- a/mode/rst/rst.js +++ b/mode/rst/rst.js @@ -496,7 +496,7 @@ CodeMirror.defineMode('rst', function (config, options) { var rx_uri_protocol = "[Hh][Tt][Tt][Pp][Ss]?://"; var rx_uri_domain = "(?:[\\d\\w.-]+)\\.(?:\\w{2,6})"; - var rx_uri_path = "(?:/[\\d\\w\\#\\%\\&\\-\\.\\/\\:\\=\\?\\~]+)*"; + var rx_uri_path = "(?:/[\\d\\w\\#\\%\\&\\-\\.\\,\\/\\:\\=\\?\\~]+)*"; var rx_uri = new RegExp("^" + rx_uri_protocol + rx_uri_domain + rx_uri_path ); From 15600db901199b4e04125e2627a1c7e8bc425983 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 7 Mar 2013 09:10:46 +0100 Subject: [PATCH 0317/5273] [css mode] Fix bug introduced by recent refactoring The state.tokenize property could return an array, but the token method didn't count on that. Closes #1326 --- mode/css/css.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mode/css/css.js b/mode/css/css.js index 058ae42036..00d605a69d 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -22,7 +22,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { if (hooks[ch]) { // result[0] is style and result[1] is type var result = hooks[ch](stream, state); - if (result !== false) return ret(result[0], result[1]); + if (result !== false) return result; } if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("def", stream.current());} else if (ch == "=") ret(null, "compare"); @@ -157,6 +157,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { state.tokenize = state.tokenize || tokenBase; if (state.tokenize == tokenBase && stream.eatSpace()) return null; var style = state.tokenize(stream, state); + if (style && typeof style != "string") style = ret(style[0], style[1]); // Changing style returned based on context var context = state.stack[state.stack.length-1]; From 41c156f44903bded870bee8261d5b77bea4c5f10 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 7 Mar 2013 09:22:01 +0100 Subject: [PATCH 0318/5273] Make sure shared marker's widgets are cloned --- lib/codemirror.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 10888bac1f..a95d2bcb51 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3587,7 +3587,9 @@ window.CodeMirror = (function() { options = copyObj(options); options.shared = false; var markers = [markText(doc, from, to, options, type)], primary = markers[0]; + var widget = options.replacedWith; linkedDocs(doc, function(doc) { + if (widget) options.replacedWith = 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; From e5df8cc3ae1bde4b547bea879c78154189ebe890 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 7 Mar 2013 16:00:54 +0100 Subject: [PATCH 0319/5273] Fix spanAffectsWrapping for new Safari versions --- demo/spanaffectswrapping_shim.html | 73 ++++++++++++++++++++++++++++++ lib/codemirror.js | 4 +- 2 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 demo/spanaffectswrapping_shim.html diff --git a/demo/spanaffectswrapping_shim.html b/demo/spanaffectswrapping_shim.html new file mode 100644 index 0000000000..2d43eec05b --- /dev/null +++ b/demo/spanaffectswrapping_shim.html @@ -0,0 +1,73 @@ + + + + + CodeMirror: Automatically derive odd wrapping behavior for your browser + + + +

    CodeMirror: odd wrapping shim

    + +

    This is a hack to automatically derive + a spanAffectsWrapping regexp for a browser. See the + comments above that variable + in lib/codemirror.js + for some more details.

    + +
    +
    
    +
    +    
    +  
    +
    diff --git a/lib/codemirror.js b/lib/codemirror.js
    index a95d2bcb51..562ed009ee 100644
    --- a/lib/codemirror.js
    +++ b/lib/codemirror.js
    @@ -5102,8 +5102,8 @@ window.CodeMirror = (function() {
       // various browsers.
       var spanAffectsWrapping = /^$/; // Won't match any two-character string
       if (gecko) spanAffectsWrapping = /$'/;
    -  else if (safari) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
    -  else if (chrome) spanAffectsWrapping = /\-[^ \-\.?]|\?[^ \-\.?\]\}:;!'\"\),\/]|[\.!\"#&%\)*+,:;=>\]|\}~][\(\{\[<]|\$'/;
    +  else if (safari && !/Version\/([6-9]|\d\d)\b/.test(navigator.userAgent)) spanAffectsWrapping = /\-[^ \-?]|\?[^ !'\"\),.\-\/:;\?\]\}]/;
    +  else if (webkit) spanAffectsWrapping = /[~!#%&*)=+}\]|\"\.>,][({[<]|-[^\-?\.]|\?[^!)\-}\]\'\"\/?\.,]/;
     
       var knownScrollbarWidth;
       function scrollbarWidth(measure) {
    
    From 04d8fc6e48b9214a08d806e0fe8acbe7b119045c Mon Sep 17 00:00:00 2001
    From: Marijn Haverbeke 
    Date: Thu, 7 Mar 2013 17:23:15 +0100
    Subject: [PATCH 0320/5273] Another tweak to the spanAffectsWrapping regexp
    
    ---
     demo/spanaffectswrapping_shim.html | 2 +-
     lib/codemirror.js                  | 2 +-
     2 files changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/demo/spanaffectswrapping_shim.html b/demo/spanaffectswrapping_shim.html
    index 2d43eec05b..733db067ff 100644
    --- a/demo/spanaffectswrapping_shim.html
    +++ b/demo/spanaffectswrapping_shim.html
    @@ -19,7 +19,7 @@ 

    CodeMirror: odd wrapping shim

    + + + + + + +

    CodeMirror: Indented wrapped line demo

    + +
    + +

    This page uses a hack on top of the "renderLine" + event to make wrapped text line up with the base indentation of + the line.

    + + + + + diff --git a/demo/visibletabs.html b/demo/visibletabs.html index ddc12fb46a..109d1a6b08 100644 --- a/demo/visibletabs.html +++ b/demo/visibletabs.html @@ -37,7 +37,7 @@

    CodeMirror: Visible tabs demo

    Tabs inside the editor are spans with the -class cm-tab, and can be styled. +class cm-tab, and can be styled.

    + + + + + + +

    CodeMirror: LiveScript mode

    +
    + + +

    MIME types defined: text/x-livescript.

    + +

    The LiveScript mode was written by Kenneth Bentley (license).

    + + + diff --git a/mode/livescript/livescript.js b/mode/livescript/livescript.js new file mode 100644 index 0000000000..96d8813334 --- /dev/null +++ b/mode/livescript/livescript.js @@ -0,0 +1,265 @@ +/** + * Link to the project's GitHub page: + * https://github.com/duralog/CodeMirror + */ +var indenter, identifier, keywordend, stringfill, Rules, idx, r, i$, len$, i, rr; +CodeMirror.defineMode('livescript', function(conf){ + var tokenBase, external; + tokenBase = function(stream, state){ + var next_rule, nr, i$, len$, r, m; + if (next_rule = state.next || 'start') { + state.next = state.next; + if (Array.isArray(nr = Rules[next_rule])) { + for (i$ = 0, len$ = nr.length; i$ < len$; ++i$) { + r = nr[i$]; + if (r.regex && (m = stream.match(r.regex))) { + state.next = r.next; + return r.token; + } + } + stream.next(); + return 'error'; + } + if (stream.match(r = Rules[next_rule])) { + if (r.regex && stream.match(r.regex)) { + state.next = r.next; + return r.token; + } else { + stream.next(); + return 'error'; + } + } + } + stream.next(); + return 'error'; + }; + external = { + startState: function(basecolumn){ + return { + next: 'start', + lastToken: null + }; + }, + token: function(stream, state){ + var style; + style = tokenBase(stream, state); + state.lastToken = { + style: style, + indent: stream.indentation(), + content: stream.current() + }; + return style.replace(/\./g, ' '); + }, + indent: function(state, textAfter){ + var indentation; + indentation = state.lastToken.indent; + if (state.lastToken.content.match(indenter)) { + indentation += 2; + } + return indentation; + } + }; + return external; +}); +indenter = RegExp('(?:[({[=:]|[-~]>|\\b(?:e(?:lse|xport)|d(?:o|efault)|t(?:ry|hen)|finally|import(?:\\s*all)?|const|var|let|new|catch(?:\\s*' + identifier + ')?))\\s*$'); +identifier = '(?![\\d\\s])[$\\w\\xAA-\\uFFDC](?:(?!\\s)[$\\w\\xAA-\\uFFDC]|-[A-Za-z])*'; +keywordend = '(?![$\\w]|-[A-Za-z]|\\s*:(?![:=]))'; +stringfill = { + token: 'string', + regex: '.+' +}; +Rules = { + start: [ + { + token: 'comment.doc', + regex: '/\\*', + next: 'comment' + }, { + token: 'comment', + regex: '#.*' + }, { + token: 'keyword', + regex: '(?:t(?:h(?:is|row|en)|ry|ypeof!?)|c(?:on(?:tinue|st)|a(?:se|tch)|lass)|i(?:n(?:stanceof)?|mp(?:ort(?:\\s+all)?|lements)|[fs])|d(?:e(?:fault|lete|bugger)|o)|f(?:or(?:\\s+own)?|inally|unction)|s(?:uper|witch)|e(?:lse|x(?:tends|port)|val)|a(?:nd|rguments)|n(?:ew|ot)|un(?:less|til)|w(?:hile|ith)|o[fr]|return|break|let|var|loop)' + keywordend + }, { + token: 'constant.language', + regex: '(?:true|false|yes|no|on|off|null|void|undefined)' + keywordend + }, { + token: 'invalid.illegal', + regex: '(?:p(?:ackage|r(?:ivate|otected)|ublic)|i(?:mplements|nterface)|enum|static|yield)' + keywordend + }, { + token: 'language.support.class', + regex: '(?:R(?:e(?:gExp|ferenceError)|angeError)|S(?:tring|yntaxError)|E(?:rror|valError)|Array|Boolean|Date|Function|Number|Object|TypeError|URIError)' + keywordend + }, { + token: 'language.support.function', + regex: '(?:is(?:NaN|Finite)|parse(?:Int|Float)|Math|JSON|(?:en|de)codeURI(?:Component)?)' + keywordend + }, { + token: 'variable.language', + regex: '(?:t(?:hat|il|o)|f(?:rom|allthrough)|it|by|e)' + keywordend + }, { + token: 'identifier', + regex: identifier + '\\s*:(?![:=])' + }, { + token: 'variable', + regex: identifier + }, { + token: 'keyword.operator', + regex: '(?:\\.{3}|\\s+\\?)' + }, { + token: 'keyword.variable', + regex: '(?:@+|::|\\.\\.)', + next: 'key' + }, { + token: 'keyword.operator', + regex: '\\.\\s*', + next: 'key' + }, { + token: 'string', + regex: '\\\\\\S[^\\s,;)}\\]]*' + }, { + token: 'string.doc', + regex: '\'\'\'', + next: 'qdoc' + }, { + token: 'string.doc', + regex: '"""', + next: 'qqdoc' + }, { + token: 'string', + regex: '\'', + next: 'qstring' + }, { + token: 'string', + regex: '"', + next: 'qqstring' + }, { + token: 'string', + regex: '`', + next: 'js' + }, { + token: 'string', + regex: '<\\[', + next: 'words' + }, { + token: 'string.regex', + regex: '//', + next: 'heregex' + }, { + token: 'string.regex', + regex: '\\/(?:[^[\\/\\n\\\\]*(?:(?:\\\\.|\\[[^\\]\\n\\\\]*(?:\\\\.[^\\]\\n\\\\]*)*\\])[^[\\/\\n\\\\]*)*)\\/[gimy$]{0,4}', + next: 'key' + }, { + token: 'constant.numeric', + regex: '(?:0x[\\da-fA-F][\\da-fA-F_]*|(?:[2-9]|[12]\\d|3[0-6])r[\\da-zA-Z][\\da-zA-Z_]*|(?:\\d[\\d_]*(?:\\.\\d[\\d_]*)?|\\.\\d[\\d_]*)(?:e[+-]?\\d[\\d_]*)?[\\w$]*)' + }, { + token: 'lparen', + regex: '[({[]' + }, { + token: 'rparen', + regex: '[)}\\]]', + next: 'key' + }, { + token: 'keyword.operator', + regex: '\\S+' + }, { + token: 'text', + regex: '\\s+' + } + ], + heregex: [ + { + token: 'string.regex', + regex: '.*?//[gimy$?]{0,4}', + next: 'start' + }, { + token: 'string.regex', + regex: '\\s*#{' + }, { + token: 'comment.regex', + regex: '\\s+(?:#.*)?' + }, { + token: 'string.regex', + regex: '\\S+' + } + ], + key: [ + { + token: 'keyword.operator', + regex: '[.?@!]+' + }, { + token: 'identifier', + regex: identifier, + next: 'start' + }, { + token: 'text', + regex: '.', + next: 'start' + } + ], + comment: [ + { + token: 'comment.doc', + regex: '.*?\\*/', + next: 'start' + }, { + token: 'comment.doc', + regex: '.+' + } + ], + qdoc: [ + { + token: 'string', + regex: ".*?'''", + next: 'key' + }, stringfill + ], + qqdoc: [ + { + token: 'string', + regex: '.*?"""', + next: 'key' + }, stringfill + ], + qstring: [ + { + token: 'string', + regex: '[^\\\\\']*(?:\\\\.[^\\\\\']*)*\'', + next: 'key' + }, stringfill + ], + qqstring: [ + { + token: 'string', + regex: '[^\\\\"]*(?:\\\\.[^\\\\"]*)*"', + next: 'key' + }, stringfill + ], + js: [ + { + token: 'string', + regex: '[^\\\\`]*(?:\\\\.[^\\\\`]*)*`', + next: 'key' + }, stringfill + ], + words: [ + { + token: 'string', + regex: '.*?\\]>', + next: 'key' + }, stringfill + ] +}; +for (idx in Rules) { + r = Rules[idx]; + if (Array.isArray(r)) { + for (i$ = 0, len$ = r.length; i$ < len$; ++i$) { + i = i$; + rr = r[i$]; + if (rr.regex) { + Rules[idx][i].regex = new RegExp('^' + rr.regex); + } + } + } else if (r.regex) { + Rules[idx].regex = new RegExp('^' + r.regex); + } +} +CodeMirror.defineMIME('text/x-livescript', 'livescript'); diff --git a/mode/livescript/livescript.ls b/mode/livescript/livescript.ls new file mode 100644 index 0000000000..065242312a --- /dev/null +++ b/mode/livescript/livescript.ls @@ -0,0 +1,266 @@ +/** + * Link to the project's GitHub page: + * https://github.com/duralog/CodeMirror + */ +CodeMirror.defineMode 'livescript', (conf) -> + tokenBase = (stream, state) -> + #indent = + if next_rule = state.next or \start + state.next = state.next + if Array.isArray nr = Rules[next_rule] + for r in nr + if r.regex and m = stream.match r.regex + state.next = r.next + return r.token + stream.next! + return \error + if stream.match r = Rules[next_rule] + if r.regex and stream.match r.regex + state.next = r.next + return r.token + else + stream.next! + return \error + stream.next! + return 'error' + external = { + startState: (basecolumn) -> + { + next: \start + lastToken: null + } + token: (stream, state) -> + style = tokenBase stream, state #tokenLexer stream, state + state.lastToken = { + style: style + indent: stream.indentation! + content: stream.current! + } + style.replace /\./g, ' ' + indent: (state, textAfter) -> + # XXX this won't work with backcalls + indentation = state.lastToken.indent + if state.lastToken.content.match indenter then indentation += 2 + return indentation + } + external + +### Highlight Rules +# taken from mode-ls.ls + +indenter = // (? + : [({[=:] + | [-~]> + | \b (?: e(?:lse|xport) | d(?:o|efault) | t(?:ry|hen) | finally | + import (?:\s* all)? | const | var | + let | new | catch (?:\s* #identifier)? ) + ) \s* $ // + +identifier = /(?![\d\s])[$\w\xAA-\uFFDC](?:(?!\s)[$\w\xAA-\uFFDC]|-[A-Za-z])*/$ +keywordend = /(?![$\w]|-[A-Za-z]|\s*:(?![:=]))/$ +stringfill = token: \string, regex: '.+' + +Rules = + start: + * token: \comment.doc + regex: '/\\*' + next : \comment + + * token: \comment + regex: '#.*' + + * token: \keyword + regex: //(? + :t(?:h(?:is|row|en)|ry|ypeof!?) + |c(?:on(?:tinue|st)|a(?:se|tch)|lass) + |i(?:n(?:stanceof)?|mp(?:ort(?:\s+all)?|lements)|[fs]) + |d(?:e(?:fault|lete|bugger)|o) + |f(?:or(?:\s+own)?|inally|unction) + |s(?:uper|witch) + |e(?:lse|x(?:tends|port)|val) + |a(?:nd|rguments) + |n(?:ew|ot) + |un(?:less|til) + |w(?:hile|ith) + |o[fr]|return|break|let|var|loop + )//$ + keywordend + + * token: \constant.language + regex: '(?:true|false|yes|no|on|off|null|void|undefined)' + keywordend + + * token: \invalid.illegal + regex: '(? + :p(?:ackage|r(?:ivate|otected)|ublic) + |i(?:mplements|nterface) + |enum|static|yield + )' + keywordend + + * token: \language.support.class + regex: '(? + :R(?:e(?:gExp|ferenceError)|angeError) + |S(?:tring|yntaxError) + |E(?:rror|valError) + |Array|Boolean|Date|Function|Number|Object|TypeError|URIError + )' + keywordend + + * token: \language.support.function + regex: '(? + :is(?:NaN|Finite) + |parse(?:Int|Float) + |Math|JSON + |(?:en|de)codeURI(?:Component)? + )' + keywordend + + * token: \variable.language + regex: '(?:t(?:hat|il|o)|f(?:rom|allthrough)|it|by|e)' + keywordend + + * token: \identifier + regex: identifier + /\s*:(?![:=])/$ + + * token: \variable + regex: identifier + + * token: \keyword.operator + regex: /(?:\.{3}|\s+\?)/$ + + * token: \keyword.variable + regex: /(?:@+|::|\.\.)/$ + next : \key + + * token: \keyword.operator + regex: /\.\s*/$ + next : \key + + * token: \string + regex: /\\\S[^\s,;)}\]]*/$ + + * token: \string.doc + regex: \''' + next : \qdoc + + * token: \string.doc + regex: \""" + next : \qqdoc + + * token: \string + regex: \' + next : \qstring + + * token: \string + regex: \" + next : \qqstring + + * token: \string + regex: \` + next : \js + + * token: \string + regex: '<\\[' + next : \words + + * token: \string.regex + regex: \// + next : \heregex + + * token: \string.regex + regex: // + /(?: [^ [ / \n \\ ]* + (?: (?: \\. + | \[ [^\]\n\\]* (?:\\.[^\]\n\\]*)* \] + ) [^ [ / \n \\ ]* + )* + )/ [gimy$]{0,4} + //$ + next : \key + + * token: \constant.numeric + regex: '(?:0x[\\da-fA-F][\\da-fA-F_]* + |(?:[2-9]|[12]\\d|3[0-6])r[\\da-zA-Z][\\da-zA-Z_]* + |(?:\\d[\\d_]*(?:\\.\\d[\\d_]*)?|\\.\\d[\\d_]*) + (?:e[+-]?\\d[\\d_]*)?[\\w$]*)' + + * token: \lparen + regex: '[({[]' + + * token: \rparen + regex: '[)}\\]]' + next : \key + + * token: \keyword.operator + regex: \\\S+ + + * token: \text + regex: \\\s+ + + heregex: + * token: \string.regex + regex: '.*?//[gimy$?]{0,4}' + next : \start + * token: \string.regex + regex: '\\s*#{' + * token: \comment.regex + regex: '\\s+(?:#.*)?' + * token: \string.regex + regex: '\\S+' + + key: + * token: \keyword.operator + regex: '[.?@!]+' + * token: \identifier + regex: identifier + next : \start + * token: \text + regex: '.' + next : \start + + comment: + * token: \comment.doc + regex: '.*?\\*/' + next : \start + * token: \comment.doc + regex: '.+' + + qdoc: + token: \string + regex: ".*?'''" + next : \key + stringfill + + qqdoc: + token: \string + regex: '.*?"""' + next : \key + stringfill + + qstring: + token: \string + regex: /[^\\']*(?:\\.[^\\']*)*'/$ + next : \key + stringfill + + qqstring: + token: \string + regex: /[^\\"]*(?:\\.[^\\"]*)*"/$ + next : \key + stringfill + + js: + token: \string + regex: /[^\\`]*(?:\\.[^\\`]*)*`/$ + next : \key + stringfill + + words: + token: \string + regex: '.*?\\]>' + next : \key + stringfill + +# for optimization, precompile the regexps +for idx, r of Rules + if Array.isArray r + for rr, i in r + if rr.regex then Rules[idx][i].regex = new RegExp '^'+rr.regex + else if r.regex then Rules[idx].regex = new RegExp '^'+r.regex + +CodeMirror.defineMIME 'text/x-livescript', 'livescript' From ed2e51993575f0629df3240804416232c4805dbe Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Mar 2013 12:07:11 +0100 Subject: [PATCH 0332/5273] [livescript mode] Integrate --- doc/compress.html | 1 + doc/modes.html | 1 + mode/livescript/livescript.js | 496 +++++++++++++++++----------------- mode/meta.js | 1 + 4 files changed, 252 insertions(+), 247 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index a92f36396c..22b8362fc1 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -89,6 +89,7 @@

    { } CodeMi + diff --git a/doc/modes.html b/doc/modes.html index c3d16059ac..f8080a46e8 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -45,6 +45,7 @@

    { } CodeMi
  • JavaScript
  • Jinja2
  • LESS
  • +
  • LiveScript
  • Lua
  • Markdown (GitHub-flavour)
  • mIRC
  • diff --git a/mode/livescript/livescript.js b/mode/livescript/livescript.js index 96d8813334..c000324b8c 100644 --- a/mode/livescript/livescript.js +++ b/mode/livescript/livescript.js @@ -2,264 +2,266 @@ * Link to the project's GitHub page: * https://github.com/duralog/CodeMirror */ -var indenter, identifier, keywordend, stringfill, Rules, idx, r, i$, len$, i, rr; -CodeMirror.defineMode('livescript', function(conf){ - var tokenBase, external; - tokenBase = function(stream, state){ - var next_rule, nr, i$, len$, r, m; - if (next_rule = state.next || 'start') { - state.next = state.next; - if (Array.isArray(nr = Rules[next_rule])) { - for (i$ = 0, len$ = nr.length; i$ < len$; ++i$) { - r = nr[i$]; - if (r.regex && (m = stream.match(r.regex))) { +(function() { + CodeMirror.defineMode('livescript', function(){ + var tokenBase, external; + tokenBase = function(stream, state){ + var next_rule, nr, i$, len$, r, m; + if (next_rule = state.next || 'start') { + state.next = state.next; + if (Array.isArray(nr = Rules[next_rule])) { + for (i$ = 0, len$ = nr.length; i$ < len$; ++i$) { + r = nr[i$]; + if (r.regex && (m = stream.match(r.regex))) { + state.next = r.next; + return r.token; + } + } + stream.next(); + return 'error'; + } + if (stream.match(r = Rules[next_rule])) { + if (r.regex && stream.match(r.regex)) { state.next = r.next; return r.token; + } else { + stream.next(); + return 'error'; } } - stream.next(); - return 'error'; } - if (stream.match(r = Rules[next_rule])) { - if (r.regex && stream.match(r.regex)) { - state.next = r.next; - return r.token; - } else { - stream.next(); - return 'error'; + stream.next(); + return 'error'; + }; + external = { + startState: function(){ + return { + next: 'start', + lastToken: null + }; + }, + token: function(stream, state){ + var style; + style = tokenBase(stream, state); + state.lastToken = { + style: style, + indent: stream.indentation(), + content: stream.current() + }; + return style.replace(/\./g, ' '); + }, + indent: function(state){ + var indentation; + indentation = state.lastToken.indent; + if (state.lastToken.content.match(indenter)) { + indentation += 2; } + return indentation; } - } - stream.next(); - return 'error'; + }; + return external; + }); + + var identifier = '(?![\\d\\s])[$\\w\\xAA-\\uFFDC](?:(?!\\s)[$\\w\\xAA-\\uFFDC]|-[A-Za-z])*'; + var indenter = RegExp('(?:[({[=:]|[-~]>|\\b(?:e(?:lse|xport)|d(?:o|efault)|t(?:ry|hen)|finally|import(?:\\s*all)?|const|var|let|new|catch(?:\\s*' + identifier + ')?))\\s*$'); + var keywordend = '(?![$\\w]|-[A-Za-z]|\\s*:(?![:=]))'; + var stringfill = { + token: 'string', + regex: '.+' }; - external = { - startState: function(basecolumn){ - return { - next: 'start', - lastToken: null - }; - }, - token: function(stream, state){ - var style; - style = tokenBase(stream, state); - state.lastToken = { - style: style, - indent: stream.indentation(), - content: stream.current() - }; - return style.replace(/\./g, ' '); - }, - indent: function(state, textAfter){ - var indentation; - indentation = state.lastToken.indent; - if (state.lastToken.content.match(indenter)) { - indentation += 2; + var Rules = { + start: [ + { + token: 'comment.doc', + regex: '/\\*', + next: 'comment' + }, { + token: 'comment', + regex: '#.*' + }, { + token: 'keyword', + regex: '(?:t(?:h(?:is|row|en)|ry|ypeof!?)|c(?:on(?:tinue|st)|a(?:se|tch)|lass)|i(?:n(?:stanceof)?|mp(?:ort(?:\\s+all)?|lements)|[fs])|d(?:e(?:fault|lete|bugger)|o)|f(?:or(?:\\s+own)?|inally|unction)|s(?:uper|witch)|e(?:lse|x(?:tends|port)|val)|a(?:nd|rguments)|n(?:ew|ot)|un(?:less|til)|w(?:hile|ith)|o[fr]|return|break|let|var|loop)' + keywordend + }, { + token: 'constant.language', + regex: '(?:true|false|yes|no|on|off|null|void|undefined)' + keywordend + }, { + token: 'invalid.illegal', + regex: '(?:p(?:ackage|r(?:ivate|otected)|ublic)|i(?:mplements|nterface)|enum|static|yield)' + keywordend + }, { + token: 'language.support.class', + regex: '(?:R(?:e(?:gExp|ferenceError)|angeError)|S(?:tring|yntaxError)|E(?:rror|valError)|Array|Boolean|Date|Function|Number|Object|TypeError|URIError)' + keywordend + }, { + token: 'language.support.function', + regex: '(?:is(?:NaN|Finite)|parse(?:Int|Float)|Math|JSON|(?:en|de)codeURI(?:Component)?)' + keywordend + }, { + token: 'variable.language', + regex: '(?:t(?:hat|il|o)|f(?:rom|allthrough)|it|by|e)' + keywordend + }, { + token: 'identifier', + regex: identifier + '\\s*:(?![:=])' + }, { + token: 'variable', + regex: identifier + }, { + token: 'keyword.operator', + regex: '(?:\\.{3}|\\s+\\?)' + }, { + token: 'keyword.variable', + regex: '(?:@+|::|\\.\\.)', + next: 'key' + }, { + token: 'keyword.operator', + regex: '\\.\\s*', + next: 'key' + }, { + token: 'string', + regex: '\\\\\\S[^\\s,;)}\\]]*' + }, { + token: 'string.doc', + regex: '\'\'\'', + next: 'qdoc' + }, { + token: 'string.doc', + regex: '"""', + next: 'qqdoc' + }, { + token: 'string', + regex: '\'', + next: 'qstring' + }, { + token: 'string', + regex: '"', + next: 'qqstring' + }, { + token: 'string', + regex: '`', + next: 'js' + }, { + token: 'string', + regex: '<\\[', + next: 'words' + }, { + token: 'string.regex', + regex: '//', + next: 'heregex' + }, { + token: 'string.regex', + regex: '\\/(?:[^[\\/\\n\\\\]*(?:(?:\\\\.|\\[[^\\]\\n\\\\]*(?:\\\\.[^\\]\\n\\\\]*)*\\])[^[\\/\\n\\\\]*)*)\\/[gimy$]{0,4}', + next: 'key' + }, { + token: 'constant.numeric', + regex: '(?:0x[\\da-fA-F][\\da-fA-F_]*|(?:[2-9]|[12]\\d|3[0-6])r[\\da-zA-Z][\\da-zA-Z_]*|(?:\\d[\\d_]*(?:\\.\\d[\\d_]*)?|\\.\\d[\\d_]*)(?:e[+-]?\\d[\\d_]*)?[\\w$]*)' + }, { + token: 'lparen', + regex: '[({[]' + }, { + token: 'rparen', + regex: '[)}\\]]', + next: 'key' + }, { + token: 'keyword.operator', + regex: '\\S+' + }, { + token: 'text', + regex: '\\s+' } - return indentation; - } + ], + heregex: [ + { + token: 'string.regex', + regex: '.*?//[gimy$?]{0,4}', + next: 'start' + }, { + token: 'string.regex', + regex: '\\s*#{' + }, { + token: 'comment.regex', + regex: '\\s+(?:#.*)?' + }, { + token: 'string.regex', + regex: '\\S+' + } + ], + key: [ + { + token: 'keyword.operator', + regex: '[.?@!]+' + }, { + token: 'identifier', + regex: identifier, + next: 'start' + }, { + token: 'text', + regex: '.', + next: 'start' + } + ], + comment: [ + { + token: 'comment.doc', + regex: '.*?\\*/', + next: 'start' + }, { + token: 'comment.doc', + regex: '.+' + } + ], + qdoc: [ + { + token: 'string', + regex: ".*?'''", + next: 'key' + }, stringfill + ], + qqdoc: [ + { + token: 'string', + regex: '.*?"""', + next: 'key' + }, stringfill + ], + qstring: [ + { + token: 'string', + regex: '[^\\\\\']*(?:\\\\.[^\\\\\']*)*\'', + next: 'key' + }, stringfill + ], + qqstring: [ + { + token: 'string', + regex: '[^\\\\"]*(?:\\\\.[^\\\\"]*)*"', + next: 'key' + }, stringfill + ], + js: [ + { + token: 'string', + regex: '[^\\\\`]*(?:\\\\.[^\\\\`]*)*`', + next: 'key' + }, stringfill + ], + words: [ + { + token: 'string', + regex: '.*?\\]>', + next: 'key' + }, stringfill + ] }; - return external; -}); -indenter = RegExp('(?:[({[=:]|[-~]>|\\b(?:e(?:lse|xport)|d(?:o|efault)|t(?:ry|hen)|finally|import(?:\\s*all)?|const|var|let|new|catch(?:\\s*' + identifier + ')?))\\s*$'); -identifier = '(?![\\d\\s])[$\\w\\xAA-\\uFFDC](?:(?!\\s)[$\\w\\xAA-\\uFFDC]|-[A-Za-z])*'; -keywordend = '(?![$\\w]|-[A-Za-z]|\\s*:(?![:=]))'; -stringfill = { - token: 'string', - regex: '.+' -}; -Rules = { - start: [ - { - token: 'comment.doc', - regex: '/\\*', - next: 'comment' - }, { - token: 'comment', - regex: '#.*' - }, { - token: 'keyword', - regex: '(?:t(?:h(?:is|row|en)|ry|ypeof!?)|c(?:on(?:tinue|st)|a(?:se|tch)|lass)|i(?:n(?:stanceof)?|mp(?:ort(?:\\s+all)?|lements)|[fs])|d(?:e(?:fault|lete|bugger)|o)|f(?:or(?:\\s+own)?|inally|unction)|s(?:uper|witch)|e(?:lse|x(?:tends|port)|val)|a(?:nd|rguments)|n(?:ew|ot)|un(?:less|til)|w(?:hile|ith)|o[fr]|return|break|let|var|loop)' + keywordend - }, { - token: 'constant.language', - regex: '(?:true|false|yes|no|on|off|null|void|undefined)' + keywordend - }, { - token: 'invalid.illegal', - regex: '(?:p(?:ackage|r(?:ivate|otected)|ublic)|i(?:mplements|nterface)|enum|static|yield)' + keywordend - }, { - token: 'language.support.class', - regex: '(?:R(?:e(?:gExp|ferenceError)|angeError)|S(?:tring|yntaxError)|E(?:rror|valError)|Array|Boolean|Date|Function|Number|Object|TypeError|URIError)' + keywordend - }, { - token: 'language.support.function', - regex: '(?:is(?:NaN|Finite)|parse(?:Int|Float)|Math|JSON|(?:en|de)codeURI(?:Component)?)' + keywordend - }, { - token: 'variable.language', - regex: '(?:t(?:hat|il|o)|f(?:rom|allthrough)|it|by|e)' + keywordend - }, { - token: 'identifier', - regex: identifier + '\\s*:(?![:=])' - }, { - token: 'variable', - regex: identifier - }, { - token: 'keyword.operator', - regex: '(?:\\.{3}|\\s+\\?)' - }, { - token: 'keyword.variable', - regex: '(?:@+|::|\\.\\.)', - next: 'key' - }, { - token: 'keyword.operator', - regex: '\\.\\s*', - next: 'key' - }, { - token: 'string', - regex: '\\\\\\S[^\\s,;)}\\]]*' - }, { - token: 'string.doc', - regex: '\'\'\'', - next: 'qdoc' - }, { - token: 'string.doc', - regex: '"""', - next: 'qqdoc' - }, { - token: 'string', - regex: '\'', - next: 'qstring' - }, { - token: 'string', - regex: '"', - next: 'qqstring' - }, { - token: 'string', - regex: '`', - next: 'js' - }, { - token: 'string', - regex: '<\\[', - next: 'words' - }, { - token: 'string.regex', - regex: '//', - next: 'heregex' - }, { - token: 'string.regex', - regex: '\\/(?:[^[\\/\\n\\\\]*(?:(?:\\\\.|\\[[^\\]\\n\\\\]*(?:\\\\.[^\\]\\n\\\\]*)*\\])[^[\\/\\n\\\\]*)*)\\/[gimy$]{0,4}', - next: 'key' - }, { - token: 'constant.numeric', - regex: '(?:0x[\\da-fA-F][\\da-fA-F_]*|(?:[2-9]|[12]\\d|3[0-6])r[\\da-zA-Z][\\da-zA-Z_]*|(?:\\d[\\d_]*(?:\\.\\d[\\d_]*)?|\\.\\d[\\d_]*)(?:e[+-]?\\d[\\d_]*)?[\\w$]*)' - }, { - token: 'lparen', - regex: '[({[]' - }, { - token: 'rparen', - regex: '[)}\\]]', - next: 'key' - }, { - token: 'keyword.operator', - regex: '\\S+' - }, { - token: 'text', - regex: '\\s+' - } - ], - heregex: [ - { - token: 'string.regex', - regex: '.*?//[gimy$?]{0,4}', - next: 'start' - }, { - token: 'string.regex', - regex: '\\s*#{' - }, { - token: 'comment.regex', - regex: '\\s+(?:#.*)?' - }, { - token: 'string.regex', - regex: '\\S+' - } - ], - key: [ - { - token: 'keyword.operator', - regex: '[.?@!]+' - }, { - token: 'identifier', - regex: identifier, - next: 'start' - }, { - token: 'text', - regex: '.', - next: 'start' - } - ], - comment: [ - { - token: 'comment.doc', - regex: '.*?\\*/', - next: 'start' - }, { - token: 'comment.doc', - regex: '.+' - } - ], - qdoc: [ - { - token: 'string', - regex: ".*?'''", - next: 'key' - }, stringfill - ], - qqdoc: [ - { - token: 'string', - regex: '.*?"""', - next: 'key' - }, stringfill - ], - qstring: [ - { - token: 'string', - regex: '[^\\\\\']*(?:\\\\.[^\\\\\']*)*\'', - next: 'key' - }, stringfill - ], - qqstring: [ - { - token: 'string', - regex: '[^\\\\"]*(?:\\\\.[^\\\\"]*)*"', - next: 'key' - }, stringfill - ], - js: [ - { - token: 'string', - regex: '[^\\\\`]*(?:\\\\.[^\\\\`]*)*`', - next: 'key' - }, stringfill - ], - words: [ - { - token: 'string', - regex: '.*?\\]>', - next: 'key' - }, stringfill - ] -}; -for (idx in Rules) { - r = Rules[idx]; - if (Array.isArray(r)) { - for (i$ = 0, len$ = r.length; i$ < len$; ++i$) { - i = i$; - rr = r[i$]; - if (rr.regex) { - Rules[idx][i].regex = new RegExp('^' + rr.regex); + for (var idx in Rules) { + var r = Rules[idx]; + if (Array.isArray(r)) { + for (var i = 0, len = r.length; i < len; ++i) { + var rr = r[i]; + if (rr.regex) { + Rules[idx][i].regex = new RegExp('^' + rr.regex); + } } + } else if (r.regex) { + Rules[idx].regex = new RegExp('^' + r.regex); } - } else if (r.regex) { - Rules[idx].regex = new RegExp('^' + r.regex); } -} +})(); + CodeMirror.defineMIME('text/x-livescript', 'livescript'); diff --git a/mode/meta.js b/mode/meta.js index cf8a7ec3ea..7ca7333b2c 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -29,6 +29,7 @@ CodeMirror.modeInfo = [ {name: 'TypeScript', mime: 'application/typescript', mode: 'javascript'}, {name: 'Jinja2', mime: 'jinja2', mode: 'jinja2'}, {name: 'LESS', mime: 'text/x-less', mode: 'less'}, + {name: 'LiveScript', mime: 'text/x-livescript', mode: 'livescript'}, {name: 'Lua', mime: 'text/x-lua', mode: 'lua'}, {name: 'Markdown (GitHub-flavour)', mime: 'text/x-markdown', mode: 'markdown'}, {name: 'mIRC', mime: 'text/mirc', mode: 'mirc'}, From d55a02aea32d4000b768f59bc1d873e01492dcee Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Mar 2013 12:14:55 +0100 Subject: [PATCH 0333/5273] Set viewportMargin to Infinity in the autoresize demo --- demo/resize.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/demo/resize.html b/demo/resize.html index ddd4e56695..7badc2bfbb 100644 --- a/demo/resize.html +++ b/demo/resize.html @@ -33,12 +33,15 @@

    CodeMirror: Autoresize demo

    } -

    By setting a few CSS properties, CodeMirror can be made to +

    By setting a few CSS properties, and giving +the viewportMargin +a value of Infinity, CodeMirror can be made to automatically resize to fit its content.

    From 6752696cfc534c6422870fe1eadaa375fdc0bd7a Mon Sep 17 00:00:00 2001 From: satchmorun Date: Mon, 11 Mar 2013 09:15:07 -0500 Subject: [PATCH 0334/5273] [addon continuelist.js] Make the listiness check Just a small nit. Without the list check, `getStateAfter` looks like it will always be true. --- addon/edit/continuelist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/edit/continuelist.js b/addon/edit/continuelist.js index 907eb5fdcd..fb1fc38ba2 100644 --- a/addon/edit/continuelist.js +++ b/addon/edit/continuelist.js @@ -6,7 +6,7 @@ CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { var pos = cm.getCursor(), - inList = cm.getStateAfter(pos.line), + inList = cm.getStateAfter(pos.line).list, match; if (!inList || !(match = cm.getLine(pos.line).match(listRE))) { From 262bf5264501cac42ac3d2fc957c1b80ef13894c Mon Sep 17 00:00:00 2001 From: satchmorun Date: Mon, 11 Mar 2013 15:35:09 -0500 Subject: [PATCH 0335/5273] [addon closebrackets] Add smart backspace behavior When any specified pair is empty, backspacing will also delete the closing bracket. --- addon/edit/closebrackets.js | 22 +++++++++++++++++++++- demo/closebrackets.html | 8 ++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 9ca4ce1f5c..f512a54553 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -10,7 +10,10 @@ }); function buildKeymap(pairs) { - var map = {name : "autoCloseBrackets"}; + var map = { + name : "autoCloseBrackets", + Backspace: buildBackspacer(pairs) + }; for (var i = 0; i < pairs.length; i += 2) (function(left, right) { function maybeOverwrite(cm) { var cur = cm.getCursor(), ahead = cm.getRange(cur, CodeMirror.Pos(cur.line, cur.ch + 1)); @@ -26,4 +29,21 @@ })(pairs.charAt(i), pairs.charAt(i + 1)); return map; } + + function buildBackspacer(pairs) { + var pairmap = {}; + + for (var i = 0; i < pairs.length; i += 2) + pairmap[pairs.charAt(i)] = pairs.charAt(i + 1); + + return function(cm) { + var cur = cm.getCursor(), + from = CodeMirror.Pos(cur.line, cur.ch - 1), + to = CodeMirror.Pos(cur.line, cur.ch + 1), + str = cm.getRange(from, to); + + if (pairmap[str.charAt(0)] !== str.charAt(1)) return CodeMirror.Pass; + cm.replaceRange('', from, to); + }; + } })(); diff --git a/demo/closebrackets.html b/demo/closebrackets.html index 58ba0330a1..47304ea889 100644 --- a/demo/closebrackets.html +++ b/demo/closebrackets.html @@ -13,14 +13,18 @@ - +

    CodeMirror: Closebrackets Demo

    - +

    Type a bracket like '[', '(', '{', '"', or ''' and the addon will auto-close it. Type the closing variant when directly in front of a matching character and it will overwrite it.

    +

    If you backspace over a starting bracket while inside empty brackets + (e.g. {|}), it will delete the closing bracket for you.

    + +
    + +

    The placeholder + plug-in adds an option placeholder that can be set to + make text appear in the editor when it is empty and not focused. + If the source textarea has a placeholder attribute, + it will automatically be inherited.

    + + + + + diff --git a/doc/manual.html b/doc/manual.html index b6e1c8670d..1e84ca9313 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1549,6 +1549,12 @@

    Add-ons

    called newlineAndIndentContinueComment that you can bind Enter to in order to have the editor prefix new lines inside C-like block comments with an asterisk.

    +
    display/placeholder.js
    +
    Adds a placeholder option that can be used to + make text appear in the editor when it is empty and not focused. + Also gives the editor a CodeMirror-empty CSS class + whenever it doesn't contain any text. + See the demo.

    Writing CodeMirror Modes

    diff --git a/lib/codemirror.js b/lib/codemirror.js index 60a91a291b..e485219c18 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3312,6 +3312,8 @@ window.CodeMirror = (function() { options.value = textarea.value; if (!options.tabindex && textarea.tabindex) options.tabindex = textarea.tabindex; + if (!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) { From f936a703e1606122d61ba81299a3726cc014d042 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 12 Mar 2013 10:20:58 +0100 Subject: [PATCH 0339/5273] Remove unused variable --- addon/display/placeholder.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/addon/display/placeholder.js b/addon/display/placeholder.js index 66c2f1e16b..97f6d15fcc 100644 --- a/addon/display/placeholder.js +++ b/addon/display/placeholder.js @@ -1,6 +1,4 @@ (function() { - var placeholder; - CodeMirror.defineOption("placeholder", "", function(cm, val, old) { var prev = old && old != CodeMirror.Init; if (val && !prev) { From 5e881b9276f166c0e6c0640a12b7c4adc52f5b91 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 13 Mar 2013 17:48:49 +0100 Subject: [PATCH 0340/5273] Set a default background and color Closes #1346 --- lib/codemirror.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/codemirror.css b/lib/codemirror.css index e36fbeb88f..913a1a9c3d 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -102,6 +102,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} line-height: 1; position: relative; overflow: hidden; + background: white; + color: black; } .CodeMirror-scroll { From 165b65af88cfcaa8d74f9c0bd51cbb535964352a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 13 Mar 2013 17:58:46 +0100 Subject: [PATCH 0341/5273] [closetag addon] Fix bug in self-closing tags typed directly in front of word Closes #1349 --- addon/edit/closetag.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index 46a5f4c76c..5d6131c38b 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -55,8 +55,8 @@ if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); var lowerTagName = tagName.toLowerCase(); // Don't process the '>' at the end of an end-tag or self-closing tag - if (tok.type == "tag" && state.type == "closeTag" || - /\/\s*$/.test(tok.string) || + console.log(tok.string); + if (tok.type == "tag" && state.type == "closeTag" || tok.string.indexOf("/") > -1 || dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1) return CodeMirror.Pass; From 6220a2c75911c542ba4ed1dbd6fdc50bca4d0a97 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 13 Mar 2013 17:59:14 +0100 Subject: [PATCH 0342/5273] Remove a debug statement --- addon/edit/closetag.js | 1 - 1 file changed, 1 deletion(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index 5d6131c38b..54fa195463 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -55,7 +55,6 @@ if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); var lowerTagName = tagName.toLowerCase(); // Don't process the '>' at the end of an end-tag or self-closing tag - console.log(tok.string); if (tok.type == "tag" && state.type == "closeTag" || tok.string.indexOf("/") > -1 || dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1) return CodeMirror.Pass; From 1d12a3823366eda72ff40e20effc094633d4f1f1 Mon Sep 17 00:00:00 2001 From: Narciso Jaramillo Date: Tue, 12 Mar 2013 17:06:56 -0700 Subject: [PATCH 0343/5273] Don't try to scroll if editor isn't visible --- lib/codemirror.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index e485219c18..65126e0587 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1432,15 +1432,17 @@ window.CodeMirror = (function() { if (!captureMiddleClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); on(d.scroller, "scroll", function() { - setScrollTop(cm, d.scroller.scrollTop); - setScrollLeft(cm, d.scroller.scrollLeft, true); - signal(cm, "scroll", cm); + if (d.scroller.clientHeight) { + setScrollTop(cm, d.scroller.scrollTop); + setScrollLeft(cm, d.scroller.scrollLeft, true); + signal(cm, "scroll", cm); + } }); on(d.scrollbarV, "scroll", function() { - setScrollTop(cm, d.scrollbarV.scrollTop); + if (d.scroller.clientHeight) setScrollTop(cm, d.scrollbarV.scrollTop); }); on(d.scrollbarH, "scroll", function() { - setScrollLeft(cm, d.scrollbarH.scrollLeft); + if (d.scroller.clientHeight) setScrollLeft(cm, d.scrollbarH.scrollLeft); }); on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); From 50621941b536805b2c62cb0fb5e1bc8a98e8877d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 10:44:30 +0100 Subject: [PATCH 0344/5273] Make sure doc.scrollTop is accurate post-display-update Closes #1351 --- lib/codemirror.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 65126e0587..d04ff42cc7 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -405,6 +405,7 @@ window.CodeMirror = (function() { } updateSelection(cm); updateScrollbars(cm.display, cm.doc.height); + cm.doc.scrollTop = cm.display.scroller.scrollTop; return updated; } From db6242871c860c62f7c987edd032be2797378caf Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Wed, 13 Mar 2013 18:24:23 +0400 Subject: [PATCH 0345/5273] Improve closebrackets.js addon - Do not insert closing bracket if a spacechar or closing bracket follows cursor - Do not handle backspace if selection is not empty - Do not overwrite anything if selection is not empty - If selection is not empty and open bracket is inserted - surround selection with brackets. --- addon/edit/closebrackets.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 1ce5ba0511..b46caca02a 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -1,5 +1,6 @@ (function() { var DEFAULT_BRACKETS = "()[]{}''\"\""; + var SPACE_CHAR_REGEX = /\s/; CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { var wasOn = old && old != CodeMirror.Init; @@ -13,6 +14,7 @@ var map = { name : "autoCloseBrackets", Backspace: function(cm) { + if (cm.somethingSelected()) return CodeMirror.Pass; var cur = cm.getCursor(), line = cm.getLine(cur.line); if (cur.ch && cur.ch < line.length && pairs.indexOf(line.slice(cur.ch - 1, cur.ch + 1)) % 2 == 0) @@ -21,16 +23,27 @@ return CodeMirror.Pass; } }; + var closingBrackets = []; for (var i = 0; i < pairs.length; i += 2) (function(left, right) { + if (left != right) closingBrackets.push(right); + function surround(cm) { + var selection = cm.getSelection(); + cm.replaceSelection(left + selection + right); + } function maybeOverwrite(cm) { var cur = cm.getCursor(), ahead = cm.getRange(cur, CodeMirror.Pos(cur.line, cur.ch + 1)); - if (ahead != right) return CodeMirror.Pass; + if (ahead != right || cm.somethingSelected()) return CodeMirror.Pass; else cm.execCommand("goCharRight"); } map["'" + left + "'"] = function(cm) { + if (cm.somethingSelected()) return surround(cm); if (left == right && maybeOverwrite(cm) != CodeMirror.Pass) return; - var cur = cm.getCursor("start"), ahead = CodeMirror.Pos(cur.line, cur.ch + 1); - cm.replaceSelection(left + right, {head: ahead, anchor: ahead}); + var cur = cm.getCursor(), ahead = CodeMirror.Pos(cur.line, cur.ch + 1); + var line = cm.getLine(cur.line), nextChar = line.charAt(cur.ch); + if (line.length == cur.ch || closingBrackets.indexOf(nextChar) >= 0 || SPACE_CHAR_REGEX.test(nextChar)) + cm.replaceSelection(left + right, {head: ahead, anchor: ahead}); + else + return CodeMirror.Pass; }; if (left != right) map["'" + right + "'"] = maybeOverwrite; })(pairs.charAt(i), pairs.charAt(i + 1)); From 9338ba490fa5c73d3a9d47839b88565456d9084d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 11:38:15 +0100 Subject: [PATCH 0346/5273] Revise patch 50621941b536805b2c62cb0fb5e1bc8a98e8877d The previous solution broke test doc_docKeepsScroll. --- lib/codemirror.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index d04ff42cc7..cab11e813b 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -405,7 +405,6 @@ window.CodeMirror = (function() { } updateSelection(cm); updateScrollbars(cm.display, cm.doc.height); - cm.doc.scrollTop = cm.display.scroller.scrollTop; return updated; } @@ -1271,8 +1270,10 @@ window.CodeMirror = (function() { var coords = cursorCoords(cm, doc.sel.head); newScrollPos = calculateScrollPos(cm, coords.left, coords.top, coords.left, coords.bottom); } - if (op.changes.length || newScrollPos && newScrollPos.scrollTop != null) + if (op.changes.length || newScrollPos && newScrollPos.scrollTop != null) { updated = updateDisplay(cm, op.changes, newScrollPos && newScrollPos.scrollTop); + if (cm.display.scroller.offsetHeight) cm.doc.scrollTop = cm.display.scroller.scrollTop; + } if (!updated && op.selectionChanged) updateSelection(cm); if (op.updateScrollPos) { display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = newScrollPos.scrollTop; From 02b0f47d504eb96788f566b150f8ebc95cddf443 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 11:42:44 +0100 Subject: [PATCH 0347/5273] [placeholder addon] Fix corner case --- 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 97f6d15fcc..f85f2df127 100644 --- a/addon/display/placeholder.js +++ b/addon/display/placeholder.js @@ -15,7 +15,7 @@ wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); } - if (val && !cm.hasFocus()) setPlaceholder(cm); + if (val && !cm.hasFocus()) onBlur(cm); }); function clearPlaceholder(cm) { From 4a4f1a873076da0b6caa5dbfe01d1fdce762cae0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 11:55:34 +0100 Subject: [PATCH 0348/5273] Revert "Make the default by-word movement stop at word boundaries, rather than word end" This reverts commit dd919a2bcf93a59b2ab28aa766c50fe6e5d9d239. --- lib/codemirror.js | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index cab11e813b..cb5a781138 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2584,20 +2584,13 @@ window.CodeMirror = (function() { if (unit == "char") moveOnce(); else if (unit == "column") moveOnce(true); - else if (unit == "word" || unit == "wordBoundary") { - var sawWord = false, boundary = unit == "wordBoundary", cur = null; + else if (unit == "word") { + var sawWord = false; for (;;) { - if (dir < 0 && !moveOnce()) break; - var wordChar = isWordChar(lineObj.text.charAt(ch)), done = false; - if (boundary) { - if (cur == null) cur = wordChar; - else done = cur != wordChar; - } else { - if (wordChar) sawWord = true; - else done = sawWord; - } - if (done) {if (dir < 0) {dir = 1; moveOnce();} break;} - if (dir > 0 && !moveOnce()) break; + if (dir < 0) if (!moveOnce()) break; + if (isWordChar(lineObj.text.charAt(ch))) sawWord = true; + else if (sawWord) {if (dir < 0) {dir = 1; moveOnce();} break;} + if (dir > 0) if (!moveOnce()) break; } } var result = skipAtomic(doc, Pos(line, ch), dir, true); @@ -3195,8 +3188,6 @@ window.CodeMirror = (function() { goColumnRight: function(cm) {cm.moveH(1, "column");}, goWordLeft: function(cm) {cm.moveH(-1, "word");}, goWordRight: function(cm) {cm.moveH(1, "word");}, - goWordBoundaryLeft: function(cm) {cm.moveH(-1, "wordBoundary");}, - goWordBoundaryRight: function(cm) {cm.moveH(1, "wordBoundary");}, delCharBefore: function(cm) {cm.deleteH(-1, "char");}, delCharAfter: function(cm) {cm.deleteH(1, "char");}, delWordBefore: function(cm) {cm.deleteH(-1, "word");}, @@ -3238,7 +3229,7 @@ window.CodeMirror = (function() { keyMap.pcDefault = { "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", "Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd", - "Ctrl-Left": "goWordBoundaryLeft", "Ctrl-Right": "goWordBoundaryRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", "Ctrl-Backspace": "delWordBefore", "Ctrl-Delete": "delWordAfter", "Ctrl-S": "save", "Ctrl-F": "find", "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", @@ -3246,8 +3237,8 @@ window.CodeMirror = (function() { }; keyMap.macDefault = { "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", - "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goWordBoundaryLeft", - "Alt-Right": "goWordBoundaryRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordBefore", + "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goWordLeft", + "Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordBefore", "Ctrl-Alt-Backspace": "delWordAfter", "Alt-Delete": "delWordAfter", "Cmd-S": "save", "Cmd-F": "find", "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", "Cmd-[": "indentLess", "Cmd-]": "indentMore", From 047e0f513122e62a42e7341f61b9ae08c030f532 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 12:19:19 +0100 Subject: [PATCH 0349/5273] By-word movement change, take 2: count groups of punctuation as words Adds goGroupLeft/Right, delGroupLeft/Right as alternative to word-based motion/deletion. Binds ctrl-left/right/del/backspace to these commands. Also makes word and group-based motion stop at line boundaries. --- lib/codemirror.js | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index cb5a781138..86889e32be 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2584,13 +2584,21 @@ window.CodeMirror = (function() { if (unit == "char") moveOnce(); else if (unit == "column") moveOnce(true); - else if (unit == "word") { - var sawWord = false; - for (;;) { - if (dir < 0) if (!moveOnce()) break; - if (isWordChar(lineObj.text.charAt(ch))) sawWord = true; - else if (sawWord) {if (dir < 0) {dir = 1; moveOnce();} break;} - if (dir > 0) if (!moveOnce()) break; + else if (unit == "word" || unit == "group") { + var sawType = null, group = unit == "group"; + for (var first = true;; first = false) { + if (dir < 0 && !moveOnce(!first)) break; + var cur = lineObj.text.charAt(ch) || "\n"; + var type = isWordChar(cur) ? "w" + : !group ? null + : /\s/.test(cur) ? null + : "p"; + if (sawType && sawType != type) { + if (dir < 0) {dir = 1; moveOnce();} + break; + } + if (type) sawType = type; + if (dir > 0 && !moveOnce(!first)) break; } } var result = skipAtomic(doc, Pos(line, ch), dir, true); @@ -2620,9 +2628,9 @@ window.CodeMirror = (function() { if (line) { if (pos.after === false || end == line.length) --start; else ++end; var startChar = line.charAt(start); - var check = isWordChar(startChar) ? isWordChar : - /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} : - function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; + var check = isWordChar(startChar) ? isWordChar + : /\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; } @@ -3187,11 +3195,15 @@ window.CodeMirror = (function() { 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");}, @@ -3229,17 +3241,17 @@ window.CodeMirror = (function() { keyMap.pcDefault = { "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", "Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd", - "Ctrl-Left": "goWordLeft", "Ctrl-Right": "goWordRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", - "Ctrl-Backspace": "delWordBefore", "Ctrl-Delete": "delWordAfter", "Ctrl-S": "save", "Ctrl-F": "find", + "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", + "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", fallthrough: "basic" }; keyMap.macDefault = { "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", - "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goWordLeft", - "Alt-Right": "goWordRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delWordBefore", - "Ctrl-Alt-Backspace": "delWordAfter", "Alt-Delete": "delWordAfter", "Cmd-S": "save", "Cmd-F": "find", + "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", + "Alt-Right": "goGroupRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delGroupBefore", + "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", "Cmd-[": "indentLess", "Cmd-]": "indentMore", fallthrough: ["basic", "emacsy"] From d77ad465da4bf87d62829b5339d5451b3904da5d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 12:31:53 +0100 Subject: [PATCH 0350/5273] Add tests for by-group motion --- test/test.js | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/test/test.js b/test/test.js index 51631feb1c..3225b0498a 100644 --- a/test/test.js +++ b/test/test.js @@ -910,8 +910,8 @@ testCM("wordMovementCommands", function(cm) { cm.execCommand("goWordLeft"); eqPos(cm.getCursor(), Pos(0, 9)); cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); - eqPos(cm.getCursor(), Pos(1, 1)); - cm.execCommand("goWordRight"); + eqPos(cm.getCursor(), Pos(0, 24)); + cm.execCommand("goWordRight"); cm.execCommand("goWordRight"); eqPos(cm.getCursor(), Pos(1, 9)); cm.execCommand("goWordRight"); eqPos(cm.getCursor(), Pos(1, 13)); @@ -919,6 +919,34 @@ testCM("wordMovementCommands", function(cm) { eqPos(cm.getCursor(), Pos(2, 0)); }, {value: "this is (the) firstline.\na foo12\u00e9\u00f8\u00d7bar\n"}); +testCM("groupMovementCommands", function(cm) { + cm.execCommand("goGroupLeft"); + eqPos(cm.getCursor(), Pos(0, 0)); + cm.execCommand("goGroupRight"); + eqPos(cm.getCursor(), Pos(0, 4)); + cm.execCommand("goGroupRight"); + eqPos(cm.getCursor(), Pos(0, 7)); + cm.execCommand("goGroupRight"); + eqPos(cm.getCursor(), Pos(0, 10)); + cm.execCommand("goGroupLeft"); + eqPos(cm.getCursor(), Pos(0, 7)); + cm.execCommand("goGroupRight"); cm.execCommand("goGroupRight"); cm.execCommand("goGroupRight"); + eqPos(cm.getCursor(), Pos(0, 15)); + cm.setCursor(Pos(0, 17)); + cm.execCommand("goGroupLeft"); + eqPos(cm.getCursor(), Pos(0, 16)); + cm.execCommand("goGroupLeft"); + eqPos(cm.getCursor(), Pos(0, 14)); + cm.execCommand("goGroupRight"); cm.execCommand("goGroupRight"); + eqPos(cm.getCursor(), Pos(0, 20)); + cm.execCommand("goGroupRight"); + eqPos(cm.getCursor(), Pos(1, 5)); + cm.execCommand("goGroupLeft"); cm.execCommand("goGroupLeft"); + eqPos(cm.getCursor(), Pos(1, 0)); + cm.execCommand("goGroupLeft"); + eqPos(cm.getCursor(), Pos(0, 16)); +}, {value: "booo ba---quux. ffff\n abc d"}); + testCM("charMovementCommands", function(cm) { cm.execCommand("goCharLeft"); cm.execCommand("goColumnLeft"); eqPos(cm.getCursor(), Pos(0, 0)); @@ -1344,4 +1372,4 @@ testCM("beforeSelectionChange", function(cm) { cm.execCommand("selectAll"); eqPos(cm.getCursor("start"), Pos(0, 0)); eqPos(cm.getCursor("end"), Pos(9, 9)); -}); \ No newline at end of file +}); From 79d1c6ee34813328e1bd438b23b74f4e3af86557 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 13:00:26 +0100 Subject: [PATCH 0351/5273] Add a removed property to the info passed to change event handlers Issue #1358 --- doc/manual.html | 8 +++++--- lib/codemirror.js | 19 ++++++++++++------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 1e84ca9313..80dd59ba5a 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -352,7 +352,7 @@

    Events

    "change" (instance, changeObj)
    Fires every time the content of the editor is changed. - The changeObj is a {from, to, text, + The changeObj is a {from, to, text, removed, next} object containing information about the changes that occurred as second argument. from and to are the positions (in the pre-change @@ -360,8 +360,10 @@

    Events

    example, it might be {ch:0, line:18} if the position is at the beginning of line #19). text is an array of strings representing the text that replaced the - changed range (split by line). If multiple changes happened - during a single operation, the object will have + changed range (split by line). removed is the text + that used to be between from and to, + which is overwritten by this change. If multiple changes + happened during a single operation, the object will have a next property pointing to another change object (which may point to another, etc).
    diff --git a/lib/codemirror.js b/lib/codemirror.js index 86889e32be..0e66bae7bd 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2256,6 +2256,18 @@ window.CodeMirror = (function() { }); } + if (hasHandler(cm, "change")) { + var changeObj = {from: from, to: to, + text: change.text, + removed: getBetween(doc, from, to), + origin: change.origin}; + + if (cm.curOp.textChanged) { + for (var cur = cm.curOp.textChanged; cur.next; cur = cur.next) {} + cur.next = changeObj; + } else cm.curOp.textChanged = changeObj; + } + updateDoc(doc, change, spans, selAfter, estimateHeight(cm)); if (!cm.options.lineWrapping) { @@ -2278,13 +2290,6 @@ window.CodeMirror = (function() { var lendiff = change.text.length - (to.line - from.line) - 1; // Remember that these lines changed, for updating the display regChange(cm, from.line, to.line + 1, lendiff); - if (hasHandler(cm, "change")) { - var changeObj = {from: from, to: to, text: change.text, origin: change.origin}; - if (cm.curOp.textChanged) { - for (var cur = cm.curOp.textChanged; cur.next; cur = cur.next) {} - cur.next = changeObj; - } else cm.curOp.textChanged = changeObj; - } } function replaceRange(doc, code, from, to, origin) { From 5dad49618755398fc5c5af115961497a17df5d54 Mon Sep 17 00:00:00 2001 From: Michael Lehenbauer Date: Fri, 15 Mar 2013 13:01:19 +0100 Subject: [PATCH 0352/5273] Add test for change.removed property --- test/test.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/test.js b/test/test.js index 3225b0498a..d3e78f80bb 100644 --- a/test/test.js +++ b/test/test.js @@ -1373,3 +1373,28 @@ testCM("beforeSelectionChange", function(cm) { eqPos(cm.getCursor("start"), Pos(0, 0)); eqPos(cm.getCursor("end"), Pos(9, 9)); }); + +testCM("change_removedText", function(cm) { + cm.setValue("abc\ndef"); + + var removedText; + cm.on("change", function(cm, change) { + removedText = [change.removed, change.next && change.next.removed]; + }); + + cm.operation(function() { + cm.replaceRange("xyz", Pos(0, 0), Pos(1,1)); + cm.replaceRange("123", Pos(0,0)); + }); + + eq(removedText[0].join("\n"), "abc\nd"); + eq(removedText[1].join("\n"), ""); + + cm.undo(); + eq(removedText[0].join("\n"), "123"); + eq(removedText[1].join("\n"), "xyz"); + + cm.redo(); + eq(removedText[0].join("\n"), "abc\nd"); + eq(removedText[1].join("\n"), ""); +}); From f0dbe85b3143a451b11b6f4fd7e5e33824b77c5b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 13:10:16 +0100 Subject: [PATCH 0353/5273] Pass change event to line handle's change handlers --- doc/manual.html | 7 +++++-- lib/codemirror.js | 19 ++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 80dd59ba5a..e16c255c9c 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -468,9 +468,12 @@

    Events

    is associated with the start of the line. Mostly useful when you need to find out when your gutter markers on a given line are removed. -
    "change" ()
    +
    "change" (line, changeObj)
    Fires when the line's text content is changed in any way - (but the line is not deleted outright).
    + (but the line is not deleted outright). The change + object is similar to the one passed + to change event on the editor + object.

    Marked range handles, as returned diff --git a/lib/codemirror.js b/lib/codemirror.js index 0e66bae7bd..772b4807c9 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3917,7 +3917,6 @@ window.CodeMirror = (function() { attachMarkedSpans(line, markedSpans); var estHeight = estimateHeight ? estimateHeight(line) : 1; if (estHeight != line.height) updateLineHeight(line, estHeight); - signalLater(line, "change"); } function cleanUpLine(line) { @@ -4208,6 +4207,10 @@ window.CodeMirror = (function() { function updateDoc(doc, change, markedSpans, selAfter, estimateHeight) { function spansFor(n) {return markedSpans ? markedSpans[n] : null;} + function update(line, text, spans) { + updateLine(line, text, spans, estimateHeight); + signalLater(line, "change", line, change); + } var from = change.from, to = change.to, text = change.text; var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); @@ -4219,27 +4222,25 @@ window.CodeMirror = (function() { // sure line objects move the way they are supposed to. for (var i = 0, e = text.length - 1, added = []; i < e; ++i) added.push(makeLine(text[i], spansFor(i), estimateHeight)); - updateLine(lastLine, lastLine.text, lastSpans, estimateHeight); + 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) { - updateLine(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), - lastSpans, estimateHeight); + update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); } else { for (var added = [], i = 1, e = text.length - 1; i < e; ++i) added.push(makeLine(text[i], spansFor(i), estimateHeight)); added.push(makeLine(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); - updateLine(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0), estimateHeight); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); doc.insert(from.line + 1, added); } } else if (text.length == 1) { - updateLine(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), - spansFor(0), estimateHeight); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); doc.remove(from.line + 1, nlines); } else { - updateLine(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0), estimateHeight); - updateLine(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans, estimateHeight); + update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); + update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); for (var i = 1, e = text.length - 1, added = []; i < e; ++i) added.push(makeLine(text[i], spansFor(i), estimateHeight)); if (nlines > 1) doc.remove(from.line + 1, nlines - 1); From be5560dfcddb49e6ce3cdcdddceec2cf0fea4d1b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 13:12:19 +0100 Subject: [PATCH 0354/5273] Make sure change objects passed to doc and line objs also have removed prop --- lib/codemirror.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 772b4807c9..99f711ce1e 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2237,6 +2237,8 @@ window.CodeMirror = (function() { text: [change.text[0]], origin: change.origin}; } + change.removed = getBetween(doc, change.from, change.to); + if (!selAfter) selAfter = computeSelAfterChange(doc, change, null); if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans, selAfter); else updateDoc(doc, change, spans, selAfter); @@ -2256,18 +2258,6 @@ window.CodeMirror = (function() { }); } - if (hasHandler(cm, "change")) { - var changeObj = {from: from, to: to, - text: change.text, - removed: getBetween(doc, from, to), - origin: change.origin}; - - if (cm.curOp.textChanged) { - for (var cur = cm.curOp.textChanged; cur.next; cur = cur.next) {} - cur.next = changeObj; - } else cm.curOp.textChanged = changeObj; - } - updateDoc(doc, change, spans, selAfter, estimateHeight(cm)); if (!cm.options.lineWrapping) { @@ -2290,6 +2280,17 @@ window.CodeMirror = (function() { var lendiff = change.text.length - (to.line - from.line) - 1; // Remember that these lines changed, for updating the display regChange(cm, from.line, to.line + 1, lendiff); + + if (hasHandler(cm, "change")) { + var changeObj = {from: from, to: to, + text: change.text, + removed: change.removed, + origin: change.origin}; + if (cm.curOp.textChanged) { + for (var cur = cm.curOp.textChanged; cur.next; cur = cur.next) {} + cur.next = changeObj; + } else cm.curOp.textChanged = changeObj; + } } function replaceRange(doc, code, from, to, origin) { From c5554d5f42776b629b4a786dba43170baf16874a Mon Sep 17 00:00:00 2001 From: "angelo.zerr@gmail.com" Date: Fri, 15 Mar 2013 13:21:29 +0100 Subject: [PATCH 0355/5273] Add xq-light theme --- demo/theme.html | 2 ++ theme/xq-light.css | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 theme/xq-light.css diff --git a/demo/theme.html b/demo/theme.html index 42a1b0cde7..046d1fc3e1 100644 --- a/demo/theme.html +++ b/demo/theme.html @@ -15,6 +15,7 @@ + @@ -62,6 +63,7 @@

    CodeMirror: Theme demo

    +

    diff --git a/theme/xq-light.css b/theme/xq-light.css new file mode 100644 index 0000000000..08784d58c4 --- /dev/null +++ b/theme/xq-light.css @@ -0,0 +1,43 @@ +/* +Copyright (C) 2011 by MarkLogic Corporation +Author: Mike Brevoort + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +.cm-s-xq-light span.cm-keyword {line-height: 1em; font-weight: bold; color: #5A5CAD; } +.cm-s-xq-light span.cm-atom {color: #6C8CD5;} +.cm-s-xq-light span.cm-number {color: #164;} +.cm-s-xq-light span.cm-def {text-decoration:underline;} +.cm-s-xq-light span.cm-variable {color: black; } +.cm-s-xq-light span.cm-variable-2 {color:black;} +.cm-s-xq-light span.cm-variable-3 {color: black; } +.cm-s-xq-light span.cm-property {} +.cm-s-xq-light span.cm-operator {} +.cm-s-xq-light span.cm-comment {color: #0080FF; font-style: italic;} +.cm-s-xq-light span.cm-string {color: red;} +.cm-s-xq-light span.cm-meta {color: yellow;} +.cm-s-xq-light span.cm-error {color: #f00;} +.cm-s-xq-light span.cm-qualifier {color: grey} +.cm-s-xq-light span.cm-builtin {color: #7EA656;} +.cm-s-xq-light span.cm-bracket {color: #cc7;} +.cm-s-xq-light span.cm-tag {color: #3F7F7F;} +.cm-s-xq-light span.cm-attribute {color: #7F007F;} + +.cm-s-xq-light .CodeMirror-activeline-background {background: #e8f2ff !important;} +.cm-s-xq-light .CodeMirror-matchingbracket {border:1px solid grey;color:black !important;background:yellow;} \ No newline at end of file From fb5791135f848e9af921ee44a07fd13e6130eb04 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 13:22:38 +0100 Subject: [PATCH 0356/5273] Add .tern-* to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ea08f9d785..bc20ab58d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /node_modules /npm-debug.log test.html +.tern-* From 8be65a4e5fa69070d77d215f06aa5f06b19ddc86 Mon Sep 17 00:00:00 2001 From: "angelo.zerr@gmail.com" Date: Fri, 15 Mar 2013 13:44:56 +0100 Subject: [PATCH 0357/5273] [lint addon] Support onUpdateLinting callback --- addon/lint/lint.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/lint/lint.js b/addon/lint/lint.js index f8aa3365df..dd838e7ea5 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -127,6 +127,7 @@ CodeMirror.validate = (function() { if (state.hasGutter) cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1)); } + if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); } function onChange(cm) { From 0a8b204d70ff3a2d0dde80d814cf56a5e139e5b2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 13:56:01 +0100 Subject: [PATCH 0358/5273] [javascript-lint addon] Make it possible to pass options to JSHint --- addon/lint/javascript-lint.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/addon/lint/javascript-lint.js b/addon/lint/javascript-lint.js index 0d8ec32ed0..2da0e55438 100644 --- a/addon/lint/javascript-lint.js +++ b/addon/lint/javascript-lint.js @@ -9,13 +9,19 @@ "Unmatched ", " and instead saw", " is not defined", "Unclosed string", "Stopping, unable to continue" ]; - CodeMirror.javascriptValidator = function(text) { + function validator(options, text) { JSHINT(text); var errors = JSHINT.data().errors, result = []; if (errors) parseErrors(errors, result); return result; + } + + CodeMirror.javascriptValidatorWithOptions = function(options) { + return function(text) { return validator(options, text); }; }; + CodeMirror.javascriptValidator = CodeMirror.javascriptValidatorWithOptions(null); + function cleanup(error) { // All problems are warnings by default fixWith(error, warnings, "warning", true); From 804e62ba8963ccfaea34032c3af57bb7e36d1156 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 13:59:11 +0100 Subject: [PATCH 0359/5273] Mistake in patch 0a8b204d70ff3a2d0dde80d814cf56a5e139e5b2 --- addon/lint/javascript-lint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/lint/javascript-lint.js b/addon/lint/javascript-lint.js index 2da0e55438..db9ff6b224 100644 --- a/addon/lint/javascript-lint.js +++ b/addon/lint/javascript-lint.js @@ -10,7 +10,7 @@ "Unclosed string", "Stopping, unable to continue" ]; function validator(options, text) { - JSHINT(text); + JSHINT(text, options); var errors = JSHINT.data().errors, result = []; if (errors) parseErrors(errors, result); return result; From ef896f9531ceac49c174eb8f84c7123b419e2702 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 14:58:22 +0100 Subject: [PATCH 0360/5273] [folding addon] Rewrite tagRangeFinder Closes #1360 --- addon/fold/foldcode.js | 142 +++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 92 deletions(-) diff --git a/addon/fold/foldcode.js b/addon/fold/foldcode.js index 90019762fc..bdc641d3c6 100644 --- a/addon/fold/foldcode.js +++ b/addon/fold/foldcode.js @@ -1,109 +1,67 @@ -// the tagRangeFinder function is -// Copyright (C) 2011 by Daniel Glazman -// released under the MIT license (../../LICENSE) like the rest of CodeMirror -CodeMirror.tagRangeFinder = function(cm, start) { +CodeMirror.tagRangeFinder = (function() { var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; - var xmlNAMERegExp = new RegExp("^[" + nameStartChar + "][" + nameChar + "]*"); + var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); - var lineText = cm.getLine(start.line); - var found = false; - var tag = null; - var pos = start.ch; - while (!found) { - pos = lineText.indexOf("<", pos); - if (-1 == pos) // no tag on line - return; - if (pos + 1 < lineText.length && lineText[pos + 1] == "/") { // closing tag - pos++; - continue; - } - // ok we seem to have a start tag - if (!lineText.substr(pos + 1).match(xmlNAMERegExp)) { // not a tag name... - pos++; - continue; + return function(cm, start) { + var line = start.line, ch = start.ch, lineText = cm.getLine(line); + + function nextLine() { + if (line >= cm.lastLine()) return; + ch = 0; + lineText = cm.getLine(++line); + return true; } - var gtPos = lineText.indexOf(">", pos + 1); - if (-1 == gtPos) { // end of start tag not in line - var l = start.line + 1; - var foundGt = false; - var lastLine = cm.lineCount(); - while (l < lastLine && !foundGt) { - var lt = cm.getLine(l); - gtPos = lt.indexOf(">"); - if (-1 != gtPos) { // found a > - foundGt = true; - var slash = lt.lastIndexOf("/", gtPos); - if (-1 != slash && slash < gtPos) { - var str = lineText.substr(slash, gtPos - slash + 1); - if (!str.match( /\/\s*\>/ )) // yep, that's the end of empty tag - return; - } - } - l++; + function toTagEnd() { + for (;;) { + var gt = lineText.indexOf(">", ch); + if (gt == -1) { if (nextLine()) continue; else return; } + var lastSlash = lineText.lastIndexOf("/", gt); + var selfClose = lastSlash > -1 && /^\s*$/.test(lineText.slice(lastSlash + 1, gt)); + ch = gt + 1; + return selfClose ? "selfClose" : "regular"; } - found = true; } - else { - var slashPos = lineText.lastIndexOf("/", gtPos); - if (-1 == slashPos) { // cannot be empty tag - found = true; - // don't continue - } - else { // empty tag? - // check if really empty tag - var str = lineText.substr(slashPos, gtPos - slashPos + 1); - if (!str.match( /\/\s*\>/ )) { // finally not empty - found = true; - // don't continue - } + function toNextTag() { + for (;;) { + xmlTagStart.lastIndex = ch; + var found = xmlTagStart.exec(lineText); + if (!found) { if (nextLine()) continue; else return; } + ch = found.index + found[0].length; + return found; } } - if (found) { - var subLine = lineText.substr(pos + 1); - tag = subLine.match(xmlNAMERegExp); - if (tag) { - // we have an element name, wooohooo ! - tag = tag[0]; - // do we have the close tag on same line ??? - if (-1 != lineText.indexOf("", pos)) // yep - { - found = false; - } - // we don't, so we have a candidate... + + var stack = [], startCh; + for (;;) { + var openTag = toNextTag(), end; + if (!openTag || line != start.line || !(end = toTagEnd())) return; + if (!openTag[1] && end != "selfClose") { + stack.push(openTag[2]); + startCh = ch; + break; } - else - found = false; } - if (!found) - pos++; - } - if (found) { - var startTag = "(\\<\\/" + tag + "\\>)|(\\<" + tag + "\\>)|(\\<" + tag + "\\s)|(\\<" + tag + "$)"; - var startTagRegExp = new RegExp(startTag); - var endTag = ""; - var depth = 1; - var l = start.line + 1; - var lastLine = cm.lineCount(); - while (l < lastLine) { - lineText = cm.getLine(l); - var match = lineText.match(startTagRegExp); - if (match) { - for (var i = 0; i < match.length; i++) { - if (match[i] == endTag) - depth--; - else - depth++; - if (!depth) return {from: CodeMirror.Pos(start.line, gtPos + 1), - to: CodeMirror.Pos(l, match.index)}; + for (;;) { + var next = toNextTag(), end, tagLine = line, tagCh = ch - (next ? next[0].length : 0); + if (!next || !(end = toTagEnd())) return; + if (end == "selfClose") continue; + if (next[1]) { // closing tag + for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { + stack.length = i; + break; } + if (!stack.length) return { + from: CodeMirror.Pos(start.line, startCh), + to: CodeMirror.Pos(tagLine, tagCh) + }; + } else { // opening tag + stack.push(next[2]); } - l++; } - return; - } -}; + }; +})(); CodeMirror.braceRangeFinder = function(cm, start) { var line = start.line, lineText = cm.getLine(line); From 00bcbcde2e0571ed4e635b34593f4a126d62c4b1 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Tue, 12 Mar 2013 02:49:02 -0400 Subject: [PATCH 0361/5273] [vim] Make search highlighting respect ^ (start of line) --- keymap/vim.js | 67 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 5a3469453e..e5c1121532 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -729,7 +729,7 @@ getSearchState(cm).setReversed(!forward); var promptPrefix = (forward) ? '/' : '?'; var originalQuery = getSearchState(cm).getQuery(); - var originalPos = cm.getCursor(); + var originalScrollPos = cm.getScrollInfo(); function handleQuery(query, ignoreCase, smartCase) { try { updateSearchQuery(cm, query, ignoreCase, smartCase); @@ -744,21 +744,22 @@ }); } function onPromptClose(query) { - cm.scrollIntoView(originalPos); + cm.scrollTo(originalScrollPos.left, originalScrollPos.top); handleQuery(query, true /** ignoreCase */, true /** smartCase */); } function onPromptKeyUp(e, query) { - if (query) { - try { - updateSearchQuery(cm, query, true /** ignoreCase */, - true /** smartCase */); - cm.scrollIntoView(findNext(cm, forward, query)); - } catch (e) { - // Swallow bad regexes for incremental search. - } + var parsedQuery; + try { + parsedQuery = updateSearchQuery(cm, query, + true /** ignoreCase */, true /** smartCase */) + } catch (e) { + // Swallow bad regexes for incremental search. + } + if (parsedQuery) { + cm.scrollIntoView(findNext(cm, !forward, parsedQuery), 30); } else { clearSearchHighlight(cm); - cm.scrollIntoView(originalPos); + cm.scrollTo(originalScrollPos.left, originalScrollPos.top); } } function onPromptKeyDown(e, query, close) { @@ -766,7 +767,7 @@ if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[') { updateSearchQuery(cm, originalQuery); clearSearchHighlight(cm); - cm.scrollIntoView(originalPos); + cm.scrollTo(originalScrollPos.left, originalScrollPos.top); CodeMirror.e_stop(e); close(); @@ -2148,28 +2149,40 @@ } return(false); } + // Returns true if the query is valid. function updateSearchQuery(cm, rawQuery, ignoreCase, smartCase) { - cm.operation(function() { - var state = getSearchState(cm); - if (!rawQuery) { - return; - } - var query = parseQuery(cm, rawQuery, !!ignoreCase, !!smartCase); - if (!query) { - return; - } - highlightSearchMatches(cm, query); - if (regexEqual(query, state.getQuery())) { - return; - } - state.setQuery(query); - }); + if (!rawQuery) { + return; + } + var state = getSearchState(cm); + var query = parseQuery(cm, rawQuery, !!ignoreCase, !!smartCase); + if (!query) { + return; + } + highlightSearchMatches(cm, query); + if (regexEqual(query, state.getQuery())) { + return query; + } + state.setQuery(query); + return query; } function searchOverlay(query) { + if (query.source.charAt(0) == '^') { + var matchSol = true; + } return { token: function(stream) { + if (matchSol && !stream.sol()) { + stream.skipToEnd(); + return; + } var match = stream.match(query, false); if (match) { + if (match[0].length == 0) { + // Matched empty string, skip to next. + stream.next(); + return; + } if (!stream.sol()) { // Backtrack 1 to match \b stream.backUp(1); From a36f4e941143996eee30a96c9042e4fd52650f63 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 15:12:29 +0100 Subject: [PATCH 0362/5273] [searchcursor addon] Fix reverse searching of regexps Closes #1364 --- addon/search/searchcursor.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/addon/search/searchcursor.js b/addon/search/searchcursor.js index e6554ce56b..0d2d874103 100644 --- a/addon/search/searchcursor.js +++ b/addon/search/searchcursor.js @@ -17,16 +17,15 @@ this.matches = function(reverse, pos) { if (reverse) { query.lastIndex = 0; - var line = cm.getLine(pos.line).slice(0, pos.ch), match = query.exec(line), start = 0; - while (match) { - start += match.index + 1; - line = line.slice(start); - query.lastIndex = 0; - var newmatch = query.exec(line); - if (newmatch) match = newmatch; - else break; + var line = cm.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start; + for (;;) { + query.lastIndex = cutOff; + var newMatch = query.exec(line); + if (!newMatch) break; + match = newMatch; + start = cutOff; + cutOff = match.index + 1; } - start--; } else { query.lastIndex = pos.ch; var line = cm.getLine(pos.line), match = query.exec(line), From 7b09d40c8999ede663ff1b27ba627e424678f386 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 14 Mar 2013 23:38:33 -0700 Subject: [PATCH 0363/5273] Added syntax highlighting for Math modes --- mode/stex/stex.js | 313 ++++++++++++++++++++++++++++------------------ mode/stex/test.js | 13 ++ 2 files changed, 205 insertions(+), 121 deletions(-) diff --git a/mode/stex/stex.js b/mode/stex/stex.js index 42ed82c669..318b63acd4 100644 --- a/mode/stex/stex.js +++ b/mode/stex/stex.js @@ -3,95 +3,93 @@ * Licence: MIT */ -CodeMirror.defineMode("stex", function() -{ +CodeMirror.defineMode("stex", function() { + "use strict"; + function pushCommand(state, command) { - state.cmdState.push(command); + state.cmdState.push(command); } - function peekCommand(state) { - if (state.cmdState.length>0) - return state.cmdState[state.cmdState.length-1]; - else - return null; + function peekCommand(state) { + if (state.cmdState.length > 0) { + return state.cmdState[state.cmdState.length - 1]; + } else { + return null; + } } function popCommand(state) { - if (state.cmdState.length>0) { - var plug = state.cmdState.pop(); - plug.closeBracket(); - } + var plug = state.cmdState.pop(); + if (plug) { + plug.closeBracket(); + } } - function applyMostPowerful(state) { - var context = state.cmdState; - for (var i = context.length - 1; i >= 0; i--) { - var plug = context[i]; - if (plug.name=="DEFAULT") - continue; - return plug.styleIdentifier(); - } - return null; + // returns the non-default plugin closest to the end of the list + function getMostPowerful(state) { + var context = state.cmdState; + for (var i = context.length - 1; i >= 0; i--) { + var plug = context[i]; + if (plug.name == "DEFAULT") { + continue; + } + return plug; + } + return { styleIdentifier: function() { return null; } }; } - function addPluginPattern(pluginName, cmdStyle, brackets, styles) { - return function () { - this.name=pluginName; - this.bracketNo = 0; - this.style=cmdStyle; - this.styles = styles; - this.brackets = brackets; - - this.styleIdentifier = function() { - if (this.bracketNo<=this.styles.length) - return this.styles[this.bracketNo-1]; - else - return null; - }; - this.openBracket = function() { - this.bracketNo++; - return "bracket"; - }; - this.closeBracket = function() {}; - }; + function addPluginPattern(pluginName, cmdStyle, styles) { + return function () { + this.name = pluginName; + this.bracketNo = 0; + this.style = cmdStyle; + this.styles = styles; + this.argument = null; // \begin and \end have arguments that follow. These are stored in the plugin + + this.styleIdentifier = function() { + return this.styles[this.bracketNo - 1] || null; + }; + this.openBracket = function() { + this.bracketNo++; + return "bracket"; + }; + this.closeBracket = function() {}; + }; } - var plugins = new Array(); - - plugins["importmodule"] = addPluginPattern("importmodule", "tag", "{[", ["string", "builtin"]); - plugins["documentclass"] = addPluginPattern("documentclass", "tag", "{[", ["", "atom"]); - plugins["usepackage"] = addPluginPattern("documentclass", "tag", "[", ["atom"]); - plugins["begin"] = addPluginPattern("documentclass", "tag", "[", ["atom"]); - plugins["end"] = addPluginPattern("documentclass", "tag", "[", ["atom"]); + var plugins = {}; + + plugins["importmodule"] = addPluginPattern("importmodule", "tag", ["string", "builtin"]); + plugins["documentclass"] = addPluginPattern("documentclass", "tag", ["", "atom"]); + plugins["usepackage"] = addPluginPattern("usepackage", "tag", ["atom"]); + plugins["begin"] = addPluginPattern("begin", "tag", ["atom"]); + plugins["end"] = addPluginPattern("end", "tag", ["atom"]); plugins["DEFAULT"] = function () { - this.name="DEFAULT"; - this.style="tag"; + this.name = "DEFAULT"; + this.style = "tag"; - this.styleIdentifier = this.openBracket = this.closeBracket = function() {}; + this.styleIdentifier = this.openBracket = this.closeBracket = function() {}; }; function setState(state, f) { - state.f = f; + state.f = f; } + // called when in a normal (no environment) context function normal(source, state) { - if (source.match(/^\\[a-zA-Z@]+/)) { - var cmdName = source.current(); - cmdName = cmdName.substr(1, cmdName.length-1); - var plug; - if (plugins.hasOwnProperty(cmdName)) { - plug = plugins[cmdName]; - } else { - plug = plugins["DEFAULT"]; - } - plug = new plug(); - pushCommand(state, plug); - setState(state, beginParams); - return plug.style; - } + var plug; + // Do we look like '\command' ? If so, attempt to apply the plugin 'command' + if (source.match(/^\\[a-zA-Z@]+/)) { + var cmdName = source.current().slice(1); + plug = plugins[cmdName] || plugins["DEFAULT"]; + plug = new plug(); + pushCommand(state, plug); + setState(state, beginParams); + return plug.style; + } - // escape characters + // escape characters if (source.match(/^\\[$&%#{}_]/)) { return "tag"; } @@ -101,74 +99,147 @@ CodeMirror.defineMode("stex", function() return "tag"; } - var ch = source.next(); - if (ch == "%") { + // find if we're starting various math modes + if (source.match("\\[")) { + setState(state, function(source, state){ return inMathMode(source, state, "\\]"); }); + return "keyword"; + } + if (source.match("$$")) { + setState(state, function(source, state){ return inMathMode(source, state, "$$"); }); + return "keyword"; + } + if (source.match("$")) { + setState(state, function(source, state){ return inMathMode(source, state, "$"); }); + return "keyword"; + } + + var ch = source.next(); + if (ch == "%") { // special case: % at end of its own line; stay in same state if (!source.eol()) { setState(state, inCComment); } - return "comment"; - } - else if (ch=='}' || ch==']') { - plug = peekCommand(state); - if (plug) { - plug.closeBracket(ch); - setState(state, beginParams); - } else - return "error"; - return "bracket"; - } else if (ch=='{' || ch=='[') { - plug = plugins["DEFAULT"]; - plug = new plug(); - pushCommand(state, plug); - return "bracket"; - } - else if (/\d/.test(ch)) { - source.eatWhile(/[\w.%]/); - return "atom"; - } - else { - source.eatWhile(/[\w-_]/); - return applyMostPowerful(state); - } + return "comment"; + } + else if (ch == '}' || ch == ']') { + plug = peekCommand(state); + if (plug) { + plug.closeBracket(ch); + setState(state, beginParams); + } else { + return "error"; + } + return "bracket"; + } else if (ch == '{' || ch == '[') { + plug = plugins["DEFAULT"]; + plug = new plug(); + pushCommand(state, plug); + return "bracket"; + } + else if (/\d/.test(ch)) { + source.eatWhile(/[\w.%]/); + return "atom"; + } + else { + source.eatWhile(/[\w\-_]/); + plug = getMostPowerful(state); + if (plug.name == 'begin') { + plug.argument = source.current(); + } + return plug.styleIdentifier(); + } } function inCComment(source, state) { - source.skipToEnd(); - setState(state, normal); - return "comment"; + source.skipToEnd(); + setState(state, normal); + return "comment"; + } + + function inMathMode(source, state, endModeSeq) { + if (source.eatSpace()) { + return null; + } + if (source.match(endModeSeq)) { + setState(state, normal); + return "keyword"; + } + if (source.match(/^\\[a-zA-Z@]+/)) { + return "tag"; + } + if (source.match(/^[a-zA-Z]+/)) { + return "variable-2"; + } + // escape characters + if (source.match(/^\\[$&%#{}_]/)) { + return "tag"; + } + // white space control characters + if (source.match(/^\\[,;!\/]/)) { + return "tag"; + } + // special math-mode characters + if (source.match(/^[\^_&]/)) { + return "tag"; + } + // non-special characters + if (source.match(/^[+\-<>|=,\/@!*:;'"`~#?]/)) { + return null; + } + if (source.match(/^(\d+\.\d*|\d*\.\d+|\d+)/)) { + return "number"; + } + var ch = source.next(); + if (ch == "{" || ch == "}" || ch == "[" || ch == "]" || ch == "(" || ch == ")") { + return "bracket"; + } + + // eat comments here, because inCComment returns us to normal state! + if (ch == "%") { + if (!source.eol()) { + source.skipToEnd(); + } + return "comment"; + } + return "error"; } function beginParams(source, state) { - var ch = source.peek(); - if (ch == '{' || ch == '[') { - var lastPlug = peekCommand(state); - lastPlug.openBracket(ch); - source.eat(ch); - setState(state, normal); - return "bracket"; - } - if (/[ \t\r]/.test(ch)) { - source.eat(ch); - return null; - } - setState(state, normal); - lastPlug = peekCommand(state); - if (lastPlug) { - popCommand(state); - } + var ch = source.peek(), lastPlug; + if (ch == '{' || ch == '[') { + lastPlug = peekCommand(state); + lastPlug.openBracket(ch); + source.eat(ch); + setState(state, normal); + return "bracket"; + } + if (/[ \t\r]/.test(ch)) { + source.eat(ch); + return null; + } + setState(state, normal); + popCommand(state); + return normal(source, state); } return { - startState: function() { return { f:normal, cmdState:[] }; }, - copyState: function(s) { return { f: s.f, cmdState: s.cmdState.slice(0, s.cmdState.length) }; }, - - token: function(stream, state) { - var t = state.f(stream, state); - return t; - } - }; + startState: function() { + return { + cmdState: [], + f: normal + }; + }, + copyState: function(s) { + return { + cmdState: s.cmdState.slice(), + f: s.f + }; + }, + token: function(stream, state) { + return state.f(stream, state); + } + }; }); CodeMirror.defineMIME("text/x-stex", "stex"); diff --git a/mode/stex/test.js b/mode/stex/test.js index e7e9c29c1e..727a7db07e 100644 --- a/mode/stex/test.js +++ b/mode/stex/test.js @@ -101,4 +101,17 @@ MT("tagBracket", "[tag \\newcommand][bracket {][tag \\pop][bracket }]"); + + MT("inlineMathTagFollowedByNumber", + "[keyword $][tag \\pi][number 2][keyword $]"); + + MT("inlineMath", + "[keyword $][number 3][variable-2 x][tag ^][number 2.45]-[tag \\sqrt][bracket {][tag \\$\\alpha][bracket }] = [number 2][keyword $] other text"); + + MT("displayMath", + "More [keyword $$]\t[variable-2 S][tag ^][variable-2 n][tag \\sum] [variable-2 i][keyword $$] other text"); + + MT("mathWithComment", + "[keyword $][variable-2 x] [comment % $]", + "[variable-2 y][keyword $] other text"); })(); From a9b6656e26ce591394de398f9ea4dbe628bc0c64 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 15:45:21 +0100 Subject: [PATCH 0364/5273] Add a second parameter to coordsChar to determine the origin --- doc/manual.html | 11 +++++++---- lib/codemirror.js | 28 +++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index e16c255c9c..6fee9965eb 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1205,10 +1205,13 @@

    Sizing, scrolling and positioning methods

    it'll give the size of the whole character, rather than just the position that the cursor would have when it would sit at that position. -
    cm.coordsChar(object) → pos
    -
    Given an {left, top} object (in page coordinates), - returns the {line, ch} position that corresponds to - it.
    +
    cm.coordsChar(object, mode) → pos
    +
    Given an {left, top} object, returns + the {line, ch} position that corresponds to it. The + optional mode parameter determines relative to what + the coordinates are interpreted. It may + be "window", "page" (the default), + or "local".
    cm.defaultTextHeight() → number
    Returns the line height of the default font for the editor.
    diff --git a/lib/codemirror.js b/lib/codemirror.js index 99f711ce1e..1baf27e308 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1087,6 +1087,26 @@ window.CodeMirror = (function() { return rect; } + // Context may be "window", "page", "div", or "local"/null + // Result is in local coords + function fromCoordSystem(cm, coords, context) { + if (context == "div") return coords; + var left = coords.left, top = coords.top; + if (context == "page") { + left -= window.pageXOffset || (document.documentElement || document.body).scrollLeft; + top -= window.pageYOffset || (document.documentElement || document.body).scrollTop; + } + var lineSpaceBox = getRect(cm.display.lineSpace); + left -= lineSpaceBox.left; + top -= lineSpaceBox.top; + if (context == "local" || !context) { + var editorBox = getRect(cm.display.wrapper); + left -= editorBox.left; + top -= editorBox.top; + } + return {left: left, top: top}; + } + function charCoords(cm, pos, context, lineObj) { if (!lineObj) lineObj = getLine(cm.doc, pos.line); return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch), context); @@ -2749,11 +2769,9 @@ window.CodeMirror = (function() { return charCoords(this, clipPos(this.doc, pos), mode || "page"); }, - coordsChar: function(coords) { - var off = getRect(this.display.lineSpace); - var scrollY = window.pageYOffset || (document.documentElement || document.body).scrollTop; - var scrollX = window.pageXOffset || (document.documentElement || document.body).scrollLeft; - return coordsChar(this, coords.left - off.left - scrollX, coords.top - off.top - scrollY); + coordsChar: function(coords, mode) { + coords = fromCoordSystem(this, coords, mode || "page"); + return coordsChar(this, coords.left, coords.top); }, defaultTextHeight: function() { return textHeight(this.display); }, From e8419a8e661b6bafa65a0404520fd3927d3ffea3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 15:52:52 +0100 Subject: [PATCH 0365/5273] Add goLineLeft and goLineRight commands For line-end/start navigation that stops when a line wraps. --- lib/codemirror.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 1baf27e308..a3743b4cf6 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1158,7 +1158,7 @@ window.CodeMirror = (function() { function coordsChar(cm, x, y) { var doc = cm.doc; y += cm.display.viewOffset; - if (y < 0) return PosMaybeOutside(doc.first, 0, true); + if (y < 0) y = 0; var lineNo = lineAtHeight(doc, y), last = doc.first + doc.size - 1; if (lineNo > last) return PosMaybeOutside(doc.first + doc.size - 1, getLine(doc, last).text.length, true); @@ -3210,6 +3210,14 @@ window.CodeMirror = (function() { goLineEnd: function(cm) { cm.extendSelection(lineEnd(cm, cm.getCursor().line)); }, + goLineRight: function(cm) { + var top = cm.charCoords(cm.getCursor(), "div").top + 5; + cm.extendSelection(cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")); + }, + goLineLeft: function(cm) { + var top = cm.charCoords(cm.getCursor(), "div").top + 5; + cm.extendSelection(cm.coordsChar({left: 0, top: top}, "div")); + }, goLineUp: function(cm) {cm.moveV(-1, "line");}, goLineDown: function(cm) {cm.moveV(1, "line");}, goPageUp: function(cm) {cm.moveV(-1, "page");}, From a4cda3dbb7b7c508843181c6d1a77e70d57e4ab5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 16:13:02 +0100 Subject: [PATCH 0366/5273] Fix mistake in a36f4e941143996eee30a96c9042e4fd52650f63 Issue #1364 --- 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 0d2d874103..fd134636e3 100644 --- a/addon/search/searchcursor.js +++ b/addon/search/searchcursor.js @@ -23,7 +23,7 @@ var newMatch = query.exec(line); if (!newMatch) break; match = newMatch; - start = cutOff; + start = match.index; cutOff = match.index + 1; } } else { From 5eac0a248a1b1000295dfe4972e60848c02ec166 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 16:16:32 +0100 Subject: [PATCH 0367/5273] Fix bad change from e8419a8e661b6bafa65a0404520fd3927d3ffea3 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index a3743b4cf6..cd604c1433 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1158,7 +1158,7 @@ window.CodeMirror = (function() { function coordsChar(cm, x, y) { var doc = cm.doc; y += cm.display.viewOffset; - if (y < 0) y = 0; + if (y < 0) return PosMaybeOutside(doc.first, 0, true); var lineNo = lineAtHeight(doc, y), last = doc.first + doc.size - 1; if (lineNo > last) return PosMaybeOutside(doc.first + doc.size - 1, getLine(doc, last).text.length, true); From 037993fbf02483d19a47334d1bbdfeb9b6237ceb Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 17:06:33 +0100 Subject: [PATCH 0368/5273] Kludge to force trailing space on a wrapped line to be rendered in Webkit and IE Closes #1362 --- lib/codemirror.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index cd604c1433..3a40c06ffe 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4058,6 +4058,8 @@ window.CodeMirror = (function() { builder.measure = line == realLine && measure; builder.pos = 0; builder.addToken = builder.measure ? buildTokenMeasure : buildToken; + if ((ie || webkit) && cm.getOption("lineWrapping")) + builder.addToken = buildTokenSplitSpaces(builder.addToken); if (measure && sawBefore && line != realLine && !builder.addedOne) { measure[0] = builder.pre.appendChild(zeroWidthElement(cm.display.measure)); builder.addedOne = true; @@ -4158,6 +4160,18 @@ window.CodeMirror = (function() { if (text.length) builder.addedOne = true; } + function buildTokenSplitSpaces(inner) { + function split(old) { + var out = " "; + for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0"; + out += " "; + return out; + } + return function(builder, text, style, startStyle, endStyle) { + return inner(builder, text.replace(/ {3,}/, split), style, startStyle, endStyle); + }; + } + function buildCollapsedSpan(builder, size, widget) { if (widget) { if (!builder.display) widget = widget.cloneNode(true); From fbefd524e9079db7e01c95bc36985443559bc927 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 15 Mar 2013 17:31:21 +0100 Subject: [PATCH 0369/5273] [xml mode] Fix indentation bug when attributes are contd on indented line Closes #1366 --- mode/xml/xml.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mode/xml/xml.js b/mode/xml/xml.js index 7b11fd6746..f08f9f5679 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -165,7 +165,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { }; } - var curState, setStyle; + var curState, curStream, setStyle; function pass() { for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]); } @@ -191,6 +191,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { function element(type) { if (type == "openTag") { curState.tagName = tagName; + curState.tagStart = curStream.column(); return cont(attributes, endtag(curState.startOfLine)); } else if (type == "closeTag") { var err = false; @@ -212,7 +213,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { function endtag(startOfLine) { return function(type) { var tagName = curState.tagName; - curState.tagName = null; + curState.tagName = curState.tagStart = null; if (type == "selfcloseTag" || (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase()))) { maybePopContext(tagName.toLowerCase()); @@ -274,11 +275,11 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { return { startState: function() { - return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, context: null}; + return {tokenize: inText, cc: [], indented: 0, startOfLine: true, tagName: null, tagStart: null, context: null}; }, token: function(stream, state) { - if (stream.sol()) { + if (!state.tagName && stream.sol()) { state.startOfLine = true; state.indented = stream.indentation(); } @@ -288,7 +289,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { var style = state.tokenize(stream, state); state.type = type; if ((style || type) && style != "comment") { - curState = state; + curState = state; curStream = stream; while (true) { var comb = state.cc.pop() || element; if (comb(type || style)) break; @@ -303,6 +304,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { if ((state.tokenize != inTag && state.tokenize != inText) || context && context.noIndent) return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; + if (state.tagName) return state.tagStart + indentUnit; if (alignCDATA && / Date: Mon, 18 Mar 2013 10:21:27 +0100 Subject: [PATCH 0370/5273] [sql mode] Work when not given a configuration Closes #1374 --- 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 2a16882aea..510110b307 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -4,7 +4,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { var client = parserConfig.client || {}, atoms = parserConfig.atoms || {"false": true, "true": true, "null": true}, builtin = parserConfig.builtin || {}, - keywords = parserConfig.keywords, + keywords = parserConfig.keywords || {}, operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/, support = parserConfig.support || {}, hooks = parserConfig.hooks || {}, From fdacdc1ca6507d7aef1310730a263b8f03fdd5d7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 18 Mar 2013 11:41:39 +0100 Subject: [PATCH 0371/5273] Signal a beforeCursorEnter event on marked ranges Closes #1368 --- doc/manual.html | 5 +++++ lib/codemirror.js | 18 +++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 6fee9965eb..0dc390082c 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -482,6 +482,11 @@

    Events

    following events:

    +
    "beforeCursorEnter" ()
    +
    Fired when the cursor enters the marked range. From this + event handler, the editor state may be inspected + but not modified, with the exception that the range on + which the event fires may be cleared.
    "clear" ()
    Fired when the range is cleared, either through cursor movement in combination diff --git a/lib/codemirror.js b/lib/codemirror.js index 3a40c06ffe..3b964669e1 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2418,16 +2418,20 @@ window.CodeMirror = (function() { var dir = bias || 1; doc.cantEdit = false; search: for (;;) { - var line = getLine(doc, curPos.line), toClear; + var line = getLine(doc, curPos.line); if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { var sp = line.markedSpans[i], m = sp.marker; if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) && (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) { - if (mayClear && m.clearOnEnter) { - (toClear || (toClear = [])).push(m); - continue; - } else if (!m.atomic) continue; + if (mayClear) { + signal(m, "beforeCursorEnter"); + if (m.explicitlyCleared) { + if (!line.markedSpans) break; + else {--i; continue;} + } + } + if (!m.atomic) continue; var newPos = m.find()[dir < 0 ? "from" : "to"]; if (posEq(newPos, curPos)) { newPos.ch += dir; @@ -2454,7 +2458,6 @@ window.CodeMirror = (function() { continue search; } } - if (toClear) for (var i = 0; i < toClear.length; ++i) toClear[i].clear(); } return curPos; } @@ -3534,7 +3537,6 @@ window.CodeMirror = (function() { inclusiveLeft: this.inclusiveLeft, inclusiveRight: this.inclusiveRight, atomic: this.atomic, collapsed: this.collapsed, - clearOnEnter: this.clearOnEnter, replacedWith: copyWidget ? repl && repl.cloneNode(true) : repl, readOnly: this.readOnly, startStyle: this.startStyle, endStyle: this.endStyle}; @@ -3589,6 +3591,8 @@ window.CodeMirror = (function() { if (lineIsHidden(doc, line)) updateLineHeight(line, 0); }); + if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); }); + if (marker.readOnly) { sawReadOnlySpans = true; if (doc.history.done.length || doc.history.undone.length) From 60876156245226aafc9a5479e41120cb3cef8f32 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 18 Mar 2013 11:44:26 +0100 Subject: [PATCH 0372/5273] Prevent undo/redo from working in readOnly mode Closes #1369 --- lib/codemirror.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 3b964669e1..fb04e6150e 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2197,6 +2197,8 @@ window.CodeMirror = (function() { } function makeChangeFromHistory(doc, type) { + if (doc.cm && doc.cm.state.suppressEdits) return; + var hist = doc.history; var event = (type == "undo" ? hist.done : hist.undone).pop(); if (!event) return; From a10cd333b96636ec1ba993f2da63261945ac8772 Mon Sep 17 00:00:00 2001 From: John Connor Date: Fri, 1 Mar 2013 12:22:59 -0500 Subject: [PATCH 0373/5273] Vim keybindings for jump to next and prev marks. The functionality should be identical to vim 7. In normal mode "[`" takes you to the next lowercase mark, "]`" takes you to the previous. "['" and "]'" work similarly but just take you to the line of the mark, not the column. --- keymap/vim.js | 48 +++++++++++++++++ test/vim_test.js | 132 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) diff --git a/keymap/vim.js b/keymap/vim.js index e5c1121532..af964a666d 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -169,6 +169,10 @@ motionArgs: { forward: false }}, { keys: ['\'', 'character'], type: 'motion', motion: 'goToMark' }, { keys: ['`', 'character'], type: 'motion', motion: 'goToMark' }, + { keys: [']', '`',], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } }, + { keys: ['[', '`',], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } }, + { keys: [']', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } }, + { keys: ['[', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } }, { keys: ['|'], type: 'motion', motion: 'moveToColumn', motionArgs: { }}, @@ -1009,6 +1013,44 @@ } return null; }, + jumpToMark: function(cm, motionArgs, vim) { + var best = cm.getCursor(); + for (var i = 0; i < motionArgs.repeat; i++) { + var cursor = best; + for (var key in vim.marks) { + if (!isLowerCase(key)) { + continue; + } + var mark = vim.marks[key].find(); + var isWrongDirection = (motionArgs.forward) ? + cursorIsBefore(mark, cursor) : cursorIsBefore(cursor, mark) + + if (isWrongDirection) { + continue; + } + if (motionArgs.linewise && (mark.line == cursor.line)) { + continue; + } + + var equal = cursorEqual(cursor, best); + var between = (motionArgs.forward) ? + cusrorIsBetween(cursor, mark, best) : + cusrorIsBetween(best, mark, cursor); + + if (equal || between) { + best = mark; + } + } + } + + if (motionArgs.linewise) { + // Vim places the cursor on the first non-whitespace character of + // the line if there is one, else it places the cursor at the end + // of the line, regardless of whether a mark was found. + best.ch = findFirstNonWhiteSpaceCharacter(cm.getLine(best.line)); + } + return best; + }, moveByCharacters: function(cm, motionArgs) { var cur = cm.getCursor(); var repeat = motionArgs.repeat; @@ -1596,6 +1638,12 @@ } return false; } + function cusrorIsBetween(cur1, cur2, cur3) { + // returns true if cur2 is between cur1 and cur3. + var cur1before2 = cursorIsBefore(cur1, cur2); + var cur2before3 = cursorIsBefore(cur2, cur3); + return cur1before2 && cur2before3; + } function lineLength(cm, lineNum) { return cm.getLine(lineNum).length; } diff --git a/test/vim_test.js b/test/vim_test.js index 4764c639b5..c3b23a3b4a 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -813,6 +813,138 @@ testVim('mark', function(cm, vim, helpers) { helpers.doKeys('`', 't'); helpers.assertCursorAt(2, 2); }); +testVim('jumpToMark_next', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 't'); + cm.setCursor(0, 0); + helpers.doKeys(']', '`'); + helpers.assertCursorAt(2, 2); + cm.setCursor(0, 0); + helpers.doKeys(']', '\''); + helpers.assertCursorAt(2, 0); +}); +testVim('jumpToMark_next_repeat', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(3, 2); + helpers.doKeys('m', 'b'); + cm.setCursor(4, 2); + helpers.doKeys('m', 'c'); + cm.setCursor(0, 0); + helpers.doKeys('2', ']', '`'); + helpers.assertCursorAt(3, 2); + cm.setCursor(0, 0); + helpers.doKeys('2', ']', '\''); + helpers.assertCursorAt(3, 1); +}); +testVim('jumpToMark_next_sameline', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 4); + helpers.doKeys('m', 'b'); + cm.setCursor(2, 2); + helpers.doKeys(']', '`'); + helpers.assertCursorAt(2, 4); +}); +testVim('jumpToMark_next_onlyprev', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('m', 'a'); + cm.setCursor(4, 0); + helpers.doKeys(']', '`'); + helpers.assertCursorAt(4, 0); +}); +testVim('jumpToMark_next_nomark', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys(']', '`'); + helpers.assertCursorAt(2, 2); + helpers.doKeys(']', '\''); + helpers.assertCursorAt(2, 0); +}); +testVim('jumpToMark_next_linewise_over', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(3, 4); + helpers.doKeys('m', 'b'); + cm.setCursor(2, 1); + helpers.doKeys(']', '\''); + helpers.assertCursorAt(3, 1); +}); +testVim('jumpToMark_next_action', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 't'); + cm.setCursor(0, 0); + helpers.doKeys('d', ']', '`'); + helpers.assertCursorAt(0, 0); + var actual = cm.getLine(0); + var expected = 'pop pop 0 1 2 3 4'; + eq(actual, expected, "Deleting while jumping to the next mark failed."); +}); +testVim('jumpToMark_next_line_action', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 't'); + cm.setCursor(0, 0); + helpers.doKeys('d', ']', '\''); + helpers.assertCursorAt(0, 1); + var actual = cm.getLine(0); + var expected = ' (a) [b] {c} ' + eq(actual, expected, "Deleting while jumping to the next mark line failed."); +}); +testVim('jumpToMark_prev', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 't'); + cm.setCursor(4, 0); + helpers.doKeys('[', '`'); + helpers.assertCursorAt(2, 2); + cm.setCursor(4, 0); + helpers.doKeys('[', '\''); + helpers.assertCursorAt(2, 0); +}); +testVim('jumpToMark_prev_repeat', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(3, 2); + helpers.doKeys('m', 'b'); + cm.setCursor(4, 2); + helpers.doKeys('m', 'c'); + cm.setCursor(5, 0); + helpers.doKeys('2', '[', '`'); + helpers.assertCursorAt(3, 2); + cm.setCursor(5, 0); + helpers.doKeys('2', '[', '\''); + helpers.assertCursorAt(3, 1); +}); +testVim('jumpToMark_prev_sameline', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 4); + helpers.doKeys('m', 'b'); + cm.setCursor(2, 2); + helpers.doKeys('[', '`'); + helpers.assertCursorAt(2, 0); +}); +testVim('jumpToMark_prev_onlynext', function(cm, vim, helpers) { + cm.setCursor(4, 4); + helpers.doKeys('m', 'a'); + cm.setCursor(2, 0); + helpers.doKeys('[', '`'); + helpers.assertCursorAt(2, 0); +}); +testVim('jumpToMark_prev_nomark', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('[', '`'); + helpers.assertCursorAt(2, 2); + helpers.doKeys('[', '\''); + helpers.assertCursorAt(2, 0); +}); +testVim('jumpToMark_prev_linewise_over', function(cm, vim, helpers) { + cm.setCursor(2, 2); + helpers.doKeys('m', 'a'); + cm.setCursor(3, 4); + helpers.doKeys('m', 'b'); + cm.setCursor(3, 6); + helpers.doKeys('[', '\''); + helpers.assertCursorAt(2, 0); +}); testVim('delmark_single', function(cm, vim, helpers) { cm.setCursor(1, 2); helpers.doKeys('m', 't'); From 965dc47c24c6b95eb191e77be85fee88e75cd67c Mon Sep 17 00:00:00 2001 From: Drew Hintz Date: Sat, 16 Mar 2013 00:40:49 -0700 Subject: [PATCH 0374/5273] remove old Opera-specific CSS properties where Opera supports the standard properties. --- lib/codemirror.css | 2 +- theme/ambiance-mobile.css | 1 - theme/ambiance.css | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index 913a1a9c3d..bab16bc2c9 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -166,7 +166,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} } .CodeMirror pre { /* Reset some styles that the rest of the page might have set */ - -moz-border-radius: 0; -webkit-border-radius: 0; -o-border-radius: 0; border-radius: 0; + -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; border-width: 0; background: transparent; font-family: inherit; diff --git a/theme/ambiance-mobile.css b/theme/ambiance-mobile.css index 35b3750c1b..88d332e1a7 100644 --- a/theme/ambiance-mobile.css +++ b/theme/ambiance-mobile.css @@ -1,6 +1,5 @@ .cm-s-ambiance.CodeMirror { -webkit-box-shadow: none; -moz-box-shadow: none; - -o-box-shadow: none; box-shadow: none; } diff --git a/theme/ambiance.css b/theme/ambiance.css index beec553851..0185426f01 100644 --- a/theme/ambiance.css +++ b/theme/ambiance.css @@ -46,7 +46,6 @@ background-color: #202020; -webkit-box-shadow: inset 0 0 10px black; -moz-box-shadow: inset 0 0 10px black; - -o-box-shadow: inset 0 0 10px black; box-shadow: inset 0 0 10px black; } From 5f591a013e11c9a00bd439e6494b1c17d7d2813b Mon Sep 17 00:00:00 2001 From: Nikita Beloglazov Date: Sat, 16 Mar 2013 13:15:40 +0300 Subject: [PATCH 0375/5273] Add character higlighting to clojure mode. --- mode/clojure/clojure.js | 19 ++++++++++++++++++- mode/clojure/index.html | 23 ++++++++++++++++------- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/mode/clojure/clojure.js b/mode/clojure/clojure.js index 8b9614cc20..658ff140e0 100644 --- a/mode/clojure/clojure.js +++ b/mode/clojure/clojure.js @@ -3,7 +3,7 @@ * Branched from CodeMirror's Scheme mode (by Koh Zi Han, based on implementation by Koh Zi Chun) */ CodeMirror.defineMode("clojure", function () { - var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", + var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", CHARACTER = "string-2", ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD = "keyword"; var INDENT_WORD_SKIP = 2; @@ -95,6 +95,20 @@ CodeMirror.defineMode("clojure", function () { return false; } + // Eat character that starts after backslash \ + function eatCharacter(stream) { + var first = stream.next(); + // Read special literals: backspace, newline, space, return. + // Just read all lowercase letters. + if (first.match(/[a-z]/) && stream.match(/[a-z]+/, true)) { + return; + } + // Read unicode character: \u1000 \uA0a1 + if (first === "u") { + stream.match(/[0-9a-z]{4}/i, true); + } + } + return { startState: function () { return { @@ -135,6 +149,9 @@ CodeMirror.defineMode("clojure", function () { if (ch == "\"") { state.mode = "string"; returnType = STRING; + } else if (ch == "\\") { + eatCharacter(stream); + returnType = CHARACTER; } else if (ch == "'" && !( tests.digit_or_colon.test(stream.peek()) )) { returnType = ATOM; } else if (ch == ";") { // comment diff --git a/mode/clojure/index.html b/mode/clojure/index.html index bce0473530..bfe6fc955a 100644 --- a/mode/clojure/index.html +++ b/mode/clojure/index.html @@ -21,13 +21,13 @@

    CodeMirror: Clojure mode

    ;; Core game of life's algorithm functions -(defn neighbours +(defn neighbours "Given a cell's coordinates, returns the coordinates of its neighbours." [[x y]] (for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [-1 0 1])] [(+ dx x) (+ dy y)])) -(defn step +(defn step "Given a set of living cells, computes the new set of living cells." [cells] (set (for [[cell n] (frequencies (mapcat neighbours cells)) @@ -36,14 +36,14 @@

    CodeMirror: Clojure mode

    ;; Utility methods for displaying game on a text terminal -(defn print-board +(defn print-board "Prints a board on *out*, representing a step in the game." [board w h] (doseq [x (range (inc w)) y (range (inc h))] - (if (= y 0) (print "\n")) + (if (= y 0) (print "\n")) (print (if (board [x y]) "[X]" " . ")))) -(defn display-grids +(defn display-grids "Prints a squence of boards on *out*, representing several steps." [grids w h] (doseq [board grids] @@ -52,11 +52,20 @@

    CodeMirror: Clojure mode

    ;; Launches an example board -(def +(def ^{:doc "board represents the initial set of living cells"} board #{[2 1] [2 2] [2 3]}) -(display-grids (take 3 (iterate step board)) 5 5) +(display-grids (take 3 (iterate step board)) 5 5) + +;; Let's play with characters +(println \1 \a \# \\ + \" \( \newline + \} \" \space + \tab \return \backspace + \u1000 \uAaAa \u9F9F) + + From 8cf1f1a50ac99e59e45f68c9b683b34b3de70d9a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 18 Mar 2013 13:54:18 +0100 Subject: [PATCH 0376/5273] [xml mode] Support config parameter for indentation in wrapped tags Closes #1375 --- mode/xml/xml.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mode/xml/xml.js b/mode/xml/xml.js index f08f9f5679..a68b033841 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -1,5 +1,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { var indentUnit = config.indentUnit; + var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1; + var Kludges = parserConfig.htmlMode ? { autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, @@ -304,7 +306,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { if ((state.tokenize != inTag && state.tokenize != inText) || context && context.noIndent) return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; - if (state.tagName) return state.tagStart + indentUnit; + if (state.tagName) return state.tagStart + indentUnit * multilineTagIndentFactor; if (alignCDATA && / Date: Mon, 18 Mar 2013 14:28:01 +0100 Subject: [PATCH 0377/5273] Use a simpler, faster approach in removeChildren Closes #1376 --- lib/codemirror.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index fb04e6150e..a8f7778451 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -5136,9 +5136,8 @@ window.CodeMirror = (function() { } function removeChildren(e) { - // IE will break all parent-child relations in subnodes when setting innerHTML - if (!ie) e.innerHTML = ""; - else while (e.firstChild) e.removeChild(e.firstChild); + for (var count = e.childNodes.length; count > 0; --count) + e.removeChild(e.firstChild); return e; } From d8a583e913f9ccfb516e9b891b48b4d05d635c4a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 18 Mar 2013 16:18:49 +0100 Subject: [PATCH 0378/5273] Don't leave text with newlines in the textarea There's no multi-line-unit IME that I'm aware of. Issue #1231 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index a8f7778451..5b844010b2 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1410,7 +1410,7 @@ window.CodeMirror = (function() { origin: cm.state.pasteIncoming ? "paste" : "+input"}, "end"); cm.curOp.updateInput = updateInput; - if (text.length > 1000) input.value = cm.display.prevInput = ""; + if (text.length > 1000 || text.indexOf("\n") > -1) input.value = cm.display.prevInput = ""; else cm.display.prevInput = text; if (withOp) endOperation(cm); cm.state.pasteIncoming = false; From 20ea151001909161cdd940571450b8c1426bc001 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 19 Mar 2013 09:59:06 +0100 Subject: [PATCH 0379/5273] Give extraKeys a lower prec than addKeyMap keys, add bottom arg to addKeyMap --- doc/manual.html | 20 +++++++++++--------- lib/codemirror.js | 6 +++--- test/test.js | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 0dc390082c..db192e08d1 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -834,16 +834,18 @@

    Configuration methods

    Retrieves the current value of the given option for this editor instance.
    -
    cm.addKeyMap(map)
    -
    Attach an additional keymap to the editor. This is mostly - useful for add-ons that need to register some key handlers - without trampling on +
    cm.addKeyMap(map, bottom)
    +
    Attach an additional keymap to the + editor. This is mostly useful for add-ons that need to register + some key handlers without trampling on the extraKeys - option. Maps added in this way have a lower precedence - than extraKeys, a higher precedence than the - base keyMap, and - between them, the maps added earlier have a higher precedence - than those added later.
    + option. Maps added in this way have a higher precedence than + the extraKeys + and keyMap options, + and between them, the maps added earlier have a lower precedence + than those added later, unless the bottom argument + was passed, in which case they end up below other keymaps added + with this method.
    cm.removeKeyMap(map)
    Disable a keymap added with addKeyMap. Either diff --git a/lib/codemirror.js b/lib/codemirror.js index 5b844010b2..6f475f8b54 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1925,8 +1925,8 @@ window.CodeMirror = (function() { function allKeyMaps(cm) { var maps = cm.state.keyMaps.slice(0); + if (cm.options.extraKeys) maps.push(cm.options.extraKeys); maps.push(cm.options.keyMap); - if (cm.options.extraKeys) maps.unshift(cm.options.extraKeys); return maps; } @@ -2691,8 +2691,8 @@ window.CodeMirror = (function() { getOption: function(option) {return this.options[option];}, getDoc: function() {return this.doc;}, - addKeyMap: function(map) { - this.state.keyMaps.push(map); + addKeyMap: function(map, bottom) { + this.state.keyMaps[bottom ? "push" : "unshift"](map); }, removeKeyMap: function(map) { var maps = this.state.keyMaps; diff --git a/test/test.js b/test/test.js index d3e78f80bb..96f37353aa 100644 --- a/test/test.js +++ b/test/test.js @@ -1298,7 +1298,7 @@ testCM("addKeyMap", function(cm) { sendKey(39); eqPos(cm.getCursor(), Pos(0, 1)); eq(test, 1); - cm.addKeyMap(map2); + cm.addKeyMap(map2, true); sendKey(39); eq(test, 2); cm.removeKeyMap(map1); From 14b8063dd83bb745e1b506c26fce80ca597a9913 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 19 Mar 2013 10:09:31 +0100 Subject: [PATCH 0380/5273] Revise interface to continueComment It's better to have it only take effect when in a comment, so that Enter's regular behavior isn't overridden in other situations. --- addon/edit/continuecomment.js | 14 +++++++++++--- doc/manual.html | 9 +++++---- mode/javascript/index.html | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/addon/edit/continuecomment.js b/addon/edit/continuecomment.js index 4ee0b48015..308026229f 100644 --- a/addon/edit/continuecomment.js +++ b/addon/edit/continuecomment.js @@ -5,7 +5,7 @@ blockCommentEnd: "*/", blockCommentContinue: " * "}); - CodeMirror.commands.newlineAndIndentContinueComment = function(cm) { + function continueComment(cm) { var pos = cm.getCursor(), token = cm.getTokenAt(pos); var mode = CodeMirror.innerMode(cm.getMode(), token.state).mode; var space; @@ -31,6 +31,14 @@ if (space != null) cm.replaceSelection("\n" + space + mode.blockCommentContinue, "end"); else - cm.execCommand("newlineAndIndent"); - }; + return CodeMirror.Pass; + } + + CodeMirror.defineOption("continueComments", null, function(cm, val, prev) { + if (prev && prev != CodeMirror.Init) + cm.removeKeyMap("continueComment"); + var map = {name: "continueComment"}; + map[typeof val == "string" ? val : "Enter"] = continueComment; + cm.addKeyMap(map); + }); })(); diff --git a/doc/manual.html b/doc/manual.html index db192e08d1..d8cd2db783 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1560,10 +1560,11 @@

    Add-ons

    editor instance to refresh its mode when the loading succeeded. See the demo.
    edit/continuecomment.js
    -
    Adds a command - called newlineAndIndentContinueComment that you can - bind Enter to in order to have the editor prefix - new lines inside C-like block comments with an asterisk.
    +
    Adds an continueComments option, which can be + set to true to have the editor prefix new lines inside C-like + block comments with an asterisk when Enter is pressed. It can + also be set to a string in order to bind this functionality to a + specific key..
    display/placeholder.js
    Adds a placeholder option that can be used to make text appear in the editor when it is empty and not focused. diff --git a/mode/javascript/index.html b/mode/javascript/index.html index 9222ddf170..cca7d04eaf 100644 --- a/mode/javascript/index.html +++ b/mode/javascript/index.html @@ -68,7 +68,7 @@

    CodeMirror: JavaScript mode

    var editor = CodeMirror.fromTextArea(document.getElementById("code"), { lineNumbers: true, matchBrackets: true, - extraKeys: {"Enter": "newlineAndIndentContinueComment"} + continueComments: "Enter" }); From 962cabe4a3a30da1536c8a4a06cdd9ac22e5acfb Mon Sep 17 00:00:00 2001 From: Drew Hintz Date: Sat, 16 Mar 2013 01:07:30 -0700 Subject: [PATCH 0381/5273] use 3 character color codes instead of 6 where appropriate --- mode/tiki/tiki.css | 4 ++-- theme/erlang-dark.css | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mode/tiki/tiki.css b/mode/tiki/tiki.css index e3c3c0fd2d..0dbc3ea0e0 100644 --- a/mode/tiki/tiki.css +++ b/mode/tiki/tiki.css @@ -1,6 +1,6 @@ .cm-tw-syntaxerror { - color: #FFFFFF; - background-color: #990000; + color: #FFF; + background-color: #900; } .cm-tw-deleted { diff --git a/theme/erlang-dark.css b/theme/erlang-dark.css index ea9c26c44d..cf5bf2bd6e 100644 --- a/theme/erlang-dark.css +++ b/theme/erlang-dark.css @@ -7,15 +7,15 @@ .cm-s-erlang-dark span.cm-atom { color: #845dc4; } .cm-s-erlang-dark span.cm-attribute { color: #ff80e1; } .cm-s-erlang-dark span.cm-bracket { color: #ff9d00; } -.cm-s-erlang-dark span.cm-builtin { color: #eeaaaa; } -.cm-s-erlang-dark span.cm-comment { color: #7777ff; } -.cm-s-erlang-dark span.cm-def { color: #ee77aa; } +.cm-s-erlang-dark span.cm-builtin { color: #eaa; } +.cm-s-erlang-dark span.cm-comment { color: #77f; } +.cm-s-erlang-dark span.cm-def { color: #e7a; } .cm-s-erlang-dark span.cm-error { color: #9d1e15; } .cm-s-erlang-dark span.cm-keyword { color: #ffee80; } .cm-s-erlang-dark span.cm-meta { color: #50fefe; } .cm-s-erlang-dark span.cm-number { color: #ffd0d0; } -.cm-s-erlang-dark span.cm-operator { color: #dd1111; } +.cm-s-erlang-dark span.cm-operator { color: #d11; } .cm-s-erlang-dark span.cm-string { color: #3ad900; } .cm-s-erlang-dark span.cm-tag { color: #9effff; } .cm-s-erlang-dark span.cm-variable { color: #50fe50; } -.cm-s-erlang-dark span.cm-variable-2 { color: #ee00ee; } +.cm-s-erlang-dark span.cm-variable-2 { color: #e0e; } From 2faf0349770b2ad02321814244595a5a89b81b6f Mon Sep 17 00:00:00 2001 From: Juan Benavides Romero Date: Thu, 7 Mar 2013 10:02:13 +0100 Subject: [PATCH 0382/5273] standard html5 code completation --- addon/hint/html-hint.js | 586 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 586 insertions(+) create mode 100755 addon/hint/html-hint.js diff --git a/addon/hint/html-hint.js b/addon/hint/html-hint.js new file mode 100755 index 0000000000..0e43e79c93 --- /dev/null +++ b/addon/hint/html-hint.js @@ -0,0 +1,586 @@ +(function () { + function scriptHint(editor, htmlStructure, getToken) { + var cur = editor.getCursor(); + var token = getToken(editor, cur); + var keywords = []; + var i = 0; + var j = 0; + var k = 0; + var from = {line: cur.line, ch: cur.ch}; + var to = {line: cur.line, ch: cur.ch}; + var flagClean = true; + + text = editor.getRange({line: 0, ch: 0}, cur); + + var open = text.lastIndexOf('<'); + var close = text.lastIndexOf('>'); + var tokenString = token.string.replace("<",""); + + if(open > close) { + var last = editor.getRange({line: cur.line, ch: cur.ch - 1}, cur); + if(last == "<") { + for(i = 0; i < htmlStructure.length; i++) { + keywords.push(htmlStructure[i].tag); + } + from.ch = token.start + 1; + } else { + var counter = 0; + var found = function(token, type, position) { + counter++; + if(counter > 50) return; + if(token.type == type) { + return token; + } else { + position.ch = token.start; + var newToken = editor.getTokenAt(position); + return found(newToken, type, position); + } + }; + + var nodeToken = found(token, "tag", {line: cur.line, ch: cur.ch}); + var node = nodeToken.string.substring(1); + + if(token.type === null && token.string.trim() === "") { + for(i = 0; i < htmlStructure.length; i++) { + if(htmlStructure[i].tag == node) { + for(j = 0; j < htmlStructure[i].attr.length; j++) { + keywords.push(htmlStructure[i].attr[j].key + "=\"\" "); + } + + for(k = 0; k < globalAttributes.length; k++) { + keywords.push(globalAttributes[k].key + "=\"\" "); + } + } + } + } else if(token.type == "string") { + tokenString = tokenString.substring(1, tokenString.length - 1); + var attributeToken = found(token, "attribute", {line: cur.line, ch: cur.ch}); + var attribute = attributeToken.string; + + for(i = 0; i < htmlStructure.length; i++) { + if(htmlStructure[i].tag == node) { + for(j = 0; j < htmlStructure[i].attr.length; j++) { + if(htmlStructure[i].attr[j].key == attribute) { + for(k = 0; k < htmlStructure[i].attr[j].values.length; k++) { + keywords.push(htmlStructure[i].attr[j].values[k]); + } + } + } + + for(j = 0; j < globalAttributes.length; j++) { + if(globalAttributes[j].key == attribute) { + for(k = 0; k < globalAttributes[j].values.length; k++) { + keywords.push(globalAttributes[j].values[k]); + } + } + } + } + } + from.ch = token.start + 1; + } else if(token.type == "attribute") { + for(i = 0; i < htmlStructure.length; i++) { + if(htmlStructure[i].tag == node) { + for(j = 0; j < htmlStructure[i].attr.length; j++) { + keywords.push(htmlStructure[i].attr[j].key + "=\"\" "); + } + + for(k = 0; k < globalAttributes.length; k++) { + keywords.push(globalAttributes[k].key + "=\"\" "); + } + } + } + from.ch = token.start; + } else if(token.type == "tag") { + for(i = 0; i < htmlStructure.length; i++) { + keywords.push(htmlStructure[i].tag); + } + + from.ch = token.start + 1; + } + } + } else { + for(i = 0; i < htmlStructure.length; i++) { + keywords.push("<" + htmlStructure[i].tag); + } + + tokenString = ("<" + tokenString).trim(); + from.ch = token.start; + } + + if(flagClean === true && tokenString.trim() === "") { + flagClean = false; + } + + if(flagClean) { + keywords = cleanResults(tokenString, keywords); + } + + return {list: keywords, from: from, to: to}; + } + + + var cleanResults = function(text, keywords) { + var results = []; + var i = 0; + + for(i = 0; i < keywords.length; i++) { + if(keywords[i].substring(0, text.length) == text) { + results.push(keywords[i]); + } + } + + return results; + }; + + + var htmlStructure = [ + {tag: '!DOCTYPE', attr: []}, + {tag: 'a', attr: [ + {key: 'href', values: ["#"]}, + {key: 'target', values: ["_blank","_self","_top","_parent"]}, + {key: 'ping', values: [""]}, + {key: 'media', values: ["#"]}, + {key: 'hreflang', values: ["en","es"]}, + {key: 'type', values: []} + ]}, + {tag: 'abbr', attr: []}, + {tag: 'acronym', attr: []}, + {tag: 'address', attr: []}, + {tag: 'applet', attr: []}, + {tag: 'area', attr: [ + {key: 'alt', values: [""]}, + {key: 'coords', values: ["rect: left, top, right, bottom","circle: center-x, center-y, radius","poly: x1, y1, x2, y2, ..."]}, + {key: 'shape', values: ["default","rect","circle","poly"]}, + {key: 'href', values: ["#"]}, + {key: 'target', values: ["#"]}, + {key: 'ping', values: []}, + {key: 'media', values: []}, + {key: 'hreflang', values: []}, + {key: 'type', values: []} + + ]}, + {tag: 'article', attr: []}, + {tag: 'aside', attr: []}, + {tag: 'audio', attr: [ + {key: 'src', values: []}, + {key: 'crossorigin', values: ["anonymous","use-credentials"]}, + {key: 'preload', values: ["none","metadata","auto"]}, + {key: 'autoplay', values: ["","autoplay"]}, + {key: 'mediagroup', values: []}, + {key: 'loop', values: ["","loop"]}, + {key: 'controls', values: ["","controls"]} + ]}, + {tag: 'b', attr: []}, + {tag: 'base', attr: [ + {key: 'href', values: ["#"]}, + {key: 'target', values: ["_blank","_self","_top","_parent"]} + ]}, + {tag: 'basefont', attr: []}, + {tag: 'bdi', attr: []}, + {tag: 'bdo', attr: []}, + {tag: 'big', attr: []}, + {tag: 'blockquote', attr: [ + {key: 'cite', values: ["http://"]} + ]}, + {tag: 'body', attr: []}, + {tag: 'br', attr: []}, + {tag: 'button', attr: [ + {key: 'autofocus', values: ["","autofocus"]}, + {key: 'disabled', values: ["","disabled"]}, + {key: 'form', values: []}, + {key: 'formaction', values: []}, + {key: 'formenctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]}, + {key: 'formmethod', values: ["get","post","put","delete"]}, + {key: 'formnovalidate', values: ["","novalidate"]}, + {key: 'formtarget', values: ["_blank","_self","_top","_parent"]}, + {key: 'name', values: []}, + {key: 'type', values: ["submit","reset","button"]}, + {key: 'value', values: []} + ]}, + {tag: 'canvas', attr: [ + {key: 'width', values: []}, + {key: 'height', values: []} + ]}, + {tag: 'caption', attr: []}, + {tag: 'center', attr: []}, + {tag: 'cite', attr: []}, + {tag: 'code', attr: []}, + {tag: 'col', attr: [ + {key: 'span', values: []} + ]}, + {tag: 'colgroup', attr: [ + {key: 'span', values: []} + ]}, + {tag: 'command', attr: [ + {key: 'type', values: ["command","checkbox","radio"]}, + {key: 'label', values: []}, + {key: 'icon', values: []}, + {key: 'disabled', values: ["","disabled"]}, + {key: 'checked', values: ["","checked"]}, + {key: 'radiogroup', values: []}, + {key: 'command', values: []}, + {key: 'title', values: []} + ]}, + {tag: 'data', attr: [ + {key: 'value', values: []} + ]}, + {tag: 'datagrid', attr: [ + {key: 'disabled', values: ["","disabled"]}, + {key: 'multiple', values: ["","multiple"]} + ]}, + {tag: 'datalist', attr: [ + {key: 'data', values: []} + ]}, + {tag: 'dd', attr: []}, + {tag: 'del', attr: [ + {key: 'cite', values: []}, + {key: 'datetime', values: []} + ]}, + {tag: 'details', attr: [ + {key: 'open', values: ["","open"]} + ]}, + {tag: 'dfn', attr: []}, + {tag: 'dir', attr: []}, + {tag: 'div', attr: [ + {key: 'id', values: []}, + {key: 'class', values: []}, + {key: 'style', values: []} + ]}, + {tag: 'dl', attr: []}, + {tag: 'dt', attr: []}, + {tag: 'em', attr: []}, + {tag: 'embed', attr: [ + {key: 'src', values: []}, + {key: 'type', values: []}, + {key: 'width', values: []}, + {key: 'height', values: []} + ]}, + {tag: 'eventsource', attr: [ + {key: 'src', values: []} + ]}, + {tag: 'fieldset', attr: [ + {key: 'disabled', values: ["","disabled"]}, + {key: 'form', values: []}, + {key: 'name', values: []} + ]}, + {tag: 'figcaption', attr: []}, + {tag: 'figure', attr: []}, + {tag: 'font', attr: []}, + {tag: 'footer', attr: []}, + {tag: 'form', attr: [ + {key: 'accept-charset', values: ["UNKNOWN","utf-8"]}, + {key: 'action', values: []}, + {key: 'autocomplete', values: ["on","off"]}, + {key: 'enctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]}, + {key: 'method', values: ["get","post","put","delete","dialog"]}, + {key: 'name', values: []}, + {key: 'novalidate', values: ["","novalidate"]}, + {key: 'target', values: ["_blank","_self","_top","_parent"]} + ]}, + {tag: 'frame', attr: []}, + {tag: 'frameset', attr: []}, + {tag: 'h1', attr: []}, + {tag: 'h2', attr: []}, + {tag: 'h3', attr: []}, + {tag: 'h4', attr: []}, + {tag: 'h5', attr: []}, + {tag: 'h6', attr: []}, + {tag: 'head', attr: []}, + {tag: 'header', attr: []}, + {tag: 'hgroup', attr: []}, + {tag: 'hr', attr: []}, + {tag: 'html', attr: [ + {key: 'manifest', values: []} + ]}, + {tag: 'i', attr: []}, + {tag: 'iframe', attr: [ + {key: 'src', values: []}, + {key: 'srcdoc', values: []}, + {key: 'name', values: []}, + {key: 'sandbox', values: ["allow-top-navigation","allow-same-origin","allow-forms","allow-scripts"]}, + {key: 'seamless', values: ["","seamless"]}, + {key: 'width', values: []}, + {key: 'height', values: []} + ]}, + {tag: 'img', attr: [ + {key: 'alt', values: []}, + {key: 'src', values: []}, + {key: 'crossorigin', values: ["anonymous","use-credentials"]}, + {key: 'ismap', values: []}, + {key: 'usemap', values: []}, + {key: 'width', values: []}, + {key: 'height', values: []} + ]}, + {tag: 'input', attr: [ + {key: 'accept', values: ["audio/*","video/*","image/*"]}, + {key: 'alt', values: []}, + {key: 'autocomplete', values: ["on","off"]}, + {key: 'autofocus', values: ["","autofocus"]}, + {key: 'checked', values: ["","checked"]}, + {key: 'disabled', values: ["","disabled"]}, + {key: 'dirname', values: []}, + {key: 'form', values: []}, + {key: 'formaction', values: []}, + {key: 'formenctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]}, + {key: 'formmethod', values: ["get","post","put","delete"]}, + {key: 'formnovalidate', values: ["","novalidate"]}, + {key: 'formtarget', values: ["_blank","_self","_top","_parent"]}, + {key: 'height', values: []}, + {key: 'list', values: []}, + {key: 'max', values: []}, + {key: 'maxlength', values: []}, + {key: 'min', values: []}, + {key: 'multiple', values: ["","multiple"]}, + {key: 'name', values: []}, + {key: 'pattern', values: []}, + {key: 'placeholder', values: []}, + {key: 'readonly', values: ["","readonly"]}, + {key: 'required', values: ["","required"]}, + {key: 'size', values: []}, + {key: 'src', values: []}, + {key: 'step', values: []}, + {key: 'type', values: [ + "hidden","text","search","tel","url","email","password","datetime","date","month","week","time","datetime-local", + "number","range","color","checkbox","radio","file","submit","image","reset","button" + ]}, + {key: 'value', values: []}, + {key: 'width', values: []} + ]}, + {tag: 'ins', attr: [ + {key: 'cite', values: []}, + {key: 'datetime', values: []} + ]}, + {tag: 'kbd', attr: []}, + {tag: 'keygen', attr: [ + {key: 'autofocus', values: ["","autofocus"]}, + {key: 'challenge', values: []}, + {key: 'disabled', values: ["","disabled"]}, + {key: 'form', values: []}, + {key: 'keytype', values: ["RSA"]}, + {key: 'name', values: []} + ]}, + {tag: 'label', attr: [ + {key: 'for', values: []}, + {key: 'form', values: []} + ]}, + {tag: 'legend', attr: []}, + {tag: 'li', attr: [ + {key: 'value', values: []} + ]}, + {tag: 'link', attr: [ + {key: 'href', values: []}, + {key: 'hreflang', values: ["en","es"]}, + {key: 'media', values: [ + "all","screen","print","embossed","braille","handheld","print","projection","screen","tty","tv","speech","3d-glasses", + "resolution [>][<][=] [X]dpi","resolution [>][<][=] [X]dpcm","device-aspect-ratio: 16/9","device-aspect-ratio: 4/3", + "device-aspect-ratio: 32/18","device-aspect-ratio: 1280/720","device-aspect-ratio: 2560/1440","orientation:portrait", + "orientation:landscape","device-height: [X]px","device-width: [X]px","-webkit-min-device-pixel-ratio: 2" + ]}, + {key: 'type', values: []}, + {key: 'sizes', values: ["all","16x16","16x16 32x32","16x16 32x32 64x64"]} + ]}, + {tag: 'map', attr: [ + {key: 'name', values: []} + ]}, + {tag: 'mark', attr: []}, + {tag: 'menu', attr: [ + {key: 'type', values: ["list","context","toolbar"]}, + {key: 'label', values: []} + ]}, + {tag: 'meta', attr: [ + {key: 'charset', attr: ["utf-8"]}, + {key: 'name', attr: ["viewport","application-name","author","description","generator","keywords"]}, + {key: 'content', attr: ["","width=device-width","initial-scale=1, maximum-scale=1, minimun-scale=1, user-scale=no"]}, + {key: 'http-equiv', attr: ["content-language","content-type","default-style","refresh"]} + ]}, + {tag: 'meter', attr: [ + {key: 'value', values: []}, + {key: 'min', values: []}, + {key: 'low', values: []}, + {key: 'high', values: []}, + {key: 'max', values: []}, + {key: 'optimum', values: []} + ]}, + {tag: 'nav', attr: []}, + {tag: 'noframes', attr: []}, + {tag: 'noscript', attr: []}, + {tag: 'object', attr: [ + {key: 'data', values: []}, + {key: 'type', values: []}, + {key: 'typemustmatch', values: ["","typemustmatch"]}, + {key: 'name', values: []}, + {key: 'usemap', values: []}, + {key: 'form', values: []}, + {key: 'width', values: []}, + {key: 'height', values: []} + ]}, + {tag: 'ol', attr: [ + {key: 'reversed', values: ["", "reversed"]}, + {key: 'start', values: []}, + {key: 'type', values: ["1","a","A","i","I"]} + ]}, + {tag: 'optgroup', attr: [ + {key: 'disabled', values: ["","disabled"]}, + {key: 'label', values: []} + ]}, + {tag: 'option', attr: [ + {key: 'disabled', values: ["", "disabled"]}, + {key: 'label', values: []}, + {key: 'selected', values: ["", "selected"]}, + {key: 'value', values: []} + ]}, + {tag: 'output', attr: [ + {key: 'for', values: []}, + {key: 'form', values: []}, + {key: 'name', values: []} + ]}, + {tag: 'p', attr: []}, + {tag: 'param', attr: [ + {key: 'name', values: []}, + {key: 'value', values: []} + ]}, + {tag: 'pre', attr: []}, + {tag: 'progress', attr: [ + {key: 'value', values: []}, + {key: 'max', values: []} + ]}, + {tag: 'q', attr: [ + {key: 'cite', values: []} + ]}, + {tag: 'rp', attr: []}, + {tag: 'rt', attr: []}, + {tag: 'ruby', attr: []}, + {tag: 's', attr: []}, + {tag: 'samp', attr: []}, + {tag: 'script', attr: [ + {key: 'type', values: ["text/javascript"]}, + {key: 'src', values: []}, + {key: 'async', values: ["","async"]}, + {key: 'defer', values: ["","defer"]}, + {key: 'charset', values: ["utf-8"]} + ]}, + {tag: 'section', attr: []}, + {tag: 'select', attr: [ + {key: 'autofocus', values: ["", "autofocus"]}, + {key: 'disabled', values: ["", "disabled"]}, + {key: 'form', values: []}, + {key: 'multiple', values: ["", "multiple"]}, + {key: 'name', values: []}, + {key: 'size', values: []} + ]}, + {tag: 'small', attr: []}, + {tag: 'source', attr: [ + {key: 'src', values: []}, + {key: 'type', values: []}, + {key: 'media', values: []} + ]}, + {tag: 'span', attr: []}, + {tag: 'strike', attr: []}, + {tag: 'strong', attr: []}, + {tag: 'style', attr: [ + {key: 'type', values: ["text/css"]}, + {key: 'media', values: ["all","braille","print","projection","screen","speech"]}, + {key: 'scoped', values: []} + ]}, + {tag: 'sub', attr: []}, + {tag: 'summary', attr: []}, + {tag: 'sup', attr: []}, + {tag: 'table', attr: [ + {key: 'border', values: []} + ]}, + {tag: 'tbody', attr: []}, + {tag: 'td', attr: [ + {key: 'colspan', values: []}, + {key: 'rowspan', values: []}, + {key: 'headers', values: []} + ]}, + {tag: 'textarea', attr: [ + {key: 'autofocus', values: ["","autofocus"]}, + {key: 'disabled', values: ["","disabled"]}, + {key: 'dirname', values: []}, + {key: 'form', values: []}, + {key: 'maxlength', values: []}, + {key: 'name', values: []}, + {key: 'placeholder', values: []}, + {key: 'readonly', values: ["","readonly"]}, + {key: 'required', values: ["","required"]}, + {key: 'rows', values: []}, + {key: 'cols', values: []}, + {key: 'wrap', values: ["soft","hard"]} + ]}, + {tag: 'tfoot', attr: []}, + {tag: 'th', attr: [ + {key: 'colspan', values: []}, + {key: 'rowspan', values: []}, + {key: 'headers', values: []}, + {key: 'scope', values: ["row","col","rowgroup","colgroup"]} + ]}, + {tag: 'thead', attr: []}, + {tag: 'time', attr: [ + {key: 'datetime', values: []} + ]}, + {tag: 'title', attr: []}, + {tag: 'tr', attr: []}, + {tag: 'track', attr: [ + {key: 'kind', values: ["subtitles","captions","descriptions","chapters","metadata"]}, + {key: 'src', values: []}, + {key: 'srclang', values: ["en","es"]}, + {key: 'label', values: []}, + {key: 'default', values: []} + ]}, + {tag: 'tt', attr: []}, + {tag: 'u', attr: []}, + {tag: 'ul', attr: []}, + {tag: 'var', attr: []}, + {tag: 'video', attr: [ + {key: "src", values: []}, + {key: "crossorigin", values: ["anonymous","use-credentials"]}, + {key: "poster", values: []}, + {key: "preload", values: ["auto","metadata","none"]}, + {key: "autoplay", values: ["","autoplay"]}, + {key: "mediagroup", values: ["movie"]}, + {key: "loop", values: ["","loop"]}, + {key: "muted", values: ["","muted"]}, + {key: "controls", values: ["","controls"]}, + {key: "width", values: []}, + {key: "height", values: []} + ]}, + {tag: 'wbr', attr: []} + ]; + + + + var globalAttributes = [ + {key: "accesskey", values: ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"]}, + {key: "class", values: []}, + {key: "contenteditable", values: ["true", "false"]}, + {key: "contextmenu", values: []}, + {key: "dir", values: ["ltr","rtl","auto"]}, + {key: "draggable", values: ["true","false","auto"]}, + {key: "dropzone", values: ["copy","move","link","string:","file:"]}, + {key: "hidden", values: ["hidden"]}, + {key: "id", values: []}, + {key: "inert", values: ["inert"]}, + {key: "itemid", values: []}, + {key: "itemprop", values: []}, + {key: "itemref", values: []}, + {key: "itemscope", values: ["itemscope"]}, + {key: "itemtype", values: []}, + {key: "lang", values: ["en","es"]}, + {key: "spellcheck", values: ["true","false"]}, + {key: "style", values: []}, + {key: "tabindex", values: ["1","2","3","4","5","6","7","8","9"]}, + {key: "title", values: []}, + {key: "translate", values: ["yes","no"]}, + {key: "onclick", values: []}, + {key: 'rel', values: ["stylesheet","alternate","author","bookmark","help","license","next","nofollow","noreferrer","prefetch","prev","search","tag"]} + ]; + + + CodeMirror.htmlHint = function(editor) { + if(String.prototype.trim == undefined) { + String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g, '');}; + } + return scriptHint(editor, htmlStructure, function (e, cur) { return e.getTokenAt(cur); }); + }; +})(); \ No newline at end of file From bbd6439b84df0bb52c80beeb6923f3b9a53bf3df Mon Sep 17 00:00:00 2001 From: Juan Benavides Romero Date: Thu, 7 Mar 2013 10:06:32 +0100 Subject: [PATCH 0383/5273] Change tabs for 2 spaces --- addon/hint/html-hint.js | 1154 +++++++++++++++++++-------------------- 1 file changed, 577 insertions(+), 577 deletions(-) diff --git a/addon/hint/html-hint.js b/addon/hint/html-hint.js index 0e43e79c93..4becb34f18 100755 --- a/addon/hint/html-hint.js +++ b/addon/hint/html-hint.js @@ -1,586 +1,586 @@ (function () { - function scriptHint(editor, htmlStructure, getToken) { - var cur = editor.getCursor(); - var token = getToken(editor, cur); - var keywords = []; - var i = 0; - var j = 0; - var k = 0; - var from = {line: cur.line, ch: cur.ch}; - var to = {line: cur.line, ch: cur.ch}; - var flagClean = true; - - text = editor.getRange({line: 0, ch: 0}, cur); - - var open = text.lastIndexOf('<'); + function scriptHint(editor, htmlStructure, getToken) { + var cur = editor.getCursor(); + var token = getToken(editor, cur); + var keywords = []; + var i = 0; + var j = 0; + var k = 0; + var from = {line: cur.line, ch: cur.ch}; + var to = {line: cur.line, ch: cur.ch}; + var flagClean = true; + + text = editor.getRange({line: 0, ch: 0}, cur); + + var open = text.lastIndexOf('<'); var close = text.lastIndexOf('>'); - var tokenString = token.string.replace("<",""); - - if(open > close) { - var last = editor.getRange({line: cur.line, ch: cur.ch - 1}, cur); - if(last == "<") { - for(i = 0; i < htmlStructure.length; i++) { - keywords.push(htmlStructure[i].tag); - } - from.ch = token.start + 1; - } else { - var counter = 0; - var found = function(token, type, position) { - counter++; - if(counter > 50) return; - if(token.type == type) { - return token; - } else { - position.ch = token.start; - var newToken = editor.getTokenAt(position); - return found(newToken, type, position); - } - }; + var tokenString = token.string.replace("<",""); + + if(open > close) { + var last = editor.getRange({line: cur.line, ch: cur.ch - 1}, cur); + if(last == "<") { + for(i = 0; i < htmlStructure.length; i++) { + keywords.push(htmlStructure[i].tag); + } + from.ch = token.start + 1; + } else { + var counter = 0; + var found = function(token, type, position) { + counter++; + if(counter > 50) return; + if(token.type == type) { + return token; + } else { + position.ch = token.start; + var newToken = editor.getTokenAt(position); + return found(newToken, type, position); + } + }; - var nodeToken = found(token, "tag", {line: cur.line, ch: cur.ch}); - var node = nodeToken.string.substring(1); - - if(token.type === null && token.string.trim() === "") { - for(i = 0; i < htmlStructure.length; i++) { - if(htmlStructure[i].tag == node) { - for(j = 0; j < htmlStructure[i].attr.length; j++) { - keywords.push(htmlStructure[i].attr[j].key + "=\"\" "); - } - - for(k = 0; k < globalAttributes.length; k++) { - keywords.push(globalAttributes[k].key + "=\"\" "); - } - } - } - } else if(token.type == "string") { - tokenString = tokenString.substring(1, tokenString.length - 1); - var attributeToken = found(token, "attribute", {line: cur.line, ch: cur.ch}); - var attribute = attributeToken.string; - - for(i = 0; i < htmlStructure.length; i++) { - if(htmlStructure[i].tag == node) { - for(j = 0; j < htmlStructure[i].attr.length; j++) { - if(htmlStructure[i].attr[j].key == attribute) { - for(k = 0; k < htmlStructure[i].attr[j].values.length; k++) { - keywords.push(htmlStructure[i].attr[j].values[k]); - } - } - } - - for(j = 0; j < globalAttributes.length; j++) { - if(globalAttributes[j].key == attribute) { - for(k = 0; k < globalAttributes[j].values.length; k++) { - keywords.push(globalAttributes[j].values[k]); - } - } - } - } - } - from.ch = token.start + 1; - } else if(token.type == "attribute") { - for(i = 0; i < htmlStructure.length; i++) { - if(htmlStructure[i].tag == node) { - for(j = 0; j < htmlStructure[i].attr.length; j++) { - keywords.push(htmlStructure[i].attr[j].key + "=\"\" "); - } - - for(k = 0; k < globalAttributes.length; k++) { - keywords.push(globalAttributes[k].key + "=\"\" "); - } - } - } - from.ch = token.start; - } else if(token.type == "tag") { - for(i = 0; i < htmlStructure.length; i++) { - keywords.push(htmlStructure[i].tag); - } - - from.ch = token.start + 1; - } - } - } else { - for(i = 0; i < htmlStructure.length; i++) { - keywords.push("<" + htmlStructure[i].tag); - } - - tokenString = ("<" + tokenString).trim(); - from.ch = token.start; - } - - if(flagClean === true && tokenString.trim() === "") { - flagClean = false; - } - - if(flagClean) { - keywords = cleanResults(tokenString, keywords); - } + var nodeToken = found(token, "tag", {line: cur.line, ch: cur.ch}); + var node = nodeToken.string.substring(1); + + if(token.type === null && token.string.trim() === "") { + for(i = 0; i < htmlStructure.length; i++) { + if(htmlStructure[i].tag == node) { + for(j = 0; j < htmlStructure[i].attr.length; j++) { + keywords.push(htmlStructure[i].attr[j].key + "=\"\" "); + } + + for(k = 0; k < globalAttributes.length; k++) { + keywords.push(globalAttributes[k].key + "=\"\" "); + } + } + } + } else if(token.type == "string") { + tokenString = tokenString.substring(1, tokenString.length - 1); + var attributeToken = found(token, "attribute", {line: cur.line, ch: cur.ch}); + var attribute = attributeToken.string; + + for(i = 0; i < htmlStructure.length; i++) { + if(htmlStructure[i].tag == node) { + for(j = 0; j < htmlStructure[i].attr.length; j++) { + if(htmlStructure[i].attr[j].key == attribute) { + for(k = 0; k < htmlStructure[i].attr[j].values.length; k++) { + keywords.push(htmlStructure[i].attr[j].values[k]); + } + } + } + + for(j = 0; j < globalAttributes.length; j++) { + if(globalAttributes[j].key == attribute) { + for(k = 0; k < globalAttributes[j].values.length; k++) { + keywords.push(globalAttributes[j].values[k]); + } + } + } + } + } + from.ch = token.start + 1; + } else if(token.type == "attribute") { + for(i = 0; i < htmlStructure.length; i++) { + if(htmlStructure[i].tag == node) { + for(j = 0; j < htmlStructure[i].attr.length; j++) { + keywords.push(htmlStructure[i].attr[j].key + "=\"\" "); + } + + for(k = 0; k < globalAttributes.length; k++) { + keywords.push(globalAttributes[k].key + "=\"\" "); + } + } + } + from.ch = token.start; + } else if(token.type == "tag") { + for(i = 0; i < htmlStructure.length; i++) { + keywords.push(htmlStructure[i].tag); + } + + from.ch = token.start + 1; + } + } + } else { + for(i = 0; i < htmlStructure.length; i++) { + keywords.push("<" + htmlStructure[i].tag); + } + + tokenString = ("<" + tokenString).trim(); + from.ch = token.start; + } + + if(flagClean === true && tokenString.trim() === "") { + flagClean = false; + } + + if(flagClean) { + keywords = cleanResults(tokenString, keywords); + } - return {list: keywords, from: from, to: to}; - } - - - var cleanResults = function(text, keywords) { - var results = []; - var i = 0; + return {list: keywords, from: from, to: to}; + } + + + var cleanResults = function(text, keywords) { + var results = []; + var i = 0; - for(i = 0; i < keywords.length; i++) { - if(keywords[i].substring(0, text.length) == text) { - results.push(keywords[i]); - } - } - - return results; - }; - - - var htmlStructure = [ - {tag: '!DOCTYPE', attr: []}, - {tag: 'a', attr: [ - {key: 'href', values: ["#"]}, - {key: 'target', values: ["_blank","_self","_top","_parent"]}, - {key: 'ping', values: [""]}, - {key: 'media', values: ["#"]}, - {key: 'hreflang', values: ["en","es"]}, - {key: 'type', values: []} - ]}, - {tag: 'abbr', attr: []}, - {tag: 'acronym', attr: []}, - {tag: 'address', attr: []}, - {tag: 'applet', attr: []}, - {tag: 'area', attr: [ - {key: 'alt', values: [""]}, - {key: 'coords', values: ["rect: left, top, right, bottom","circle: center-x, center-y, radius","poly: x1, y1, x2, y2, ..."]}, - {key: 'shape', values: ["default","rect","circle","poly"]}, - {key: 'href', values: ["#"]}, - {key: 'target', values: ["#"]}, - {key: 'ping', values: []}, - {key: 'media', values: []}, - {key: 'hreflang', values: []}, - {key: 'type', values: []} - - ]}, - {tag: 'article', attr: []}, - {tag: 'aside', attr: []}, - {tag: 'audio', attr: [ - {key: 'src', values: []}, - {key: 'crossorigin', values: ["anonymous","use-credentials"]}, - {key: 'preload', values: ["none","metadata","auto"]}, - {key: 'autoplay', values: ["","autoplay"]}, - {key: 'mediagroup', values: []}, - {key: 'loop', values: ["","loop"]}, - {key: 'controls', values: ["","controls"]} - ]}, - {tag: 'b', attr: []}, - {tag: 'base', attr: [ - {key: 'href', values: ["#"]}, - {key: 'target', values: ["_blank","_self","_top","_parent"]} - ]}, - {tag: 'basefont', attr: []}, - {tag: 'bdi', attr: []}, - {tag: 'bdo', attr: []}, - {tag: 'big', attr: []}, - {tag: 'blockquote', attr: [ - {key: 'cite', values: ["http://"]} - ]}, - {tag: 'body', attr: []}, - {tag: 'br', attr: []}, - {tag: 'button', attr: [ - {key: 'autofocus', values: ["","autofocus"]}, - {key: 'disabled', values: ["","disabled"]}, - {key: 'form', values: []}, - {key: 'formaction', values: []}, - {key: 'formenctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]}, - {key: 'formmethod', values: ["get","post","put","delete"]}, - {key: 'formnovalidate', values: ["","novalidate"]}, - {key: 'formtarget', values: ["_blank","_self","_top","_parent"]}, - {key: 'name', values: []}, - {key: 'type', values: ["submit","reset","button"]}, - {key: 'value', values: []} - ]}, - {tag: 'canvas', attr: [ - {key: 'width', values: []}, - {key: 'height', values: []} - ]}, - {tag: 'caption', attr: []}, - {tag: 'center', attr: []}, - {tag: 'cite', attr: []}, - {tag: 'code', attr: []}, - {tag: 'col', attr: [ - {key: 'span', values: []} - ]}, - {tag: 'colgroup', attr: [ - {key: 'span', values: []} - ]}, - {tag: 'command', attr: [ - {key: 'type', values: ["command","checkbox","radio"]}, - {key: 'label', values: []}, - {key: 'icon', values: []}, - {key: 'disabled', values: ["","disabled"]}, - {key: 'checked', values: ["","checked"]}, - {key: 'radiogroup', values: []}, - {key: 'command', values: []}, - {key: 'title', values: []} - ]}, - {tag: 'data', attr: [ - {key: 'value', values: []} - ]}, - {tag: 'datagrid', attr: [ - {key: 'disabled', values: ["","disabled"]}, - {key: 'multiple', values: ["","multiple"]} - ]}, - {tag: 'datalist', attr: [ - {key: 'data', values: []} - ]}, - {tag: 'dd', attr: []}, - {tag: 'del', attr: [ - {key: 'cite', values: []}, - {key: 'datetime', values: []} - ]}, - {tag: 'details', attr: [ - {key: 'open', values: ["","open"]} - ]}, - {tag: 'dfn', attr: []}, - {tag: 'dir', attr: []}, - {tag: 'div', attr: [ - {key: 'id', values: []}, - {key: 'class', values: []}, - {key: 'style', values: []} - ]}, - {tag: 'dl', attr: []}, - {tag: 'dt', attr: []}, - {tag: 'em', attr: []}, - {tag: 'embed', attr: [ - {key: 'src', values: []}, - {key: 'type', values: []}, - {key: 'width', values: []}, - {key: 'height', values: []} - ]}, - {tag: 'eventsource', attr: [ - {key: 'src', values: []} - ]}, - {tag: 'fieldset', attr: [ - {key: 'disabled', values: ["","disabled"]}, - {key: 'form', values: []}, - {key: 'name', values: []} - ]}, - {tag: 'figcaption', attr: []}, - {tag: 'figure', attr: []}, - {tag: 'font', attr: []}, - {tag: 'footer', attr: []}, - {tag: 'form', attr: [ - {key: 'accept-charset', values: ["UNKNOWN","utf-8"]}, - {key: 'action', values: []}, - {key: 'autocomplete', values: ["on","off"]}, - {key: 'enctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]}, - {key: 'method', values: ["get","post","put","delete","dialog"]}, - {key: 'name', values: []}, - {key: 'novalidate', values: ["","novalidate"]}, - {key: 'target', values: ["_blank","_self","_top","_parent"]} - ]}, - {tag: 'frame', attr: []}, - {tag: 'frameset', attr: []}, - {tag: 'h1', attr: []}, - {tag: 'h2', attr: []}, - {tag: 'h3', attr: []}, - {tag: 'h4', attr: []}, - {tag: 'h5', attr: []}, - {tag: 'h6', attr: []}, - {tag: 'head', attr: []}, - {tag: 'header', attr: []}, - {tag: 'hgroup', attr: []}, - {tag: 'hr', attr: []}, - {tag: 'html', attr: [ - {key: 'manifest', values: []} - ]}, - {tag: 'i', attr: []}, - {tag: 'iframe', attr: [ - {key: 'src', values: []}, - {key: 'srcdoc', values: []}, - {key: 'name', values: []}, - {key: 'sandbox', values: ["allow-top-navigation","allow-same-origin","allow-forms","allow-scripts"]}, - {key: 'seamless', values: ["","seamless"]}, - {key: 'width', values: []}, - {key: 'height', values: []} - ]}, - {tag: 'img', attr: [ - {key: 'alt', values: []}, - {key: 'src', values: []}, - {key: 'crossorigin', values: ["anonymous","use-credentials"]}, - {key: 'ismap', values: []}, - {key: 'usemap', values: []}, - {key: 'width', values: []}, - {key: 'height', values: []} - ]}, - {tag: 'input', attr: [ - {key: 'accept', values: ["audio/*","video/*","image/*"]}, - {key: 'alt', values: []}, - {key: 'autocomplete', values: ["on","off"]}, - {key: 'autofocus', values: ["","autofocus"]}, - {key: 'checked', values: ["","checked"]}, - {key: 'disabled', values: ["","disabled"]}, - {key: 'dirname', values: []}, - {key: 'form', values: []}, - {key: 'formaction', values: []}, - {key: 'formenctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]}, - {key: 'formmethod', values: ["get","post","put","delete"]}, - {key: 'formnovalidate', values: ["","novalidate"]}, - {key: 'formtarget', values: ["_blank","_self","_top","_parent"]}, - {key: 'height', values: []}, - {key: 'list', values: []}, - {key: 'max', values: []}, - {key: 'maxlength', values: []}, - {key: 'min', values: []}, - {key: 'multiple', values: ["","multiple"]}, - {key: 'name', values: []}, - {key: 'pattern', values: []}, - {key: 'placeholder', values: []}, - {key: 'readonly', values: ["","readonly"]}, - {key: 'required', values: ["","required"]}, - {key: 'size', values: []}, - {key: 'src', values: []}, - {key: 'step', values: []}, - {key: 'type', values: [ - "hidden","text","search","tel","url","email","password","datetime","date","month","week","time","datetime-local", - "number","range","color","checkbox","radio","file","submit","image","reset","button" - ]}, - {key: 'value', values: []}, - {key: 'width', values: []} - ]}, - {tag: 'ins', attr: [ - {key: 'cite', values: []}, - {key: 'datetime', values: []} - ]}, - {tag: 'kbd', attr: []}, - {tag: 'keygen', attr: [ - {key: 'autofocus', values: ["","autofocus"]}, - {key: 'challenge', values: []}, - {key: 'disabled', values: ["","disabled"]}, - {key: 'form', values: []}, - {key: 'keytype', values: ["RSA"]}, - {key: 'name', values: []} - ]}, - {tag: 'label', attr: [ - {key: 'for', values: []}, - {key: 'form', values: []} - ]}, - {tag: 'legend', attr: []}, - {tag: 'li', attr: [ - {key: 'value', values: []} - ]}, - {tag: 'link', attr: [ - {key: 'href', values: []}, - {key: 'hreflang', values: ["en","es"]}, - {key: 'media', values: [ - "all","screen","print","embossed","braille","handheld","print","projection","screen","tty","tv","speech","3d-glasses", - "resolution [>][<][=] [X]dpi","resolution [>][<][=] [X]dpcm","device-aspect-ratio: 16/9","device-aspect-ratio: 4/3", - "device-aspect-ratio: 32/18","device-aspect-ratio: 1280/720","device-aspect-ratio: 2560/1440","orientation:portrait", - "orientation:landscape","device-height: [X]px","device-width: [X]px","-webkit-min-device-pixel-ratio: 2" - ]}, - {key: 'type', values: []}, - {key: 'sizes', values: ["all","16x16","16x16 32x32","16x16 32x32 64x64"]} - ]}, - {tag: 'map', attr: [ - {key: 'name', values: []} - ]}, - {tag: 'mark', attr: []}, - {tag: 'menu', attr: [ - {key: 'type', values: ["list","context","toolbar"]}, - {key: 'label', values: []} - ]}, - {tag: 'meta', attr: [ - {key: 'charset', attr: ["utf-8"]}, - {key: 'name', attr: ["viewport","application-name","author","description","generator","keywords"]}, - {key: 'content', attr: ["","width=device-width","initial-scale=1, maximum-scale=1, minimun-scale=1, user-scale=no"]}, - {key: 'http-equiv', attr: ["content-language","content-type","default-style","refresh"]} - ]}, - {tag: 'meter', attr: [ - {key: 'value', values: []}, - {key: 'min', values: []}, - {key: 'low', values: []}, - {key: 'high', values: []}, - {key: 'max', values: []}, - {key: 'optimum', values: []} - ]}, - {tag: 'nav', attr: []}, - {tag: 'noframes', attr: []}, - {tag: 'noscript', attr: []}, - {tag: 'object', attr: [ - {key: 'data', values: []}, - {key: 'type', values: []}, - {key: 'typemustmatch', values: ["","typemustmatch"]}, - {key: 'name', values: []}, - {key: 'usemap', values: []}, - {key: 'form', values: []}, - {key: 'width', values: []}, - {key: 'height', values: []} - ]}, - {tag: 'ol', attr: [ - {key: 'reversed', values: ["", "reversed"]}, - {key: 'start', values: []}, - {key: 'type', values: ["1","a","A","i","I"]} - ]}, - {tag: 'optgroup', attr: [ - {key: 'disabled', values: ["","disabled"]}, - {key: 'label', values: []} - ]}, - {tag: 'option', attr: [ - {key: 'disabled', values: ["", "disabled"]}, - {key: 'label', values: []}, - {key: 'selected', values: ["", "selected"]}, - {key: 'value', values: []} - ]}, - {tag: 'output', attr: [ - {key: 'for', values: []}, - {key: 'form', values: []}, - {key: 'name', values: []} - ]}, - {tag: 'p', attr: []}, - {tag: 'param', attr: [ - {key: 'name', values: []}, - {key: 'value', values: []} - ]}, - {tag: 'pre', attr: []}, - {tag: 'progress', attr: [ - {key: 'value', values: []}, - {key: 'max', values: []} - ]}, - {tag: 'q', attr: [ - {key: 'cite', values: []} - ]}, - {tag: 'rp', attr: []}, - {tag: 'rt', attr: []}, - {tag: 'ruby', attr: []}, - {tag: 's', attr: []}, - {tag: 'samp', attr: []}, - {tag: 'script', attr: [ - {key: 'type', values: ["text/javascript"]}, - {key: 'src', values: []}, - {key: 'async', values: ["","async"]}, - {key: 'defer', values: ["","defer"]}, - {key: 'charset', values: ["utf-8"]} - ]}, - {tag: 'section', attr: []}, - {tag: 'select', attr: [ - {key: 'autofocus', values: ["", "autofocus"]}, - {key: 'disabled', values: ["", "disabled"]}, - {key: 'form', values: []}, - {key: 'multiple', values: ["", "multiple"]}, - {key: 'name', values: []}, - {key: 'size', values: []} - ]}, - {tag: 'small', attr: []}, - {tag: 'source', attr: [ - {key: 'src', values: []}, - {key: 'type', values: []}, - {key: 'media', values: []} - ]}, - {tag: 'span', attr: []}, - {tag: 'strike', attr: []}, - {tag: 'strong', attr: []}, - {tag: 'style', attr: [ - {key: 'type', values: ["text/css"]}, - {key: 'media', values: ["all","braille","print","projection","screen","speech"]}, - {key: 'scoped', values: []} - ]}, - {tag: 'sub', attr: []}, - {tag: 'summary', attr: []}, - {tag: 'sup', attr: []}, - {tag: 'table', attr: [ - {key: 'border', values: []} - ]}, - {tag: 'tbody', attr: []}, - {tag: 'td', attr: [ - {key: 'colspan', values: []}, - {key: 'rowspan', values: []}, - {key: 'headers', values: []} - ]}, - {tag: 'textarea', attr: [ - {key: 'autofocus', values: ["","autofocus"]}, - {key: 'disabled', values: ["","disabled"]}, - {key: 'dirname', values: []}, - {key: 'form', values: []}, - {key: 'maxlength', values: []}, - {key: 'name', values: []}, - {key: 'placeholder', values: []}, - {key: 'readonly', values: ["","readonly"]}, - {key: 'required', values: ["","required"]}, - {key: 'rows', values: []}, - {key: 'cols', values: []}, - {key: 'wrap', values: ["soft","hard"]} - ]}, - {tag: 'tfoot', attr: []}, - {tag: 'th', attr: [ - {key: 'colspan', values: []}, - {key: 'rowspan', values: []}, - {key: 'headers', values: []}, - {key: 'scope', values: ["row","col","rowgroup","colgroup"]} - ]}, - {tag: 'thead', attr: []}, - {tag: 'time', attr: [ - {key: 'datetime', values: []} - ]}, - {tag: 'title', attr: []}, - {tag: 'tr', attr: []}, - {tag: 'track', attr: [ - {key: 'kind', values: ["subtitles","captions","descriptions","chapters","metadata"]}, - {key: 'src', values: []}, - {key: 'srclang', values: ["en","es"]}, - {key: 'label', values: []}, - {key: 'default', values: []} - ]}, - {tag: 'tt', attr: []}, - {tag: 'u', attr: []}, - {tag: 'ul', attr: []}, - {tag: 'var', attr: []}, - {tag: 'video', attr: [ - {key: "src", values: []}, - {key: "crossorigin", values: ["anonymous","use-credentials"]}, - {key: "poster", values: []}, - {key: "preload", values: ["auto","metadata","none"]}, - {key: "autoplay", values: ["","autoplay"]}, - {key: "mediagroup", values: ["movie"]}, - {key: "loop", values: ["","loop"]}, - {key: "muted", values: ["","muted"]}, - {key: "controls", values: ["","controls"]}, - {key: "width", values: []}, - {key: "height", values: []} - ]}, - {tag: 'wbr', attr: []} - ]; - - - - var globalAttributes = [ - {key: "accesskey", values: ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"]}, - {key: "class", values: []}, - {key: "contenteditable", values: ["true", "false"]}, - {key: "contextmenu", values: []}, - {key: "dir", values: ["ltr","rtl","auto"]}, - {key: "draggable", values: ["true","false","auto"]}, - {key: "dropzone", values: ["copy","move","link","string:","file:"]}, - {key: "hidden", values: ["hidden"]}, - {key: "id", values: []}, - {key: "inert", values: ["inert"]}, - {key: "itemid", values: []}, - {key: "itemprop", values: []}, - {key: "itemref", values: []}, - {key: "itemscope", values: ["itemscope"]}, - {key: "itemtype", values: []}, - {key: "lang", values: ["en","es"]}, - {key: "spellcheck", values: ["true","false"]}, - {key: "style", values: []}, - {key: "tabindex", values: ["1","2","3","4","5","6","7","8","9"]}, - {key: "title", values: []}, - {key: "translate", values: ["yes","no"]}, - {key: "onclick", values: []}, - {key: 'rel', values: ["stylesheet","alternate","author","bookmark","help","license","next","nofollow","noreferrer","prefetch","prev","search","tag"]} - ]; - - - CodeMirror.htmlHint = function(editor) { + for(i = 0; i < keywords.length; i++) { + if(keywords[i].substring(0, text.length) == text) { + results.push(keywords[i]); + } + } + + return results; + }; + + + var htmlStructure = [ + {tag: '!DOCTYPE', attr: []}, + {tag: 'a', attr: [ + {key: 'href', values: ["#"]}, + {key: 'target', values: ["_blank","_self","_top","_parent"]}, + {key: 'ping', values: [""]}, + {key: 'media', values: ["#"]}, + {key: 'hreflang', values: ["en","es"]}, + {key: 'type', values: []} + ]}, + {tag: 'abbr', attr: []}, + {tag: 'acronym', attr: []}, + {tag: 'address', attr: []}, + {tag: 'applet', attr: []}, + {tag: 'area', attr: [ + {key: 'alt', values: [""]}, + {key: 'coords', values: ["rect: left, top, right, bottom","circle: center-x, center-y, radius","poly: x1, y1, x2, y2, ..."]}, + {key: 'shape', values: ["default","rect","circle","poly"]}, + {key: 'href', values: ["#"]}, + {key: 'target', values: ["#"]}, + {key: 'ping', values: []}, + {key: 'media', values: []}, + {key: 'hreflang', values: []}, + {key: 'type', values: []} + + ]}, + {tag: 'article', attr: []}, + {tag: 'aside', attr: []}, + {tag: 'audio', attr: [ + {key: 'src', values: []}, + {key: 'crossorigin', values: ["anonymous","use-credentials"]}, + {key: 'preload', values: ["none","metadata","auto"]}, + {key: 'autoplay', values: ["","autoplay"]}, + {key: 'mediagroup', values: []}, + {key: 'loop', values: ["","loop"]}, + {key: 'controls', values: ["","controls"]} + ]}, + {tag: 'b', attr: []}, + {tag: 'base', attr: [ + {key: 'href', values: ["#"]}, + {key: 'target', values: ["_blank","_self","_top","_parent"]} + ]}, + {tag: 'basefont', attr: []}, + {tag: 'bdi', attr: []}, + {tag: 'bdo', attr: []}, + {tag: 'big', attr: []}, + {tag: 'blockquote', attr: [ + {key: 'cite', values: ["http://"]} + ]}, + {tag: 'body', attr: []}, + {tag: 'br', attr: []}, + {tag: 'button', attr: [ + {key: 'autofocus', values: ["","autofocus"]}, + {key: 'disabled', values: ["","disabled"]}, + {key: 'form', values: []}, + {key: 'formaction', values: []}, + {key: 'formenctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]}, + {key: 'formmethod', values: ["get","post","put","delete"]}, + {key: 'formnovalidate', values: ["","novalidate"]}, + {key: 'formtarget', values: ["_blank","_self","_top","_parent"]}, + {key: 'name', values: []}, + {key: 'type', values: ["submit","reset","button"]}, + {key: 'value', values: []} + ]}, + {tag: 'canvas', attr: [ + {key: 'width', values: []}, + {key: 'height', values: []} + ]}, + {tag: 'caption', attr: []}, + {tag: 'center', attr: []}, + {tag: 'cite', attr: []}, + {tag: 'code', attr: []}, + {tag: 'col', attr: [ + {key: 'span', values: []} + ]}, + {tag: 'colgroup', attr: [ + {key: 'span', values: []} + ]}, + {tag: 'command', attr: [ + {key: 'type', values: ["command","checkbox","radio"]}, + {key: 'label', values: []}, + {key: 'icon', values: []}, + {key: 'disabled', values: ["","disabled"]}, + {key: 'checked', values: ["","checked"]}, + {key: 'radiogroup', values: []}, + {key: 'command', values: []}, + {key: 'title', values: []} + ]}, + {tag: 'data', attr: [ + {key: 'value', values: []} + ]}, + {tag: 'datagrid', attr: [ + {key: 'disabled', values: ["","disabled"]}, + {key: 'multiple', values: ["","multiple"]} + ]}, + {tag: 'datalist', attr: [ + {key: 'data', values: []} + ]}, + {tag: 'dd', attr: []}, + {tag: 'del', attr: [ + {key: 'cite', values: []}, + {key: 'datetime', values: []} + ]}, + {tag: 'details', attr: [ + {key: 'open', values: ["","open"]} + ]}, + {tag: 'dfn', attr: []}, + {tag: 'dir', attr: []}, + {tag: 'div', attr: [ + {key: 'id', values: []}, + {key: 'class', values: []}, + {key: 'style', values: []} + ]}, + {tag: 'dl', attr: []}, + {tag: 'dt', attr: []}, + {tag: 'em', attr: []}, + {tag: 'embed', attr: [ + {key: 'src', values: []}, + {key: 'type', values: []}, + {key: 'width', values: []}, + {key: 'height', values: []} + ]}, + {tag: 'eventsource', attr: [ + {key: 'src', values: []} + ]}, + {tag: 'fieldset', attr: [ + {key: 'disabled', values: ["","disabled"]}, + {key: 'form', values: []}, + {key: 'name', values: []} + ]}, + {tag: 'figcaption', attr: []}, + {tag: 'figure', attr: []}, + {tag: 'font', attr: []}, + {tag: 'footer', attr: []}, + {tag: 'form', attr: [ + {key: 'accept-charset', values: ["UNKNOWN","utf-8"]}, + {key: 'action', values: []}, + {key: 'autocomplete', values: ["on","off"]}, + {key: 'enctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]}, + {key: 'method', values: ["get","post","put","delete","dialog"]}, + {key: 'name', values: []}, + {key: 'novalidate', values: ["","novalidate"]}, + {key: 'target', values: ["_blank","_self","_top","_parent"]} + ]}, + {tag: 'frame', attr: []}, + {tag: 'frameset', attr: []}, + {tag: 'h1', attr: []}, + {tag: 'h2', attr: []}, + {tag: 'h3', attr: []}, + {tag: 'h4', attr: []}, + {tag: 'h5', attr: []}, + {tag: 'h6', attr: []}, + {tag: 'head', attr: []}, + {tag: 'header', attr: []}, + {tag: 'hgroup', attr: []}, + {tag: 'hr', attr: []}, + {tag: 'html', attr: [ + {key: 'manifest', values: []} + ]}, + {tag: 'i', attr: []}, + {tag: 'iframe', attr: [ + {key: 'src', values: []}, + {key: 'srcdoc', values: []}, + {key: 'name', values: []}, + {key: 'sandbox', values: ["allow-top-navigation","allow-same-origin","allow-forms","allow-scripts"]}, + {key: 'seamless', values: ["","seamless"]}, + {key: 'width', values: []}, + {key: 'height', values: []} + ]}, + {tag: 'img', attr: [ + {key: 'alt', values: []}, + {key: 'src', values: []}, + {key: 'crossorigin', values: ["anonymous","use-credentials"]}, + {key: 'ismap', values: []}, + {key: 'usemap', values: []}, + {key: 'width', values: []}, + {key: 'height', values: []} + ]}, + {tag: 'input', attr: [ + {key: 'accept', values: ["audio/*","video/*","image/*"]}, + {key: 'alt', values: []}, + {key: 'autocomplete', values: ["on","off"]}, + {key: 'autofocus', values: ["","autofocus"]}, + {key: 'checked', values: ["","checked"]}, + {key: 'disabled', values: ["","disabled"]}, + {key: 'dirname', values: []}, + {key: 'form', values: []}, + {key: 'formaction', values: []}, + {key: 'formenctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]}, + {key: 'formmethod', values: ["get","post","put","delete"]}, + {key: 'formnovalidate', values: ["","novalidate"]}, + {key: 'formtarget', values: ["_blank","_self","_top","_parent"]}, + {key: 'height', values: []}, + {key: 'list', values: []}, + {key: 'max', values: []}, + {key: 'maxlength', values: []}, + {key: 'min', values: []}, + {key: 'multiple', values: ["","multiple"]}, + {key: 'name', values: []}, + {key: 'pattern', values: []}, + {key: 'placeholder', values: []}, + {key: 'readonly', values: ["","readonly"]}, + {key: 'required', values: ["","required"]}, + {key: 'size', values: []}, + {key: 'src', values: []}, + {key: 'step', values: []}, + {key: 'type', values: [ + "hidden","text","search","tel","url","email","password","datetime","date","month","week","time","datetime-local", + "number","range","color","checkbox","radio","file","submit","image","reset","button" + ]}, + {key: 'value', values: []}, + {key: 'width', values: []} + ]}, + {tag: 'ins', attr: [ + {key: 'cite', values: []}, + {key: 'datetime', values: []} + ]}, + {tag: 'kbd', attr: []}, + {tag: 'keygen', attr: [ + {key: 'autofocus', values: ["","autofocus"]}, + {key: 'challenge', values: []}, + {key: 'disabled', values: ["","disabled"]}, + {key: 'form', values: []}, + {key: 'keytype', values: ["RSA"]}, + {key: 'name', values: []} + ]}, + {tag: 'label', attr: [ + {key: 'for', values: []}, + {key: 'form', values: []} + ]}, + {tag: 'legend', attr: []}, + {tag: 'li', attr: [ + {key: 'value', values: []} + ]}, + {tag: 'link', attr: [ + {key: 'href', values: []}, + {key: 'hreflang', values: ["en","es"]}, + {key: 'media', values: [ + "all","screen","print","embossed","braille","handheld","print","projection","screen","tty","tv","speech","3d-glasses", + "resolution [>][<][=] [X]dpi","resolution [>][<][=] [X]dpcm","device-aspect-ratio: 16/9","device-aspect-ratio: 4/3", + "device-aspect-ratio: 32/18","device-aspect-ratio: 1280/720","device-aspect-ratio: 2560/1440","orientation:portrait", + "orientation:landscape","device-height: [X]px","device-width: [X]px","-webkit-min-device-pixel-ratio: 2" + ]}, + {key: 'type', values: []}, + {key: 'sizes', values: ["all","16x16","16x16 32x32","16x16 32x32 64x64"]} + ]}, + {tag: 'map', attr: [ + {key: 'name', values: []} + ]}, + {tag: 'mark', attr: []}, + {tag: 'menu', attr: [ + {key: 'type', values: ["list","context","toolbar"]}, + {key: 'label', values: []} + ]}, + {tag: 'meta', attr: [ + {key: 'charset', attr: ["utf-8"]}, + {key: 'name', attr: ["viewport","application-name","author","description","generator","keywords"]}, + {key: 'content', attr: ["","width=device-width","initial-scale=1, maximum-scale=1, minimun-scale=1, user-scale=no"]}, + {key: 'http-equiv', attr: ["content-language","content-type","default-style","refresh"]} + ]}, + {tag: 'meter', attr: [ + {key: 'value', values: []}, + {key: 'min', values: []}, + {key: 'low', values: []}, + {key: 'high', values: []}, + {key: 'max', values: []}, + {key: 'optimum', values: []} + ]}, + {tag: 'nav', attr: []}, + {tag: 'noframes', attr: []}, + {tag: 'noscript', attr: []}, + {tag: 'object', attr: [ + {key: 'data', values: []}, + {key: 'type', values: []}, + {key: 'typemustmatch', values: ["","typemustmatch"]}, + {key: 'name', values: []}, + {key: 'usemap', values: []}, + {key: 'form', values: []}, + {key: 'width', values: []}, + {key: 'height', values: []} + ]}, + {tag: 'ol', attr: [ + {key: 'reversed', values: ["", "reversed"]}, + {key: 'start', values: []}, + {key: 'type', values: ["1","a","A","i","I"]} + ]}, + {tag: 'optgroup', attr: [ + {key: 'disabled', values: ["","disabled"]}, + {key: 'label', values: []} + ]}, + {tag: 'option', attr: [ + {key: 'disabled', values: ["", "disabled"]}, + {key: 'label', values: []}, + {key: 'selected', values: ["", "selected"]}, + {key: 'value', values: []} + ]}, + {tag: 'output', attr: [ + {key: 'for', values: []}, + {key: 'form', values: []}, + {key: 'name', values: []} + ]}, + {tag: 'p', attr: []}, + {tag: 'param', attr: [ + {key: 'name', values: []}, + {key: 'value', values: []} + ]}, + {tag: 'pre', attr: []}, + {tag: 'progress', attr: [ + {key: 'value', values: []}, + {key: 'max', values: []} + ]}, + {tag: 'q', attr: [ + {key: 'cite', values: []} + ]}, + {tag: 'rp', attr: []}, + {tag: 'rt', attr: []}, + {tag: 'ruby', attr: []}, + {tag: 's', attr: []}, + {tag: 'samp', attr: []}, + {tag: 'script', attr: [ + {key: 'type', values: ["text/javascript"]}, + {key: 'src', values: []}, + {key: 'async', values: ["","async"]}, + {key: 'defer', values: ["","defer"]}, + {key: 'charset', values: ["utf-8"]} + ]}, + {tag: 'section', attr: []}, + {tag: 'select', attr: [ + {key: 'autofocus', values: ["", "autofocus"]}, + {key: 'disabled', values: ["", "disabled"]}, + {key: 'form', values: []}, + {key: 'multiple', values: ["", "multiple"]}, + {key: 'name', values: []}, + {key: 'size', values: []} + ]}, + {tag: 'small', attr: []}, + {tag: 'source', attr: [ + {key: 'src', values: []}, + {key: 'type', values: []}, + {key: 'media', values: []} + ]}, + {tag: 'span', attr: []}, + {tag: 'strike', attr: []}, + {tag: 'strong', attr: []}, + {tag: 'style', attr: [ + {key: 'type', values: ["text/css"]}, + {key: 'media', values: ["all","braille","print","projection","screen","speech"]}, + {key: 'scoped', values: []} + ]}, + {tag: 'sub', attr: []}, + {tag: 'summary', attr: []}, + {tag: 'sup', attr: []}, + {tag: 'table', attr: [ + {key: 'border', values: []} + ]}, + {tag: 'tbody', attr: []}, + {tag: 'td', attr: [ + {key: 'colspan', values: []}, + {key: 'rowspan', values: []}, + {key: 'headers', values: []} + ]}, + {tag: 'textarea', attr: [ + {key: 'autofocus', values: ["","autofocus"]}, + {key: 'disabled', values: ["","disabled"]}, + {key: 'dirname', values: []}, + {key: 'form', values: []}, + {key: 'maxlength', values: []}, + {key: 'name', values: []}, + {key: 'placeholder', values: []}, + {key: 'readonly', values: ["","readonly"]}, + {key: 'required', values: ["","required"]}, + {key: 'rows', values: []}, + {key: 'cols', values: []}, + {key: 'wrap', values: ["soft","hard"]} + ]}, + {tag: 'tfoot', attr: []}, + {tag: 'th', attr: [ + {key: 'colspan', values: []}, + {key: 'rowspan', values: []}, + {key: 'headers', values: []}, + {key: 'scope', values: ["row","col","rowgroup","colgroup"]} + ]}, + {tag: 'thead', attr: []}, + {tag: 'time', attr: [ + {key: 'datetime', values: []} + ]}, + {tag: 'title', attr: []}, + {tag: 'tr', attr: []}, + {tag: 'track', attr: [ + {key: 'kind', values: ["subtitles","captions","descriptions","chapters","metadata"]}, + {key: 'src', values: []}, + {key: 'srclang', values: ["en","es"]}, + {key: 'label', values: []}, + {key: 'default', values: []} + ]}, + {tag: 'tt', attr: []}, + {tag: 'u', attr: []}, + {tag: 'ul', attr: []}, + {tag: 'var', attr: []}, + {tag: 'video', attr: [ + {key: "src", values: []}, + {key: "crossorigin", values: ["anonymous","use-credentials"]}, + {key: "poster", values: []}, + {key: "preload", values: ["auto","metadata","none"]}, + {key: "autoplay", values: ["","autoplay"]}, + {key: "mediagroup", values: ["movie"]}, + {key: "loop", values: ["","loop"]}, + {key: "muted", values: ["","muted"]}, + {key: "controls", values: ["","controls"]}, + {key: "width", values: []}, + {key: "height", values: []} + ]}, + {tag: 'wbr', attr: []} + ]; + + + + var globalAttributes = [ + {key: "accesskey", values: ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"]}, + {key: "class", values: []}, + {key: "contenteditable", values: ["true", "false"]}, + {key: "contextmenu", values: []}, + {key: "dir", values: ["ltr","rtl","auto"]}, + {key: "draggable", values: ["true","false","auto"]}, + {key: "dropzone", values: ["copy","move","link","string:","file:"]}, + {key: "hidden", values: ["hidden"]}, + {key: "id", values: []}, + {key: "inert", values: ["inert"]}, + {key: "itemid", values: []}, + {key: "itemprop", values: []}, + {key: "itemref", values: []}, + {key: "itemscope", values: ["itemscope"]}, + {key: "itemtype", values: []}, + {key: "lang", values: ["en","es"]}, + {key: "spellcheck", values: ["true","false"]}, + {key: "style", values: []}, + {key: "tabindex", values: ["1","2","3","4","5","6","7","8","9"]}, + {key: "title", values: []}, + {key: "translate", values: ["yes","no"]}, + {key: "onclick", values: []}, + {key: 'rel', values: ["stylesheet","alternate","author","bookmark","help","license","next","nofollow","noreferrer","prefetch","prev","search","tag"]} + ]; + + + CodeMirror.htmlHint = function(editor) { if(String.prototype.trim == undefined) { String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g, '');}; } - return scriptHint(editor, htmlStructure, function (e, cur) { return e.getTokenAt(cur); }); - }; + return scriptHint(editor, htmlStructure, function (e, cur) { return e.getTokenAt(cur); }); + }; })(); \ No newline at end of file From 52e691cb1198cce8b9966d99ea006c4ea19ed8c3 Mon Sep 17 00:00:00 2001 From: Juan Benavides Romero Date: Thu, 7 Mar 2013 17:57:54 +0100 Subject: [PATCH 0384/5273] Added a demo page for html5 autocomplete --- demo/html5complete.html | 92 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 demo/html5complete.html diff --git a/demo/html5complete.html b/demo/html5complete.html new file mode 100644 index 0000000000..5091354ae9 --- /dev/null +++ b/demo/html5complete.html @@ -0,0 +1,92 @@ + + + + + CodeMirror: Close-Tag Demo + + + + + + + + + + + + + + + + +

    HTML5 code completation demo

    +
      +
    • Type an html tag. If you press Ctrl+Space a hint panel show the code suggest. You can type to autocomplete tags, attributes if your cursor are inner a tag or attribute values if your cursor are inner a attribute value.
    • +
    + +
    + + + From 92b6fa34b6ea6912eb4295dbee111412769c8569 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 19 Mar 2013 10:26:41 +0100 Subject: [PATCH 0385/5273] [html-hint addon] Integrate --- addon/hint/html-hint.js | 70 +++++++++++++++++++---------------------- doc/compress.html | 1 + 2 files changed, 34 insertions(+), 37 deletions(-) diff --git a/addon/hint/html-hint.js b/addon/hint/html-hint.js index 4becb34f18..8b5dc6f002 100755 --- a/addon/hint/html-hint.js +++ b/addon/hint/html-hint.js @@ -1,5 +1,5 @@ (function () { - function scriptHint(editor, htmlStructure, getToken) { + function htmlHint(editor, htmlStructure, getToken) { var cur = editor.getCursor(); var token = getToken(editor, cur); var keywords = []; @@ -9,13 +9,13 @@ var from = {line: cur.line, ch: cur.ch}; var to = {line: cur.line, ch: cur.ch}; var flagClean = true; - - text = editor.getRange({line: 0, ch: 0}, cur); - + + var text = editor.getRange({line: 0, ch: 0}, cur); + var open = text.lastIndexOf('<'); - var close = text.lastIndexOf('>'); + var close = text.lastIndexOf('>'); var tokenString = token.string.replace("<",""); - + if(open > close) { var last = editor.getRange({line: cur.line, ch: cur.ch - 1}, cur); if(last == "<") { @@ -29,24 +29,24 @@ counter++; if(counter > 50) return; if(token.type == type) { - return token; + return token; } else { position.ch = token.start; var newToken = editor.getTokenAt(position); return found(newToken, type, position); } }; - + var nodeToken = found(token, "tag", {line: cur.line, ch: cur.ch}); var node = nodeToken.string.substring(1); - + if(token.type === null && token.string.trim() === "") { for(i = 0; i < htmlStructure.length; i++) { if(htmlStructure[i].tag == node) { for(j = 0; j < htmlStructure[i].attr.length; j++) { keywords.push(htmlStructure[i].attr[j].key + "=\"\" "); } - + for(k = 0; k < globalAttributes.length; k++) { keywords.push(globalAttributes[k].key + "=\"\" "); } @@ -56,7 +56,7 @@ tokenString = tokenString.substring(1, tokenString.length - 1); var attributeToken = found(token, "attribute", {line: cur.line, ch: cur.ch}); var attribute = attributeToken.string; - + for(i = 0; i < htmlStructure.length; i++) { if(htmlStructure[i].tag == node) { for(j = 0; j < htmlStructure[i].attr.length; j++) { @@ -66,7 +66,7 @@ } } } - + for(j = 0; j < globalAttributes.length; j++) { if(globalAttributes[j].key == attribute) { for(k = 0; k < globalAttributes[j].values.length; k++) { @@ -83,7 +83,7 @@ for(j = 0; j < htmlStructure[i].attr.length; j++) { keywords.push(htmlStructure[i].attr[j].key + "=\"\" "); } - + for(k = 0; k < globalAttributes.length; k++) { keywords.push(globalAttributes[k].key + "=\"\" "); } @@ -94,7 +94,7 @@ for(i = 0; i < htmlStructure.length; i++) { keywords.push(htmlStructure[i].tag); } - + from.ch = token.start + 1; } } @@ -102,37 +102,36 @@ for(i = 0; i < htmlStructure.length; i++) { keywords.push("<" + htmlStructure[i].tag); } - + tokenString = ("<" + tokenString).trim(); from.ch = token.start; } - + if(flagClean === true && tokenString.trim() === "") { - flagClean = false; + flagClean = false; } - + if(flagClean) { keywords = cleanResults(tokenString, keywords); } - + return {list: keywords, from: from, to: to}; } - - + + var cleanResults = function(text, keywords) { var results = []; var i = 0; - + for(i = 0; i < keywords.length; i++) { if(keywords[i].substring(0, text.length) == text) { - results.push(keywords[i]); + results.push(keywords[i]); } } - + return results; }; - - + var htmlStructure = [ {tag: '!DOCTYPE', attr: []}, {tag: 'a', attr: [ @@ -157,7 +156,7 @@ {key: 'media', values: []}, {key: 'hreflang', values: []}, {key: 'type', values: []} - + ]}, {tag: 'article', attr: []}, {tag: 'aside', attr: []}, @@ -547,9 +546,7 @@ ]}, {tag: 'wbr', attr: []} ]; - - - + var globalAttributes = [ {key: "accesskey", values: ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"]}, {key: "class", values: []}, @@ -575,12 +572,11 @@ {key: "onclick", values: []}, {key: 'rel', values: ["stylesheet","alternate","author","bookmark","help","license","next","nofollow","noreferrer","prefetch","prev","search","tag"]} ]; - - + CodeMirror.htmlHint = function(editor) { - if(String.prototype.trim == undefined) { - String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g, '');}; - } - return scriptHint(editor, htmlStructure, function (e, cur) { return e.getTokenAt(cur); }); + if(String.prototype.trim == undefined) { + String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g, '');}; + } + return htmlHint(editor, htmlStructure, function (e, cur) { return e.getTokenAt(cur); }); }; -})(); \ No newline at end of file +})(); diff --git a/doc/compress.html b/doc/compress.html index 22b8362fc1..c559730e90 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -146,6 +146,7 @@

    { } CodeMi + From 3c07efc9bd12472a2d10ece99e68d4cb2ce61162 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 19 Mar 2013 10:38:56 +0100 Subject: [PATCH 0386/5273] [compression helper] Fix copy-paste mistake --- doc/compress.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/compress.html b/doc/compress.html index c559730e90..71ae09d149 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -146,7 +146,7 @@

    { } CodeMi - + From df76d4ecfd4adbe884eeab81a003875e1b8cc9ad Mon Sep 17 00:00:00 2001 From: "Daniel, Dao Quang Minh" Date: Wed, 20 Mar 2013 09:33:42 +0800 Subject: [PATCH 0387/5273] [css mode] fix navy and yellow not hightlighted as color --- mode/css/css.js | 4 ++-- mode/css/test.js | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index 00d605a69d..7fc5387ffe 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -445,7 +445,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "menu", "menulist", "menulist-button", "menulist-text", "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic", "mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize", - "narrower", "navy", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", + "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", @@ -477,7 +477,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", "visibleStroke", "visual", "w-resize", "wait", "wave", "white", "wider", "window", "windowframe", "windowtext", "x-large", "x-small", "xor", - "xx-large", "xx-small", "yellow" + "xx-large", "xx-small" ]); function tokenCComment(stream, state) { diff --git a/mode/css/test.js b/mode/css/test.js index 0f68deb1c4..97dd0a8a34 100644 --- a/mode/css/test.js +++ b/mode/css/test.js @@ -75,7 +75,11 @@ "[tag foo] { [property font-family][operator :] [string 'hello world']; }"); MT("tagColorKeyword", - "[tag foo] { [property color][operator :] [keyword black]; }"); + "[tag foo] {" + + "[property color][operator :] [keyword black];" + + "[property color][operator :] [keyword navy];" + + "[property color][operator :] [keyword yellow];" + + "}"); MT("tagColorHex3", "[tag foo] { [property background][operator :] [atom #fff]; }"); From 6abe503b62f4347d80afdbe2cc3f0a3f019d403d Mon Sep 17 00:00:00 2001 From: "Daniel, Dao Quang Minh" Date: Wed, 20 Mar 2013 09:23:02 +0800 Subject: [PATCH 0388/5273] [scss mode] fix nested id selector not highlighted properly --- mode/css/css.js | 2 +- mode/css/scss.html | 3 +++ mode/css/scss_test.js | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/mode/css/css.js b/mode/css/css.js index 7fc5387ffe..1ef72b517d 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -234,7 +234,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { style = "error"; } } else if (style == "atom") { - if(!context || context == "@media{") { + if(!context || context == "@media{" || context == "block") { style = "builtin"; } else if (context == "propertyValue") { if (!/^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(stream.current())) { diff --git a/mode/css/scss.html b/mode/css/scss.html index b67d7ff28a..b90cbe876c 100644 --- a/mode/css/scss.html +++ b/mode/css/scss.html @@ -21,6 +21,9 @@

    CodeMirror: SCSS mode

    $margin: 16px; .content-navigation { + #nested { + background-color: black; + } border-color: $blue; color: darken($blue, 9%); diff --git a/mode/css/scss_test.js b/mode/css/scss_test.js index 330b0a6a5b..996dc78849 100644 --- a/mode/css/scss_test.js +++ b/mode/css/scss_test.js @@ -74,4 +74,7 @@ MT("divide_operator", "[tag foo] { [property width][operator :][number 4] [operator /] [number 2] }"); + + MT('nested_structure_with_id_selector', + "[tag p] { [builtin #hello] { [property color][operator :][keyword red]; } }"); })(); From 192b2c2b9216a8063504334732536aa293e55657 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Mar 2013 07:33:46 +0100 Subject: [PATCH 0389/5273] Make tab elements inline blocks Closes #1380 --- lib/codemirror.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/codemirror.css b/lib/codemirror.css index bab16bc2c9..411166bc72 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -56,6 +56,8 @@ /* Can style cursor different in overwrite (non-insert) mode */ .CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite {} +.cm-tab { display: inline-block; } + /* DEFAULT THEME */ .cm-s-default .cm-keyword {color: #708;} From 740366d3a2aba3c6d1a3a1affd50ed4d08f1ed05 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Tue, 19 Mar 2013 21:22:29 -0400 Subject: [PATCH 0390/5273] [vim] Fix :num and add unit test --- keymap/vim.js | 3 ++- test/vim_test.js | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/keymap/vim.js b/keymap/vim.js index af964a666d..77b696d93b 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2543,7 +2543,8 @@ exCommandDispatcher.map(mapArgs[0], mapArgs[1], cm); }, move: function(cm, params) { - commandDispatcher.processMotion(cm, getVimState(cm), { + commandDispatcher.processCommand(cm, getVimState(cm), { + type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, linewise: true }, diff --git a/test/vim_test.js b/test/vim_test.js index c3b23a3b4a..f91be02f9e 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1158,6 +1158,11 @@ testVim('._repeat', function(cm, vim, helpers) { }, { value: '1 2 3 4 5 6'}); // Ex mode tests +testVim('ex_go_to_line', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doEx('4'); + helpers.assertCursorAt(3, 0); +}, { value: 'a\nb\nc\nd\ne\n'}); testVim('ex_write', function(cm, vim, helpers) { var tmp = CodeMirror.commands.save; var written; From 4a745fe6680d104ff4c4347617a5964dcb01c46b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Mar 2013 11:25:32 +0100 Subject: [PATCH 0391/5273] Work around element size rounding issue on OS X Also fixes a problem where individual gutter backgrounds would not fill the space next to the horiz scrollbar. --- lib/codemirror.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/codemirror.css b/lib/codemirror.css index 411166bc72..4e126154f6 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -152,6 +152,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} } .CodeMirror-gutter { height: 100%; + padding-bottom: 30px; + margin-bottom: -32px; display: inline-block; /* Hack to make IE7 behave */ *zoom:1; From bac7936e9e26c4f1cb26cd99e3a680555a32338c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Mar 2013 11:41:01 +0100 Subject: [PATCH 0392/5273] Drop the formatting addon It's flaky, and I don't want to support it. Everybody: feel free to take the code, put it in some other repo and maintain it. --- addon/format/formatting.js | 114 ------------------------------------- demo/formatting.html | 89 ----------------------------- doc/compress.html | 1 - doc/manual.html | 9 ++- 4 files changed, 4 insertions(+), 209 deletions(-) delete mode 100644 addon/format/formatting.js delete mode 100644 demo/formatting.html diff --git a/addon/format/formatting.js b/addon/format/formatting.js deleted file mode 100644 index 88b84307f6..0000000000 --- a/addon/format/formatting.js +++ /dev/null @@ -1,114 +0,0 @@ -(function() { - - CodeMirror.extendMode("css", { - commentStart: "/*", - commentEnd: "*/", - newlineAfterToken: function(_type, content) { - return /^[;{}]$/.test(content); - } - }); - - CodeMirror.extendMode("javascript", { - commentStart: "/*", - commentEnd: "*/", - // FIXME semicolons inside of for - newlineAfterToken: function(_type, content, textAfter, state) { - if (this.jsonMode) { - return /^[\[,{]$/.test(content) || /^}/.test(textAfter); - } else { - if (content == ";" && state.lexical && state.lexical.type == ")") return false; - return /^[;{}]$/.test(content) && !/^;/.test(textAfter); - } - } - }); - - var inlineElements = /^(a|abbr|acronym|area|base|bdo|big|br|button|caption|cite|code|col|colgroup|dd|del|dfn|em|frame|hr|iframe|img|input|ins|kbd|label|legend|link|map|object|optgroup|option|param|q|samp|script|select|small|span|strong|sub|sup|textarea|tt|var)$/; - - CodeMirror.extendMode("xml", { - commentStart: "", - newlineAfterToken: function(type, content, textAfter, state) { - var inline = false; - if (this.configuration == "html") - inline = state.context ? inlineElements.test(state.context.tagName) : false; - return !inline && ((type == "tag" && />$/.test(content) && state.context) || - /^ -1 && endIndex > -1 && endIndex > startIndex) { - // Take string till comment start - selText = selText.substr(0, startIndex) - // From comment start till comment end - + selText.substring(startIndex + curMode.commentStart.length, endIndex) - // From comment end till string end - + selText.substr(endIndex + curMode.commentEnd.length); - } - cm.replaceRange(selText, from, to); - } - }); - }); - - // Applies automatic mode-aware indentation to the specified range - CodeMirror.defineExtension("autoIndentRange", function (from, to) { - var cmInstance = this; - this.operation(function () { - for (var i = from.line; i <= to.line; i++) { - cmInstance.indentLine(i, "smart"); - } - }); - }); - - // Applies automatic formatting to the specified range - CodeMirror.defineExtension("autoFormatRange", function (from, to) { - var cm = this; - var outer = cm.getMode(), text = cm.getRange(from, to).split("\n"); - var state = CodeMirror.copyState(outer, cm.getTokenAt(from).state); - var tabSize = cm.getOption("tabSize"); - - var out = "", lines = 0, atSol = from.ch == 0; - function newline() { - out += "\n"; - atSol = true; - ++lines; - } - - for (var i = 0; i < text.length; ++i) { - var stream = new CodeMirror.StringStream(text[i], tabSize); - while (!stream.eol()) { - var inner = CodeMirror.innerMode(outer, state); - var style = outer.token(stream, state), cur = stream.current(); - stream.start = stream.pos; - if (!atSol || /\S/.test(cur)) { - out += cur; - atSol = false; - } - if (!atSol && inner.mode.newlineAfterToken && - inner.mode.newlineAfterToken(style, cur, stream.string.slice(stream.pos) || text[i+1] || "", inner.state)) - newline(); - } - if (!stream.pos && outer.blankLine) outer.blankLine(state); - if (!atSol && i < text.length - 1) newline(); - } - - cm.operation(function () { - cm.replaceRange(out, from, to); - for (var cur = from.line + 1, end = from.line + lines; cur <= end; ++cur) - cm.indentLine(cur, "smart"); - cm.setSelection(from, cm.getCursor(false)); - }); - }); -})(); diff --git a/demo/formatting.html b/demo/formatting.html deleted file mode 100644 index 6a05794b20..0000000000 --- a/demo/formatting.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - CodeMirror: Formatting Demo - - - - - - - - - - - - -

    CodeMirror: Formatting demo

    - -

    Note: The formatting addon receives a fair - amount of bug requests. I (the maintainer of CodeMirror) do not - intend to spend time on improving it. Pull requests (if clean and - intelligent) are welcome, but you should see this code as a - proof-of-concept (using CodeMirror's mode tokenizers to help - format code), not a finished, robust module.

    - -
    - -

    Select a piece of code and click one of the links below to apply automatic formatting to the selected text or comment/uncomment the selected text. Note that the formatting behavior depends on the current block's mode. - - - - - - -
    - - Autoformat Selected - - - - Comment Selected - - - - Uncomment Selected - -
    -

    - - - - diff --git a/doc/compress.html b/doc/compress.html index 71ae09d149..fc6b225a90 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -142,7 +142,6 @@

    { } CodeMi - diff --git a/doc/manual.html b/doc/manual.html index d8cd2db783..2f2d064a9e 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1761,11 +1761,10 @@

    Writing CodeMirror Modes

    extra methods, innerMode which, given a state object, returns a {state, mode} object with the inner mode and its state for the current position. These are used by utility - scripts such as the
    autoformatter - and the tag closer to get context - information. Use the CodeMirror.innerMode helper - function to, starting from a mode and a state, recursively walk - down to the innermost mode and state.

    + scripts such as the tag closer to + get context information. Use the CodeMirror.innerMode + helper function to, starting from a mode and a state, recursively + walk down to the innermost mode and state.

    To make indentation work properly in a nested parser, it is advisable to give the startState method of modes that From 478119ff5f61f06387cd1e477408009aa4c35de2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Mar 2013 11:42:44 +0100 Subject: [PATCH 0393/5273] Remove mysql and plsql modes Use the generic sql mode, which has MIME types for these dialects. --- doc/compress.html | 2 - mode/meta.js | 2 - mode/mysql/index.html | 43 --------- mode/mysql/mysql.js | 203 --------------------------------------- mode/plsql/index.html | 64 ------------- mode/plsql/plsql.js | 216 ------------------------------------------ 6 files changed, 530 deletions(-) delete mode 100644 mode/mysql/index.html delete mode 100644 mode/mysql/mysql.js delete mode 100644 mode/plsql/index.html delete mode 100644 mode/plsql/plsql.js diff --git a/doc/compress.html b/doc/compress.html index fc6b225a90..aefa37aa4a 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -93,14 +93,12 @@

    { } CodeMi - - diff --git a/mode/meta.js b/mode/meta.js index 7ca7333b2c..e01ea30d40 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -56,9 +56,7 @@ CodeMirror.modeInfo = [ {name: 'Smarty', mime: 'text/x-smarty', mode: 'smarty'}, {name: 'SPARQL', mime: 'application/x-sparql-query', mode: 'sparql'}, {name: 'SQL', mime: 'text/x-sql', mode: 'sql'}, - {name: 'MySQL', mime: 'text/x-mysql', mode: 'sql'}, {name: 'MariaDB', mime: 'text/x-mariadb', mode: 'sql'}, - {name: 'PL/SQL', mime: 'text/x-plsql', mode: 'sql'}, {name: 'sTeX', mime: 'text/x-stex', mode: 'stex'}, {name: 'LaTeX', mime: 'text/x-latex', mode: 'stex'}, {name: 'Tcl', mime: 'text/x-tcl', mode: 'tcl'}, diff --git a/mode/mysql/index.html b/mode/mysql/index.html deleted file mode 100644 index 41aeed12d8..0000000000 --- a/mode/mysql/index.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - CodeMirror: MySQL mode - - - - - - - -

    CodeMirror: MySQL mode

    -
    - - -

    !! This mode is deprecated in favor of the generic SQL mode (which can be configured to handle MySQL).

    - -

    MIME types defined: text/x-mysql.

    - - - diff --git a/mode/mysql/mysql.js b/mode/mysql/mysql.js deleted file mode 100644 index 69d3f9952b..0000000000 --- a/mode/mysql/mysql.js +++ /dev/null @@ -1,203 +0,0 @@ -/* - * MySQL Mode for CodeMirror 2 by MySQL-Tools - * @author James Thorne (partydroid) - * @link http://github.com/partydroid/MySQL-Tools - * @link http://mysqltools.org - * @version 02/Jan/2012 -*/ -CodeMirror.defineMode("mysql", function(config) { - var indentUnit = config.indentUnit; - var curPunc; - - function wordRegexp(words) { - return new RegExp("^(?:" + words.join("|") + ")$", "i"); - } - var ops = wordRegexp(["str", "lang", "langmatches", "datatype", "bound", "sameterm", "isiri", "isuri", - "isblank", "isliteral", "union", "a"]); - var keywords = wordRegexp([ - ('ACCESSIBLE'),('ALTER'),('AS'),('BEFORE'),('BINARY'),('BY'),('CASE'),('CHARACTER'),('COLUMN'),('CONTINUE'),('CROSS'),('CURRENT_TIMESTAMP'),('DATABASE'),('DAY_MICROSECOND'),('DEC'),('DEFAULT'), - ('DESC'),('DISTINCT'),('DOUBLE'),('EACH'),('ENCLOSED'),('EXIT'),('FETCH'),('FLOAT8'),('FOREIGN'),('GRANT'),('HIGH_PRIORITY'),('HOUR_SECOND'),('IN'),('INNER'),('INSERT'),('INT2'),('INT8'), - ('INTO'),('JOIN'),('KILL'),('LEFT'),('LINEAR'),('LOCALTIME'),('LONG'),('LOOP'),('MATCH'),('MEDIUMTEXT'),('MINUTE_SECOND'),('NATURAL'),('NULL'),('OPTIMIZE'),('OR'),('OUTER'),('PRIMARY'), - ('RANGE'),('READ_WRITE'),('REGEXP'),('REPEAT'),('RESTRICT'),('RIGHT'),('SCHEMAS'),('SENSITIVE'),('SHOW'),('SPECIFIC'),('SQLSTATE'),('SQL_CALC_FOUND_ROWS'),('STARTING'),('TERMINATED'), - ('TINYINT'),('TRAILING'),('UNDO'),('UNLOCK'),('USAGE'),('UTC_DATE'),('VALUES'),('VARCHARACTER'),('WHERE'),('WRITE'),('ZEROFILL'),('ALL'),('AND'),('ASENSITIVE'),('BIGINT'),('BOTH'),('CASCADE'), - ('CHAR'),('COLLATE'),('CONSTRAINT'),('CREATE'),('CURRENT_TIME'),('CURSOR'),('DAY_HOUR'),('DAY_SECOND'),('DECLARE'),('DELETE'),('DETERMINISTIC'),('DIV'),('DUAL'),('ELSEIF'),('EXISTS'),('FALSE'), - ('FLOAT4'),('FORCE'),('FULLTEXT'),('HAVING'),('HOUR_MINUTE'),('IGNORE'),('INFILE'),('INSENSITIVE'),('INT1'),('INT4'),('INTERVAL'),('ITERATE'),('KEYS'),('LEAVE'),('LIMIT'),('LOAD'),('LOCK'), - ('LONGTEXT'),('MASTER_SSL_VERIFY_SERVER_CERT'),('MEDIUMINT'),('MINUTE_MICROSECOND'),('MODIFIES'),('NO_WRITE_TO_BINLOG'),('ON'),('OPTIONALLY'),('OUT'),('PRECISION'),('PURGE'),('READS'), - ('REFERENCES'),('RENAME'),('REQUIRE'),('REVOKE'),('SCHEMA'),('SELECT'),('SET'),('SPATIAL'),('SQLEXCEPTION'),('SQL_BIG_RESULT'),('SSL'),('TABLE'),('TINYBLOB'),('TO'),('TRUE'),('UNIQUE'), - ('UPDATE'),('USING'),('UTC_TIMESTAMP'),('VARCHAR'),('WHEN'),('WITH'),('YEAR_MONTH'),('ADD'),('ANALYZE'),('ASC'),('BETWEEN'),('BLOB'),('CALL'),('CHANGE'),('CHECK'),('CONDITION'),('CONVERT'), - ('CURRENT_DATE'),('CURRENT_USER'),('DATABASES'),('DAY_MINUTE'),('DECIMAL'),('DELAYED'),('DESCRIBE'),('DISTINCTROW'),('DROP'),('ELSE'),('ESCAPED'),('EXPLAIN'),('FLOAT'),('FOR'),('FROM'), - ('GROUP'),('HOUR_MICROSECOND'),('IF'),('INDEX'),('INOUT'),('INT'),('INT3'),('INTEGER'),('IS'),('KEY'),('LEADING'),('LIKE'),('LINES'),('LOCALTIMESTAMP'),('LONGBLOB'),('LOW_PRIORITY'), - ('MEDIUMBLOB'),('MIDDLEINT'),('MOD'),('NOT'),('NUMERIC'),('OPTION'),('ORDER'),('OUTFILE'),('PROCEDURE'),('READ'),('REAL'),('RELEASE'),('REPLACE'),('RETURN'),('RLIKE'),('SECOND_MICROSECOND'), - ('SEPARATOR'),('SMALLINT'),('SQL'),('SQLWARNING'),('SQL_SMALL_RESULT'),('STRAIGHT_JOIN'),('THEN'),('TINYTEXT'),('TRIGGER'),('UNION'),('UNSIGNED'),('USE'),('UTC_TIME'),('VARBINARY'),('VARYING'), - ('WHILE'),('XOR'),('FULL'),('COLUMNS'),('MIN'),('MAX'),('STDEV'),('COUNT') - ]); - var operatorChars = /[*+\-<>=&|]/; - - function tokenBase(stream, state) { - var ch = stream.next(); - curPunc = null; - if (ch == "$" || ch == "?") { - stream.match(/^[\w\d]*/); - return "variable-2"; - } - else if (ch == "<" && !stream.match(/^[\s\u00a0=]/, false)) { - stream.match(/^[^\s\u00a0>]*>?/); - return "atom"; - } - else if (ch == "\"" || ch == "'") { - state.tokenize = tokenLiteral(ch); - return state.tokenize(stream, state); - } - else if (ch == "`") { - state.tokenize = tokenOpLiteral(ch); - return state.tokenize(stream, state); - } - else if (/[{}\(\),\.;\[\]]/.test(ch)) { - curPunc = ch; - return null; - } - else if (ch == "-" && stream.eat("-")) { - stream.skipToEnd(); - return "comment"; - } - else if (ch == "/" && stream.eat("*")) { - state.tokenize = tokenComment; - return state.tokenize(stream, state); - } - else if (operatorChars.test(ch)) { - stream.eatWhile(operatorChars); - return null; - } - else if (ch == ":") { - stream.eatWhile(/[\w\d\._\-]/); - return "atom"; - } - else { - stream.eatWhile(/[_\w\d]/); - if (stream.eat(":")) { - stream.eatWhile(/[\w\d_\-]/); - return "atom"; - } - var word = stream.current(); - if (ops.test(word)) - return null; - else if (keywords.test(word)) - return "keyword"; - else - return "variable"; - } - } - - function tokenLiteral(quote) { - return function(stream, state) { - var escaped = false, ch; - while ((ch = stream.next()) != null) { - if (ch == quote && !escaped) { - state.tokenize = tokenBase; - break; - } - escaped = !escaped && ch == "\\"; - } - return "string"; - }; - } - - function tokenOpLiteral(quote) { - return function(stream, state) { - var escaped = false, ch; - while ((ch = stream.next()) != null) { - if (ch == quote && !escaped) { - state.tokenize = tokenBase; - break; - } - escaped = !escaped && ch == "\\"; - } - return "variable-2"; - }; - } - - function tokenComment(stream, state) { - for (;;) { - if (stream.skipTo("*")) { - stream.next(); - if (stream.eat("/")) { - state.tokenize = tokenBase; - break; - } - } else { - stream.skipToEnd(); - break; - } - } - return "comment"; - } - - - function pushContext(state, type, col) { - state.context = {prev: state.context, indent: state.indent, col: col, type: type}; - } - function popContext(state) { - state.indent = state.context.indent; - state.context = state.context.prev; - } - - return { - startState: function() { - return {tokenize: tokenBase, - context: null, - indent: 0, - col: 0}; - }, - - token: function(stream, state) { - if (stream.sol()) { - if (state.context && state.context.align == null) state.context.align = false; - state.indent = stream.indentation(); - } - if (stream.eatSpace()) return null; - var style = state.tokenize(stream, state); - - if (style != "comment" && state.context && state.context.align == null && state.context.type != "pattern") { - state.context.align = true; - } - - if (curPunc == "(") pushContext(state, ")", stream.column()); - else if (curPunc == "[") pushContext(state, "]", stream.column()); - else if (curPunc == "{") pushContext(state, "}", stream.column()); - else if (/[\]\}\)]/.test(curPunc)) { - while (state.context && state.context.type == "pattern") popContext(state); - if (state.context && curPunc == state.context.type) popContext(state); - } - else if (curPunc == "." && state.context && state.context.type == "pattern") popContext(state); - else if (/atom|string|variable/.test(style) && state.context) { - if (/[\}\]]/.test(state.context.type)) - pushContext(state, "pattern", stream.column()); - else if (state.context.type == "pattern" && !state.context.align) { - state.context.align = true; - state.context.col = stream.column(); - } - } - - return style; - }, - - indent: function(state, textAfter) { - var firstChar = textAfter && textAfter.charAt(0); - var context = state.context; - if (/[\]\}]/.test(firstChar)) - while (context && context.type == "pattern") context = context.prev; - - var closing = context && firstChar == context.type; - if (!context) - return 0; - else if (context.type == "pattern") - return context.col; - else if (context.align) - return context.col + (closing ? 0 : 1); - else - return context.indent + (closing ? 0 : indentUnit); - } - }; -}); - -CodeMirror.defineMIME("text/x-mysql", "mysql"); diff --git a/mode/plsql/index.html b/mode/plsql/index.html deleted file mode 100644 index 52e60710d5..0000000000 --- a/mode/plsql/index.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - CodeMirror: Oracle PL/SQL mode - - - - - - - -

    CodeMirror: Oracle PL/SQL mode

    - -
    - - - -

    !! This mode is deprecated in favor of the generic SQL mode (which can be configured to handle PL/SQL).

    - -

    - Simple mode that handles Oracle PL/SQL language (and Oracle SQL, of course). -

    - -

    MIME type defined: text/x-plsql - (PLSQL code) - diff --git a/mode/plsql/plsql.js b/mode/plsql/plsql.js deleted file mode 100644 index df119baee1..0000000000 --- a/mode/plsql/plsql.js +++ /dev/null @@ -1,216 +0,0 @@ -CodeMirror.defineMode("plsql", function(_config, parserConfig) { - var keywords = parserConfig.keywords, - functions = parserConfig.functions, - types = parserConfig.types, - sqlplus = parserConfig.sqlplus, - multiLineStrings = parserConfig.multiLineStrings; - var isOperatorChar = /[+\-*&%=<>!?:\/|]/; - function chain(stream, state, f) { - state.tokenize = f; - return f(stream, state); - } - - var type; - function ret(tp, style) { - type = tp; - return style; - } - - function tokenBase(stream, state) { - var ch = stream.next(); - // start of string? - if (ch == '"' || ch == "'") - return chain(stream, state, tokenString(ch)); - // is it one of the special signs []{}().,;? Seperator? - else if (/[\[\]{}\(\),;\.]/.test(ch)) - return ret(ch); - // start of a number value? - else if (/\d/.test(ch)) { - stream.eatWhile(/[\w\.]/); - return ret("number", "number"); - } - // multi line comment or simple operator? - else if (ch == "/") { - if (stream.eat("*")) { - return chain(stream, state, tokenComment); - } - else { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator"); - } - } - // single line comment or simple operator? - else if (ch == "-") { - if (stream.eat("-")) { - stream.skipToEnd(); - return ret("comment", "comment"); - } - else { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator"); - } - } - // pl/sql variable? - else if (ch == "@" || ch == "$") { - stream.eatWhile(/[\w\d\$_]/); - return ret("word", "variable"); - } - // is it a operator? - else if (isOperatorChar.test(ch)) { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator"); - } - else { - // get the whole word - stream.eatWhile(/[\w\$_]/); - // is it one of the listed keywords? - if (keywords && keywords.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "keyword"); - // is it one of the listed functions? - if (functions && functions.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "builtin"); - // is it one of the listed types? - if (types && types.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "variable-2"); - // is it one of the listed sqlplus keywords? - if (sqlplus && sqlplus.propertyIsEnumerable(stream.current().toLowerCase())) return ret("keyword", "variable-3"); - // default: just a "variable" - return ret("word", "variable"); - } - } - - function tokenString(quote) { - return function(stream, state) { - var escaped = false, next, end = false; - while ((next = stream.next()) != null) { - if (next == quote && !escaped) {end = true; break;} - escaped = !escaped && next == "\\"; - } - if (end || !(escaped || multiLineStrings)) - state.tokenize = tokenBase; - return ret("string", "plsql-string"); - }; - } - - function tokenComment(stream, state) { - var maybeEnd = false, ch; - while (ch = stream.next()) { - if (ch == "/" && maybeEnd) { - state.tokenize = tokenBase; - break; - } - maybeEnd = (ch == "*"); - } - return ret("comment", "plsql-comment"); - } - - // Interface - - return { - startState: function() { - return { - tokenize: tokenBase, - startOfLine: true - }; - }, - - token: function(stream, state) { - if (stream.eatSpace()) return null; - var style = state.tokenize(stream, state); - return style; - } - }; -}); - -(function() { - function keywords(str) { - var obj = {}, words = str.split(" "); - for (var i = 0; i < words.length; ++i) obj[words[i]] = true; - return obj; - } - var cKeywords = "abort accept access add all alter and any array arraylen as asc assert assign at attributes audit " + - "authorization avg " + - "base_table begin between binary_integer body boolean by " + - "case cast char char_base check close cluster clusters colauth column comment commit compress connect " + - "connected constant constraint crash create current currval cursor " + - "data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete " + - "desc digits dispose distinct do drop " + - "else elsif enable end entry escape exception exception_init exchange exclusive exists exit external " + - "fast fetch file for force form from function " + - "generic goto grant group " + - "having " + - "identified if immediate in increment index indexes indicator initial initrans insert interface intersect " + - "into is " + - "key " + - "level library like limited local lock log logging long loop " + - "master maxextents maxtrans member minextents minus mislabel mode modify multiset " + - "new next no noaudit nocompress nologging noparallel not nowait number_base " + - "object of off offline on online only open option or order out " + - "package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior " + - "private privileges procedure public " + - "raise range raw read rebuild record ref references refresh release rename replace resource restrict return " + - "returning reverse revoke rollback row rowid rowlabel rownum rows run " + - "savepoint schema segment select separate session set share snapshot some space split sql start statement " + - "storage subtype successful synonym " + - "tabauth table tables tablespace task terminate then to trigger truncate type " + - "union unique unlimited unrecoverable unusable update use using " + - "validate value values variable view views " + - "when whenever where while with work"; - - var cFunctions = "abs acos add_months ascii asin atan atan2 average " + - "bfilename " + - "ceil chartorowid chr concat convert cos cosh count " + - "decode deref dual dump dup_val_on_index " + - "empty error exp " + - "false floor found " + - "glb greatest " + - "hextoraw " + - "initcap instr instrb isopen " + - "last_day least lenght lenghtb ln lower lpad ltrim lub " + - "make_ref max min mod months_between " + - "new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower " + - "nls_sort nls_upper nlssort no_data_found notfound null nvl " + - "others " + - "power " + - "rawtohex reftohex round rowcount rowidtochar rpad rtrim " + - "sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate " + - "tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc " + - "uid upper user userenv " + - "variance vsize"; - - var cTypes = "bfile blob " + - "character clob " + - "dec " + - "float " + - "int integer " + - "mlslabel " + - "natural naturaln nchar nclob number numeric nvarchar2 " + - "real rowtype " + - "signtype smallint string " + - "varchar varchar2"; - - var cSqlplus = "appinfo arraysize autocommit autoprint autorecovery autotrace " + - "blockterminator break btitle " + - "cmdsep colsep compatibility compute concat copycommit copytypecheck " + - "define describe " + - "echo editfile embedded escape exec execute " + - "feedback flagger flush " + - "heading headsep " + - "instance " + - "linesize lno loboffset logsource long longchunksize " + - "markup " + - "native newpage numformat numwidth " + - "pagesize pause pno " + - "recsep recsepchar release repfooter repheader " + - "serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber " + - "sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix " + - "tab term termout time timing trimout trimspool ttitle " + - "underline " + - "verify version " + - "wrap"; - - CodeMirror.defineMIME("text/x-plsql", { - name: "plsql", - keywords: keywords(cKeywords), - functions: keywords(cFunctions), - types: keywords(cTypes), - sqlplus: keywords(cSqlplus) - }); -}()); From 68b2994f012fbb15450b8dfd6bc3c061a42b3491 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Mar 2013 11:47:49 +0100 Subject: [PATCH 0394/5273] Split folding functions into their own files --- addon/fold/brace-fold.js | 31 +++++++++++ addon/fold/foldcode.js | 109 -------------------------------------- addon/fold/indent-fold.js | 11 ++++ addon/fold/xml-fold.js | 64 ++++++++++++++++++++++ demo/folding.html | 4 +- doc/compress.html | 3 ++ doc/manual.html | 9 ++-- 7 files changed, 117 insertions(+), 114 deletions(-) create mode 100644 addon/fold/brace-fold.js create mode 100644 addon/fold/indent-fold.js create mode 100644 addon/fold/xml-fold.js diff --git a/addon/fold/brace-fold.js b/addon/fold/brace-fold.js new file mode 100644 index 0000000000..aad6e0141e --- /dev/null +++ b/addon/fold/brace-fold.js @@ -0,0 +1,31 @@ +CodeMirror.braceRangeFinder = function(cm, start) { + var line = start.line, lineText = cm.getLine(line); + var at = lineText.length, startChar, tokenType; + for (;;) { + var found = lineText.lastIndexOf("{", at); + if (found < start.ch) break; + tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type; + if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; } + at = found - 1; + } + if (startChar == null || lineText.lastIndexOf("}") > startChar) return; + var count = 1, lastLine = cm.lineCount(), end, endCh; + outer: for (var i = line + 1; i < lastLine; ++i) { + var text = cm.getLine(i), pos = 0; + for (;;) { + var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos); + if (nextOpen < 0) nextOpen = text.length; + if (nextClose < 0) nextClose = text.length; + pos = Math.min(nextOpen, nextClose); + if (pos == text.length) break; + if (cm.getTokenAt(CodeMirror.Pos(i, pos + 1)).type == tokenType) { + if (pos == nextOpen) ++count; + else if (!--count) { end = i; endCh = pos; break outer; } + } + ++pos; + } + } + if (end == null || end == line + 1) return; + return {from: CodeMirror.Pos(line, startChar + 1), + to: CodeMirror.Pos(end, endCh)}; +}; diff --git a/addon/fold/foldcode.js b/addon/fold/foldcode.js index bdc641d3c6..b8b4b0da9e 100644 --- a/addon/fold/foldcode.js +++ b/addon/fold/foldcode.js @@ -1,112 +1,3 @@ -CodeMirror.tagRangeFinder = (function() { - var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; - var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; - var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); - - return function(cm, start) { - var line = start.line, ch = start.ch, lineText = cm.getLine(line); - - function nextLine() { - if (line >= cm.lastLine()) return; - ch = 0; - lineText = cm.getLine(++line); - return true; - } - function toTagEnd() { - for (;;) { - var gt = lineText.indexOf(">", ch); - if (gt == -1) { if (nextLine()) continue; else return; } - var lastSlash = lineText.lastIndexOf("/", gt); - var selfClose = lastSlash > -1 && /^\s*$/.test(lineText.slice(lastSlash + 1, gt)); - ch = gt + 1; - return selfClose ? "selfClose" : "regular"; - } - } - function toNextTag() { - for (;;) { - xmlTagStart.lastIndex = ch; - var found = xmlTagStart.exec(lineText); - if (!found) { if (nextLine()) continue; else return; } - ch = found.index + found[0].length; - return found; - } - } - - var stack = [], startCh; - for (;;) { - var openTag = toNextTag(), end; - if (!openTag || line != start.line || !(end = toTagEnd())) return; - if (!openTag[1] && end != "selfClose") { - stack.push(openTag[2]); - startCh = ch; - break; - } - } - - for (;;) { - var next = toNextTag(), end, tagLine = line, tagCh = ch - (next ? next[0].length : 0); - if (!next || !(end = toTagEnd())) return; - if (end == "selfClose") continue; - if (next[1]) { // closing tag - for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { - stack.length = i; - break; - } - if (!stack.length) return { - from: CodeMirror.Pos(start.line, startCh), - to: CodeMirror.Pos(tagLine, tagCh) - }; - } else { // opening tag - stack.push(next[2]); - } - } - }; -})(); - -CodeMirror.braceRangeFinder = function(cm, start) { - var line = start.line, lineText = cm.getLine(line); - var at = lineText.length, startChar, tokenType; - for (;;) { - var found = lineText.lastIndexOf("{", at); - if (found < start.ch) break; - tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type; - if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; } - at = found - 1; - } - if (startChar == null || lineText.lastIndexOf("}") > startChar) return; - var count = 1, lastLine = cm.lineCount(), end, endCh; - outer: for (var i = line + 1; i < lastLine; ++i) { - var text = cm.getLine(i), pos = 0; - for (;;) { - var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos); - if (nextOpen < 0) nextOpen = text.length; - if (nextClose < 0) nextClose = text.length; - pos = Math.min(nextOpen, nextClose); - if (pos == text.length) break; - if (cm.getTokenAt(CodeMirror.Pos(i, pos + 1)).type == tokenType) { - if (pos == nextOpen) ++count; - else if (!--count) { end = i; endCh = pos; break outer; } - } - ++pos; - } - } - if (end == null || end == line + 1) return; - return {from: CodeMirror.Pos(line, startChar + 1), - to: CodeMirror.Pos(end, endCh)}; -}; - -CodeMirror.indentRangeFinder = function(cm, start) { - var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line); - var myIndent = CodeMirror.countColumn(firstLine, null, tabSize); - for (var i = start.line + 1, end = cm.lineCount(); i < end; ++i) { - var curLine = cm.getLine(i); - if (CodeMirror.countColumn(curLine, null, tabSize) < myIndent && - CodeMirror.countColumn(cm.getLine(i-1), null, tabSize) > myIndent) - return {from: CodeMirror.Pos(start.line, firstLine.length), - to: CodeMirror.Pos(i, curLine.length)}; - } -}; - CodeMirror.newFoldFunction = function(rangeFinder, widget) { if (widget == null) widget = "\u2194"; if (typeof widget == "string") { diff --git a/addon/fold/indent-fold.js b/addon/fold/indent-fold.js new file mode 100644 index 0000000000..94a0a1ffae --- /dev/null +++ b/addon/fold/indent-fold.js @@ -0,0 +1,11 @@ +CodeMirror.indentRangeFinder = function(cm, start) { + var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line); + var myIndent = CodeMirror.countColumn(firstLine, null, tabSize); + for (var i = start.line + 1, end = cm.lineCount(); i < end; ++i) { + var curLine = cm.getLine(i); + if (CodeMirror.countColumn(curLine, null, tabSize) < myIndent && + CodeMirror.countColumn(cm.getLine(i-1), null, tabSize) > myIndent) + return {from: CodeMirror.Pos(start.line, firstLine.length), + to: CodeMirror.Pos(i, curLine.length)}; + } +}; diff --git a/addon/fold/xml-fold.js b/addon/fold/xml-fold.js new file mode 100644 index 0000000000..79c524d485 --- /dev/null +++ b/addon/fold/xml-fold.js @@ -0,0 +1,64 @@ +CodeMirror.tagRangeFinder = (function() { + var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; + var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; + var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); + + return function(cm, start) { + var line = start.line, ch = start.ch, lineText = cm.getLine(line); + + function nextLine() { + if (line >= cm.lastLine()) return; + ch = 0; + lineText = cm.getLine(++line); + return true; + } + function toTagEnd() { + for (;;) { + var gt = lineText.indexOf(">", ch); + if (gt == -1) { if (nextLine()) continue; else return; } + var lastSlash = lineText.lastIndexOf("/", gt); + var selfClose = lastSlash > -1 && /^\s*$/.test(lineText.slice(lastSlash + 1, gt)); + ch = gt + 1; + return selfClose ? "selfClose" : "regular"; + } + } + function toNextTag() { + for (;;) { + xmlTagStart.lastIndex = ch; + var found = xmlTagStart.exec(lineText); + if (!found) { if (nextLine()) continue; else return; } + ch = found.index + found[0].length; + return found; + } + } + + var stack = [], startCh; + for (;;) { + var openTag = toNextTag(), end; + if (!openTag || line != start.line || !(end = toTagEnd())) return; + if (!openTag[1] && end != "selfClose") { + stack.push(openTag[2]); + startCh = ch; + break; + } + } + + for (;;) { + var next = toNextTag(), end, tagLine = line, tagCh = ch - (next ? next[0].length : 0); + if (!next || !(end = toTagEnd())) return; + if (end == "selfClose") continue; + if (next[1]) { // closing tag + for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { + stack.length = i; + break; + } + if (!stack.length) return { + from: CodeMirror.Pos(start.line, startCh), + to: CodeMirror.Pos(tagLine, tagCh) + }; + } else { // opening tag + stack.push(next[2]); + } + } + }; +})(); diff --git a/demo/folding.html b/demo/folding.html index f28e5af469..cd0417aac6 100644 --- a/demo/folding.html +++ b/demo/folding.html @@ -6,6 +6,8 @@ + + @@ -27,7 +29,7 @@

    CodeMirror: Code Folding Demo

    Demonstration of code folding using the code in foldcode.js. Press ctrl-q or click on the gutter to fold a block, again - to unfold.
    Try the Range Colapse demo as well.

    + to unfold.

    JavaScript:
    HTML:
    diff --git a/doc/compress.html b/doc/compress.html index aefa37aa4a..70f0ef0c45 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -139,6 +139,9 @@

    { } CodeMi + + + diff --git a/doc/manual.html b/doc/manual.html index 2f2d064a9e..819396f8e2 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1454,10 +1454,11 @@

    Add-ons

    a CodeMirror instance and a line number, attempt to fold or unfold the block starting at the given line. A range-finder is a language-specific function that also takes an instance and a - line number, and returns an range to be folded, or null if - no block is started on that line. This file - provides CodeMirror.braceRangeFinder, which finds - blocks in brace languages (JavaScript, C, Java, + line number, and returns an range to be folded, or null if no + block is started on that line. There are files in + the
    addon/fold/ + directory providing CodeMirror.braceRangeFinder, + which finds blocks in brace languages (JavaScript, C, Java, etc), CodeMirror.indentRangeFinder, for languages where indentation determines block structure (Python, Haskell), and CodeMirror.tagRangeFinder, for XML-style From e72589ddff4028a07a2f1e6050f1695feafb820e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Mar 2013 11:48:44 +0100 Subject: [PATCH 0395/5273] Remove the collapserange addon Too specialized. Out of scope. --- addon/fold/collapserange.js | 68 ----------------------- demo/collapserange.html | 104 ------------------------------------ doc/compress.html | 1 - doc/manual.html | 5 -- 4 files changed, 178 deletions(-) delete mode 100644 addon/fold/collapserange.js delete mode 100644 demo/collapserange.html diff --git a/addon/fold/collapserange.js b/addon/fold/collapserange.js deleted file mode 100644 index e2c013734d..0000000000 --- a/addon/fold/collapserange.js +++ /dev/null @@ -1,68 +0,0 @@ -(function() { - CodeMirror.defineOption("collapseRange", false, function(cm, val, old) { - var wasOn = old && old != CodeMirror.Init; - if (val && !wasOn) - enableRangeCollapsing(cm); - else if (!val && wasOn) - disableRangeCollapsing(cm); - }); - - var gutterClass = "CodeMirror-collapserange"; - - function enableRangeCollapsing(cm) { - cm.on("gutterClick", gutterClick); - cm.setOption("gutters", (cm.getOption("gutters") || []).concat([gutterClass])); - } - - function disableRangeCollapsing(cm) { - cm.rangeCollapseStart = null; - cm.off("gutterClick", gutterClick); - var gutters = cm.getOption("gutters"); - for (var i = 0; i < gutters.length && gutters[i] != gutterClass; ++i) {} - cm.setOption("gutters", gutters.slice(0, i).concat(gutters.slice(i + 1))); - } - - function gutterClick(cm, line, gutter) { - if (gutter != gutterClass) return; - - var start = cm.rangeCollapseStart; - if (start) { - var old = cm.getLineNumber(start); - cm.setGutterMarker(start, gutterClass, null); - cm.rangeCollapseStart = null; - var from = Math.min(old, line), to = Math.max(old, line); - if (from != to) { - // Finish this fold - var fold = cm.markText(CodeMirror.Pos(from + 1, 0), {line: to - 1}, { - collapsed: true, - inclusiveLeft: true, - inclusiveRight: true, - clearOnEnter: true - }); - var clear = function() { - cm.setGutterMarker(topLine, gutterClass, null); - cm.setGutterMarker(botLine, gutterClass, null); - fold.clear(); - }; - var topLine = cm.setGutterMarker(from, gutterClass, makeMarker(true, true, clear)); - var botLine = cm.setGutterMarker(to, gutterClass, makeMarker(false, true, clear)); - CodeMirror.on(fold, "clear", clear); - - return; - } - } - - // Start a new fold - cm.rangeCollapseStart = cm.setGutterMarker(line, gutterClass, makeMarker(true, false)); - } - - function makeMarker(isTop, isFinished, handler) { - var node = document.createElement("div"); - node.innerHTML = isTop ? "\u25bc" : "\u25b2"; - if (!isFinished) node.style.color = "red"; - node.style.fontSize = "85%"; - node.style.cursor = "pointer"; - if (handler) CodeMirror.on(node, "mousedown", handler); - return node; - } -})(); diff --git a/demo/collapserange.html b/demo/collapserange.html deleted file mode 100644 index 5a6df0d257..0000000000 --- a/demo/collapserange.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - CodeMirror: Range Collapsing Demo - - - - - - - - - -

    CodeMirror: Range Collapsing Demo

    - - - - - -

    Click on the right side of the gutter, then click again below, - the code between will collapse. Click on either arrow to expand. - To use, simply include the collapserange.js file and - set collapseRange: true in options.

    - - - diff --git a/doc/compress.html b/doc/compress.html index 70f0ef0c45..458365bf32 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -142,7 +142,6 @@

    { } CodeMi - diff --git a/doc/manual.html b/doc/manual.html index 819396f8e2..9fdd7c0a40 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1463,11 +1463,6 @@

    Add-ons

    where indentation determines block structure (Python, Haskell), and CodeMirror.tagRangeFinder, for XML-style languages.

    -
    fold/collapserange.js
    -
    Another approach to - folding. See demo. - Allows the user to select a range to fold by clicking in the - gutter.
    runmode/runmode.js
    Can be used to run a CodeMirror mode over text without actually opening an editor instance. From 7658b31c14988264d6169d3dea66185132ae94ac Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Mar 2013 11:57:03 +0100 Subject: [PATCH 0396/5273] Remove simple-hint addon Use show-hint, which is much more solid and configurable. --- addon/hint/simple-hint.css | 16 ------ addon/hint/simple-hint.js | 102 ------------------------------------- doc/compress.html | 1 - 3 files changed, 119 deletions(-) delete mode 100644 addon/hint/simple-hint.css delete mode 100644 addon/hint/simple-hint.js diff --git a/addon/hint/simple-hint.css b/addon/hint/simple-hint.css deleted file mode 100644 index 4387cb9411..0000000000 --- a/addon/hint/simple-hint.css +++ /dev/null @@ -1,16 +0,0 @@ -.CodeMirror-completions { - position: absolute; - z-index: 10; - overflow: hidden; - -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); - -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); - box-shadow: 2px 3px 5px rgba(0,0,0,.2); -} -.CodeMirror-completions select { - background: #fafafa; - outline: none; - border: none; - padding: 0; - margin: 0; - font-family: monospace; -} diff --git a/addon/hint/simple-hint.js b/addon/hint/simple-hint.js deleted file mode 100644 index 1565bd4785..0000000000 --- a/addon/hint/simple-hint.js +++ /dev/null @@ -1,102 +0,0 @@ -(function() { - CodeMirror.simpleHint = function(editor, getHints, givenOptions) { - // Determine effective options based on given values and defaults. - var options = {}, defaults = CodeMirror.simpleHint.defaults; - for (var opt in defaults) - if (defaults.hasOwnProperty(opt)) - options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt]; - - function collectHints(previousToken) { - // We want a single cursor position. - if (editor.somethingSelected()) return; - - var tempToken = editor.getTokenAt(editor.getCursor()); - - // Don't show completions if token has changed and the option is set. - if (options.closeOnTokenChange && previousToken != null && - (tempToken.start != previousToken.start || tempToken.type != previousToken.type)) { - return; - } - - var result = getHints(editor, givenOptions); - if (!result || !result.list.length) return; - var completions = result.list; - function insert(str) { - editor.replaceRange(str, result.from, result.to); - } - // When there is only one completion, use it directly. - if (options.completeSingle && completions.length == 1) { - insert(completions[0]); - return true; - } - - // Build the select widget - var complete = document.createElement("div"); - complete.className = "CodeMirror-completions"; - var sel = complete.appendChild(document.createElement("select")); - // Opera doesn't move the selection when pressing up/down in a - // multi-select, but it does properly support the size property on - // single-selects, so no multi-select is necessary. - if (!window.opera) sel.multiple = true; - for (var i = 0; i < completions.length; ++i) { - var opt = sel.appendChild(document.createElement("option")); - opt.appendChild(document.createTextNode(completions[i])); - } - sel.firstChild.selected = true; - sel.size = Math.min(10, completions.length); - var pos = editor.cursorCoords(options.alignWithWord ? result.from : null); - complete.style.left = pos.left + "px"; - complete.style.top = pos.bottom + "px"; - document.body.appendChild(complete); - // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. - var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); - if(winW - pos.left < sel.clientWidth) - complete.style.left = (pos.left - sel.clientWidth) + "px"; - // Hack to hide the scrollbar. - if (completions.length <= 10) - complete.style.width = (sel.clientWidth - 1) + "px"; - - var done = false; - function close() { - if (done) return; - done = true; - complete.parentNode.removeChild(complete); - } - function pick() { - insert(completions[sel.selectedIndex]); - close(); - setTimeout(function(){editor.focus();}, 50); - } - CodeMirror.on(sel, "blur", close); - CodeMirror.on(sel, "keydown", function(event) { - var code = event.keyCode; - // Enter - if (code == 13) {CodeMirror.e_stop(event); pick();} - // Escape - else if (code == 27) {CodeMirror.e_stop(event); close(); editor.focus();} - else if (code != 38 && code != 40 && code != 33 && code != 34 && !CodeMirror.isModifierKey(event)) { - close(); editor.focus(); - // Pass the event to the CodeMirror instance so that it can handle things like backspace properly. - editor.triggerOnKeyDown(event); - // Don't show completions if the code is backspace and the option is set. - if (!options.closeOnBackspace || code != 8) { - setTimeout(function(){collectHints(tempToken);}, 50); - } - } - }); - CodeMirror.on(sel, "dblclick", pick); - - sel.focus(); - // Opera sometimes ignores focusing a freshly created node - if (window.opera) setTimeout(function(){if (!done) sel.focus();}, 100); - return true; - } - return collectHints(); - }; - CodeMirror.simpleHint.defaults = { - closeOnBackspace: true, - closeOnTokenChange: false, - completeSingle: true, - alignWithWord: true - }; -})(); diff --git a/doc/compress.html b/doc/compress.html index 458365bf32..7a43622a20 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -142,7 +142,6 @@

    { } CodeMi - From e34c62a607e6fd28ae2f9976fc3ae718b567f021 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 20 Mar 2013 12:17:49 +0100 Subject: [PATCH 0397/5273] Mark release 3.11 --- doc/compress.html | 1 + doc/manual.html | 12 ++++++++++++ doc/oldrelease.html | 16 ++++++++++++++++ index.html | 41 +++++++++++++++++++++++++---------------- lib/codemirror.js | 2 +- package.json | 2 +- 6 files changed, 56 insertions(+), 18 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 7a43622a20..06ed4970ad 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -30,6 +30,7 @@

    { } CodeMi

    Version: + + + + +

    Handles AT&T assembler syntax (more specifically this handles + the GNU Assembler (gas) syntax.) + It takes a single optional configuration parameter: + architecture, which can be one of "ARM", + "ARMv6" or "x86". + Including the parameter adds syntax for the registers and special + directives for the supplied architecture. + +

    MIME types defined: text/x-gas

    + + diff --git a/mode/s/s.js b/mode/s/s.js new file mode 100644 index 0000000000..ae83c3efa0 --- /dev/null +++ b/mode/s/s.js @@ -0,0 +1,326 @@ +CodeMirror.defineMode("s", function(config, parserConfig) { + 'use strict'; + + // If an architecture is specified, its initialization function may + // populate this array with custom parsing functions which will be + // tried in the event that the standard functions do not find a match. + var custom = []; + + // The symbol used to start a line comment changes based on the target + // architecture. + // If no architecture is pased in "parserConfig" then only multiline + // comments will have syntax support. + var lineCommentStartSymbol = ""; + + // These directives are architecture independent. + // Machine specific directives should go in their respective + // architecture initialization function. + // Reference: + // http://sourceware.org/binutils/docs/as/Pseudo-Ops.html#Pseudo-Ops + var directives = { + ".abort" : "builtin", + ".align" : "builtin", + ".altmacro" : "builtin", + ".ascii" : "builtin", + ".asciz" : "builtin", + ".balign" : "builtin", + ".balignw" : "builtin", + ".balignl" : "builtin", + ".bundle_align_mode" : "builtin", + ".bundle_lock" : "builtin", + ".bundle_unlock" : "builtin", + ".byte" : "builtin", + ".cfi_startproc" : "builtin", + ".comm" : "builtin", + ".data" : "builtin", + ".def" : "builtin", + ".desc" : "builtin", + ".dim" : "builtin", + ".double" : "builtin", + ".eject" : "builtin", + ".else" : "builtin", + ".elseif" : "builtin", + ".end" : "builtin", + ".endef" : "builtin", + ".endfunc" : "builtin", + ".endif" : "builtin", + ".equ" : "builtin", + ".equiv" : "builtin", + ".eqv" : "builtin", + ".err" : "builtin", + ".error" : "builtin", + ".exitm" : "builtin", + ".extern" : "builtin", + ".fail" : "builtin", + ".file" : "builtin", + ".fill" : "builtin", + ".float" : "builtin", + ".func" : "builtin", + ".global" : "builtin", + ".gnu_attribute" : "builtin", + ".hidden" : "builtin", + ".hword" : "builtin", + ".ident" : "builtin", + ".if" : "builtin", + ".incbin" : "builtin", + ".include" : "builtin", + ".int" : "builtin", + ".internal" : "builtin", + ".irp" : "builtin", + ".irpc" : "builtin", + ".lcomm" : "builtin", + ".lflags" : "builtin", + ".line" : "builtin", + ".linkonce" : "builtin", + ".list" : "builtin", + ".ln" : "builtin", + ".loc" : "builtin", + ".loc_mark_labels" : "builtin", + ".local" : "builtin", + ".long" : "builtin", + ".macro" : "builtin", + ".mri" : "builtin", + ".noaltmacro" : "builtin", + ".nolist" : "builtin", + ".octa" : "builtin", + ".offset" : "builtin", + ".org" : "builtin", + ".p2align" : "builtin", + ".popsection" : "builtin", + ".previous" : "builtin", + ".print" : "builtin", + ".protected" : "builtin", + ".psize" : "builtin", + ".purgem" : "builtin", + ".pushsection" : "builtin", + ".quad" : "builtin", + ".reloc" : "builtin", + ".rept" : "builtin", + ".sbttl" : "builtin", + ".scl" : "builtin", + ".section" : "builtin", + ".set" : "builtin", + ".short" : "builtin", + ".single" : "builtin", + ".size" : "builtin", + ".skip" : "builtin", + ".sleb128" : "builtin", + ".space" : "builtin", + ".stab" : "builtin", + ".string" : "builtin", + ".struct" : "builtin", + ".subsection" : "builtin", + ".symver" : "builtin", + ".tag" : "builtin", + ".text" : "builtin", + ".title" : "builtin", + ".type" : "builtin", + ".uleb128" : "builtin", + ".val" : "builtin", + ".version" : "builtin", + ".vtable_entry" : "builtin", + ".vtable_inherit" : "builtin", + ".warning" : "builtin", + ".weak" : "builtin", + ".weakref" : "builtin", + ".word" : "builtin", + }; + + var registers = {}; + + function x86(config, parserConfig) { + lineCommentStartSymbol = "#"; + + registers.ax = "variable"; + registers.eax = "variable-2"; + registers.rax = "variable-3"; + + registers.bx = "variable"; + registers.ebx = "variable-2"; + registers.rbx = "variable-3"; + + registers.cx = "variable"; + registers.ecx = "variable-2"; + registers.rcx = "variable-3"; + + registers.dx = "variable"; + registers.edx = "variable-2"; + registers.rdx = "variable-3"; + + registers.si = "variable"; + registers.esi = "variable-2"; + registers.rsi = "variable-3"; + + registers.di = "variable"; + registers.edi = "variable-2"; + registers.rdi = "variable-3"; + + registers.sp = "variable"; + registers.esp = "variable-2"; + registers.rsp = "variable-3"; + + registers.bp = "variable"; + registers.ebp = "variable-2"; + registers.rbp = "variable-3"; + + registers.ip = "variable"; + registers.eip = "variable-2"; + registers.rip = "variable-3"; + + registers.cs = "keyword"; + registers.ds = "keyword"; + registers.ss = "keyword"; + registers.es = "keyword"; + registers.fs = "keyword"; + registers.gs = "keyword"; + } + + function armv6(config, parserConfig) { + // Reference: + // http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf + // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf + lineCommentStartSymbol = "@"; + directives.syntax = "builtin"; + + registers.r0 = "variable"; + registers.r1 = "variable"; + registers.r2 = "variable"; + registers.r3 = "variable"; + registers.r4 = "variable"; + registers.r5 = "variable"; + registers.r6 = "variable"; + registers.r7 = "variable"; + registers.r8 = "variable"; + registers.r9 = "variable"; + registers.r10 = "variable"; + registers.r11 = "variable"; + registers.r12 = "variable"; + + registers.sp = "variable-2"; + registers.lr = "variable-2"; + registers.pc = "variable-2"; + registers.r13 = registers.sp; + registers.r14 = registers.lr; + registers.r15 = registers.pc; + + custom.push(function(ch, stream, state) { + if (ch === '#') { + stream.eatWhile(/\w/); + return "number"; + } + }); + } + + var arch = parserConfig.architecture.toLowerCase(); + if (arch === "x86") { + x86(config, parserConfig); + } else if (arch === "arm" || arch === "armv6") { + armv6(config, parserConfig); + } + + function nextUntilUnescaped(stream, end) { + var escaped = false, next; + while ((next = stream.next()) !== null) { + if (next === end && !escaped) { + return false; + } + escaped = !escaped && next === "\\"; + } + return escaped; + } + + function clikeComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) !== null) { + if (ch === "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch === "*"); + } + return "comment"; + } + + return { + startState: function(basecolumn) { + return { + tokenize: null, + }; + }, + + token: function(stream, state) { + if (state.tokenize) { + return state.tokenize(stream, state); + } + + if (stream.eatSpace()) { + return null; + } + + var style, cur, ch = stream.next(); + + if (ch === "/") { + if (stream.eat("*")) { + state.tokenize = clikeComment; + return clikeComment(stream, state); + } + } + + if (ch === lineCommentStartSymbol) { + stream.skipToEnd(); + return "comment"; + } + + if (ch === '"') { + nextUntilUnescaped(stream, '"'); + return "string"; + } + + if (ch === '.') { + stream.eatWhile(/\w/); + cur = stream.current().toLowerCase(); + style = directives[cur]; + return style || null; + } + + if (ch === '=') { + stream.eatWhile(/\w/); + return "tag"; + } + + if (ch === '{') { + return "braket"; + } + + if (ch === '}') { + return "braket"; + } + + if (/\d/.test(ch)) { + if (ch === "0" && stream.eat("x")) { + stream.eatWhile(/[0-9a-fA-F]/); + return "number"; + } + stream.eatWhile(/\d/); + return "number"; + } + + if (/\w/.test(ch)) { + stream.eatWhile(/\w/); + if (stream.eat(":")) { + return 'tag'; + } + cur = stream.current().toLowerCase(); + style = registers[cur]; + return style || null; + } + + for (var i = 0; i < custom.length; i++) { + style = custom[i](ch, stream, state); + if (style) { + return style; + } + } + }, + } +}); From 6de5ea6cd8c8986c6b1aa96e6291a3bf31d3ee78 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 25 Mar 2013 10:41:02 +0100 Subject: [PATCH 0411/5273] [gas mode] Fix overly precise comparisons --- mode/s/s.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/s/s.js b/mode/s/s.js index ae83c3efa0..1edfb7acdc 100644 --- a/mode/s/s.js +++ b/mode/s/s.js @@ -220,7 +220,7 @@ CodeMirror.defineMode("s", function(config, parserConfig) { function nextUntilUnescaped(stream, end) { var escaped = false, next; - while ((next = stream.next()) !== null) { + while ((next = stream.next()) != null) { if (next === end && !escaped) { return false; } @@ -231,7 +231,7 @@ CodeMirror.defineMode("s", function(config, parserConfig) { function clikeComment(stream, state) { var maybeEnd = false, ch; - while ((ch = stream.next()) !== null) { + while ((ch = stream.next()) != null) { if (ch === "/" && maybeEnd) { state.tokenize = null; break; From eaea95295e24c6cc36983872e63ba04be1ec438e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 25 Mar 2013 10:41:21 +0100 Subject: [PATCH 0412/5273] [gas mode] Untabify --- mode/s/s.js | 640 ++++++++++++++++++++++++++-------------------------- 1 file changed, 320 insertions(+), 320 deletions(-) diff --git a/mode/s/s.js b/mode/s/s.js index 1edfb7acdc..4a5dc2972d 100644 --- a/mode/s/s.js +++ b/mode/s/s.js @@ -1,326 +1,326 @@ CodeMirror.defineMode("s", function(config, parserConfig) { - 'use strict'; - - // If an architecture is specified, its initialization function may - // populate this array with custom parsing functions which will be - // tried in the event that the standard functions do not find a match. - var custom = []; - - // The symbol used to start a line comment changes based on the target - // architecture. - // If no architecture is pased in "parserConfig" then only multiline - // comments will have syntax support. - var lineCommentStartSymbol = ""; - - // These directives are architecture independent. - // Machine specific directives should go in their respective - // architecture initialization function. - // Reference: - // http://sourceware.org/binutils/docs/as/Pseudo-Ops.html#Pseudo-Ops - var directives = { - ".abort" : "builtin", - ".align" : "builtin", - ".altmacro" : "builtin", - ".ascii" : "builtin", - ".asciz" : "builtin", - ".balign" : "builtin", - ".balignw" : "builtin", - ".balignl" : "builtin", - ".bundle_align_mode" : "builtin", - ".bundle_lock" : "builtin", - ".bundle_unlock" : "builtin", - ".byte" : "builtin", - ".cfi_startproc" : "builtin", - ".comm" : "builtin", - ".data" : "builtin", - ".def" : "builtin", - ".desc" : "builtin", - ".dim" : "builtin", - ".double" : "builtin", - ".eject" : "builtin", - ".else" : "builtin", - ".elseif" : "builtin", - ".end" : "builtin", - ".endef" : "builtin", - ".endfunc" : "builtin", - ".endif" : "builtin", - ".equ" : "builtin", - ".equiv" : "builtin", - ".eqv" : "builtin", - ".err" : "builtin", - ".error" : "builtin", - ".exitm" : "builtin", - ".extern" : "builtin", - ".fail" : "builtin", - ".file" : "builtin", - ".fill" : "builtin", - ".float" : "builtin", - ".func" : "builtin", - ".global" : "builtin", - ".gnu_attribute" : "builtin", - ".hidden" : "builtin", - ".hword" : "builtin", - ".ident" : "builtin", - ".if" : "builtin", - ".incbin" : "builtin", - ".include" : "builtin", - ".int" : "builtin", - ".internal" : "builtin", - ".irp" : "builtin", - ".irpc" : "builtin", - ".lcomm" : "builtin", - ".lflags" : "builtin", - ".line" : "builtin", - ".linkonce" : "builtin", - ".list" : "builtin", - ".ln" : "builtin", - ".loc" : "builtin", - ".loc_mark_labels" : "builtin", - ".local" : "builtin", - ".long" : "builtin", - ".macro" : "builtin", - ".mri" : "builtin", - ".noaltmacro" : "builtin", - ".nolist" : "builtin", - ".octa" : "builtin", - ".offset" : "builtin", - ".org" : "builtin", - ".p2align" : "builtin", - ".popsection" : "builtin", - ".previous" : "builtin", - ".print" : "builtin", - ".protected" : "builtin", - ".psize" : "builtin", - ".purgem" : "builtin", - ".pushsection" : "builtin", - ".quad" : "builtin", - ".reloc" : "builtin", - ".rept" : "builtin", - ".sbttl" : "builtin", - ".scl" : "builtin", - ".section" : "builtin", - ".set" : "builtin", - ".short" : "builtin", - ".single" : "builtin", - ".size" : "builtin", - ".skip" : "builtin", - ".sleb128" : "builtin", - ".space" : "builtin", - ".stab" : "builtin", - ".string" : "builtin", - ".struct" : "builtin", - ".subsection" : "builtin", - ".symver" : "builtin", - ".tag" : "builtin", - ".text" : "builtin", - ".title" : "builtin", - ".type" : "builtin", - ".uleb128" : "builtin", - ".val" : "builtin", - ".version" : "builtin", - ".vtable_entry" : "builtin", - ".vtable_inherit" : "builtin", - ".warning" : "builtin", - ".weak" : "builtin", - ".weakref" : "builtin", - ".word" : "builtin", - }; - - var registers = {}; - - function x86(config, parserConfig) { - lineCommentStartSymbol = "#"; - - registers.ax = "variable"; - registers.eax = "variable-2"; - registers.rax = "variable-3"; - - registers.bx = "variable"; - registers.ebx = "variable-2"; - registers.rbx = "variable-3"; - - registers.cx = "variable"; - registers.ecx = "variable-2"; - registers.rcx = "variable-3"; - - registers.dx = "variable"; - registers.edx = "variable-2"; - registers.rdx = "variable-3"; - - registers.si = "variable"; - registers.esi = "variable-2"; - registers.rsi = "variable-3"; - - registers.di = "variable"; - registers.edi = "variable-2"; - registers.rdi = "variable-3"; - - registers.sp = "variable"; - registers.esp = "variable-2"; - registers.rsp = "variable-3"; - - registers.bp = "variable"; - registers.ebp = "variable-2"; - registers.rbp = "variable-3"; - - registers.ip = "variable"; - registers.eip = "variable-2"; - registers.rip = "variable-3"; - - registers.cs = "keyword"; - registers.ds = "keyword"; - registers.ss = "keyword"; - registers.es = "keyword"; - registers.fs = "keyword"; - registers.gs = "keyword"; + 'use strict'; + + // If an architecture is specified, its initialization function may + // populate this array with custom parsing functions which will be + // tried in the event that the standard functions do not find a match. + var custom = []; + + // The symbol used to start a line comment changes based on the target + // architecture. + // If no architecture is pased in "parserConfig" then only multiline + // comments will have syntax support. + var lineCommentStartSymbol = ""; + + // These directives are architecture independent. + // Machine specific directives should go in their respective + // architecture initialization function. + // Reference: + // http://sourceware.org/binutils/docs/as/Pseudo-Ops.html#Pseudo-Ops + var directives = { + ".abort" : "builtin", + ".align" : "builtin", + ".altmacro" : "builtin", + ".ascii" : "builtin", + ".asciz" : "builtin", + ".balign" : "builtin", + ".balignw" : "builtin", + ".balignl" : "builtin", + ".bundle_align_mode" : "builtin", + ".bundle_lock" : "builtin", + ".bundle_unlock" : "builtin", + ".byte" : "builtin", + ".cfi_startproc" : "builtin", + ".comm" : "builtin", + ".data" : "builtin", + ".def" : "builtin", + ".desc" : "builtin", + ".dim" : "builtin", + ".double" : "builtin", + ".eject" : "builtin", + ".else" : "builtin", + ".elseif" : "builtin", + ".end" : "builtin", + ".endef" : "builtin", + ".endfunc" : "builtin", + ".endif" : "builtin", + ".equ" : "builtin", + ".equiv" : "builtin", + ".eqv" : "builtin", + ".err" : "builtin", + ".error" : "builtin", + ".exitm" : "builtin", + ".extern" : "builtin", + ".fail" : "builtin", + ".file" : "builtin", + ".fill" : "builtin", + ".float" : "builtin", + ".func" : "builtin", + ".global" : "builtin", + ".gnu_attribute" : "builtin", + ".hidden" : "builtin", + ".hword" : "builtin", + ".ident" : "builtin", + ".if" : "builtin", + ".incbin" : "builtin", + ".include" : "builtin", + ".int" : "builtin", + ".internal" : "builtin", + ".irp" : "builtin", + ".irpc" : "builtin", + ".lcomm" : "builtin", + ".lflags" : "builtin", + ".line" : "builtin", + ".linkonce" : "builtin", + ".list" : "builtin", + ".ln" : "builtin", + ".loc" : "builtin", + ".loc_mark_labels" : "builtin", + ".local" : "builtin", + ".long" : "builtin", + ".macro" : "builtin", + ".mri" : "builtin", + ".noaltmacro" : "builtin", + ".nolist" : "builtin", + ".octa" : "builtin", + ".offset" : "builtin", + ".org" : "builtin", + ".p2align" : "builtin", + ".popsection" : "builtin", + ".previous" : "builtin", + ".print" : "builtin", + ".protected" : "builtin", + ".psize" : "builtin", + ".purgem" : "builtin", + ".pushsection" : "builtin", + ".quad" : "builtin", + ".reloc" : "builtin", + ".rept" : "builtin", + ".sbttl" : "builtin", + ".scl" : "builtin", + ".section" : "builtin", + ".set" : "builtin", + ".short" : "builtin", + ".single" : "builtin", + ".size" : "builtin", + ".skip" : "builtin", + ".sleb128" : "builtin", + ".space" : "builtin", + ".stab" : "builtin", + ".string" : "builtin", + ".struct" : "builtin", + ".subsection" : "builtin", + ".symver" : "builtin", + ".tag" : "builtin", + ".text" : "builtin", + ".title" : "builtin", + ".type" : "builtin", + ".uleb128" : "builtin", + ".val" : "builtin", + ".version" : "builtin", + ".vtable_entry" : "builtin", + ".vtable_inherit" : "builtin", + ".warning" : "builtin", + ".weak" : "builtin", + ".weakref" : "builtin", + ".word" : "builtin", + }; + + var registers = {}; + + function x86(config, parserConfig) { + lineCommentStartSymbol = "#"; + + registers.ax = "variable"; + registers.eax = "variable-2"; + registers.rax = "variable-3"; + + registers.bx = "variable"; + registers.ebx = "variable-2"; + registers.rbx = "variable-3"; + + registers.cx = "variable"; + registers.ecx = "variable-2"; + registers.rcx = "variable-3"; + + registers.dx = "variable"; + registers.edx = "variable-2"; + registers.rdx = "variable-3"; + + registers.si = "variable"; + registers.esi = "variable-2"; + registers.rsi = "variable-3"; + + registers.di = "variable"; + registers.edi = "variable-2"; + registers.rdi = "variable-3"; + + registers.sp = "variable"; + registers.esp = "variable-2"; + registers.rsp = "variable-3"; + + registers.bp = "variable"; + registers.ebp = "variable-2"; + registers.rbp = "variable-3"; + + registers.ip = "variable"; + registers.eip = "variable-2"; + registers.rip = "variable-3"; + + registers.cs = "keyword"; + registers.ds = "keyword"; + registers.ss = "keyword"; + registers.es = "keyword"; + registers.fs = "keyword"; + registers.gs = "keyword"; + } + + function armv6(config, parserConfig) { + // Reference: + // http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf + // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf + lineCommentStartSymbol = "@"; + directives.syntax = "builtin"; + + registers.r0 = "variable"; + registers.r1 = "variable"; + registers.r2 = "variable"; + registers.r3 = "variable"; + registers.r4 = "variable"; + registers.r5 = "variable"; + registers.r6 = "variable"; + registers.r7 = "variable"; + registers.r8 = "variable"; + registers.r9 = "variable"; + registers.r10 = "variable"; + registers.r11 = "variable"; + registers.r12 = "variable"; + + registers.sp = "variable-2"; + registers.lr = "variable-2"; + registers.pc = "variable-2"; + registers.r13 = registers.sp; + registers.r14 = registers.lr; + registers.r15 = registers.pc; + + custom.push(function(ch, stream, state) { + if (ch === '#') { + stream.eatWhile(/\w/); + return "number"; + } + }); + } + + var arch = parserConfig.architecture.toLowerCase(); + if (arch === "x86") { + x86(config, parserConfig); + } else if (arch === "arm" || arch === "armv6") { + armv6(config, parserConfig); + } + + function nextUntilUnescaped(stream, end) { + var escaped = false, next; + while ((next = stream.next()) != null) { + if (next === end && !escaped) { + return false; + } + escaped = !escaped && next === "\\"; + } + return escaped; + } + + function clikeComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (ch === "/" && maybeEnd) { + state.tokenize = null; + break; + } + maybeEnd = (ch === "*"); + } + return "comment"; + } + + return { + startState: function(basecolumn) { + return { + tokenize: null, + }; + }, + + token: function(stream, state) { + if (state.tokenize) { + return state.tokenize(stream, state); + } + + if (stream.eatSpace()) { + return null; + } + + var style, cur, ch = stream.next(); + + if (ch === "/") { + if (stream.eat("*")) { + state.tokenize = clikeComment; + return clikeComment(stream, state); } - - function armv6(config, parserConfig) { - // Reference: - // http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf - // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf - lineCommentStartSymbol = "@"; - directives.syntax = "builtin"; - - registers.r0 = "variable"; - registers.r1 = "variable"; - registers.r2 = "variable"; - registers.r3 = "variable"; - registers.r4 = "variable"; - registers.r5 = "variable"; - registers.r6 = "variable"; - registers.r7 = "variable"; - registers.r8 = "variable"; - registers.r9 = "variable"; - registers.r10 = "variable"; - registers.r11 = "variable"; - registers.r12 = "variable"; - - registers.sp = "variable-2"; - registers.lr = "variable-2"; - registers.pc = "variable-2"; - registers.r13 = registers.sp; - registers.r14 = registers.lr; - registers.r15 = registers.pc; - - custom.push(function(ch, stream, state) { - if (ch === '#') { - stream.eatWhile(/\w/); - return "number"; - } - }); - } - - var arch = parserConfig.architecture.toLowerCase(); - if (arch === "x86") { - x86(config, parserConfig); - } else if (arch === "arm" || arch === "armv6") { - armv6(config, parserConfig); + } + + if (ch === lineCommentStartSymbol) { + stream.skipToEnd(); + return "comment"; + } + + if (ch === '"') { + nextUntilUnescaped(stream, '"'); + return "string"; + } + + if (ch === '.') { + stream.eatWhile(/\w/); + cur = stream.current().toLowerCase(); + style = directives[cur]; + return style || null; + } + + if (ch === '=') { + stream.eatWhile(/\w/); + return "tag"; + } + + if (ch === '{') { + return "braket"; + } + + if (ch === '}') { + return "braket"; + } + + if (/\d/.test(ch)) { + if (ch === "0" && stream.eat("x")) { + stream.eatWhile(/[0-9a-fA-F]/); + return "number"; } - - function nextUntilUnescaped(stream, end) { - var escaped = false, next; - while ((next = stream.next()) != null) { - if (next === end && !escaped) { - return false; - } - escaped = !escaped && next === "\\"; - } - return escaped; + stream.eatWhile(/\d/); + return "number"; + } + + if (/\w/.test(ch)) { + stream.eatWhile(/\w/); + if (stream.eat(":")) { + return 'tag'; } - - function clikeComment(stream, state) { - var maybeEnd = false, ch; - while ((ch = stream.next()) != null) { - if (ch === "/" && maybeEnd) { - state.tokenize = null; - break; - } - maybeEnd = (ch === "*"); - } - return "comment"; - } - - return { - startState: function(basecolumn) { - return { - tokenize: null, - }; - }, - - token: function(stream, state) { - if (state.tokenize) { - return state.tokenize(stream, state); - } - - if (stream.eatSpace()) { - return null; - } - - var style, cur, ch = stream.next(); - - if (ch === "/") { - if (stream.eat("*")) { - state.tokenize = clikeComment; - return clikeComment(stream, state); - } - } - - if (ch === lineCommentStartSymbol) { - stream.skipToEnd(); - return "comment"; - } - - if (ch === '"') { - nextUntilUnescaped(stream, '"'); - return "string"; - } - - if (ch === '.') { - stream.eatWhile(/\w/); - cur = stream.current().toLowerCase(); - style = directives[cur]; - return style || null; - } - - if (ch === '=') { - stream.eatWhile(/\w/); - return "tag"; - } - - if (ch === '{') { - return "braket"; - } - - if (ch === '}') { - return "braket"; - } - - if (/\d/.test(ch)) { - if (ch === "0" && stream.eat("x")) { - stream.eatWhile(/[0-9a-fA-F]/); - return "number"; - } - stream.eatWhile(/\d/); - return "number"; - } - - if (/\w/.test(ch)) { - stream.eatWhile(/\w/); - if (stream.eat(":")) { - return 'tag'; - } - cur = stream.current().toLowerCase(); - style = registers[cur]; - return style || null; - } - - for (var i = 0; i < custom.length; i++) { - style = custom[i](ch, stream, state); - if (style) { - return style; - } - } - }, + cur = stream.current().toLowerCase(); + style = registers[cur]; + return style || null; + } + + for (var i = 0; i < custom.length; i++) { + style = custom[i](ch, stream, state); + if (style) { + return style; } + } + }, + } }); From db7666a1e2f82625e42e1fe9c10c2f510cf5bf5b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 25 Mar 2013 10:46:47 +0100 Subject: [PATCH 0413/5273] [gas mode] Integrate --- doc/compress.html | 1 + doc/modes.html | 1 + mode/{s/s.js => gas/gas.js} | 18 +++++++++--------- mode/{s => gas}/index.html | 4 ++-- mode/meta.js | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) rename mode/{s/s.js => gas/gas.js} (96%) rename mode/{s => gas}/index.html (93%) diff --git a/doc/compress.html b/doc/compress.html index 7f14fc78b2..a100f9b965 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -80,6 +80,7 @@

    { } CodeMi + diff --git a/doc/modes.html b/doc/modes.html index f8080a46e8..d016aca8ee 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -34,6 +34,7 @@

    { } CodeMi
  • diff
  • ECL
  • Erlang
  • +
  • Gas (AT&T-style assembly)
  • Go
  • Groovy
  • Haskell
  • diff --git a/mode/s/s.js b/mode/gas/gas.js similarity index 96% rename from mode/s/s.js rename to mode/gas/gas.js index 4a5dc2972d..52620c6f08 100644 --- a/mode/s/s.js +++ b/mode/gas/gas.js @@ -1,4 +1,4 @@ -CodeMirror.defineMode("s", function(config, parserConfig) { +CodeMirror.defineMode("gas", function(_config, parserConfig) { 'use strict'; // If an architecture is specified, its initialization function may @@ -123,12 +123,12 @@ CodeMirror.defineMode("s", function(config, parserConfig) { ".warning" : "builtin", ".weak" : "builtin", ".weakref" : "builtin", - ".word" : "builtin", + ".word" : "builtin" }; var registers = {}; - function x86(config, parserConfig) { + function x86(_config, _parserConfig) { lineCommentStartSymbol = "#"; registers.ax = "variable"; @@ -175,7 +175,7 @@ CodeMirror.defineMode("s", function(config, parserConfig) { registers.gs = "keyword"; } - function armv6(config, parserConfig) { + function armv6(_config, _parserConfig) { // Reference: // http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf @@ -203,7 +203,7 @@ CodeMirror.defineMode("s", function(config, parserConfig) { registers.r14 = registers.lr; registers.r15 = registers.pc; - custom.push(function(ch, stream, state) { + custom.push(function(ch, stream) { if (ch === '#') { stream.eatWhile(/\w/); return "number"; @@ -242,9 +242,9 @@ CodeMirror.defineMode("s", function(config, parserConfig) { } return { - startState: function(basecolumn) { + startState: function() { return { - tokenize: null, + tokenize: null }; }, @@ -321,6 +321,6 @@ CodeMirror.defineMode("s", function(config, parserConfig) { return style; } } - }, - } + } + }; }); diff --git a/mode/s/index.html b/mode/gas/index.html similarity index 93% rename from mode/s/index.html rename to mode/gas/index.html index 8c55cb155a..7684bc18df 100644 --- a/mode/s/index.html +++ b/mode/gas/index.html @@ -5,7 +5,7 @@ CodeMirror: Gas mode - + @@ -40,7 +40,7 @@

    CodeMirror: Gas mode

    diff --git a/mode/meta.js b/mode/meta.js index 4bc03e67a7..87000c4aa2 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -14,7 +14,7 @@ CodeMirror.modeInfo = [ {name: 'diff', mime: 'text/x-diff', mode: 'diff'}, {name: 'ECL', mime: 'text/x-ecl', mode: 'ecl'}, {name: 'Erlang', mime: 'text/x-erlang', mode: 'erlang'}, - {name: 'Gas', mime: 'text/x-gas', mode: 's'}, + {name: 'Gas', mime: 'text/x-gas', mode: 'gas'}, {name: 'GitHub Flavored Markdown', mode: 'gfm'}, {name: 'GO', mime: 'text/x-go', mode: 'go'}, {name: 'Groovy', mime: 'text/x-groovy', mode: 'groovy'}, From f365868e814fda6680ab630764b2bd89b74cc802 Mon Sep 17 00:00:00 2001 From: Ansel Santosa Date: Thu, 21 Mar 2013 11:01:29 -0700 Subject: [PATCH 0414/5273] Prevent crashing on IE when in iframes "Unspecified error" on document.activeElement when running in an iframe in IE. --- lib/codemirror.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index d06456bf91..2098f4adeb 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -484,11 +484,14 @@ window.CodeMirror = (function() { } intact.sort(function(a, b) {return a.from - b.from;}); - var focused = document.activeElement; + // Avoid crashing on IE's "unspecified error" when in iframes + try { + var focused = document.activeElement; + } catch(e) {} if (intactLines < (to - from) * .7) display.lineDiv.style.display = "none"; patchDisplay(cm, from, to, intact, positionsChangedFrom); display.lineDiv.style.display = ""; - if (document.activeElement != focused && focused.offsetHeight) focused.focus(); + if (focused && document.activeElement != focused && focused.offsetHeight) focused.focus(); var different = from != display.showingFrom || to != display.showingTo || display.lastSizeC != display.wrapper.clientHeight; From f12685dc6ec10b2c0f81f1a0f9061d9d04839d6d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 25 Mar 2013 10:54:50 +0100 Subject: [PATCH 0415/5273] Make text inside hidden textarea tiny To prevent it from pushing the scroll position of the wrapper. --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 2098f4adeb..32067c1a11 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -92,7 +92,7 @@ window.CodeMirror = (function() { function makeDisplay(place, docStart) { var d = {}; - var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none;"); + var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none; font-size: 4px;"); if (webkit) input.style.width = "1000px"; else input.setAttribute("wrap", "off"); // if border: 0; -- iOS fails to open keyboard (issue #1287) @@ -742,7 +742,7 @@ window.CodeMirror = (function() { // Move the hidden textarea near the cursor to prevent scrolling artifacts var headPos = cursorCoords(cm, cm.doc.sel.head, "div"); var wrapOff = getRect(display.wrapper), lineOff = getRect(display.lineDiv); - display.inputDiv.style.top = Math.max(0, Math.min(display.wrapper.clientHeight - 20, + display.inputDiv.style.top = Math.max(0, Math.min(display.wrapper.clientHeight - 10, headPos.top + lineOff.top - wrapOff.top)) + "px"; display.inputDiv.style.left = Math.max(0, Math.min(display.wrapper.clientWidth - 10, headPos.left + lineOff.left - wrapOff.left)) + "px"; From d155c412be65acb31c6605f65b407f47408778ba Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 25 Mar 2013 17:25:46 +0100 Subject: [PATCH 0416/5273] More careful checking of viewport coverage after updateDisplayInner Closes #1391 --- lib/codemirror.js | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 32067c1a11..1de32f1468 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -396,15 +396,22 @@ window.CodeMirror = (function() { // DISPLAY DRAWING function updateDisplay(cm, changes, viewPort) { - var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo; - var updated = updateDisplayInner(cm, changes, viewPort); - if (updated) { - signalLater(cm, "update", cm); - if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo) - signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display.showingTo); + var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; + for (;;) { + var visible = visibleLines(cm.display, cm.doc, viewPort); + if (updateDisplayInner(cm, changes, visible)) { + updated = true; + signalLater(cm, "update", cm); + if (cm.display.showingFrom != oldFrom || cm.display.showingTo != oldTo) + signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display.showingTo); + } else break; + updateSelection(cm); + updateScrollbars(cm.display, cm.doc.height); + + var newVisible = visibleLines(cm.display, cm.doc, viewPort); + if (newVisible.from >= cm.display.showingFrom && newVisible.to <= cm.display.showingTo) + break; } - updateSelection(cm); - updateScrollbars(cm.display, cm.doc.height); return updated; } @@ -412,7 +419,7 @@ window.CodeMirror = (function() { // Uses a set of changes plus the current scroll position to // determine which DOM updates have to be made, and makes the // updates. - function updateDisplayInner(cm, changes, viewPort) { + function updateDisplayInner(cm, changes, visible) { var display = cm.display, doc = cm.doc; if (!display.wrapper.clientWidth) { display.showingFrom = display.showingTo = doc.first; @@ -420,10 +427,6 @@ window.CodeMirror = (function() { return; } - // Compute the new visible window - // If scrollTop is specified, use that to determine which lines - // to render instead of the current scrollbar position. - var visible = visibleLines(display, doc, viewPort); // Bail out if the visible area is already rendered and nothing changed. if (changes.length == 0 && visible.from > display.showingFrom && visible.to < display.showingTo) @@ -522,8 +525,6 @@ window.CodeMirror = (function() { } updateViewOffset(cm); - if (visibleLines(display, doc, viewPort).to > to) - updateDisplayInner(cm, [], viewPort); return true; } From 84b8fb36bfe2252cdc4412b49319580617b9dc2a Mon Sep 17 00:00:00 2001 From: Tarmil Date: Mon, 25 Mar 2013 17:07:21 +0100 Subject: [PATCH 0417/5273] Fix multiplex close on blank line. --- addon/mode/multiplex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/mode/multiplex.js b/addon/mode/multiplex.js index e77ff2a9c3..459a918ea5 100644 --- a/addon/mode/multiplex.js +++ b/addon/mode/multiplex.js @@ -81,7 +81,7 @@ CodeMirror.multiplexingMode = function(outer /*, others */) { state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "") : 0); } } - } else if (mode.close === "\n") { + } else if (state.innerActive.close === "\n") { state.innerActive = state.inner = null; } }, From 8197a87bb2c09c8b2e742306101d8f346aa921dd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 26 Mar 2013 12:02:27 +0100 Subject: [PATCH 0418/5273] [gas mode] Fix undefined var error --- lib/codemirror.js | 2 +- mode/gas/gas.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 1de32f1468..4c3ff3a853 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1067,7 +1067,7 @@ window.CodeMirror = (function() { function clearCaches(cm) { cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0; cm.display.cachedCharWidth = cm.display.cachedTextHeight = null; - cm.display.maxLineChanged = true; + if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; cm.display.lineNumChars = null; } diff --git a/mode/gas/gas.js b/mode/gas/gas.js index 52620c6f08..a03382b61f 100644 --- a/mode/gas/gas.js +++ b/mode/gas/gas.js @@ -128,7 +128,7 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) { var registers = {}; - function x86(_config, _parserConfig) { + function x86(_parserConfig) { lineCommentStartSymbol = "#"; registers.ax = "variable"; @@ -175,7 +175,7 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) { registers.gs = "keyword"; } - function armv6(_config, _parserConfig) { + function armv6(_parserConfig) { // Reference: // http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf // http://infocenter.arm.com/help/topic/com.arm.doc.ddi0301h/DDI0301H_arm1176jzfs_r0p7_trm.pdf @@ -213,9 +213,9 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) { var arch = parserConfig.architecture.toLowerCase(); if (arch === "x86") { - x86(config, parserConfig); + x86(parserConfig); } else if (arch === "arm" || arch === "armv6") { - armv6(config, parserConfig); + armv6(parserConfig); } function nextUntilUnescaped(stream, end) { From 1b150c9a4fd607508f5c6aa5e301f4f3ab7b393b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 26 Mar 2013 17:08:31 +0100 Subject: [PATCH 0419/5273] Prevent bogus error messages when a mode throws an error --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 4c3ff3a853..652f86c8ad 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1279,7 +1279,7 @@ window.CodeMirror = (function() { cm.curOp = null; if (op.updateMaxLine) computeMaxLength(cm); - if (display.maxLineChanged && !cm.options.lineWrapping) { + if (display.maxLineChanged && !cm.options.lineWrapping && display.maxLine) { var width = measureLineWidth(cm, display.maxLine); display.sizer.style.minWidth = Math.max(0, width + 3 + scrollerCutOff) + "px"; display.maxLineChanged = false; From ca79fa2066b956bc290abfcee2be6224cbed9a5b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 27 Mar 2013 10:30:42 +0100 Subject: [PATCH 0420/5273] Add maxHighlightLength option --- doc/manual.html | 7 +++++++ lib/codemirror.js | 10 ++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index f1a157cf18..4a601f2709 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -326,6 +326,13 @@

    Configuration

    document looks. You can set this option to false to disable this behavior.

    +
    maxHighlightLength (number)
    +
    When highlighting long lines, in order to stay responsive, + the editor will give up and simply style the rest of the line as + plain text when it reaches a certain position. The default is + 10000. You can set this to Infinity to turn off + this behavior.
    +
    viewportMargin (integer)
    Specifies the amount of lines that are rendered above and below the part of the document that's currently scrolled into diff --git a/lib/codemirror.js b/lib/codemirror.js index 652f86c8ad..e298ce43ba 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3087,6 +3087,7 @@ window.CodeMirror = (function() { option("pollInterval", 100); option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;}); option("viewportMargin", 10, function(cm){cm.refresh();}, true); + option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();}, true); option("tabindex", null, function(cm, val) { cm.display.input.tabIndex = val || ""; @@ -3978,15 +3979,16 @@ window.CodeMirror = (function() { var flattenSpans = mode.flattenSpans; if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; var curText = "", curStyle = null; - var stream = new StringStream(text, cm.options.tabSize); + var stream = new StringStream(text, cm.options.tabSize), style; if (text == "" && mode.blankLine) mode.blankLine(state); while (!stream.eol()) { - var style = mode.token(stream, state); - if (stream.pos > 5000) { + if (stream.pos > cm.options.maxHighlightLength) { flattenSpans = false; // Webkit seems to refuse to render text nodes longer than 57444 characters stream.pos = Math.min(text.length, stream.start + 50000); style = null; + } else { + style = mode.token(stream, state); } var substr = stream.current(); stream.start = stream.pos; @@ -4049,7 +4051,7 @@ window.CodeMirror = (function() { var mode = cm.doc.mode; var stream = new StringStream(line.text, cm.options.tabSize); if (line.text == "" && mode.blankLine) mode.blankLine(state); - while (!stream.eol() && stream.pos <= 5000) { + while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { mode.token(stream, state); stream.start = stream.pos; } From 9e62ecad1520e91cbfa70c997066ce41ba0e0890 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 27 Mar 2013 12:58:20 +0100 Subject: [PATCH 0421/5273] Reset hidden textarea when swapping an editor's document --- lib/codemirror.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index e298ce43ba..882b92b313 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3000,6 +3000,7 @@ window.CodeMirror = (function() { old.cm = null; attachDoc(this, doc); clearCaches(this); + resetInput(this, true); updateScrollPos(this, doc.scrollLeft, doc.scrollTop); return old; }), From 72d639dcfedf19de97a26b0778977d28f980b81a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 27 Mar 2013 16:28:28 +0100 Subject: [PATCH 0422/5273] Add moveInputWithCursor option --- lib/codemirror.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 882b92b313..71febb999f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -741,12 +741,14 @@ window.CodeMirror = (function() { display.selectionDiv.style.display = "none"; // Move the hidden textarea near the cursor to prevent scrolling artifacts - var headPos = cursorCoords(cm, cm.doc.sel.head, "div"); - var wrapOff = getRect(display.wrapper), lineOff = getRect(display.lineDiv); - display.inputDiv.style.top = Math.max(0, Math.min(display.wrapper.clientHeight - 10, - headPos.top + lineOff.top - wrapOff.top)) + "px"; - display.inputDiv.style.left = Math.max(0, Math.min(display.wrapper.clientWidth - 10, - headPos.left + lineOff.left - wrapOff.left)) + "px"; + if (cm.options.moveInputWithCursor) { + var headPos = cursorCoords(cm, cm.doc.sel.head, "div"); + var wrapOff = getRect(display.wrapper), lineOff = getRect(display.lineDiv); + display.inputDiv.style.top = Math.max(0, Math.min(display.wrapper.clientHeight - 10, + headPos.top + lineOff.top - wrapOff.top)) + "px"; + display.inputDiv.style.left = Math.max(0, Math.min(display.wrapper.clientWidth - 10, + headPos.left + lineOff.left - wrapOff.left)) + "px"; + } } // No selection, plain cursor @@ -3089,6 +3091,9 @@ window.CodeMirror = (function() { option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;}); option("viewportMargin", 10, function(cm){cm.refresh();}, true); option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();}, true); + option("moveInputWithCursor", true, function(cm, val) { + if (!val) cm.display.inputDiv.style.top = cm.display.inputDiv.style.left = 0; + }); option("tabindex", null, function(cm, val) { cm.display.input.tabIndex = val || ""; From f4abf68f68f9f073d67c64c5db1205d73bef7476 Mon Sep 17 00:00:00 2001 From: Narciso Jaramillo Date: Wed, 27 Mar 2013 16:08:50 -0700 Subject: [PATCH 0423/5273] Use empty changes array when calling updateDisplayInner() subsequent times --- lib/codemirror.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 71febb999f..ead5afc66a 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -411,6 +411,7 @@ window.CodeMirror = (function() { var newVisible = visibleLines(cm.display, cm.doc, viewPort); if (newVisible.from >= cm.display.showingFrom && newVisible.to <= cm.display.showingTo) break; + changes = []; } return updated; From 85d19c4d89c87caab98cfb1001af8df76eb311a1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 28 Mar 2013 13:43:18 +0100 Subject: [PATCH 0424/5273] Make scrollIntoView work properly when called inside an operation Closes #1398 --- lib/codemirror.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index ead5afc66a..49447bf909 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1306,6 +1306,8 @@ window.CodeMirror = (function() { display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = newScrollPos.scrollTop; display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = newScrollPos.scrollLeft; alignHorizontally(cm); + if (op.scrollToPos) + scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos), op.scrollToPosMargin); } else if (newScrollPos) { scrollCursorIntoView(cm); } @@ -2544,7 +2546,8 @@ window.CodeMirror = (function() { } function updateScrollPos(cm, left, top) { - cm.curOp.updateScrollPos = {scrollLeft: left, scrollTop: top}; + cm.curOp.updateScrollPos = {scrollLeft: left == null ? cm.doc.scrollLeft : left, + scrollTop: top == null ? cm.doc.scrollTop : top}; } function addToScrollPos(cm, left, top) { @@ -2968,15 +2971,19 @@ window.CodeMirror = (function() { clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co}; }, - scrollIntoView: function(pos, margin) { + scrollIntoView: operation(null, function(pos, margin) { if (typeof pos == "number") pos = Pos(pos, 0); + if (!margin) margin = 0; + var coords = pos; + if (!pos || pos.line != null) { - pos = pos ? clipPos(this.doc, pos) : this.doc.sel.head; - scrollPosIntoView(this, pos, margin); - } else { - scrollIntoView(this, pos.left, pos.top - margin, pos.right, pos.bottom + margin); + this.curOp.scrollToPos = pos ? clipPos(this.doc, pos) : this.doc.sel.head; + this.curOp.scrollToPosMargin = margin; + coords = cursorCoords(this, this.curOp.scrollToPos); } - }, + var sPos = calculateScrollPos(this, coords.left, coords.top - margin, coords.right, coords.bottom + margin); + updateScrollPos(this, sPos.scrollLeft, sPos.scrollTop); + }), setSize: function(width, height) { function interpret(val) { From 4c8daad391161f074ebb16923caf6d4ad4431a18 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 28 Mar 2013 13:45:56 +0100 Subject: [PATCH 0425/5273] Don't blink the cursor when the editor is not focused. Saves on layout computations. Closes #1044 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 49447bf909..bf464a6306 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -855,7 +855,7 @@ window.CodeMirror = (function() { var on = true; display.cursor.style.visibility = display.otherCursor.style.visibility = ""; display.blinker = setInterval(function() { - if (!display.cursor.offsetHeight) return; + if (!cm.state.focused) return; display.cursor.style.visibility = display.otherCursor.style.visibility = (on = !on) ? "" : "hidden"; }, cm.options.cursorBlinkRate); } From 8f8072a86323196631c1966bf11075824e6d714e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 28 Mar 2013 13:54:16 +0100 Subject: [PATCH 0426/5273] Don't run the cursor-blinking timeout at all when not focused --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index bf464a6306..c71c80b88f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -850,12 +850,12 @@ window.CodeMirror = (function() { // Cursor-blinking function restartBlink(cm) { + if (!cm.state.focused) return; var display = cm.display; clearInterval(display.blinker); var on = true; display.cursor.style.visibility = display.otherCursor.style.visibility = ""; display.blinker = setInterval(function() { - if (!cm.state.focused) return; display.cursor.style.visibility = display.otherCursor.style.visibility = (on = !on) ? "" : "hidden"; }, cm.options.cursorBlinkRate); } From ea3b07f5d3a0dfadb7f97af614a5fe86afa80b50 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 28 Mar 2013 13:59:20 +0100 Subject: [PATCH 0427/5273] Add XQuery tester to real-world uses --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 4f0dec346d..d1769559f7 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -90,6 +90,7 @@

    { } CodeMi
  • WeScheme (learning tool)
  • WordPress plugin
  • XOSide (online editor)
  • +
  • XQuery tester
  • From 56def7dbd341a1ccfddf0573a77fe3602c7f8f81 Mon Sep 17 00:00:00 2001 From: Eric Allam Date: Mon, 11 Mar 2013 23:30:48 -0400 Subject: [PATCH 0428/5273] Don't treat whitespace as an error, instead just eat the whitespace (fixes #1331) --- mode/sass/sass.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/sass/sass.js b/mode/sass/sass.js index 9aed75a1af..e5c82e4e1b 100644 --- a/mode/sass/sass.js +++ b/mode/sass/sass.js @@ -284,7 +284,7 @@ CodeMirror.defineMode("sass", function(config) { // If we haven't returned by now, we move 1 character // and return an error stream.next(); - return 'error'; + return null; }; var tokenLexer = function(stream, state) { @@ -302,7 +302,7 @@ CodeMirror.defineMode("sass", function(config) { indent(state); } - if (style !== "error"){ + if (style !== null){ var startOfToken = stream.pos - current.length; var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount); From 3989667893b5e4e8909f53a619ca5f616b8a054d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 09:21:12 +0200 Subject: [PATCH 0429/5273] [javascript mode] Add call tracking, as used by Tern --- mode/javascript/javascript.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index ff6bb5d803..84df5052fa 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -290,7 +290,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return cont(expression); } if (type == ";") return; - if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator); + if (type == "(") return cont(pushlex(")", "call"), commasep(expression, ")"), poplex, maybeoperator); if (type == ".") return cont(property, maybeoperator); if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator); } @@ -318,7 +318,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function commasep(what, end) { function proceed(type) { - if (type == ",") return cont(what, proceed); + if (type == ",") { + var lex = cx.state.lexical; + if (lex.info == "call") lex.pos = (lex.pos || 0) + 1; + return cont(what, proceed); + } if (type == end) return cont(); return cont(expect(end)); } From 9ed1a68835adf2667a00b1963bc8c4a277a053d3 Mon Sep 17 00:00:00 2001 From: Mike Diaz Date: Thu, 28 Mar 2013 09:34:58 -0700 Subject: [PATCH 0430/5273] add option to disable lint tooltips --- addon/lint/lint.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/addon/lint/lint.js b/addon/lint/lint.js index dd838e7ea5..1fa5aa985e 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -50,7 +50,7 @@ CodeMirror.validate = (function() { state.marked.length = 0; } - function makeMarker(labels, severity, multiple) { + function makeMarker(labels, severity, multiple, tooltips) { var marker = document.createElement("div"), inner = marker; marker.className = "CodeMirror-lint-marker-" + severity; if (multiple) { @@ -58,9 +58,11 @@ CodeMirror.validate = (function() { inner.className = "CodeMirror-lint-marker-multiple"; } - var tooltip; - CodeMirror.on(inner, "mouseover", function(e) { tooltip = showTooltip(e, labels); }); - CodeMirror.on(inner, "mouseout", function() { if (tooltip) hideTooltip(tooltip); }); + if (tooltips != false) { + var tooltip; + CodeMirror.on(inner, "mouseover", function(e) { tooltip = showTooltip(e, labels); }); + CodeMirror.on(inner, "mouseout", function() { if (tooltip) hideTooltip(tooltip); }); + } return marker; } @@ -95,7 +97,7 @@ CodeMirror.validate = (function() { else updateLinting(cm, options.getAnnotations(cm.getValue())); } - + function updateLinting(cm, annotationsNotSorted) { clearMarks(cm); var state = cm._lintState, options = state.options; @@ -125,7 +127,8 @@ CodeMirror.validate = (function() { } if (state.hasGutter) - cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1)); + cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1, + state.options.tooltips)); } if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); } @@ -170,13 +173,15 @@ CodeMirror.validate = (function() { CodeMirror.off(cm.getWrapperElement(), "mouseover", cm._lintState.onMouseOver); delete cm._lintState; } - + if (val) { var gutters = cm.getOption("gutters"), hasLintGutter = false; for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; var state = cm._lintState = new LintState(cm, parseOptions(val), hasLintGutter); cm.on("change", onChange); - CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); + if (state.options.tooltips != false) + CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); + startLinting(cm); } }); From ddaa7e8057a1a191d827a84e0be99ab7e99816d9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 11:13:24 +0200 Subject: [PATCH 0431/5273] [javascript mode] Support statementIndent option Closes #1403 --- mode/javascript/index.html | 12 ++++++++---- mode/javascript/javascript.js | 5 +++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/mode/javascript/index.html b/mode/javascript/index.html index cca7d04eaf..dd0ca220d8 100644 --- a/mode/javascript/index.html +++ b/mode/javascript/index.html @@ -76,10 +76,14 @@

    CodeMirror: JavaScript mode

    JavaScript mode supports a two configuration options:
      -
    • json which will set the mode to expect JSON data rather than a JavaScript program.
    • -
    • - typescript which will activate additional syntax highlighting and some other things for TypeScript code (demo). -
    • +
    • json which will set the mode to expect JSON + data rather than a JavaScript program.
    • +
    • typescript which will activate additional + syntax highlighting and some other things for TypeScript code + (demo).
    • +
    • statementIndent which (given a number) will + determine the amount of indentation to use for statements + continued on a new line.

    diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 84df5052fa..bfbf78378b 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -415,6 +415,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; var type = lexical.type, closing = firstChar == type; + if (parserConfig.statementIndent != null) { + if (type == ")" && lexical.prev && lexical.prev.type == "stat") lexical = lexical.prev; + if (lexical.type == "stat") return lexical.indented + parserConfig.statementIndent; + } + if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0); else if (type == "form" && firstChar == "{") return lexical.indented; else if (type == "form") return lexical.indented + indentUnit; From 6a33096e6021fa5c48abf2867e7b68569168e24a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 11:30:57 +0200 Subject: [PATCH 0432/5273] Fix another case where updateDisplay might not update the entire visible area Closes #1404 --- lib/codemirror.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index c71c80b88f..493bd71b08 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -397,8 +397,8 @@ window.CodeMirror = (function() { function updateDisplay(cm, changes, viewPort) { var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; + var visible = visibleLines(cm.display, cm.doc, viewPort); for (;;) { - var visible = visibleLines(cm.display, cm.doc, viewPort); if (updateDisplayInner(cm, changes, visible)) { updated = true; signalLater(cm, "update", cm); @@ -408,8 +408,12 @@ window.CodeMirror = (function() { updateSelection(cm); updateScrollbars(cm.display, cm.doc.height); - var newVisible = visibleLines(cm.display, cm.doc, viewPort); - if (newVisible.from >= cm.display.showingFrom && newVisible.to <= cm.display.showingTo) + // Clip forced viewport to actual scrollable area + if (viewPort) + viewPort = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, + typeof viewPort == "number" ? viewPort : viewPort.top); + visible = visibleLines(cm.display, cm.doc, viewPort); + if (visible.from >= cm.display.showingFrom && visible.to <= cm.display.showingTo) break; changes = []; } From e7dda847b3a265c5778ca66308da468e307a52d9 Mon Sep 17 00:00:00 2001 From: Joseph Pecoraro Date: Thu, 28 Mar 2013 15:39:11 -0700 Subject: [PATCH 0433/5273] Remove tabs and trailing whitespace in a few modes --- mode/less/less.js | 46 +++++++++++++++++++++++----------------------- mode/sql/sql.js | 36 ++++++++++++++++++------------------ 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/mode/less/less.js b/mode/less/less.js index 70cd5c937b..4f6214363a 100644 --- a/mode/less/less.js +++ b/mode/less/less.js @@ -41,7 +41,7 @@ CodeMirror.defineMode("less", function(config) { }else{ if(type == "string" || type == "(")return ret("string", "string"); if(state.stack[state.stack.length-1] != undefined)return ret(null, ch); - stream.eatWhile(/[\a-zA-Z0-9\-_.\s]/); + stream.eatWhile(/[\a-zA-Z0-9\-_.\s]/); if( /\/|\)|#/.test(stream.peek() || (stream.eatSpace() && stream.peek() == ")")) || stream.eol() )return ret("string", "string"); // let url(/images/logo.png) without quotes return as string } } @@ -58,7 +58,7 @@ CodeMirror.defineMode("less", function(config) { return ret(null, "select-op"); } else if (/[;{}:\[\]()~\|]/.test(ch)) { - if(ch == ":"){ + if(ch == ":"){ stream.eatWhile(/[a-z\\\-]/); if( selectors.test(stream.current()) ){ return ret("tag", "tag"); @@ -69,7 +69,7 @@ CodeMirror.defineMode("less", function(config) { if( selectors.test(stream.current().substring(1)) )return ret("tag", "tag"); return ret(null, ch); }else{ - return ret(null, ch); + return ret(null, ch); } }else if(ch == "~"){ if(type == "r")return ret("string", "string"); @@ -77,7 +77,7 @@ CodeMirror.defineMode("less", function(config) { return ret(null, ch); } } - else if (ch == ".") { + else if (ch == ".") { if(type == "(" || type == "string")return ret("string", "string"); // allow url(../image.png) stream.eatWhile(/[\a-zA-Z0-9\-_]/); if(stream.peek() == " ")stream.eatSpace(); @@ -106,7 +106,7 @@ CodeMirror.defineMode("less", function(config) { else return ret("number", "unit"); }else{//when not a valid hexvalue in the current stream e.g. #footer stream.eatWhile(/[\w\\\-]/); - return ret("atom", "tag"); + return ret("atom", "tag"); } }else{//when not a valid hexvalue length stream.eatWhile(/[\w\\\-]/); @@ -126,14 +126,14 @@ CodeMirror.defineMode("less", function(config) { return ret("string", "string"); }else if(stream.peek() == "<" || stream.peek() == ">"){ return ret("tag", "tag"); - }else if( /\(/.test(stream.peek()) ){ + }else if( /\(/.test(stream.peek()) ){ return ret(null, ch); }else if (stream.peek() == "/" && state.stack[state.stack.length-1] != undefined){ // url(dir/center/image.png) return ret("string", "string"); }else if( stream.current().match(/\-\d|\-.\d/) ){ // match e.g.: -5px -0.4 etc... only colorize the minus sign //commment out these 2 comment if you want the minus sign to be parsed as null -500px //stream.backUp(stream.current().length-1); - //return ret(null, ch); //console.log( stream.current() ); + //return ret(null, ch); //console.log( stream.current() ); return ret("number", "unit"); }else if( inTagsArray(stream.current().toLowerCase()) ){ // match html tags return ret("tag", "tag"); @@ -156,22 +156,22 @@ CodeMirror.defineMode("less", function(config) { stream.next(); var t_v = stream.peek() == ":" ? true : false; if(!t_v){ - var old_pos = stream.pos; - var sc = stream.current().length; - stream.eatWhile(/[a-z\\\-]/); - var new_pos = stream.pos; - if(stream.current().substring(sc-1).match(selectors) != null){ - stream.backUp(new_pos-(old_pos-1)); - return ret("tag", "tag"); - } else stream.backUp(new_pos-(old_pos-1)); - }else{ - stream.backUp(1); - } - if(t_v)return ret("tag", "tag"); else return ret("variable", "variable"); - }else{ - return ret("variable", "variable"); + var old_pos = stream.pos; + var sc = stream.current().length; + stream.eatWhile(/[a-z\\\-]/); + var new_pos = stream.pos; + if(stream.current().substring(sc-1).match(selectors) != null){ + stream.backUp(new_pos-(old_pos-1)); + return ret("tag", "tag"); + } else stream.backUp(new_pos-(old_pos-1)); + }else{ + stream.backUp(1); + } + if(t_v)return ret("tag", "tag"); else return ret("variable", "variable"); + }else{ + return ret("variable", "variable"); } - } + } } function tokenSComment(stream, state) { // SComment = Slash comment @@ -218,7 +218,7 @@ CodeMirror.defineMode("less", function(config) { } return { - startState: function(base) { + startState: function(base) { return {tokenize: tokenBase, baseIndent: base || 0, stack: []}; diff --git a/mode/sql/sql.js b/mode/sql/sql.js index 510110b307..78f8d7fbad 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -20,11 +20,11 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { } if ((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/)) - || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/)) { + || (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/)) { // hex return "number"; } else if (((ch == "b" || ch == "B") && stream.match(/^'[01]+'/)) - || (ch == "0" && stream.match(/^b[01]+/))) { + || (ch == "0" && stream.match(/^b[01]+/))) { // bitstring return "number"; } else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) { @@ -43,7 +43,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { return null; } else if (ch == "#" || (ch == "-" && stream.eat("-") && stream.eat(" "))) { // 1-line comments - stream.skipToEnd(); + stream.skipToEnd(); return "comment"; } else if (ch == "/" && stream.eat("*")) { // multi-line comments @@ -85,11 +85,11 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { return function(stream, state) { var escaped = false, ch; while ((ch = stream.next()) != null) { - if (ch == quote && !escaped) { - state.tokenize = tokenBase; - break; - } - escaped = !escaped && ch == "\\"; + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; } return "string"; }; @@ -97,14 +97,14 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { function tokenComment(stream, state) { while (true) { if (stream.skipTo("*")) { - stream.next(); - if (stream.eat("/")) { - state.tokenize = tokenBase; - break; - } + stream.next(); + if (stream.eat("/")) { + state.tokenize = tokenBase; + break; + } } else { - stream.skipToEnd(); - break; + stream.skipToEnd(); + break; } } return "comment"; @@ -131,8 +131,8 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { token: function(stream, state) { if (stream.sol()) { - if (state.context && state.context.align == null) - state.context.align = false; + if (state.context && state.context.align == null) + state.context.align = false; } if (stream.eatSpace()) return null; @@ -140,7 +140,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { if (style == "comment") return style; if (state.context && state.context.align == null) - state.context.align = true; + state.context.align = true; var tok = stream.current(); if (tok == "(") From e0e42aa58c27f7c88e4b9d4f267d9fac2e285af1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 11:39:48 +0200 Subject: [PATCH 0434/5273] [linter] Disallow tabs in the whole project --- test/lint/lint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lint/lint.js b/test/lint/lint.js index b1b9381dd2..60b63a2d15 100644 --- a/test/lint/lint.js +++ b/test/lint/lint.js @@ -20,7 +20,7 @@ var scopePasser = walk.make({ function checkFile(fileName) { var file = fs.readFileSync(fileName, "utf8"); - var badChar = file.match(/[\x00-\x08\x0b\x0c\x0e-\x19\uFEFF]/); + var badChar = file.match(/[\x00-\x08\x0b\x0c\x0e-\x19\uFEFF\t]/); if (badChar) fail("Undesirable character " + badChar[0].charCodeAt(0) + " at position " + badChar.index, {source: fileName}); From 2024df3c0726a01d98d2e4842471a11b054420ac Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 11:39:54 +0200 Subject: [PATCH 0435/5273] Remove a whole lot of tabs --- addon/hint/javascript-hint.js | 8 +- addon/lint/javascript-lint.js | 118 +-- addon/lint/lint.js | 12 +- mode/ecl/ecl.js | 24 +- mode/gas/gas.js | 82 +- mode/lua/lua.js | 14 +- mode/mirc/mirc.js | 114 +-- mode/perl/perl.js | 1582 ++++++++++++++++----------------- mode/pig/pig.js | 326 +++---- mode/smalltalk/smalltalk.js | 258 +++--- mode/smarty/smarty.js | 6 +- mode/tiddlywiki/tiddlywiki.js | 690 +++++++------- mode/tiki/tiki.js | 595 +++++++------ mode/turtle/turtle.js | 28 +- mode/vbscript/vbscript.js | 8 +- mode/yaml/yaml.js | 180 ++-- mode/z80/z80.js | 192 ++-- 17 files changed, 2104 insertions(+), 2133 deletions(-) diff --git a/addon/hint/javascript-hint.js b/addon/hint/javascript-hint.js index 99e4eadc35..e3366147e3 100644 --- a/addon/hint/javascript-hint.js +++ b/addon/hint/javascript-hint.js @@ -4,7 +4,7 @@ function forEach(arr, f) { for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); } - + function arrayContains(arr, item) { if (!Array.prototype.indexOf) { var i = arr.length; @@ -44,9 +44,9 @@ } } while (level > 0); tprop = getToken(editor, Pos(cur.line, tprop.start)); - if (tprop.type.indexOf("variable") === 0) - tprop.type = "function"; - else return; // no clue + if (tprop.type.indexOf("variable") === 0) + tprop.type = "function"; + else return; // no clue } if (!context) var context = []; context.push(tprop); diff --git a/addon/lint/javascript-lint.js b/addon/lint/javascript-lint.js index db9ff6b224..9a815c824e 100644 --- a/addon/lint/javascript-lint.js +++ b/addon/lint/javascript-lint.js @@ -3,11 +3,11 @@ var bogus = [ "Dangerous comment" ]; var warnings = [ [ "Expected '{'", - "Statement body should be inside '{ }' braces." ] ]; + "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" ]; + "Unmatched ", " and instead saw", " is not defined", + "Unclosed string", "Stopping, unable to continue" ]; function validator(options, text) { JSHINT(text, options); @@ -42,10 +42,10 @@ found = description.indexOf(find) !== -1; if (force || found) { - error.severity = severity; + error.severity = severity; } if (found && replace) { - error.description = replace; + error.description = replace; } } } @@ -54,7 +54,7 @@ var description = error.description; for ( var i = 0; i < bogus.length; i++) { if (description.indexOf(bogus[i]) !== -1) { - return true; + return true; } } return false; @@ -64,59 +64,59 @@ for ( var i = 0; i < errors.length; i++) { var error = errors[i]; if (error) { - var linetabpositions, index; - - linetabpositions = []; - - // This next block is to fix a problem in jshint. Jshint - // replaces - // all tabs with spaces then performs some checks. The error - // positions (character/space) are then reported incorrectly, - // not taking the replacement step into account. Here we look - // at the evidence line and try to adjust the character position - // to the correct value. - if (error.evidence) { - // Tab positions are computed once per line and cached - var tabpositions = linetabpositions[error.line]; - if (!tabpositions) { - var evidence = error.evidence; - tabpositions = []; - // ugggh phantomjs does not like this - // forEachChar(evidence, function(item, index) { - Array.prototype.forEach.call(evidence, function(item, - index) { - if (item === '\t') { - // First col is 1 (not 0) to match error - // positions - tabpositions.push(index + 1); - } - }); - linetabpositions[error.line] = tabpositions; - } - if (tabpositions.length > 0) { - var pos = error.character; - tabpositions.forEach(function(tabposition) { - if (pos > tabposition) pos -= 1; - }); - error.character = pos; - } - } - - var start = error.character - 1, end = start + 1; - if (error.evidence) { - index = error.evidence.substring(start).search(/.\b/); - if (index > -1) { - end += index; - } - } - - // Convert to format expected by validation service - error.description = error.reason;// + "(jshint)"; - error.start = error.character; - error.end = end; - error = cleanup(error); - - if (error) + var linetabpositions, index; + + linetabpositions = []; + + // This next block is to fix a problem in jshint. Jshint + // replaces + // all tabs with spaces then performs some checks. The error + // positions (character/space) are then reported incorrectly, + // not taking the replacement step into account. Here we look + // at the evidence line and try to adjust the character position + // to the correct value. + if (error.evidence) { + // Tab positions are computed once per line and cached + var tabpositions = linetabpositions[error.line]; + if (!tabpositions) { + var evidence = error.evidence; + tabpositions = []; + // ugggh phantomjs does not like this + // forEachChar(evidence, function(item, index) { + Array.prototype.forEach.call(evidence, function(item, + index) { + if (item === '\t') { + // First col is 1 (not 0) to match error + // positions + tabpositions.push(index + 1); + } + }); + linetabpositions[error.line] = tabpositions; + } + if (tabpositions.length > 0) { + var pos = error.character; + tabpositions.forEach(function(tabposition) { + if (pos > tabposition) pos -= 1; + }); + error.character = pos; + } + } + + var start = error.character - 1, end = start + 1; + if (error.evidence) { + index = error.evidence.substring(start).search(/.\b/); + if (index > -1) { + end += index; + } + } + + // Convert to format expected by validation service + error.description = error.reason;// + "(jshint)"; + error.start = error.character; + error.end = end; + error = cleanup(error); + + if (error) output.push({message: error.description, severity: error.severity, from: CodeMirror.Pos(error.line - 1, start), diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 1fa5aa985e..d8961ac3f6 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -91,11 +91,11 @@ CodeMirror.validate = (function() { } function startLinting(cm) { - var state = cm._lintState, options = state.options; - if (options.async) - options.getAnnotations(cm, updateLinting, options); - else - updateLinting(cm, options.getAnnotations(cm.getValue())); + var state = cm._lintState, options = state.options; + if (options.async) + options.getAnnotations(cm, updateLinting, options); + else + updateLinting(cm, options.getAnnotations(cm.getValue())); } function updateLinting(cm, annotationsNotSorted) { @@ -117,7 +117,7 @@ CodeMirror.validate = (function() { if (!SEVERITIES.test(severity)) severity = "error"; maxSeverity = getMaxSeverity(maxSeverity, severity); - if (options.formatAnnotation) ann = options.formatAnnotation(ann); + if (options.formatAnnotation) ann = options.formatAnnotation(ann); if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { diff --git a/mode/ecl/ecl.js b/mode/ecl/ecl.js index 3ee7a681de..7601b189a0 100644 --- a/mode/ecl/ecl.js +++ b/mode/ecl/ecl.js @@ -75,18 +75,18 @@ CodeMirror.defineMode("ecl", function(config) { } else if (builtin.propertyIsEnumerable(cur)) { if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; return "builtin"; - } else { //Data types are of from KEYWORD## - var i = cur.length - 1; - while(i >= 0 && (!isNaN(cur[i]) || cur[i] == '_')) - --i; - - if (i > 0) { - var cur2 = cur.substr(0, i + 1); - if (variable_3.propertyIsEnumerable(cur2)) { - if (blockKeywords.propertyIsEnumerable(cur2)) curPunc = "newstatement"; - return "variable-3"; - } - } + } else { //Data types are of from KEYWORD## + var i = cur.length - 1; + while(i >= 0 && (!isNaN(cur[i]) || cur[i] == '_')) + --i; + + if (i > 0) { + var cur2 = cur.substr(0, i + 1); + if (variable_3.propertyIsEnumerable(cur2)) { + if (blockKeywords.propertyIsEnumerable(cur2)) curPunc = "newstatement"; + return "variable-3"; + } + } } if (atoms.propertyIsEnumerable(cur)) return "atom"; return null; diff --git a/mode/gas/gas.js b/mode/gas/gas.js index a03382b61f..5ef4bb04ed 100644 --- a/mode/gas/gas.js +++ b/mode/gas/gas.js @@ -205,8 +205,8 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) { custom.push(function(ch, stream) { if (ch === '#') { - stream.eatWhile(/\w/); - return "number"; + stream.eatWhile(/\w/); + return "number"; } }); } @@ -222,7 +222,7 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) { var escaped = false, next; while ((next = stream.next()) != null) { if (next === end && !escaped) { - return false; + return false; } escaped = !escaped && next === "\\"; } @@ -233,8 +233,8 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) { var maybeEnd = false, ch; while ((ch = stream.next()) != null) { if (ch === "/" && maybeEnd) { - state.tokenize = null; - break; + state.tokenize = null; + break; } maybeEnd = (ch === "*"); } @@ -244,82 +244,82 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) { return { startState: function() { return { - tokenize: null + tokenize: null }; }, token: function(stream, state) { if (state.tokenize) { - return state.tokenize(stream, state); + return state.tokenize(stream, state); } if (stream.eatSpace()) { - return null; + return null; } var style, cur, ch = stream.next(); if (ch === "/") { - if (stream.eat("*")) { - state.tokenize = clikeComment; - return clikeComment(stream, state); - } + if (stream.eat("*")) { + state.tokenize = clikeComment; + return clikeComment(stream, state); + } } if (ch === lineCommentStartSymbol) { - stream.skipToEnd(); - return "comment"; + stream.skipToEnd(); + return "comment"; } if (ch === '"') { - nextUntilUnescaped(stream, '"'); - return "string"; + nextUntilUnescaped(stream, '"'); + return "string"; } if (ch === '.') { - stream.eatWhile(/\w/); - cur = stream.current().toLowerCase(); - style = directives[cur]; - return style || null; + stream.eatWhile(/\w/); + cur = stream.current().toLowerCase(); + style = directives[cur]; + return style || null; } if (ch === '=') { - stream.eatWhile(/\w/); - return "tag"; + stream.eatWhile(/\w/); + return "tag"; } if (ch === '{') { - return "braket"; + return "braket"; } if (ch === '}') { - return "braket"; + return "braket"; } if (/\d/.test(ch)) { - if (ch === "0" && stream.eat("x")) { - stream.eatWhile(/[0-9a-fA-F]/); - return "number"; - } - stream.eatWhile(/\d/); - return "number"; + if (ch === "0" && stream.eat("x")) { + stream.eatWhile(/[0-9a-fA-F]/); + return "number"; + } + stream.eatWhile(/\d/); + return "number"; } if (/\w/.test(ch)) { - stream.eatWhile(/\w/); - if (stream.eat(":")) { - return 'tag'; - } - cur = stream.current().toLowerCase(); - style = registers[cur]; - return style || null; + stream.eatWhile(/\w/); + if (stream.eat(":")) { + return 'tag'; + } + cur = stream.current().toLowerCase(); + style = registers[cur]; + return style || null; } for (var i = 0; i < custom.length; i++) { - style = custom[i](ch, stream, state); - if (style) { - return style; - } + style = custom[i](ch, stream, state); + if (style) { + return style; + } } } }; diff --git a/mode/lua/lua.js b/mode/lua/lua.js index 97fb2c6f96..90761e2941 100644 --- a/mode/lua/lua.js +++ b/mode/lua/lua.js @@ -1,7 +1,7 @@ // LUA mode. Ported to CodeMirror 2 from Franciszek Wawrzak's // CodeMirror 1 mode. // highlights keywords, strings, comments (no leveling supported! ("[==[")), tokens, basic indenting - + CodeMirror.defineMode("lua", function(config, parserConfig) { var indentUnit = config.indentUnit; @@ -12,7 +12,7 @@ CodeMirror.defineMode("lua", function(config, parserConfig) { return new RegExp("^(?:" + words.join("|") + ")$", "i"); } var specials = wordRE(parserConfig.specials || []); - + // long list of standard functions from lua manual var builtins = wordRE([ "_G","_VERSION","assert","collectgarbage","dofile","error","getfenv","getmetatable","ipairs","load", @@ -47,8 +47,8 @@ CodeMirror.defineMode("lua", function(config, parserConfig) { "table.concat","table.insert","table.maxn","table.remove","table.sort" ]); var keywords = wordRE(["and","break","elseif","false","nil","not","or","return", - "true","function", "end", "if", "then", "else", "do", - "while", "repeat", "until", "for", "in", "local" ]); + "true","function", "end", "if", "then", "else", "do", + "while", "repeat", "until", "for", "in", "local" ]); var indentTokens = wordRE(["function", "if","repeat","do", "\\(", "{"]); var dedentTokens = wordRE(["end", "until", "\\)", "}"]); @@ -68,7 +68,7 @@ CodeMirror.defineMode("lua", function(config, parserConfig) { return (state.cur = bracketed(readBracket(stream), "comment"))(stream, state); stream.skipToEnd(); return "comment"; - } + } if (ch == "\"" || ch == "'") return (state.cur = string(ch))(stream, state); if (ch == "[" && /[\[=]/.test(stream.peek())) @@ -108,7 +108,7 @@ CodeMirror.defineMode("lua", function(config, parserConfig) { return "string"; }; } - + return { startState: function(basecol) { return {basecol: basecol || 0, indentDepth: 0, cur: normal}; @@ -121,7 +121,7 @@ CodeMirror.defineMode("lua", function(config, parserConfig) { if (style == "variable") { if (keywords.test(word)) style = "keyword"; else if (builtins.test(word)) style = "builtin"; - else if (specials.test(word)) style = "variable-2"; + else if (specials.test(word)) style = "variable-2"; } if ((style != "comment") && (style != "string")){ if (indentTokens.test(word)) ++state.indentDepth; diff --git a/mode/mirc/mirc.js b/mode/mirc/mirc.js index f76f782764..fc88bc56fb 100644 --- a/mode/mirc/mirc.js +++ b/mode/mirc/mirc.js @@ -8,65 +8,65 @@ CodeMirror.defineMode("mirc", function() { } var specials = parseWords("$! $$ $& $? $+ $abook $abs $active $activecid " + "$activewid $address $addtok $agent $agentname $agentstat $agentver " + - "$alias $and $anick $ansi2mirc $aop $appactive $appstate $asc $asctime " + - "$asin $atan $avoice $away $awaymsg $awaytime $banmask $base $bfind " + - "$binoff $biton $bnick $bvar $bytes $calc $cb $cd $ceil $chan $chanmodes " + - "$chantypes $chat $chr $cid $clevel $click $cmdbox $cmdline $cnick $color " + - "$com $comcall $comchan $comerr $compact $compress $comval $cos $count " + - "$cr $crc $creq $crlf $ctime $ctimer $ctrlenter $date $day $daylight " + - "$dbuh $dbuw $dccignore $dccport $dde $ddename $debug $decode $decompress " + - "$deltok $devent $dialog $did $didreg $didtok $didwm $disk $dlevel $dll " + - "$dllcall $dname $dns $duration $ebeeps $editbox $emailaddr $encode $error " + - "$eval $event $exist $feof $ferr $fgetc $file $filename $filtered $finddir " + - "$finddirn $findfile $findfilen $findtok $fline $floor $fopen $fread $fserve " + - "$fulladdress $fulldate $fullname $fullscreen $get $getdir $getdot $gettok $gmt " + - "$group $halted $hash $height $hfind $hget $highlight $hnick $hotline " + - "$hotlinepos $ial $ialchan $ibl $idle $iel $ifmatch $ignore $iif $iil " + - "$inelipse $ini $inmidi $inpaste $inpoly $input $inrect $inroundrect " + - "$insong $instok $int $inwave $ip $isalias $isbit $isdde $isdir $isfile " + - "$isid $islower $istok $isupper $keychar $keyrpt $keyval $knick $lactive " + - "$lactivecid $lactivewid $left $len $level $lf $line $lines $link $lock " + - "$lock $locked $log $logstamp $logstampfmt $longfn $longip $lower $ltimer " + - "$maddress $mask $matchkey $matchtok $md5 $me $menu $menubar $menucontext " + - "$menutype $mid $middir $mircdir $mircexe $mircini $mklogfn $mnick $mode " + - "$modefirst $modelast $modespl $mouse $msfile $network $newnick $nick $nofile " + - "$nopath $noqt $not $notags $notify $null $numeric $numok $oline $onpoly " + - "$opnick $or $ord $os $passivedcc $pic $play $pnick $port $portable $portfree " + - "$pos $prefix $prop $protect $puttok $qt $query $rand $r $rawmsg $read $readomo " + - "$readn $regex $regml $regsub $regsubex $remove $remtok $replace $replacex " + - "$reptok $result $rgb $right $round $scid $scon $script $scriptdir $scriptline " + - "$sdir $send $server $serverip $sfile $sha1 $shortfn $show $signal $sin " + - "$site $sline $snick $snicks $snotify $sock $sockbr $sockerr $sockname " + - "$sorttok $sound $sqrt $ssl $sreq $sslready $status $strip $str $stripped " + - "$syle $submenu $switchbar $tan $target $ticks $time $timer $timestamp " + - "$timestampfmt $timezone $tip $titlebar $toolbar $treebar $trust $ulevel " + - "$ulist $upper $uptime $url $usermode $v1 $v2 $var $vcmd $vcmdstat $vcmdver " + - "$version $vnick $vol $wid $width $wildsite $wildtok $window $wrap $xor"); + "$alias $and $anick $ansi2mirc $aop $appactive $appstate $asc $asctime " + + "$asin $atan $avoice $away $awaymsg $awaytime $banmask $base $bfind " + + "$binoff $biton $bnick $bvar $bytes $calc $cb $cd $ceil $chan $chanmodes " + + "$chantypes $chat $chr $cid $clevel $click $cmdbox $cmdline $cnick $color " + + "$com $comcall $comchan $comerr $compact $compress $comval $cos $count " + + "$cr $crc $creq $crlf $ctime $ctimer $ctrlenter $date $day $daylight " + + "$dbuh $dbuw $dccignore $dccport $dde $ddename $debug $decode $decompress " + + "$deltok $devent $dialog $did $didreg $didtok $didwm $disk $dlevel $dll " + + "$dllcall $dname $dns $duration $ebeeps $editbox $emailaddr $encode $error " + + "$eval $event $exist $feof $ferr $fgetc $file $filename $filtered $finddir " + + "$finddirn $findfile $findfilen $findtok $fline $floor $fopen $fread $fserve " + + "$fulladdress $fulldate $fullname $fullscreen $get $getdir $getdot $gettok $gmt " + + "$group $halted $hash $height $hfind $hget $highlight $hnick $hotline " + + "$hotlinepos $ial $ialchan $ibl $idle $iel $ifmatch $ignore $iif $iil " + + "$inelipse $ini $inmidi $inpaste $inpoly $input $inrect $inroundrect " + + "$insong $instok $int $inwave $ip $isalias $isbit $isdde $isdir $isfile " + + "$isid $islower $istok $isupper $keychar $keyrpt $keyval $knick $lactive " + + "$lactivecid $lactivewid $left $len $level $lf $line $lines $link $lock " + + "$lock $locked $log $logstamp $logstampfmt $longfn $longip $lower $ltimer " + + "$maddress $mask $matchkey $matchtok $md5 $me $menu $menubar $menucontext " + + "$menutype $mid $middir $mircdir $mircexe $mircini $mklogfn $mnick $mode " + + "$modefirst $modelast $modespl $mouse $msfile $network $newnick $nick $nofile " + + "$nopath $noqt $not $notags $notify $null $numeric $numok $oline $onpoly " + + "$opnick $or $ord $os $passivedcc $pic $play $pnick $port $portable $portfree " + + "$pos $prefix $prop $protect $puttok $qt $query $rand $r $rawmsg $read $readomo " + + "$readn $regex $regml $regsub $regsubex $remove $remtok $replace $replacex " + + "$reptok $result $rgb $right $round $scid $scon $script $scriptdir $scriptline " + + "$sdir $send $server $serverip $sfile $sha1 $shortfn $show $signal $sin " + + "$site $sline $snick $snicks $snotify $sock $sockbr $sockerr $sockname " + + "$sorttok $sound $sqrt $ssl $sreq $sslready $status $strip $str $stripped " + + "$syle $submenu $switchbar $tan $target $ticks $time $timer $timestamp " + + "$timestampfmt $timezone $tip $titlebar $toolbar $treebar $trust $ulevel " + + "$ulist $upper $uptime $url $usermode $v1 $v2 $var $vcmd $vcmdstat $vcmdver " + + "$version $vnick $vol $wid $width $wildsite $wildtok $window $wrap $xor"); var keywords = parseWords("abook ajinvite alias aline ame amsg anick aop auser autojoin avoice " + "away background ban bcopy beep bread break breplace bset btrunc bunset bwrite " + - "channel clear clearall cline clipboard close cnick color comclose comopen " + - "comreg continue copy creq ctcpreply ctcps dcc dccserver dde ddeserver " + - "debug dec describe dialog did didtok disable disconnect dlevel dline dll " + - "dns dqwindow drawcopy drawdot drawfill drawline drawpic drawrect drawreplace " + - "drawrot drawsave drawscroll drawtext ebeeps echo editbox emailaddr enable " + - "events exit fclose filter findtext finger firewall flash flist flood flush " + - "flushini font fopen fseek fsend fserve fullname fwrite ghide gload gmove " + - "gopts goto gplay gpoint gqreq groups gshow gsize gstop gtalk gunload hadd " + - "halt haltdef hdec hdel help hfree hinc hload hmake hop hsave ial ialclear " + - "ialmark identd if ignore iline inc invite iuser join kick linesep links list " + - "load loadbuf localinfo log mdi me menubar mkdir mnick mode msg nick noop notice " + - "notify omsg onotice part partall pdcc perform play playctrl pop protect pvoice " + - "qme qmsg query queryn quit raw reload remini remote remove rename renwin " + - "reseterror resetidle return rlevel rline rmdir run ruser save savebuf saveini " + - "say scid scon server set showmirc signam sline sockaccept sockclose socklist " + - "socklisten sockmark sockopen sockpause sockread sockrename sockudp sockwrite " + - "sound speak splay sreq strip switchbar timer timestamp titlebar tnick tokenize " + - "toolbar topic tray treebar ulist unload unset unsetall updatenl url uwho " + - "var vcadd vcmd vcrem vol while whois window winhelp write writeint if isalnum " + - "isalpha isaop isavoice isban ischan ishop isignore isin isincs isletter islower " + - "isnotify isnum ison isop isprotect isreg isupper isvoice iswm iswmcs " + - "elseif else goto menu nicklist status title icon size option text edit " + - "button check radio box scroll list combo link tab item"); + "channel clear clearall cline clipboard close cnick color comclose comopen " + + "comreg continue copy creq ctcpreply ctcps dcc dccserver dde ddeserver " + + "debug dec describe dialog did didtok disable disconnect dlevel dline dll " + + "dns dqwindow drawcopy drawdot drawfill drawline drawpic drawrect drawreplace " + + "drawrot drawsave drawscroll drawtext ebeeps echo editbox emailaddr enable " + + "events exit fclose filter findtext finger firewall flash flist flood flush " + + "flushini font fopen fseek fsend fserve fullname fwrite ghide gload gmove " + + "gopts goto gplay gpoint gqreq groups gshow gsize gstop gtalk gunload hadd " + + "halt haltdef hdec hdel help hfree hinc hload hmake hop hsave ial ialclear " + + "ialmark identd if ignore iline inc invite iuser join kick linesep links list " + + "load loadbuf localinfo log mdi me menubar mkdir mnick mode msg nick noop notice " + + "notify omsg onotice part partall pdcc perform play playctrl pop protect pvoice " + + "qme qmsg query queryn quit raw reload remini remote remove rename renwin " + + "reseterror resetidle return rlevel rline rmdir run ruser save savebuf saveini " + + "say scid scon server set showmirc signam sline sockaccept sockclose socklist " + + "socklisten sockmark sockopen sockpause sockread sockrename sockudp sockwrite " + + "sound speak splay sreq strip switchbar timer timestamp titlebar tnick tokenize " + + "toolbar topic tray treebar ulist unload unset unsetall updatenl url uwho " + + "var vcadd vcmd vcrem vol while whois window winhelp write writeint if isalnum " + + "isalpha isaop isavoice isban ischan ishop isignore isin isincs isletter islower " + + "isnotify isnum ison isop isprotect isreg isupper isvoice iswm iswmcs " + + "elseif else goto menu nicklist status title icon size option text edit " + + "button check radio box scroll list combo link tab item"); var functions = parseWords("if elseif else and not or eq ne in ni for foreach while switch"); var isOperatorChar = /[+\-*&%=<>!?^\/\|]/; function chain(stream, state, f) { diff --git a/mode/perl/perl.js b/mode/perl/perl.js index 52361c6107..5954b1a61c 100644 --- a/mode/perl/perl.js +++ b/mode/perl/perl.js @@ -1,816 +1,816 @@ // CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08) // This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com) CodeMirror.defineMode("perl",function(){ - // http://perldoc.perl.org - var PERL={ // null - magic touch - // 1 - keyword - // 2 - def - // 3 - atom - // 4 - operator - // 5 - variable-2 (predefined) - // [x,y] - x=1,2,3; y=must be defined if x{...} - // PERL operators - '->' : 4, - '++' : 4, - '--' : 4, - '**' : 4, - // ! ~ \ and unary + and - - '=~' : 4, - '!~' : 4, - '*' : 4, - '/' : 4, - '%' : 4, - 'x' : 4, - '+' : 4, - '-' : 4, - '.' : 4, - '<<' : 4, - '>>' : 4, - // named unary operators - '<' : 4, - '>' : 4, - '<=' : 4, - '>=' : 4, - 'lt' : 4, - 'gt' : 4, - 'le' : 4, - 'ge' : 4, - '==' : 4, - '!=' : 4, - '<=>' : 4, - 'eq' : 4, - 'ne' : 4, - 'cmp' : 4, - '~~' : 4, - '&' : 4, - '|' : 4, - '^' : 4, - '&&' : 4, - '||' : 4, - '//' : 4, - '..' : 4, - '...' : 4, - '?' : 4, - ':' : 4, - '=' : 4, - '+=' : 4, - '-=' : 4, - '*=' : 4, // etc. ??? - ',' : 4, - '=>' : 4, - '::' : 4, - // list operators (rightward) - 'not' : 4, - 'and' : 4, - 'or' : 4, - 'xor' : 4, - // PERL predefined variables (I know, what this is a paranoid idea, but may be needed for people, who learn PERL, and for me as well, ...and may be for you?;) - 'BEGIN' : [5,1], - 'END' : [5,1], - 'PRINT' : [5,1], - 'PRINTF' : [5,1], - 'GETC' : [5,1], - 'READ' : [5,1], - 'READLINE' : [5,1], - 'DESTROY' : [5,1], - 'TIE' : [5,1], - 'TIEHANDLE' : [5,1], - 'UNTIE' : [5,1], - 'STDIN' : 5, - 'STDIN_TOP' : 5, - 'STDOUT' : 5, - 'STDOUT_TOP' : 5, - 'STDERR' : 5, - 'STDERR_TOP' : 5, - '$ARG' : 5, - '$_' : 5, - '@ARG' : 5, - '@_' : 5, - '$LIST_SEPARATOR' : 5, - '$"' : 5, - '$PROCESS_ID' : 5, - '$PID' : 5, - '$$' : 5, - '$REAL_GROUP_ID' : 5, - '$GID' : 5, - '$(' : 5, - '$EFFECTIVE_GROUP_ID' : 5, - '$EGID' : 5, - '$)' : 5, - '$PROGRAM_NAME' : 5, - '$0' : 5, - '$SUBSCRIPT_SEPARATOR' : 5, - '$SUBSEP' : 5, - '$;' : 5, - '$REAL_USER_ID' : 5, - '$UID' : 5, - '$<' : 5, - '$EFFECTIVE_USER_ID' : 5, - '$EUID' : 5, - '$>' : 5, - '$a' : 5, - '$b' : 5, - '$COMPILING' : 5, - '$^C' : 5, - '$DEBUGGING' : 5, - '$^D' : 5, - '${^ENCODING}' : 5, - '$ENV' : 5, - '%ENV' : 5, - '$SYSTEM_FD_MAX' : 5, - '$^F' : 5, - '@F' : 5, - '${^GLOBAL_PHASE}' : 5, - '$^H' : 5, - '%^H' : 5, - '@INC' : 5, - '%INC' : 5, - '$INPLACE_EDIT' : 5, - '$^I' : 5, - '$^M' : 5, - '$OSNAME' : 5, - '$^O' : 5, - '${^OPEN}' : 5, - '$PERLDB' : 5, - '$^P' : 5, - '$SIG' : 5, - '%SIG' : 5, - '$BASETIME' : 5, - '$^T' : 5, - '${^TAINT}' : 5, - '${^UNICODE}' : 5, - '${^UTF8CACHE}' : 5, - '${^UTF8LOCALE}' : 5, - '$PERL_VERSION' : 5, - '$^V' : 5, - '${^WIN32_SLOPPY_STAT}' : 5, - '$EXECUTABLE_NAME' : 5, - '$^X' : 5, - '$1' : 5, // - regexp $1, $2... - '$MATCH' : 5, - '$&' : 5, - '${^MATCH}' : 5, - '$PREMATCH' : 5, - '$`' : 5, - '${^PREMATCH}' : 5, - '$POSTMATCH' : 5, - "$'" : 5, - '${^POSTMATCH}' : 5, - '$LAST_PAREN_MATCH' : 5, - '$+' : 5, - '$LAST_SUBMATCH_RESULT' : 5, - '$^N' : 5, - '@LAST_MATCH_END' : 5, - '@+' : 5, - '%LAST_PAREN_MATCH' : 5, - '%+' : 5, - '@LAST_MATCH_START' : 5, - '@-' : 5, - '%LAST_MATCH_START' : 5, - '%-' : 5, - '$LAST_REGEXP_CODE_RESULT' : 5, - '$^R' : 5, - '${^RE_DEBUG_FLAGS}' : 5, - '${^RE_TRIE_MAXBUF}' : 5, - '$ARGV' : 5, - '@ARGV' : 5, - 'ARGV' : 5, - 'ARGVOUT' : 5, - '$OUTPUT_FIELD_SEPARATOR' : 5, - '$OFS' : 5, - '$,' : 5, - '$INPUT_LINE_NUMBER' : 5, - '$NR' : 5, - '$.' : 5, - '$INPUT_RECORD_SEPARATOR' : 5, - '$RS' : 5, - '$/' : 5, - '$OUTPUT_RECORD_SEPARATOR' : 5, - '$ORS' : 5, - '$\\' : 5, - '$OUTPUT_AUTOFLUSH' : 5, - '$|' : 5, - '$ACCUMULATOR' : 5, - '$^A' : 5, - '$FORMAT_FORMFEED' : 5, - '$^L' : 5, - '$FORMAT_PAGE_NUMBER' : 5, - '$%' : 5, - '$FORMAT_LINES_LEFT' : 5, - '$-' : 5, - '$FORMAT_LINE_BREAK_CHARACTERS' : 5, - '$:' : 5, - '$FORMAT_LINES_PER_PAGE' : 5, - '$=' : 5, - '$FORMAT_TOP_NAME' : 5, - '$^' : 5, - '$FORMAT_NAME' : 5, - '$~' : 5, - '${^CHILD_ERROR_NATIVE}' : 5, - '$EXTENDED_OS_ERROR' : 5, - '$^E' : 5, - '$EXCEPTIONS_BEING_CAUGHT' : 5, - '$^S' : 5, - '$WARNING' : 5, - '$^W' : 5, - '${^WARNING_BITS}' : 5, - '$OS_ERROR' : 5, - '$ERRNO' : 5, - '$!' : 5, - '%OS_ERROR' : 5, - '%ERRNO' : 5, - '%!' : 5, - '$CHILD_ERROR' : 5, - '$?' : 5, - '$EVAL_ERROR' : 5, - '$@' : 5, - '$OFMT' : 5, - '$#' : 5, - '$*' : 5, - '$ARRAY_BASE' : 5, - '$[' : 5, - '$OLD_PERL_VERSION' : 5, - '$]' : 5, - // PERL blocks - 'if' :[1,1], - elsif :[1,1], - 'else' :[1,1], - 'while' :[1,1], - unless :[1,1], - 'for' :[1,1], - foreach :[1,1], - // PERL functions - 'abs' :1, // - absolute value function - accept :1, // - accept an incoming socket connect - alarm :1, // - schedule a SIGALRM - 'atan2' :1, // - arctangent of Y/X in the range -PI to PI - bind :1, // - binds an address to a socket - binmode :1, // - prepare binary files for I/O - bless :1, // - create an object - bootstrap :1, // - 'break' :1, // - break out of a "given" block - caller :1, // - get context of the current subroutine call - chdir :1, // - change your current working directory - chmod :1, // - changes the permissions on a list of files - chomp :1, // - remove a trailing record separator from a string - chop :1, // - remove the last character from a string - chown :1, // - change the owership on a list of files - chr :1, // - get character this number represents - chroot :1, // - make directory new root for path lookups - close :1, // - close file (or pipe or socket) handle - closedir :1, // - close directory handle - connect :1, // - connect to a remote socket - 'continue' :[1,1], // - optional trailing block in a while or foreach - 'cos' :1, // - cosine function - crypt :1, // - one-way passwd-style encryption - dbmclose :1, // - breaks binding on a tied dbm file - dbmopen :1, // - create binding on a tied dbm file - 'default' :1, // - defined :1, // - test whether a value, variable, or function is defined - 'delete' :1, // - deletes a value from a hash - die :1, // - raise an exception or bail out - 'do' :1, // - turn a BLOCK into a TERM - dump :1, // - create an immediate core dump - each :1, // - retrieve the next key/value pair from a hash - endgrent :1, // - be done using group file - endhostent :1, // - be done using hosts file - endnetent :1, // - be done using networks file - endprotoent :1, // - be done using protocols file - endpwent :1, // - be done using passwd file - endservent :1, // - be done using services file - eof :1, // - test a filehandle for its end - 'eval' :1, // - catch exceptions or compile and run code - 'exec' :1, // - abandon this program to run another - exists :1, // - test whether a hash key is present - exit :1, // - terminate this program - 'exp' :1, // - raise I to a power - fcntl :1, // - file control system call - fileno :1, // - return file descriptor from filehandle - flock :1, // - lock an entire file with an advisory lock - fork :1, // - create a new process just like this one - format :1, // - declare a picture format with use by the write() function - formline :1, // - internal function used for formats - getc :1, // - get the next character from the filehandle - getgrent :1, // - get next group record - getgrgid :1, // - get group record given group user ID - getgrnam :1, // - get group record given group name - gethostbyaddr :1, // - get host record given its address - gethostbyname :1, // - get host record given name - gethostent :1, // - get next hosts record - getlogin :1, // - return who logged in at this tty - getnetbyaddr :1, // - get network record given its address - getnetbyname :1, // - get networks record given name - getnetent :1, // - get next networks record - getpeername :1, // - find the other end of a socket connection - getpgrp :1, // - get process group - getppid :1, // - get parent process ID - getpriority :1, // - get current nice value - getprotobyname :1, // - get protocol record given name - getprotobynumber :1, // - get protocol record numeric protocol - getprotoent :1, // - get next protocols record - getpwent :1, // - get next passwd record - getpwnam :1, // - get passwd record given user login name - getpwuid :1, // - get passwd record given user ID - getservbyname :1, // - get services record given its name - getservbyport :1, // - get services record given numeric port - getservent :1, // - get next services record - getsockname :1, // - retrieve the sockaddr for a given socket - getsockopt :1, // - get socket options on a given socket - given :1, // - glob :1, // - expand filenames using wildcards - gmtime :1, // - convert UNIX time into record or string using Greenwich time - 'goto' :1, // - create spaghetti code - grep :1, // - locate elements in a list test true against a given criterion - hex :1, // - convert a string to a hexadecimal number - 'import' :1, // - patch a module's namespace into your own - index :1, // - find a substring within a string - 'int' :1, // - get the integer portion of a number - ioctl :1, // - system-dependent device control system call - 'join' :1, // - join a list into a string using a separator - keys :1, // - retrieve list of indices from a hash - kill :1, // - send a signal to a process or process group - last :1, // - exit a block prematurely - 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 - 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 - lock :1, // - get a thread lock on a variable, subroutine, or method - 'log' :1, // - retrieve the natural logarithm for a number - lstat :1, // - stat a symbolic link - m :null, // - match a string with a regular expression pattern - map :1, // - apply a change to a list to get back a new list with the changes - mkdir :1, // - create a directory - msgctl :1, // - SysV IPC message control operations - msgget :1, // - get SysV IPC message queue - msgrcv :1, // - receive a SysV IPC message from a message queue - msgsnd :1, // - send a SysV IPC message to a message queue - my : 2, // - declare and assign a local variable (lexical scoping) - 'new' :1, // - next :1, // - iterate a block prematurely - no :1, // - unimport some module symbols or semantics at compile time - oct :1, // - convert a string to an octal number - open :1, // - open a file, pipe, or descriptor - opendir :1, // - open a directory - ord :1, // - find a character's numeric representation - our : 2, // - declare and assign a package variable (lexical scoping) - pack :1, // - convert a list into a binary representation - 'package' :1, // - declare a separate global namespace - pipe :1, // - open a pair of connected filehandles - pop :1, // - remove the last element from an array and return it - pos :1, // - find or set the offset for the last/next m//g search - print :1, // - output a list to a filehandle - printf :1, // - output a formatted list to a filehandle - prototype :1, // - get the prototype (if any) of a subroutine - push :1, // - append one or more elements to an array - q :null, // - singly quote a string - qq :null, // - doubly quote a string - qr :null, // - Compile pattern - quotemeta :null, // - quote regular expression magic characters - qw :null, // - quote a list of words - qx :null, // - backquote quote a string - rand :1, // - retrieve the next pseudorandom number - read :1, // - fixed-length buffered input from a filehandle - readdir :1, // - get a directory from a directory handle - readline :1, // - fetch a record from a file - readlink :1, // - determine where a symbolic link is pointing - readpipe :1, // - execute a system command and collect standard output - recv :1, // - receive a message over a Socket - redo :1, // - start this loop iteration over again - ref :1, // - find out the type of thing being referenced - rename :1, // - change a filename - require :1, // - load in external functions from a library at runtime - reset :1, // - clear all variables of a given name - 'return' :1, // - get out of a function early - reverse :1, // - flip a string or a list - rewinddir :1, // - reset directory handle - rindex :1, // - right-to-left substring search - rmdir :1, // - remove a directory - s :null, // - replace a pattern with a string - say :1, // - print with newline - scalar :1, // - force a scalar context - seek :1, // - reposition file pointer for random-access I/O - seekdir :1, // - reposition directory pointer - select :1, // - reset default output or do I/O multiplexing - semctl :1, // - SysV semaphore control operations - semget :1, // - get set of SysV semaphores - semop :1, // - SysV semaphore operations - send :1, // - send a message over a socket - setgrent :1, // - prepare group file for use - sethostent :1, // - prepare hosts file for use - setnetent :1, // - prepare networks file for use - setpgrp :1, // - set the process group of a process - setpriority :1, // - set a process's nice value - setprotoent :1, // - prepare protocols file for use - setpwent :1, // - prepare passwd file for use - setservent :1, // - prepare services file for use - setsockopt :1, // - set some socket options - shift :1, // - remove the first element of an array, and return it - shmctl :1, // - SysV shared memory operations - shmget :1, // - get SysV shared memory segment identifier - shmread :1, // - read SysV shared memory - shmwrite :1, // - write SysV shared memory - shutdown :1, // - close down just half of a socket connection - 'sin' :1, // - return the sine of a number - sleep :1, // - block for some number of seconds - socket :1, // - create a socket - socketpair :1, // - create a pair of sockets - 'sort' :1, // - sort a list of values - splice :1, // - add or remove elements anywhere in an array - 'split' :1, // - split up a string using a regexp delimiter - sprintf :1, // - formatted print into a string - 'sqrt' :1, // - square root function - srand :1, // - seed the random number generator - stat :1, // - get a file's status information - 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 - symlink :1, // - create a symbolic link to a file - syscall :1, // - execute an arbitrary system call - sysopen :1, // - open a file, pipe, or descriptor - sysread :1, // - fixed-length unbuffered input from a filehandle - sysseek :1, // - position I/O pointer on handle used with sysread and syswrite - system :1, // - run a separate program - syswrite :1, // - fixed-length unbuffered output to a filehandle - tell :1, // - get current seekpointer on a filehandle - telldir :1, // - get current seekpointer on a directory handle - tie :1, // - bind a variable to an object class - tied :1, // - get a reference to the object underlying a tied variable - time :1, // - return number of seconds since 1970 - times :1, // - return elapsed time for self and child processes - tr :null, // - transliterate a string - truncate :1, // - shorten a file - uc :1, // - return upper-case version of a string - ucfirst :1, // - return a string with just the next letter in upper case - umask :1, // - set file creation mode mask - undef :1, // - remove a variable or function definition - unlink :1, // - remove one link to a file - unpack :1, // - convert binary structure into normal perl variables - unshift :1, // - prepend more elements to the beginning of a list - untie :1, // - break a tie binding to a variable - use :1, // - load in a module at compile time - utime :1, // - set a file's last access and modify times - values :1, // - return a list of the values in a hash - vec :1, // - test or set particular bits in a string - wait :1, // - wait for any child process to die - waitpid :1, // - wait for a particular child process to die - wantarray :1, // - get void vs scalar vs list context of current subroutine call - warn :1, // - print debugging info - when :1, // - write :1, // - print a picture record - y :null}; // - transliterate a string + // http://perldoc.perl.org + var PERL={ // null - magic touch + // 1 - keyword + // 2 - def + // 3 - atom + // 4 - operator + // 5 - variable-2 (predefined) + // [x,y] - x=1,2,3; y=must be defined if x{...} + // PERL operators + '->' : 4, + '++' : 4, + '--' : 4, + '**' : 4, + // ! ~ \ and unary + and - + '=~' : 4, + '!~' : 4, + '*' : 4, + '/' : 4, + '%' : 4, + 'x' : 4, + '+' : 4, + '-' : 4, + '.' : 4, + '<<' : 4, + '>>' : 4, + // named unary operators + '<' : 4, + '>' : 4, + '<=' : 4, + '>=' : 4, + 'lt' : 4, + 'gt' : 4, + 'le' : 4, + 'ge' : 4, + '==' : 4, + '!=' : 4, + '<=>' : 4, + 'eq' : 4, + 'ne' : 4, + 'cmp' : 4, + '~~' : 4, + '&' : 4, + '|' : 4, + '^' : 4, + '&&' : 4, + '||' : 4, + '//' : 4, + '..' : 4, + '...' : 4, + '?' : 4, + ':' : 4, + '=' : 4, + '+=' : 4, + '-=' : 4, + '*=' : 4, // etc. ??? + ',' : 4, + '=>' : 4, + '::' : 4, + // list operators (rightward) + 'not' : 4, + 'and' : 4, + 'or' : 4, + 'xor' : 4, + // PERL predefined variables (I know, what this is a paranoid idea, but may be needed for people, who learn PERL, and for me as well, ...and may be for you?;) + 'BEGIN' : [5,1], + 'END' : [5,1], + 'PRINT' : [5,1], + 'PRINTF' : [5,1], + 'GETC' : [5,1], + 'READ' : [5,1], + 'READLINE' : [5,1], + 'DESTROY' : [5,1], + 'TIE' : [5,1], + 'TIEHANDLE' : [5,1], + 'UNTIE' : [5,1], + 'STDIN' : 5, + 'STDIN_TOP' : 5, + 'STDOUT' : 5, + 'STDOUT_TOP' : 5, + 'STDERR' : 5, + 'STDERR_TOP' : 5, + '$ARG' : 5, + '$_' : 5, + '@ARG' : 5, + '@_' : 5, + '$LIST_SEPARATOR' : 5, + '$"' : 5, + '$PROCESS_ID' : 5, + '$PID' : 5, + '$$' : 5, + '$REAL_GROUP_ID' : 5, + '$GID' : 5, + '$(' : 5, + '$EFFECTIVE_GROUP_ID' : 5, + '$EGID' : 5, + '$)' : 5, + '$PROGRAM_NAME' : 5, + '$0' : 5, + '$SUBSCRIPT_SEPARATOR' : 5, + '$SUBSEP' : 5, + '$;' : 5, + '$REAL_USER_ID' : 5, + '$UID' : 5, + '$<' : 5, + '$EFFECTIVE_USER_ID' : 5, + '$EUID' : 5, + '$>' : 5, + '$a' : 5, + '$b' : 5, + '$COMPILING' : 5, + '$^C' : 5, + '$DEBUGGING' : 5, + '$^D' : 5, + '${^ENCODING}' : 5, + '$ENV' : 5, + '%ENV' : 5, + '$SYSTEM_FD_MAX' : 5, + '$^F' : 5, + '@F' : 5, + '${^GLOBAL_PHASE}' : 5, + '$^H' : 5, + '%^H' : 5, + '@INC' : 5, + '%INC' : 5, + '$INPLACE_EDIT' : 5, + '$^I' : 5, + '$^M' : 5, + '$OSNAME' : 5, + '$^O' : 5, + '${^OPEN}' : 5, + '$PERLDB' : 5, + '$^P' : 5, + '$SIG' : 5, + '%SIG' : 5, + '$BASETIME' : 5, + '$^T' : 5, + '${^TAINT}' : 5, + '${^UNICODE}' : 5, + '${^UTF8CACHE}' : 5, + '${^UTF8LOCALE}' : 5, + '$PERL_VERSION' : 5, + '$^V' : 5, + '${^WIN32_SLOPPY_STAT}' : 5, + '$EXECUTABLE_NAME' : 5, + '$^X' : 5, + '$1' : 5, // - regexp $1, $2... + '$MATCH' : 5, + '$&' : 5, + '${^MATCH}' : 5, + '$PREMATCH' : 5, + '$`' : 5, + '${^PREMATCH}' : 5, + '$POSTMATCH' : 5, + "$'" : 5, + '${^POSTMATCH}' : 5, + '$LAST_PAREN_MATCH' : 5, + '$+' : 5, + '$LAST_SUBMATCH_RESULT' : 5, + '$^N' : 5, + '@LAST_MATCH_END' : 5, + '@+' : 5, + '%LAST_PAREN_MATCH' : 5, + '%+' : 5, + '@LAST_MATCH_START' : 5, + '@-' : 5, + '%LAST_MATCH_START' : 5, + '%-' : 5, + '$LAST_REGEXP_CODE_RESULT' : 5, + '$^R' : 5, + '${^RE_DEBUG_FLAGS}' : 5, + '${^RE_TRIE_MAXBUF}' : 5, + '$ARGV' : 5, + '@ARGV' : 5, + 'ARGV' : 5, + 'ARGVOUT' : 5, + '$OUTPUT_FIELD_SEPARATOR' : 5, + '$OFS' : 5, + '$,' : 5, + '$INPUT_LINE_NUMBER' : 5, + '$NR' : 5, + '$.' : 5, + '$INPUT_RECORD_SEPARATOR' : 5, + '$RS' : 5, + '$/' : 5, + '$OUTPUT_RECORD_SEPARATOR' : 5, + '$ORS' : 5, + '$\\' : 5, + '$OUTPUT_AUTOFLUSH' : 5, + '$|' : 5, + '$ACCUMULATOR' : 5, + '$^A' : 5, + '$FORMAT_FORMFEED' : 5, + '$^L' : 5, + '$FORMAT_PAGE_NUMBER' : 5, + '$%' : 5, + '$FORMAT_LINES_LEFT' : 5, + '$-' : 5, + '$FORMAT_LINE_BREAK_CHARACTERS' : 5, + '$:' : 5, + '$FORMAT_LINES_PER_PAGE' : 5, + '$=' : 5, + '$FORMAT_TOP_NAME' : 5, + '$^' : 5, + '$FORMAT_NAME' : 5, + '$~' : 5, + '${^CHILD_ERROR_NATIVE}' : 5, + '$EXTENDED_OS_ERROR' : 5, + '$^E' : 5, + '$EXCEPTIONS_BEING_CAUGHT' : 5, + '$^S' : 5, + '$WARNING' : 5, + '$^W' : 5, + '${^WARNING_BITS}' : 5, + '$OS_ERROR' : 5, + '$ERRNO' : 5, + '$!' : 5, + '%OS_ERROR' : 5, + '%ERRNO' : 5, + '%!' : 5, + '$CHILD_ERROR' : 5, + '$?' : 5, + '$EVAL_ERROR' : 5, + '$@' : 5, + '$OFMT' : 5, + '$#' : 5, + '$*' : 5, + '$ARRAY_BASE' : 5, + '$[' : 5, + '$OLD_PERL_VERSION' : 5, + '$]' : 5, + // PERL blocks + 'if' :[1,1], + elsif :[1,1], + 'else' :[1,1], + 'while' :[1,1], + unless :[1,1], + 'for' :[1,1], + foreach :[1,1], + // PERL functions + 'abs' :1, // - absolute value function + accept :1, // - accept an incoming socket connect + alarm :1, // - schedule a SIGALRM + 'atan2' :1, // - arctangent of Y/X in the range -PI to PI + bind :1, // - binds an address to a socket + binmode :1, // - prepare binary files for I/O + bless :1, // - create an object + bootstrap :1, // + 'break' :1, // - break out of a "given" block + caller :1, // - get context of the current subroutine call + chdir :1, // - change your current working directory + chmod :1, // - changes the permissions on a list of files + chomp :1, // - remove a trailing record separator from a string + chop :1, // - remove the last character from a string + chown :1, // - change the owership on a list of files + chr :1, // - get character this number represents + chroot :1, // - make directory new root for path lookups + close :1, // - close file (or pipe or socket) handle + closedir :1, // - close directory handle + connect :1, // - connect to a remote socket + 'continue' :[1,1], // - optional trailing block in a while or foreach + 'cos' :1, // - cosine function + crypt :1, // - one-way passwd-style encryption + dbmclose :1, // - breaks binding on a tied dbm file + dbmopen :1, // - create binding on a tied dbm file + 'default' :1, // + defined :1, // - test whether a value, variable, or function is defined + 'delete' :1, // - deletes a value from a hash + die :1, // - raise an exception or bail out + 'do' :1, // - turn a BLOCK into a TERM + dump :1, // - create an immediate core dump + each :1, // - retrieve the next key/value pair from a hash + endgrent :1, // - be done using group file + endhostent :1, // - be done using hosts file + endnetent :1, // - be done using networks file + endprotoent :1, // - be done using protocols file + endpwent :1, // - be done using passwd file + endservent :1, // - be done using services file + eof :1, // - test a filehandle for its end + 'eval' :1, // - catch exceptions or compile and run code + 'exec' :1, // - abandon this program to run another + exists :1, // - test whether a hash key is present + exit :1, // - terminate this program + 'exp' :1, // - raise I to a power + fcntl :1, // - file control system call + fileno :1, // - return file descriptor from filehandle + flock :1, // - lock an entire file with an advisory lock + fork :1, // - create a new process just like this one + format :1, // - declare a picture format with use by the write() function + formline :1, // - internal function used for formats + getc :1, // - get the next character from the filehandle + getgrent :1, // - get next group record + getgrgid :1, // - get group record given group user ID + getgrnam :1, // - get group record given group name + gethostbyaddr :1, // - get host record given its address + gethostbyname :1, // - get host record given name + gethostent :1, // - get next hosts record + getlogin :1, // - return who logged in at this tty + getnetbyaddr :1, // - get network record given its address + getnetbyname :1, // - get networks record given name + getnetent :1, // - get next networks record + getpeername :1, // - find the other end of a socket connection + getpgrp :1, // - get process group + getppid :1, // - get parent process ID + getpriority :1, // - get current nice value + getprotobyname :1, // - get protocol record given name + getprotobynumber :1, // - get protocol record numeric protocol + getprotoent :1, // - get next protocols record + getpwent :1, // - get next passwd record + getpwnam :1, // - get passwd record given user login name + getpwuid :1, // - get passwd record given user ID + getservbyname :1, // - get services record given its name + getservbyport :1, // - get services record given numeric port + getservent :1, // - get next services record + getsockname :1, // - retrieve the sockaddr for a given socket + getsockopt :1, // - get socket options on a given socket + given :1, // + glob :1, // - expand filenames using wildcards + gmtime :1, // - convert UNIX time into record or string using Greenwich time + 'goto' :1, // - create spaghetti code + grep :1, // - locate elements in a list test true against a given criterion + hex :1, // - convert a string to a hexadecimal number + 'import' :1, // - patch a module's namespace into your own + index :1, // - find a substring within a string + 'int' :1, // - get the integer portion of a number + ioctl :1, // - system-dependent device control system call + 'join' :1, // - join a list into a string using a separator + keys :1, // - retrieve list of indices from a hash + kill :1, // - send a signal to a process or process group + last :1, // - exit a block prematurely + 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 + 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 + lock :1, // - get a thread lock on a variable, subroutine, or method + 'log' :1, // - retrieve the natural logarithm for a number + lstat :1, // - stat a symbolic link + m :null, // - match a string with a regular expression pattern + map :1, // - apply a change to a list to get back a new list with the changes + mkdir :1, // - create a directory + msgctl :1, // - SysV IPC message control operations + msgget :1, // - get SysV IPC message queue + msgrcv :1, // - receive a SysV IPC message from a message queue + msgsnd :1, // - send a SysV IPC message to a message queue + my : 2, // - declare and assign a local variable (lexical scoping) + 'new' :1, // + next :1, // - iterate a block prematurely + no :1, // - unimport some module symbols or semantics at compile time + oct :1, // - convert a string to an octal number + open :1, // - open a file, pipe, or descriptor + opendir :1, // - open a directory + ord :1, // - find a character's numeric representation + our : 2, // - declare and assign a package variable (lexical scoping) + pack :1, // - convert a list into a binary representation + 'package' :1, // - declare a separate global namespace + pipe :1, // - open a pair of connected filehandles + pop :1, // - remove the last element from an array and return it + pos :1, // - find or set the offset for the last/next m//g search + print :1, // - output a list to a filehandle + printf :1, // - output a formatted list to a filehandle + prototype :1, // - get the prototype (if any) of a subroutine + push :1, // - append one or more elements to an array + q :null, // - singly quote a string + qq :null, // - doubly quote a string + qr :null, // - Compile pattern + quotemeta :null, // - quote regular expression magic characters + qw :null, // - quote a list of words + qx :null, // - backquote quote a string + rand :1, // - retrieve the next pseudorandom number + read :1, // - fixed-length buffered input from a filehandle + readdir :1, // - get a directory from a directory handle + readline :1, // - fetch a record from a file + readlink :1, // - determine where a symbolic link is pointing + readpipe :1, // - execute a system command and collect standard output + recv :1, // - receive a message over a Socket + redo :1, // - start this loop iteration over again + ref :1, // - find out the type of thing being referenced + rename :1, // - change a filename + require :1, // - load in external functions from a library at runtime + reset :1, // - clear all variables of a given name + 'return' :1, // - get out of a function early + reverse :1, // - flip a string or a list + rewinddir :1, // - reset directory handle + rindex :1, // - right-to-left substring search + rmdir :1, // - remove a directory + s :null, // - replace a pattern with a string + say :1, // - print with newline + scalar :1, // - force a scalar context + seek :1, // - reposition file pointer for random-access I/O + seekdir :1, // - reposition directory pointer + select :1, // - reset default output or do I/O multiplexing + semctl :1, // - SysV semaphore control operations + semget :1, // - get set of SysV semaphores + semop :1, // - SysV semaphore operations + send :1, // - send a message over a socket + setgrent :1, // - prepare group file for use + sethostent :1, // - prepare hosts file for use + setnetent :1, // - prepare networks file for use + setpgrp :1, // - set the process group of a process + setpriority :1, // - set a process's nice value + setprotoent :1, // - prepare protocols file for use + setpwent :1, // - prepare passwd file for use + setservent :1, // - prepare services file for use + setsockopt :1, // - set some socket options + shift :1, // - remove the first element of an array, and return it + shmctl :1, // - SysV shared memory operations + shmget :1, // - get SysV shared memory segment identifier + shmread :1, // - read SysV shared memory + shmwrite :1, // - write SysV shared memory + shutdown :1, // - close down just half of a socket connection + 'sin' :1, // - return the sine of a number + sleep :1, // - block for some number of seconds + socket :1, // - create a socket + socketpair :1, // - create a pair of sockets + 'sort' :1, // - sort a list of values + splice :1, // - add or remove elements anywhere in an array + 'split' :1, // - split up a string using a regexp delimiter + sprintf :1, // - formatted print into a string + 'sqrt' :1, // - square root function + srand :1, // - seed the random number generator + stat :1, // - get a file's status information + 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 + symlink :1, // - create a symbolic link to a file + syscall :1, // - execute an arbitrary system call + sysopen :1, // - open a file, pipe, or descriptor + sysread :1, // - fixed-length unbuffered input from a filehandle + sysseek :1, // - position I/O pointer on handle used with sysread and syswrite + system :1, // - run a separate program + syswrite :1, // - fixed-length unbuffered output to a filehandle + tell :1, // - get current seekpointer on a filehandle + telldir :1, // - get current seekpointer on a directory handle + tie :1, // - bind a variable to an object class + tied :1, // - get a reference to the object underlying a tied variable + time :1, // - return number of seconds since 1970 + times :1, // - return elapsed time for self and child processes + tr :null, // - transliterate a string + truncate :1, // - shorten a file + uc :1, // - return upper-case version of a string + ucfirst :1, // - return a string with just the next letter in upper case + umask :1, // - set file creation mode mask + undef :1, // - remove a variable or function definition + unlink :1, // - remove one link to a file + unpack :1, // - convert binary structure into normal perl variables + unshift :1, // - prepend more elements to the beginning of a list + untie :1, // - break a tie binding to a variable + use :1, // - load in a module at compile time + utime :1, // - set a file's last access and modify times + values :1, // - return a list of the values in a hash + vec :1, // - test or set particular bits in a string + wait :1, // - wait for any child process to die + waitpid :1, // - wait for a particular child process to die + wantarray :1, // - get void vs scalar vs list context of current subroutine call + warn :1, // - print debugging info + when :1, // + write :1, // - print a picture record + y :null}; // - transliterate a string - var RXstyle="string-2"; - var RXmodifiers=/[goseximacplud]/; // NOTE: "m", "s", "y" and "tr" need to correct real modifiers for each regexp type + var RXstyle="string-2"; + var RXmodifiers=/[goseximacplud]/; // NOTE: "m", "s", "y" and "tr" need to correct real modifiers for each regexp type - function tokenChain(stream,state,chain,style,tail){ // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;) - state.chain=null; // 12 3tail - state.style=null; - state.tail=null; - state.tokenize=function(stream,state){ - var e=false,c,i=0; - while(c=stream.next()){ - if(c===chain[i]&&!e){ - if(chain[++i]!==undefined){ - state.chain=chain[i]; - state.style=style; - state.tail=tail;} - else if(tail) - stream.eatWhile(tail); - state.tokenize=tokenPerl; - return style;} - e=!e&&c=="\\";} - return style;}; - return state.tokenize(stream,state);} + function tokenChain(stream,state,chain,style,tail){ // NOTE: chain.length > 2 is not working now (it's for s[...][...]geos;) + state.chain=null; // 12 3tail + state.style=null; + state.tail=null; + state.tokenize=function(stream,state){ + var e=false,c,i=0; + while(c=stream.next()){ + if(c===chain[i]&&!e){ + if(chain[++i]!==undefined){ + state.chain=chain[i]; + state.style=style; + state.tail=tail;} + else if(tail) + stream.eatWhile(tail); + state.tokenize=tokenPerl; + return style;} + e=!e&&c=="\\";} + return style;}; + return state.tokenize(stream,state);} - function tokenSOMETHING(stream,state,string){ - state.tokenize=function(stream,state){ - if(stream.string==string) - state.tokenize=tokenPerl; - stream.skipToEnd(); - return "string";}; - return state.tokenize(stream,state);} + function tokenSOMETHING(stream,state,string){ + state.tokenize=function(stream,state){ + if(stream.string==string) + state.tokenize=tokenPerl; + stream.skipToEnd(); + return "string";}; + return state.tokenize(stream,state);} - function tokenPerl(stream,state){ - if(stream.eatSpace()) - return null; - if(state.chain) - return tokenChain(stream,state,state.chain,state.style,state.tail); - 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: <"],RXstyle,RXmodifiers);} - if(/[\^'"!~\/]/.test(c)){ - stream.eatSuffix(1); - return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}} - else if(c=="q"){ - c=stream.look(1); - if(c=="("){ - stream.eatSuffix(2); - return tokenChain(stream,state,[")"],"string");} - if(c=="["){ - stream.eatSuffix(2); - return tokenChain(stream,state,["]"],"string");} - if(c=="{"){ - stream.eatSuffix(2); - return tokenChain(stream,state,["}"],"string");} - if(c=="<"){ - stream.eatSuffix(2); - return tokenChain(stream,state,[">"],"string");} - if(/[\^'"!~\/]/.test(c)){ - stream.eatSuffix(1); - return tokenChain(stream,state,[stream.eat(c)],"string");}} - else if(c=="w"){ - c=stream.look(1); - if(c=="("){ - stream.eatSuffix(2); - return tokenChain(stream,state,[")"],"bracket");} - if(c=="["){ - stream.eatSuffix(2); - return tokenChain(stream,state,["]"],"bracket");} - if(c=="{"){ - stream.eatSuffix(2); - return tokenChain(stream,state,["}"],"bracket");} - if(c=="<"){ - stream.eatSuffix(2); - return tokenChain(stream,state,[">"],"bracket");} - if(/[\^'"!~\/]/.test(c)){ - stream.eatSuffix(1); - return tokenChain(stream,state,[stream.eat(c)],"bracket");}} - else if(c=="r"){ - c=stream.look(1); - if(c=="("){ - stream.eatSuffix(2); - return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);} - if(c=="["){ - stream.eatSuffix(2); - return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);} - if(c=="{"){ - stream.eatSuffix(2); - return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);} - if(c=="<"){ - stream.eatSuffix(2); - return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);} - if(/[\^'"!~\/]/.test(c)){ - stream.eatSuffix(1); - return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}} - else if(/[\^'"!~\/(\[{<]/.test(c)){ - if(c=="("){ - stream.eatSuffix(1); - return tokenChain(stream,state,[")"],"string");} - if(c=="["){ - stream.eatSuffix(1); - return tokenChain(stream,state,["]"],"string");} - if(c=="{"){ - stream.eatSuffix(1); - return tokenChain(stream,state,["}"],"string");} - if(c=="<"){ - stream.eatSuffix(1); - return tokenChain(stream,state,[">"],"string");} - if(/[\^'"!~\/]/.test(c)){ - return tokenChain(stream,state,[stream.eat(c)],"string");}}}} - if(ch=="m"){ - var c=stream.look(-2); - if(!(c&&/\w/.test(c))){ - c=stream.eat(/[(\[{<\^'"!~\/]/); - if(c){ - if(/[\^'"!~\/]/.test(c)){ - return tokenChain(stream,state,[c],RXstyle,RXmodifiers);} - if(c=="("){ - return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);} - if(c=="["){ - return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);} - if(c=="{"){ - return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);} - if(c=="<"){ - return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}}}} - if(ch=="s"){ - var c=/[\/>\]})\w]/.test(stream.look(-2)); - if(!c){ - c=stream.eat(/[(\[{<\^'"!~\/]/); - if(c){ - if(c=="[") - return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers); - if(c=="{") - return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers); - if(c=="<") - return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers); - if(c=="(") - return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers); - return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}} - if(ch=="y"){ - var c=/[\/>\]})\w]/.test(stream.look(-2)); - if(!c){ - c=stream.eat(/[(\[{<\^'"!~\/]/); - if(c){ - if(c=="[") - return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers); - if(c=="{") - return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers); - if(c=="<") - return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers); - if(c=="(") - return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers); - return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}} - if(ch=="t"){ - var c=/[\/>\]})\w]/.test(stream.look(-2)); - if(!c){ - c=stream.eat("r");if(c){ - c=stream.eat(/[(\[{<\^'"!~\/]/); - if(c){ - if(c=="[") - return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers); - if(c=="{") - return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers); - if(c=="<") - return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers); - if(c=="(") - return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers); - return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}} - if(ch=="`"){ - return tokenChain(stream,state,[ch],"variable-2");} - if(ch=="/"){ - if(!/~\s*$/.test(stream.prefix())) - return "operator"; - else - return tokenChain(stream,state,[ch],RXstyle,RXmodifiers);} - if(ch=="$"){ - var p=stream.pos; - if(stream.eatWhile(/\d/)||stream.eat("{")&&stream.eatWhile(/\d/)&&stream.eat("}")) - return "variable-2"; - else - stream.pos=p;} - if(/[$@%]/.test(ch)){ - var p=stream.pos; - if(stream.eat("^")&&stream.eat(/[A-Z]/)||!/[@$%&]/.test(stream.look(-2))&&stream.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){ - var c=stream.current(); - if(PERL[c]) - return "variable-2";} - stream.pos=p;} - if(/[$@%&]/.test(ch)){ - if(stream.eatWhile(/[\w$\[\]]/)||stream.eat("{")&&stream.eatWhile(/[\w$\[\]]/)&&stream.eat("}")){ - var c=stream.current(); - if(PERL[c]) - return "variable-2"; - else - return "variable";}} - if(ch=="#"){ - if(stream.look(-2)!="$"){ - stream.skipToEnd(); - return "comment";}} - if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(ch)){ - var p=stream.pos; - stream.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/); - if(PERL[stream.current()]) - return "operator"; - else - stream.pos=p;} - if(ch=="_"){ - if(stream.pos==1){ - if(stream.suffix(6)=="_END__"){ - return tokenChain(stream,state,['\0'],"comment");} - else if(stream.suffix(7)=="_DATA__"){ - return tokenChain(stream,state,['\0'],"variable-2");} - else if(stream.suffix(7)=="_C__"){ - return tokenChain(stream,state,['\0'],"string");}}} - if(/\w/.test(ch)){ - var p=stream.pos; - if(stream.look(-2)=="{"&&(stream.look(0)=="}"||stream.eatWhile(/\w/)&&stream.look(0)=="}")) - return "string"; - else - stream.pos=p;} - if(/[A-Z]/.test(ch)){ - var l=stream.look(-2); - var p=stream.pos; - stream.eatWhile(/[A-Z_]/); - if(/[\da-z]/.test(stream.look(0))){ - stream.pos=p;} - else{ - var c=PERL[stream.current()]; - if(!c) - return "meta"; - if(c[1]) - c=c[0]; - if(l!=":"){ - if(c==1) - return "keyword"; - else if(c==2) - return "def"; - else if(c==3) - return "atom"; - else if(c==4) - return "operator"; - else if(c==5) - return "variable-2"; - else - return "meta";} - else - return "meta";}} - if(/[a-zA-Z_]/.test(ch)){ - var l=stream.look(-2); - stream.eatWhile(/\w/); - var c=PERL[stream.current()]; - if(!c) - return "meta"; - if(c[1]) - c=c[0]; - if(l!=":"){ - if(c==1) - return "keyword"; - else if(c==2) - return "def"; - else if(c==3) - return "atom"; - else if(c==4) - return "operator"; - else if(c==5) - return "variable-2"; - else - return "meta";} - else - return "meta";} - return null;} + function tokenPerl(stream,state){ + if(stream.eatSpace()) + return null; + if(state.chain) + return tokenChain(stream,state,state.chain,state.style,state.tail); + 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: <"],RXstyle,RXmodifiers);} + if(/[\^'"!~\/]/.test(c)){ + stream.eatSuffix(1); + return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}} + else if(c=="q"){ + c=stream.look(1); + if(c=="("){ + stream.eatSuffix(2); + return tokenChain(stream,state,[")"],"string");} + if(c=="["){ + stream.eatSuffix(2); + return tokenChain(stream,state,["]"],"string");} + if(c=="{"){ +stream.eatSuffix(2); + return tokenChain(stream,state,["}"],"string");} + if(c=="<"){ + stream.eatSuffix(2); + return tokenChain(stream,state,[">"],"string");} + if(/[\^'"!~\/]/.test(c)){ + stream.eatSuffix(1); + return tokenChain(stream,state,[stream.eat(c)],"string");}} + else if(c=="w"){ + c=stream.look(1); + if(c=="("){ + stream.eatSuffix(2); + return tokenChain(stream,state,[")"],"bracket");} + if(c=="["){ + stream.eatSuffix(2); + return tokenChain(stream,state,["]"],"bracket");} + if(c=="{"){ + stream.eatSuffix(2); + return tokenChain(stream,state,["}"],"bracket");} + if(c=="<"){ + stream.eatSuffix(2); + return tokenChain(stream,state,[">"],"bracket");} + if(/[\^'"!~\/]/.test(c)){ + stream.eatSuffix(1); + return tokenChain(stream,state,[stream.eat(c)],"bracket");}} + else if(c=="r"){ + c=stream.look(1); + if(c=="("){ + stream.eatSuffix(2); + return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);} + if(c=="["){ + stream.eatSuffix(2); + return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);} + if(c=="{"){ + stream.eatSuffix(2); + return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);} + if(c=="<"){ + stream.eatSuffix(2); + return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);} + if(/[\^'"!~\/]/.test(c)){ + stream.eatSuffix(1); + return tokenChain(stream,state,[stream.eat(c)],RXstyle,RXmodifiers);}} + else if(/[\^'"!~\/(\[{<]/.test(c)){ + if(c=="("){ + stream.eatSuffix(1); + return tokenChain(stream,state,[")"],"string");} + if(c=="["){ + stream.eatSuffix(1); + return tokenChain(stream,state,["]"],"string");} + if(c=="{"){ + stream.eatSuffix(1); + return tokenChain(stream,state,["}"],"string");} + if(c=="<"){ + stream.eatSuffix(1); + return tokenChain(stream,state,[">"],"string");} + if(/[\^'"!~\/]/.test(c)){ + return tokenChain(stream,state,[stream.eat(c)],"string");}}}} + if(ch=="m"){ + var c=stream.look(-2); + if(!(c&&/\w/.test(c))){ + c=stream.eat(/[(\[{<\^'"!~\/]/); + if(c){ + if(/[\^'"!~\/]/.test(c)){ + return tokenChain(stream,state,[c],RXstyle,RXmodifiers);} + if(c=="("){ + return tokenChain(stream,state,[")"],RXstyle,RXmodifiers);} + if(c=="["){ + return tokenChain(stream,state,["]"],RXstyle,RXmodifiers);} + if(c=="{"){ + return tokenChain(stream,state,["}"],RXstyle,RXmodifiers);} + if(c=="<"){ + return tokenChain(stream,state,[">"],RXstyle,RXmodifiers);}}}} + if(ch=="s"){ + var c=/[\/>\]})\w]/.test(stream.look(-2)); + if(!c){ + c=stream.eat(/[(\[{<\^'"!~\/]/); + if(c){ + if(c=="[") + return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers); + if(c=="{") + return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers); + if(c=="<") + return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers); + if(c=="(") + return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers); + return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}} + if(ch=="y"){ + var c=/[\/>\]})\w]/.test(stream.look(-2)); + if(!c){ + c=stream.eat(/[(\[{<\^'"!~\/]/); + if(c){ + if(c=="[") + return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers); + if(c=="{") + return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers); + if(c=="<") + return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers); + if(c=="(") + return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers); + return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}} + if(ch=="t"){ + var c=/[\/>\]})\w]/.test(stream.look(-2)); + if(!c){ + c=stream.eat("r");if(c){ + c=stream.eat(/[(\[{<\^'"!~\/]/); + if(c){ + if(c=="[") + return tokenChain(stream,state,["]","]"],RXstyle,RXmodifiers); + if(c=="{") + return tokenChain(stream,state,["}","}"],RXstyle,RXmodifiers); + if(c=="<") + return tokenChain(stream,state,[">",">"],RXstyle,RXmodifiers); + if(c=="(") + return tokenChain(stream,state,[")",")"],RXstyle,RXmodifiers); + return tokenChain(stream,state,[c,c],RXstyle,RXmodifiers);}}}} + if(ch=="`"){ + return tokenChain(stream,state,[ch],"variable-2");} + if(ch=="/"){ + if(!/~\s*$/.test(stream.prefix())) + return "operator"; + else + return tokenChain(stream,state,[ch],RXstyle,RXmodifiers);} + if(ch=="$"){ + var p=stream.pos; + if(stream.eatWhile(/\d/)||stream.eat("{")&&stream.eatWhile(/\d/)&&stream.eat("}")) + return "variable-2"; + else + stream.pos=p;} + if(/[$@%]/.test(ch)){ + var p=stream.pos; + if(stream.eat("^")&&stream.eat(/[A-Z]/)||!/[@$%&]/.test(stream.look(-2))&&stream.eat(/[=|\\\-#?@;:&`~\^!\[\]*'"$+.,\/<>()]/)){ + var c=stream.current(); + if(PERL[c]) + return "variable-2";} + stream.pos=p;} + if(/[$@%&]/.test(ch)){ + if(stream.eatWhile(/[\w$\[\]]/)||stream.eat("{")&&stream.eatWhile(/[\w$\[\]]/)&&stream.eat("}")){ + var c=stream.current(); + if(PERL[c]) + return "variable-2"; + else + return "variable";}} + if(ch=="#"){ + if(stream.look(-2)!="$"){ + stream.skipToEnd(); + return "comment";}} + if(/[:+\-\^*$&%@=<>!?|\/~\.]/.test(ch)){ + var p=stream.pos; + stream.eatWhile(/[:+\-\^*$&%@=<>!?|\/~\.]/); + if(PERL[stream.current()]) + return "operator"; + else + stream.pos=p;} + if(ch=="_"){ + if(stream.pos==1){ + if(stream.suffix(6)=="_END__"){ + return tokenChain(stream,state,['\0'],"comment");} + else if(stream.suffix(7)=="_DATA__"){ + return tokenChain(stream,state,['\0'],"variable-2");} + else if(stream.suffix(7)=="_C__"){ + return tokenChain(stream,state,['\0'],"string");}}} + if(/\w/.test(ch)){ + var p=stream.pos; + if(stream.look(-2)=="{"&&(stream.look(0)=="}"||stream.eatWhile(/\w/)&&stream.look(0)=="}")) + return "string"; + else + stream.pos=p;} + if(/[A-Z]/.test(ch)){ + var l=stream.look(-2); + var p=stream.pos; + stream.eatWhile(/[A-Z_]/); + if(/[\da-z]/.test(stream.look(0))){ + stream.pos=p;} + else{ + var c=PERL[stream.current()]; + if(!c) + return "meta"; + if(c[1]) + c=c[0]; + if(l!=":"){ + if(c==1) + return "keyword"; + else if(c==2) + return "def"; + else if(c==3) + return "atom"; + else if(c==4) + return "operator"; + else if(c==5) + return "variable-2"; + else + return "meta";} + else + return "meta";}} + if(/[a-zA-Z_]/.test(ch)){ + var l=stream.look(-2); + stream.eatWhile(/\w/); + var c=PERL[stream.current()]; + if(!c) + return "meta"; + if(c[1]) + c=c[0]; + if(l!=":"){ + if(c==1) + return "keyword"; + else if(c==2) + return "def"; + else if(c==3) + return "atom"; + else if(c==4) + return "operator"; + else if(c==5) + return "variable-2"; + else + return "meta";} + else + return "meta";} + return null;} - return{ - startState:function(){ - return{ - tokenize:tokenPerl, - chain:null, - style:null, - tail:null};}, - token:function(stream,state){ - return (state.tokenize||tokenPerl)(stream,state);}, - electricChars:"{}"};}); + return{ + startState:function(){ + return{ + tokenize:tokenPerl, + chain:null, + style:null, + tail:null};}, + token:function(stream,state){ + return (state.tokenize||tokenPerl)(stream,state);}, + electricChars:"{}"};}); CodeMirror.defineMIME("text/x-perl", "perl"); // it's like "peek", but need for look-ahead or look-behind if index < 0 CodeMirror.StringStream.prototype.look=function(c){ - return this.string.charAt(this.pos+(c||0));}; + return this.string.charAt(this.pos+(c||0));}; // return a part of prefix of current stream from current position CodeMirror.StringStream.prototype.prefix=function(c){ - if(c){ - var x=this.pos-c; - return this.string.substr((x>=0?x:0),c);} - else{ - return this.string.substr(0,this.pos-1);}}; + if(c){ + var x=this.pos-c; + return this.string.substr((x>=0?x:0),c);} + else{ + return this.string.substr(0,this.pos-1);}}; // return a part of suffix of current stream from current position CodeMirror.StringStream.prototype.suffix=function(c){ - var y=this.string.length; - var x=y-this.pos+1; - return this.string.substr(this.pos,(c&&c=(y=this.string.length-1)) - this.pos=y; - else - this.pos=x;}; + var x=this.pos+c; + var y; + if(x<=0) + this.pos=0; + else if(x>=(y=this.string.length-1)) + this.pos=y; + else + this.pos=x;}; diff --git a/mode/pig/pig.js b/mode/pig/pig.js index f8818a9b66..c2f611a1a0 100644 --- a/mode/pig/pig.js +++ b/mode/pig/pig.js @@ -1,171 +1,171 @@ /* - * Pig Latin Mode for CodeMirror 2 - * @author Prasanth Jayachandran - * @link https://github.com/prasanthj/pig-codemirror-2 + * Pig Latin Mode for CodeMirror 2 + * @author Prasanth Jayachandran + * @link https://github.com/prasanthj/pig-codemirror-2 * This implementation is adapted from PL/SQL mode in CodeMirror 2. -*/ + */ CodeMirror.defineMode("pig", function(_config, parserConfig) { - var keywords = parserConfig.keywords, - builtins = parserConfig.builtins, - types = parserConfig.types, - multiLineStrings = parserConfig.multiLineStrings; - - var isOperatorChar = /[*+\-%<>=&?:\/!|]/; - - function chain(stream, state, f) { - state.tokenize = f; - return f(stream, state); - } - - var type; - function ret(tp, style) { - type = tp; - return style; - } - - function tokenComment(stream, state) { - var isEnd = false; - var ch; - while(ch = stream.next()) { - if(ch == "/" && isEnd) { - state.tokenize = tokenBase; - break; - } - isEnd = (ch == "*"); - } - return ret("comment", "comment"); - } - - function tokenString(quote) { - return function(stream, state) { - var escaped = false, next, end = false; - while((next = stream.next()) != null) { - if (next == quote && !escaped) { - end = true; break; - } - escaped = !escaped && next == "\\"; - } - if (end || !(escaped || multiLineStrings)) - state.tokenize = tokenBase; - return ret("string", "error"); - }; - } - - function tokenBase(stream, state) { - var ch = stream.next(); - - // is a start of string? - if (ch == '"' || ch == "'") - return chain(stream, state, tokenString(ch)); - // is it one of the special chars - else if(/[\[\]{}\(\),;\.]/.test(ch)) - return ret(ch); - // is it a number? - else if(/\d/.test(ch)) { - stream.eatWhile(/[\w\.]/); - return ret("number", "number"); - } - // multi line comment or operator - else if (ch == "/") { - if (stream.eat("*")) { - return chain(stream, state, tokenComment); - } - else { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator"); - } - } - // single line comment or operator - else if (ch=="-") { - if(stream.eat("-")){ - stream.skipToEnd(); - return ret("comment", "comment"); - } - else { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator"); - } - } - // is it an operator - else if (isOperatorChar.test(ch)) { - stream.eatWhile(isOperatorChar); - return ret("operator", "operator"); - } - else { - // get the while word - stream.eatWhile(/[\w\$_]/); - // is it one of the listed keywords? - if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) { - if (stream.eat(")") || stream.eat(".")) { - //keywords can be used as variables like flatten(group), group.$0 etc.. - } - else { - return ("keyword", "keyword"); - } - } - // is it one of the builtin functions? - if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase())) - { - return ("keyword", "variable-2"); - } - // is it one of the listed types? - if (types && types.propertyIsEnumerable(stream.current().toUpperCase())) - return ("keyword", "variable-3"); - // default is a 'variable' - return ret("variable", "pig-word"); - } - } - - // Interface - return { - startState: function() { - return { - tokenize: tokenBase, - startOfLine: true - }; - }, - - token: function(stream, state) { - if(stream.eatSpace()) return null; - var style = state.tokenize(stream, state); - return style; - } - }; + var keywords = parserConfig.keywords, + builtins = parserConfig.builtins, + types = parserConfig.types, + multiLineStrings = parserConfig.multiLineStrings; + + var isOperatorChar = /[*+\-%<>=&?:\/!|]/; + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + var type; + function ret(tp, style) { + type = tp; + return style; + } + + function tokenComment(stream, state) { + var isEnd = false; + var ch; + while(ch = stream.next()) { + if(ch == "/" && isEnd) { + state.tokenize = tokenBase; + break; + } + isEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while((next = stream.next()) != null) { + if (next == quote && !escaped) { + end = true; break; + } + escaped = !escaped && next == "\\"; + } + if (end || !(escaped || multiLineStrings)) + state.tokenize = tokenBase; + return ret("string", "error"); + }; + } + + function tokenBase(stream, state) { + var ch = stream.next(); + + // is a start of string? + if (ch == '"' || ch == "'") + return chain(stream, state, tokenString(ch)); + // is it one of the special chars + else if(/[\[\]{}\(\),;\.]/.test(ch)) + return ret(ch); + // is it a number? + else if(/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return ret("number", "number"); + } + // multi line comment or operator + else if (ch == "/") { + if (stream.eat("*")) { + return chain(stream, state, tokenComment); + } + else { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator"); + } + } + // single line comment or operator + else if (ch=="-") { + if(stream.eat("-")){ + stream.skipToEnd(); + return ret("comment", "comment"); + } + else { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator"); + } + } + // is it an operator + else if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return ret("operator", "operator"); + } + else { + // get the while word + stream.eatWhile(/[\w\$_]/); + // is it one of the listed keywords? + if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) { + if (stream.eat(")") || stream.eat(".")) { + //keywords can be used as variables like flatten(group), group.$0 etc.. + } + else { + return ("keyword", "keyword"); + } + } + // is it one of the builtin functions? + if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase())) + { + return ("keyword", "variable-2"); + } + // is it one of the listed types? + if (types && types.propertyIsEnumerable(stream.current().toUpperCase())) + return ("keyword", "variable-3"); + // default is a 'variable' + return ret("variable", "pig-word"); + } + } + + // Interface + return { + startState: function() { + return { + tokenize: tokenBase, + startOfLine: true + }; + }, + + token: function(stream, state) { + if(stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + return style; + } + }; }); (function() { - function keywords(str) { - var obj = {}, words = str.split(" "); - for (var i = 0; i < words.length; ++i) obj[words[i]] = true; - return obj; - } + function keywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + // builtin funcs taken from trunk revision 1303237 + var pBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL " + + "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS " + + "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG " + + "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN " + + "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER " + + "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS " + + "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA " + + "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE " + + "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG " + + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER "; + + // taken from QueryLexer.g + var pKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP " + + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL " + + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE " + + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE " + + "NEQ MATCHES TRUE FALSE "; + + // data types + var pTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP "; - // builtin funcs taken from trunk revision 1303237 - var pBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL " - + "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS " - + "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG " - + "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN " - + "INTSUM INVOKEFORDOUBLE INVOKEFORFLOAT INVOKEFORINT INVOKEFORLONG INVOKEFORSTRING INVOKER " - + "ISEMPTY JSONLOADER JSONMETADATA JSONSTORAGE LAST_INDEX_OF LCFIRST LOG LOG10 LOWER LONGABS " - + "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA " - + "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE " - + "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG " - + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER "; - - // taken from QueryLexer.g - var pKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP " - + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL " - + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE " - + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE " - + "NEQ MATCHES TRUE FALSE "; - - // data types - var pTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP "; - - CodeMirror.defineMIME("text/x-pig", { - name: "pig", - builtins: keywords(pBuiltins), - keywords: keywords(pKeywords), - types: keywords(pTypes) - }); + CodeMirror.defineMIME("text/x-pig", { + name: "pig", + builtins: keywords(pBuiltins), + keywords: keywords(pKeywords), + types: keywords(pTypes) + }); }()); diff --git a/mode/smalltalk/smalltalk.js b/mode/smalltalk/smalltalk.js index 33ea11eae7..f8c9026bb3 100644 --- a/mode/smalltalk/smalltalk.js +++ b/mode/smalltalk/smalltalk.js @@ -1,139 +1,139 @@ CodeMirror.defineMode('smalltalk', function(config) { - var specialChars = /[+\-/\\*~<>=@%|&?!.:;^]/; - var keywords = /true|false|nil|self|super|thisContext/; - - var Context = function(tokenizer, parent) { - this.next = tokenizer; - this.parent = parent; - }; - - var Token = function(name, context, eos) { - this.name = name; - this.context = context; - this.eos = eos; - }; - - var State = function() { - this.context = new Context(next, null); - this.expectVariable = true; - this.indentation = 0; - this.userIndentationDelta = 0; - }; - - State.prototype.userIndent = function(indentation) { - this.userIndentationDelta = indentation > 0 ? (indentation / config.indentUnit - this.indentation) : 0; - }; - - var next = function(stream, context, state) { - var token = new Token(null, context, false); - var aChar = stream.next(); - - if (aChar === '"') { - token = nextComment(stream, new Context(nextComment, context)); - - } else if (aChar === '\'') { - token = nextString(stream, new Context(nextString, context)); - - } else if (aChar === '#') { - stream.eatWhile(/[^ .]/); - token.name = 'string-2'; - - } else if (aChar === '$') { - stream.eatWhile(/[^ ]/); - token.name = 'string-2'; - - } else if (aChar === '|' && state.expectVariable) { - token.context = new Context(nextTemporaries, context); - - } else if (/[\[\]{}()]/.test(aChar)) { - token.name = 'bracket'; - token.eos = /[\[{(]/.test(aChar); - - if (aChar === '[') { - state.indentation++; - } else if (aChar === ']') { - state.indentation = Math.max(0, state.indentation - 1); - } - - } else if (specialChars.test(aChar)) { - stream.eatWhile(specialChars); - token.name = 'operator'; - token.eos = aChar !== ';'; // ; cascaded message expression - - } else if (/\d/.test(aChar)) { - stream.eatWhile(/[\w\d]/); - token.name = 'number'; - - } else if (/[\w_]/.test(aChar)) { - stream.eatWhile(/[\w\d_]/); - token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null; - - } else { - token.eos = state.expectVariable; - } - - return token; - }; - - var nextComment = function(stream, context) { - stream.eatWhile(/[^"]/); - return new Token('comment', stream.eat('"') ? context.parent : context, true); - }; - - var nextString = function(stream, context) { - stream.eatWhile(/[^']/); - return new Token('string', stream.eat('\'') ? context.parent : context, false); - }; - - var nextTemporaries = function(stream, context) { - var token = new Token(null, context, false); - var aChar = stream.next(); - - if (aChar === '|') { - token.context = context.parent; - token.eos = true; - - } else { - stream.eatWhile(/[^|]/); - token.name = 'variable'; - } - - return token; - }; - - return { - startState: function() { - return new State; - }, - - token: function(stream, state) { - state.userIndent(stream.indentation()); - - if (stream.eatSpace()) { - return null; - } + var specialChars = /[+\-\/\\*~<>=@%|&?!.:;^]/; + var keywords = /true|false|nil|self|super|thisContext/; + + var Context = function(tokenizer, parent) { + this.next = tokenizer; + this.parent = parent; + }; + + var Token = function(name, context, eos) { + this.name = name; + this.context = context; + this.eos = eos; + }; + + var State = function() { + this.context = new Context(next, null); + this.expectVariable = true; + this.indentation = 0; + this.userIndentationDelta = 0; + }; + + State.prototype.userIndent = function(indentation) { + this.userIndentationDelta = indentation > 0 ? (indentation / config.indentUnit - this.indentation) : 0; + }; + + var next = function(stream, context, state) { + var token = new Token(null, context, false); + var aChar = stream.next(); + + if (aChar === '"') { + token = nextComment(stream, new Context(nextComment, context)); + + } else if (aChar === '\'') { + token = nextString(stream, new Context(nextString, context)); + + } else if (aChar === '#') { + stream.eatWhile(/[^ .]/); + token.name = 'string-2'; + + } else if (aChar === '$') { + stream.eatWhile(/[^ ]/); + token.name = 'string-2'; + + } else if (aChar === '|' && state.expectVariable) { + token.context = new Context(nextTemporaries, context); + + } else if (/[\[\]{}()]/.test(aChar)) { + token.name = 'bracket'; + token.eos = /[\[{(]/.test(aChar); + + if (aChar === '[') { + state.indentation++; + } else if (aChar === ']') { + state.indentation = Math.max(0, state.indentation - 1); + } + + } else if (specialChars.test(aChar)) { + stream.eatWhile(specialChars); + token.name = 'operator'; + token.eos = aChar !== ';'; // ; cascaded message expression + + } else if (/\d/.test(aChar)) { + stream.eatWhile(/[\w\d]/); + token.name = 'number'; + + } else if (/[\w_]/.test(aChar)) { + stream.eatWhile(/[\w\d_]/); + token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null; + + } else { + token.eos = state.expectVariable; + } + + return token; + }; + + var nextComment = function(stream, context) { + stream.eatWhile(/[^"]/); + return new Token('comment', stream.eat('"') ? context.parent : context, true); + }; + + var nextString = function(stream, context) { + stream.eatWhile(/[^']/); + return new Token('string', stream.eat('\'') ? context.parent : context, false); + }; + + var nextTemporaries = function(stream, context) { + var token = new Token(null, context, false); + var aChar = stream.next(); + + if (aChar === '|') { + token.context = context.parent; + token.eos = true; + + } else { + stream.eatWhile(/[^|]/); + token.name = 'variable'; + } + + return token; + }; + + return { + startState: function() { + return new State; + }, + + token: function(stream, state) { + state.userIndent(stream.indentation()); + + if (stream.eatSpace()) { + return null; + } - var token = state.context.next(stream, state.context, state); - state.context = token.context; - state.expectVariable = token.eos; + var token = state.context.next(stream, state.context, state); + state.context = token.context; + state.expectVariable = token.eos; - state.lastToken = token; - return token.name; - }, + state.lastToken = token; + return token.name; + }, - blankLine: function(state) { - state.userIndent(0); - }, + blankLine: function(state) { + state.userIndent(0); + }, - indent: function(state, textAfter) { - var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta; - return (state.indentation + i) * config.indentUnit; - }, + indent: function(state, textAfter) { + var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta; + return (state.indentation + i) * config.indentUnit; + }, - electricChars: ']' - }; + electricChars: ']' + }; }); -CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'}); \ No newline at end of file +CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'}); diff --git a/mode/smarty/smarty.js b/mode/smarty/smarty.js index 9ee1e4851c..7d7e62f86e 100644 --- a/mode/smarty/smarty.js +++ b/mode/smarty/smarty.js @@ -88,7 +88,7 @@ CodeMirror.defineMode("smarty", function(config) { var str = ""; if (ch != "/") { - str += ch; + str += ch; } var c = ""; while ((c = stream.eat(regs.validIdentifier))) { @@ -101,7 +101,7 @@ CodeMirror.defineMode("smarty", function(config) { } } if (/\s/.test(ch)) { - return null; + return null; } return ret("tag", "tag"); } @@ -145,4 +145,4 @@ CodeMirror.defineMode("smarty", function(config) { }; }); -CodeMirror.defineMIME("text/x-smarty", "smarty"); \ No newline at end of file +CodeMirror.defineMIME("text/x-smarty", "smarty"); diff --git a/mode/tiddlywiki/tiddlywiki.js b/mode/tiddlywiki/tiddlywiki.js index 0d506ee608..24a24786bc 100644 --- a/mode/tiddlywiki/tiddlywiki.js +++ b/mode/tiddlywiki/tiddlywiki.js @@ -1,352 +1,352 @@ /*** -|''Name''|tiddlywiki.js| -|''Description''|Enables TiddlyWikiy syntax highlighting using CodeMirror| -|''Author''|PMario| -|''Version''|0.1.7| -|''Status''|''stable''| -|''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]| -|''Documentation''|http://codemirror.tiddlyspace.com/| -|''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]| -|''CoreVersion''|2.5.0| -|''Requires''|codemirror.js| -|''Keywords''|syntax highlighting color code mirror codemirror| -! Info -CoreVersion parameter is needed for TiddlyWiki only! + |''Name''|tiddlywiki.js| + |''Description''|Enables TiddlyWikiy syntax highlighting using CodeMirror| + |''Author''|PMario| + |''Version''|0.1.7| + |''Status''|''stable''| + |''Source''|[[GitHub|https://github.com/pmario/CodeMirror2/blob/tw-syntax/mode/tiddlywiki]]| + |''Documentation''|http://codemirror.tiddlyspace.com/| + |''License''|[[MIT License|http://www.opensource.org/licenses/mit-license.php]]| + |''CoreVersion''|2.5.0| + |''Requires''|codemirror.js| + |''Keywords''|syntax highlighting color code mirror codemirror| + ! Info + CoreVersion parameter is needed for TiddlyWiki only! ***/ //{{{ CodeMirror.defineMode("tiddlywiki", function () { - // Tokenizer - var textwords = {}; - - var keywords = function () { - function kw(type) { - return { type: type, style: "macro"}; - } - return { - "allTags": kw('allTags'), "closeAll": kw('closeAll'), "list": kw('list'), - "newJournal": kw('newJournal'), "newTiddler": kw('newTiddler'), - "permaview": kw('permaview'), "saveChanges": kw('saveChanges'), - "search": kw('search'), "slider": kw('slider'), "tabs": kw('tabs'), - "tag": kw('tag'), "tagging": kw('tagging'), "tags": kw('tags'), - "tiddler": kw('tiddler'), "timeline": kw('timeline'), - "today": kw('today'), "version": kw('version'), "option": kw('option'), - - "with": kw('with'), - "filter": kw('filter') - }; - }(); - - var isSpaceName = /[\w_\-]/i, - reHR = /^\-\-\-\-+$/, //
    - reWikiCommentStart = /^\/\*\*\*$/, // /*** - reWikiCommentStop = /^\*\*\*\/$/, // ***/ - reBlockQuote = /^<<<$/, - - reJsCodeStart = /^\/\/\{\{\{$/, // //{{{ js block start - reJsCodeStop = /^\/\/\}\}\}$/, // //}}} js stop - reXmlCodeStart = /^$/, // xml block start - reXmlCodeStop = /^$/, // xml stop - - reCodeBlockStart = /^\{\{\{$/, // {{{ TW text div block start - reCodeBlockStop = /^\}\}\}$/, // }}} TW text stop - - reUntilCodeStop = /.*?\}\}\}/; - - function chain(stream, state, f) { - state.tokenize = f; - return f(stream, state); - } - - // Used as scratch variables to communicate multiple values without - // consing up tons of objects. - var type, content; - - function ret(tp, style, cont) { - type = tp; - content = cont; - return style; - } - - function jsTokenBase(stream, state) { - var sol = stream.sol(), ch; - - state.block = false; // indicates the start of a code block. - - ch = stream.peek(); // don't eat, to make matching simpler - - // check start of blocks - if (sol && /[<\/\*{}\-]/.test(ch)) { - if (stream.match(reCodeBlockStart)) { - state.block = true; - return chain(stream, state, twTokenCode); - } - if (stream.match(reBlockQuote)) { - return ret('quote', 'quote'); - } - if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) { - return ret('code', 'comment'); - } - if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) { - return ret('code', 'comment'); - } - if (stream.match(reHR)) { - return ret('hr', 'hr'); - } - } // sol - ch = stream.next(); - - if (sol && /[\/\*!#;:>|]/.test(ch)) { - if (ch == "!") { // tw header - stream.skipToEnd(); - return ret("header", "header"); - } - if (ch == "*") { // tw list - stream.eatWhile('*'); - return ret("list", "comment"); - } - if (ch == "#") { // tw numbered list - stream.eatWhile('#'); - return ret("list", "comment"); - } - if (ch == ";") { // definition list, term - stream.eatWhile(';'); - return ret("list", "comment"); - } - if (ch == ":") { // definition list, description - stream.eatWhile(':'); - return ret("list", "comment"); - } - if (ch == ">") { // single line quote - stream.eatWhile(">"); - return ret("quote", "quote"); - } - if (ch == '|') { - return ret('table', 'header'); - } - } - - if (ch == '{' && stream.match(/\{\{/)) { - return chain(stream, state, twTokenCode); - } - - // rudimentary html:// file:// link matching. TW knows much more ... - if (/[hf]/i.test(ch)) { - if (/[ti]/i.test(stream.peek()) && stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i)) { - return ret("link", "link"); - } - } - // just a little string indicator, don't want to have the whole string covered - if (ch == '"') { - return ret('string', 'string'); - } - if (ch == '~') { // _no_ CamelCase indicator should be bold - return ret('text', 'brace'); - } - if (/[\[\]]/.test(ch)) { // check for [[..]] - if (stream.peek() == ch) { - stream.next(); - return ret('brace', 'brace'); - } - } - if (ch == "@") { // check for space link. TODO fix @@...@@ highlighting - stream.eatWhile(isSpaceName); - return ret("link", "link"); - } - if (/\d/.test(ch)) { // numbers - stream.eatWhile(/\d/); - return ret("number", "number"); - } - if (ch == "/") { // tw invisible comment - if (stream.eat("%")) { - return chain(stream, state, twTokenComment); - } - else if (stream.eat("/")) { // - return chain(stream, state, twTokenEm); - } - } - if (ch == "_") { // tw underline - if (stream.eat("_")) { - return chain(stream, state, twTokenUnderline); - } - } - // strikethrough and mdash handling - if (ch == "-") { - if (stream.eat("-")) { - // if strikethrough looks ugly, change CSS. - if (stream.peek() != ' ') - return chain(stream, state, twTokenStrike); - // mdash - if (stream.peek() == ' ') - return ret('text', 'brace'); - } - } - if (ch == "'") { // tw bold - if (stream.eat("'")) { - return chain(stream, state, twTokenStrong); - } - } - if (ch == "<") { // tw macro - if (stream.eat("<")) { - return chain(stream, state, twTokenMacro); - } - } - else { - return ret(ch); - } - - // core macro handling - stream.eatWhile(/[\w\$_]/); - var word = stream.current(), - known = textwords.propertyIsEnumerable(word) && textwords[word]; - - return known ? ret(known.type, known.style, word) : ret("text", null, word); - - } // jsTokenBase() - - // tw invisible comment - function twTokenComment(stream, state) { - var maybeEnd = false, - ch; - while (ch = stream.next()) { - if (ch == "/" && maybeEnd) { - state.tokenize = jsTokenBase; - break; - } - maybeEnd = (ch == "%"); - } - return ret("comment", "comment"); - } - - // tw strong / bold - function twTokenStrong(stream, state) { - var maybeEnd = false, - ch; - while (ch = stream.next()) { - if (ch == "'" && maybeEnd) { - state.tokenize = jsTokenBase; - break; - } - maybeEnd = (ch == "'"); - } - return ret("text", "strong"); - } - - // tw code - function twTokenCode(stream, state) { - var ch, sb = state.block; - - if (sb && stream.current()) { - return ret("code", "comment"); - } - - if (!sb && stream.match(reUntilCodeStop)) { - state.tokenize = jsTokenBase; - return ret("code", "comment"); - } - - if (sb && stream.sol() && stream.match(reCodeBlockStop)) { - state.tokenize = jsTokenBase; - return ret("code", "comment"); - } - - ch = stream.next(); - return (sb) ? ret("code", "comment") : ret("code", "comment"); - } - - // tw em / italic - function twTokenEm(stream, state) { - var maybeEnd = false, - ch; - while (ch = stream.next()) { - if (ch == "/" && maybeEnd) { - state.tokenize = jsTokenBase; - break; - } - maybeEnd = (ch == "/"); - } - return ret("text", "em"); - } - - // tw underlined text - function twTokenUnderline(stream, state) { - var maybeEnd = false, - ch; - while (ch = stream.next()) { - if (ch == "_" && maybeEnd) { - state.tokenize = jsTokenBase; - break; - } - maybeEnd = (ch == "_"); - } - return ret("text", "underlined"); - } - - // tw strike through text looks ugly - // change CSS if needed - function twTokenStrike(stream, state) { - var maybeEnd = false, ch; - - while (ch = stream.next()) { - if (ch == "-" && maybeEnd) { - state.tokenize = jsTokenBase; - break; - } - maybeEnd = (ch == "-"); - } - return ret("text", "strikethrough"); - } - - // macro - function twTokenMacro(stream, state) { - var ch, word, known; - - if (stream.current() == '<<') { - return ret('brace', 'macro'); - } - - ch = stream.next(); - if (!ch) { - state.tokenize = jsTokenBase; - return ret(ch); - } - if (ch == ">") { - if (stream.peek() == '>') { - stream.next(); - state.tokenize = jsTokenBase; - return ret("brace", "macro"); - } - } - - stream.eatWhile(/[\w\$_]/); - word = stream.current(); - known = keywords.propertyIsEnumerable(word) && keywords[word]; - - if (known) { - return ret(known.type, known.style, word); - } - else { - return ret("macro", null, word); - } - } - - // Interface - return { - startState: function () { - return { - tokenize: jsTokenBase, - indented: 0, - level: 0 - }; - }, - - token: function (stream, state) { - if (stream.eatSpace()) return null; - var style = state.tokenize(stream, state); - return style; - }, - - electricChars: "" - }; + // Tokenizer + var textwords = {}; + + var keywords = function () { + function kw(type) { + return { type: type, style: "macro"}; + } + return { + "allTags": kw('allTags'), "closeAll": kw('closeAll'), "list": kw('list'), + "newJournal": kw('newJournal'), "newTiddler": kw('newTiddler'), + "permaview": kw('permaview'), "saveChanges": kw('saveChanges'), + "search": kw('search'), "slider": kw('slider'), "tabs": kw('tabs'), + "tag": kw('tag'), "tagging": kw('tagging'), "tags": kw('tags'), + "tiddler": kw('tiddler'), "timeline": kw('timeline'), + "today": kw('today'), "version": kw('version'), "option": kw('option'), + + "with": kw('with'), + "filter": kw('filter') + }; + }(); + + var isSpaceName = /[\w_\-]/i, + reHR = /^\-\-\-\-+$/, //
    + reWikiCommentStart = /^\/\*\*\*$/, // /*** + reWikiCommentStop = /^\*\*\*\/$/, // ***/ + reBlockQuote = /^<<<$/, + + reJsCodeStart = /^\/\/\{\{\{$/, // //{{{ js block start + reJsCodeStop = /^\/\/\}\}\}$/, // //}}} js stop + reXmlCodeStart = /^$/, // xml block start + reXmlCodeStop = /^$/, // xml stop + + reCodeBlockStart = /^\{\{\{$/, // {{{ TW text div block start + reCodeBlockStop = /^\}\}\}$/, // }}} TW text stop + + reUntilCodeStop = /.*?\}\}\}/; + + function chain(stream, state, f) { + state.tokenize = f; + return f(stream, state); + } + + // Used as scratch variables to communicate multiple values without + // consing up tons of objects. + var type, content; + + function ret(tp, style, cont) { + type = tp; + content = cont; + return style; + } + + function jsTokenBase(stream, state) { + var sol = stream.sol(), ch; + + state.block = false; // indicates the start of a code block. + + ch = stream.peek(); // don't eat, to make matching simpler + + // check start of blocks + if (sol && /[<\/\*{}\-]/.test(ch)) { + if (stream.match(reCodeBlockStart)) { + state.block = true; + return chain(stream, state, twTokenCode); + } + if (stream.match(reBlockQuote)) { + return ret('quote', 'quote'); + } + if (stream.match(reWikiCommentStart) || stream.match(reWikiCommentStop)) { + return ret('code', 'comment'); + } + if (stream.match(reJsCodeStart) || stream.match(reJsCodeStop) || stream.match(reXmlCodeStart) || stream.match(reXmlCodeStop)) { + return ret('code', 'comment'); + } + if (stream.match(reHR)) { + return ret('hr', 'hr'); + } + } // sol + ch = stream.next(); + + if (sol && /[\/\*!#;:>|]/.test(ch)) { + if (ch == "!") { // tw header + stream.skipToEnd(); + return ret("header", "header"); + } + if (ch == "*") { // tw list + stream.eatWhile('*'); + return ret("list", "comment"); + } + if (ch == "#") { // tw numbered list + stream.eatWhile('#'); + return ret("list", "comment"); + } + if (ch == ";") { // definition list, term + stream.eatWhile(';'); + return ret("list", "comment"); + } + if (ch == ":") { // definition list, description + stream.eatWhile(':'); + return ret("list", "comment"); + } + if (ch == ">") { // single line quote + stream.eatWhile(">"); + return ret("quote", "quote"); + } + if (ch == '|') { + return ret('table', 'header'); + } + } + + if (ch == '{' && stream.match(/\{\{/)) { + return chain(stream, state, twTokenCode); + } + + // rudimentary html:// file:// link matching. TW knows much more ... + if (/[hf]/i.test(ch)) { + if (/[ti]/i.test(stream.peek()) && stream.match(/\b(ttps?|tp|ile):\/\/[\-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$]/i)) { + return ret("link", "link"); + } + } + // just a little string indicator, don't want to have the whole string covered + if (ch == '"') { + return ret('string', 'string'); + } + if (ch == '~') { // _no_ CamelCase indicator should be bold + return ret('text', 'brace'); + } + if (/[\[\]]/.test(ch)) { // check for [[..]] + if (stream.peek() == ch) { + stream.next(); + return ret('brace', 'brace'); + } + } + if (ch == "@") { // check for space link. TODO fix @@...@@ highlighting + stream.eatWhile(isSpaceName); + return ret("link", "link"); + } + if (/\d/.test(ch)) { // numbers + stream.eatWhile(/\d/); + return ret("number", "number"); + } + if (ch == "/") { // tw invisible comment + if (stream.eat("%")) { + return chain(stream, state, twTokenComment); + } + else if (stream.eat("/")) { // + return chain(stream, state, twTokenEm); + } + } + if (ch == "_") { // tw underline + if (stream.eat("_")) { + return chain(stream, state, twTokenUnderline); + } + } + // strikethrough and mdash handling + if (ch == "-") { + if (stream.eat("-")) { + // if strikethrough looks ugly, change CSS. + if (stream.peek() != ' ') + return chain(stream, state, twTokenStrike); + // mdash + if (stream.peek() == ' ') + return ret('text', 'brace'); + } + } + if (ch == "'") { // tw bold + if (stream.eat("'")) { + return chain(stream, state, twTokenStrong); + } + } + if (ch == "<") { // tw macro + if (stream.eat("<")) { + return chain(stream, state, twTokenMacro); + } + } + else { + return ret(ch); + } + + // core macro handling + stream.eatWhile(/[\w\$_]/); + var word = stream.current(), + known = textwords.propertyIsEnumerable(word) && textwords[word]; + + return known ? ret(known.type, known.style, word) : ret("text", null, word); + + } // jsTokenBase() + + // tw invisible comment + function twTokenComment(stream, state) { + var maybeEnd = false, + ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "%"); + } + return ret("comment", "comment"); + } + + // tw strong / bold + function twTokenStrong(stream, state) { + var maybeEnd = false, + ch; + while (ch = stream.next()) { + if (ch == "'" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "'"); + } + return ret("text", "strong"); + } + + // tw code + function twTokenCode(stream, state) { + var ch, sb = state.block; + + if (sb && stream.current()) { + return ret("code", "comment"); + } + + if (!sb && stream.match(reUntilCodeStop)) { + state.tokenize = jsTokenBase; + return ret("code", "comment"); + } + + if (sb && stream.sol() && stream.match(reCodeBlockStop)) { + state.tokenize = jsTokenBase; + return ret("code", "comment"); + } + + ch = stream.next(); + return (sb) ? ret("code", "comment") : ret("code", "comment"); + } + + // tw em / italic + function twTokenEm(stream, state) { + var maybeEnd = false, + ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "/"); + } + return ret("text", "em"); + } + + // tw underlined text + function twTokenUnderline(stream, state) { + var maybeEnd = false, + ch; + while (ch = stream.next()) { + if (ch == "_" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "_"); + } + return ret("text", "underlined"); + } + + // tw strike through text looks ugly + // change CSS if needed + function twTokenStrike(stream, state) { + var maybeEnd = false, ch; + + while (ch = stream.next()) { + if (ch == "-" && maybeEnd) { + state.tokenize = jsTokenBase; + break; + } + maybeEnd = (ch == "-"); + } + return ret("text", "strikethrough"); + } + + // macro + function twTokenMacro(stream, state) { + var ch, word, known; + + if (stream.current() == '<<') { + return ret('brace', 'macro'); + } + + ch = stream.next(); + if (!ch) { + state.tokenize = jsTokenBase; + return ret(ch); + } + if (ch == ">") { + if (stream.peek() == '>') { + stream.next(); + state.tokenize = jsTokenBase; + return ret("brace", "macro"); + } + } + + stream.eatWhile(/[\w\$_]/); + word = stream.current(); + known = keywords.propertyIsEnumerable(word) && keywords[word]; + + if (known) { + return ret(known.type, known.style, word); + } + else { + return ret("macro", null, word); + } + } + + // Interface + return { + startState: function () { + return { + tokenize: jsTokenBase, + indented: 0, + level: 0 + }; + }, + + token: function (stream, state) { + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + return style; + }, + + electricChars: "" + }; }); CodeMirror.defineMIME("text/x-tiddlywiki", "tiddlywiki"); diff --git a/mode/tiki/tiki.js b/mode/tiki/tiki.js index 81e87ab213..e789163dc7 100644 --- a/mode/tiki/tiki.js +++ b/mode/tiki/tiki.js @@ -1,309 +1,308 @@ CodeMirror.defineMode('tiki', function(config) { - function inBlock(style, terminator, returnTokenizer) { - return function(stream, state) { - while (!stream.eol()) { - if (stream.match(terminator)) { - state.tokenize = inText; - break; - } - stream.next(); - } - - if (returnTokenizer) state.tokenize = returnTokenizer; - - return style; - }; - } - - function inLine(style) { - return function(stream, state) { - while(!stream.eol()) { - stream.next(); - } - state.tokenize = inText; - return style; - }; - } - - function inText(stream, state) { - function chain(parser) { - state.tokenize = parser; - return parser(stream, state); - } - - var sol = stream.sol(); - var ch = stream.next(); - - //non start of line - switch (ch) { //switch is generally much faster than if, so it is used here - case "{": //plugin - stream.eat("/"); - stream.eatSpace(); - var tagName = ""; - var c; - while ((c = stream.eat(/[^\s\u00a0=\"\'\/?(}]/))) tagName += c; - state.tokenize = inPlugin; - return "tag"; - break; - case "_": //bold - if (stream.eat("_")) { - return chain(inBlock("strong", "__", inText)); - } - break; - case "'": //italics - if (stream.eat("'")) { - // Italic text - return chain(inBlock("em", "''", inText)); - } - break; - case "(":// Wiki Link - if (stream.eat("(")) { - return chain(inBlock("variable-2", "))", inText)); - } - break; - case "[":// Weblink - return chain(inBlock("variable-3", "]", inText)); - break; - case "|": //table - if (stream.eat("|")) { - return chain(inBlock("comment", "||")); - } - break; - case "-": - if (stream.eat("=")) {//titleBar - return chain(inBlock("header string", "=-", inText)); - } else if (stream.eat("-")) {//deleted - return chain(inBlock("error tw-deleted", "--", inText)); - } - break; - case "=": //underline - if (stream.match("==")) { - return chain(inBlock("tw-underline", "===", inText)); - } - break; - case ":": - if (stream.eat(":")) { - return chain(inBlock("comment", "::")); - } - break; - case "^": //box - return chain(inBlock("tw-box", "^")); - break; - case "~": //np - if (stream.match("np~")) { - return chain(inBlock("meta", "~/np~")); - } - break; - } - - //start of line types - if (sol) { - switch (ch) { - case "!": //header at start of line - if (stream.match('!!!!!')) { - return chain(inLine("header string")); - } else if (stream.match('!!!!')) { - return chain(inLine("header string")); - } else if (stream.match('!!!')) { - return chain(inLine("header string")); - } else if (stream.match('!!')) { - return chain(inLine("header string")); - } else { - return chain(inLine("header string")); - } - break; - case "*": //unordered list line item, or
  • at start of line - case "#": //ordered list line item, or
  • at start of line - case "+": //ordered list line item, or
  • at start of line - return chain(inLine("tw-listitem bracket")); - break; - } - } - - //stream.eatWhile(/[&{]/); was eating up plugins, turned off to act less like html and more like tiki - return null; - } - - var indentUnit = config.indentUnit; + function inBlock(style, terminator, returnTokenizer) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = inText; + break; + } + stream.next(); + } - // Return variables for tokenizers - var pluginName, type; - function inPlugin(stream, state) { - var ch = stream.next(); - var peek = stream.peek(); - - if (ch == "}") { - state.tokenize = inText; - //type = ch == ")" ? "endPlugin" : "selfclosePlugin"; inPlugin - return "tag"; - } else if (ch == "(" || ch == ")") { - return "bracket"; - } else if (ch == "=") { - type = "equals"; - - if (peek == ">") { - ch = stream.next(); - peek = stream.peek(); - } - - //here we detect values directly after equal character with no quotes - if (!/[\'\"]/.test(peek)) { - state.tokenize = inAttributeNoQuote(); - } - //end detect values - - return "operator"; - } else if (/[\'\"]/.test(ch)) { - state.tokenize = inAttribute(ch); - return state.tokenize(stream, state); - } else { - stream.eatWhile(/[^\s\u00a0=\"\'\/?]/); - return "keyword"; - } - } + if (returnTokenizer) state.tokenize = returnTokenizer; - function inAttribute(quote) { - return function(stream, state) { - while (!stream.eol()) { - if (stream.next() == quote) { - state.tokenize = inPlugin; - break; - } - } - return "string"; - }; - } - - function inAttributeNoQuote() { - return function(stream, state) { - while (!stream.eol()) { - var ch = stream.next(); - var peek = stream.peek(); - if (ch == " " || ch == "," || /[ )}]/.test(peek)) { - state.tokenize = inPlugin; - break; - } - } - return "string"; - }; - } + return style; + }; + } - var curState, setStyle; - function pass() { - for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]); - } - - function cont() { - pass.apply(null, arguments); - return true; - } + function inLine(style) { + return function(stream, state) { + while(!stream.eol()) { + stream.next(); + } + state.tokenize = inText; + return style; + }; + } - function pushContext(pluginName, startOfLine) { - var noIndent = curState.context && curState.context.noIndent; - curState.context = { - prev: curState.context, - pluginName: pluginName, - indent: curState.indented, - startOfLine: startOfLine, - noIndent: noIndent - }; - } - - function popContext() { - if (curState.context) curState.context = curState.context.prev; - } + function inText(stream, state) { + function chain(parser) { + state.tokenize = parser; + return parser(stream, state); + } - function element(type) { - if (type == "openPlugin") {curState.pluginName = pluginName; return cont(attributes, endplugin(curState.startOfLine));} - else if (type == "closePlugin") { - var err = false; - if (curState.context) { - err = curState.context.pluginName != pluginName; - popContext(); - } else { - err = true; - } - if (err) setStyle = "error"; - return cont(endcloseplugin(err)); - } - else if (type == "string") { - if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata"); - if (curState.tokenize == inText) popContext(); - return cont(); - } - else return cont(); - } - - function endplugin(startOfLine) { - return function(type) { - if ( - type == "selfclosePlugin" || - type == "endPlugin" - ) - return cont(); - if (type == "endPlugin") {pushContext(curState.pluginName, startOfLine); return cont();} - return cont(); - }; - } - - function endcloseplugin(err) { - return function(type) { - if (err) setStyle = "error"; - if (type == "endPlugin") return cont(); - return pass(); - }; - } + var sol = stream.sol(); + var ch = stream.next(); - function attributes(type) { - if (type == "keyword") {setStyle = "attribute"; return cont(attributes);} - if (type == "equals") return cont(attvalue, attributes); - return pass(); - } - function attvalue(type) { - if (type == "keyword") {setStyle = "string"; return cont();} - if (type == "string") return cont(attvaluemaybe); - return pass(); - } - function attvaluemaybe(type) { - if (type == "string") return cont(attvaluemaybe); - else return pass(); - } - return { - startState: function() { - return {tokenize: inText, cc: [], indented: 0, startOfLine: true, pluginName: null, context: null}; - }, - token: function(stream, state) { - if (stream.sol()) { - state.startOfLine = true; - state.indented = stream.indentation(); - } - if (stream.eatSpace()) return null; + //non start of line + switch (ch) { //switch is generally much faster than if, so it is used here + case "{": //plugin + stream.eat("/"); + stream.eatSpace(); + var tagName = ""; + var c; + while ((c = stream.eat(/[^\s\u00a0=\"\'\/?(}]/))) tagName += c; + state.tokenize = inPlugin; + return "tag"; + break; + case "_": //bold + if (stream.eat("_")) { + return chain(inBlock("strong", "__", inText)); + } + break; + case "'": //italics + if (stream.eat("'")) { + // Italic text + return chain(inBlock("em", "''", inText)); + } + break; + case "(":// Wiki Link + if (stream.eat("(")) { + return chain(inBlock("variable-2", "))", inText)); + } + break; + case "[":// Weblink + return chain(inBlock("variable-3", "]", inText)); + break; + case "|": //table + if (stream.eat("|")) { + return chain(inBlock("comment", "||")); + } + break; + case "-": + if (stream.eat("=")) {//titleBar + return chain(inBlock("header string", "=-", inText)); + } else if (stream.eat("-")) {//deleted + return chain(inBlock("error tw-deleted", "--", inText)); + } + break; + case "=": //underline + if (stream.match("==")) { + return chain(inBlock("tw-underline", "===", inText)); + } + break; + case ":": + if (stream.eat(":")) { + return chain(inBlock("comment", "::")); + } + break; + case "^": //box + return chain(inBlock("tw-box", "^")); + break; + case "~": //np + if (stream.match("np~")) { + return chain(inBlock("meta", "~/np~")); + } + break; + } - setStyle = type = pluginName = null; - var style = state.tokenize(stream, state); - if ((style || type) && style != "comment") { - curState = state; - while (true) { - var comb = state.cc.pop() || element; - if (comb(type || style)) break; - } - } - state.startOfLine = false; - return setStyle || style; - }, - indent: function(state, textAfter) { - var context = state.context; - if (context && context.noIndent) return 0; - if (context && /^{\//.test(textAfter)) - context = context.prev; - while (context && !context.startOfLine) - context = context.prev; - if (context) return context.indent + indentUnit; - else return 0; - }, - electricChars: "/" - }; + //start of line types + if (sol) { + switch (ch) { + case "!": //header at start of line + if (stream.match('!!!!!')) { + return chain(inLine("header string")); + } else if (stream.match('!!!!')) { + return chain(inLine("header string")); + } else if (stream.match('!!!')) { + return chain(inLine("header string")); + } else if (stream.match('!!')) { + return chain(inLine("header string")); + } else { + return chain(inLine("header string")); + } + break; + case "*": //unordered list line item, or
  • at start of line + case "#": //ordered list line item, or
  • at start of line + case "+": //ordered list line item, or
  • at start of line + return chain(inLine("tw-listitem bracket")); + break; + } + } + + //stream.eatWhile(/[&{]/); was eating up plugins, turned off to act less like html and more like tiki + return null; + } + + var indentUnit = config.indentUnit; + + // Return variables for tokenizers + var pluginName, type; + function inPlugin(stream, state) { + var ch = stream.next(); + var peek = stream.peek(); + + if (ch == "}") { + state.tokenize = inText; + //type = ch == ")" ? "endPlugin" : "selfclosePlugin"; inPlugin + return "tag"; + } else if (ch == "(" || ch == ")") { + return "bracket"; + } else if (ch == "=") { + type = "equals"; + + if (peek == ">") { + ch = stream.next(); + peek = stream.peek(); + } + + //here we detect values directly after equal character with no quotes + if (!/[\'\"]/.test(peek)) { + state.tokenize = inAttributeNoQuote(); + } + //end detect values + + return "operator"; + } else if (/[\'\"]/.test(ch)) { + state.tokenize = inAttribute(ch); + return state.tokenize(stream, state); + } else { + stream.eatWhile(/[^\s\u00a0=\"\'\/?]/); + return "keyword"; + } + } + + function inAttribute(quote) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.next() == quote) { + state.tokenize = inPlugin; + break; + } + } + return "string"; + }; + } + + function inAttributeNoQuote() { + return function(stream, state) { + while (!stream.eol()) { + var ch = stream.next(); + var peek = stream.peek(); + if (ch == " " || ch == "," || /[ )}]/.test(peek)) { + state.tokenize = inPlugin; + break; + } + } + return "string"; +}; + } + +var curState, setStyle; +function pass() { + for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]); +} + +function cont() { + pass.apply(null, arguments); + return true; +} + +function pushContext(pluginName, startOfLine) { + var noIndent = curState.context && curState.context.noIndent; + curState.context = { + prev: curState.context, + pluginName: pluginName, + indent: curState.indented, + startOfLine: startOfLine, + noIndent: noIndent + }; +} + +function popContext() { + if (curState.context) curState.context = curState.context.prev; +} + +function element(type) { + if (type == "openPlugin") {curState.pluginName = pluginName; return cont(attributes, endplugin(curState.startOfLine));} + else if (type == "closePlugin") { + var err = false; + if (curState.context) { + err = curState.context.pluginName != pluginName; + popContext(); + } else { + err = true; + } + if (err) setStyle = "error"; + return cont(endcloseplugin(err)); + } + else if (type == "string") { + if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata"); + if (curState.tokenize == inText) popContext(); + return cont(); + } + else return cont(); +} + +function endplugin(startOfLine) { + return function(type) { + if ( + type == "selfclosePlugin" || + type == "endPlugin" + ) + return cont(); + if (type == "endPlugin") {pushContext(curState.pluginName, startOfLine); return cont();} + return cont(); + }; +} + +function endcloseplugin(err) { + return function(type) { + if (err) setStyle = "error"; + if (type == "endPlugin") return cont(); + return pass(); + }; +} + +function attributes(type) { + if (type == "keyword") {setStyle = "attribute"; return cont(attributes);} + if (type == "equals") return cont(attvalue, attributes); + return pass(); +} +function attvalue(type) { + if (type == "keyword") {setStyle = "string"; return cont();} + if (type == "string") return cont(attvaluemaybe); + return pass(); +} +function attvaluemaybe(type) { + if (type == "string") return cont(attvaluemaybe); + else return pass(); +} +return { + startState: function() { + return {tokenize: inText, cc: [], indented: 0, startOfLine: true, pluginName: null, context: null}; + }, + token: function(stream, state) { + if (stream.sol()) { + state.startOfLine = true; + state.indented = stream.indentation(); + } + if (stream.eatSpace()) return null; + + setStyle = type = pluginName = null; + var style = state.tokenize(stream, state); + if ((style || type) && style != "comment") { + curState = state; + while (true) { + var comb = state.cc.pop() || element; + if (comb(type || style)) break; + } + } + state.startOfLine = false; + return setStyle || style; + }, + indent: function(state, textAfter) { + var context = state.context; + if (context && context.noIndent) return 0; + if (context && /^{\//.test(textAfter)) + context = context.prev; + while (context && !context.startOfLine) + context = context.prev; + if (context) return context.indent + indentUnit; + else return 0; + }, + electricChars: "/" + }; }); -//I figure, why not CodeMirror.defineMIME("text/tiki", "tiki"); diff --git a/mode/turtle/turtle.js b/mode/turtle/turtle.js index 5c7c28eb02..e118bfbced 100644 --- a/mode/turtle/turtle.js +++ b/mode/turtle/turtle.js @@ -33,23 +33,23 @@ CodeMirror.defineMode("turtle", function(config) { return null; } else if (ch == ":") { - return "operator"; - } else { + return "operator"; + } else { stream.eatWhile(/[_\w\d]/); if(stream.peek() == ":") { return "variable-3"; } else { - var word = stream.current(); - - if(keywords.test(word)) { - return "meta"; - } - - if(ch >= "A" && ch <= "Z") { - return "comment"; - } else { - return "keyword"; - } + var word = stream.current(); + + if(keywords.test(word)) { + return "meta"; + } + + if(ch >= "A" && ch <= "Z") { + return "comment"; + } else { + return "keyword"; + } } var word = stream.current(); if (ops.test(word)) @@ -119,7 +119,7 @@ CodeMirror.defineMode("turtle", function(config) { state.context.col = stream.column(); } } - + return style; }, diff --git a/mode/vbscript/vbscript.js b/mode/vbscript/vbscript.js index 65d6c21276..3e1eedc7db 100644 --- a/mode/vbscript/vbscript.js +++ b/mode/vbscript/vbscript.js @@ -6,12 +6,12 @@ CodeMirror.defineMode("vbscript", function() { if (stream.eatSpace()) return null; var ch = stream.next(); if (ch == "'") { - stream.skipToEnd(); - return "comment"; + stream.skipToEnd(); + return "comment"; } if (ch == '"') { - stream.skipTo('"'); - return "string"; + stream.skipTo('"'); + return "string"; } if (/\w/.test(ch)) { diff --git a/mode/yaml/yaml.js b/mode/yaml/yaml.js index 59e2641a01..bdd303dfed 100644 --- a/mode/yaml/yaml.js +++ b/mode/yaml/yaml.js @@ -1,95 +1,95 @@ CodeMirror.defineMode("yaml", function() { - - var cons = ['true', 'false', 'on', 'off', 'yes', 'no']; - var keywordRegex = new RegExp("\\b(("+cons.join(")|(")+"))$", 'i'); - - return { - token: function(stream, state) { - var ch = stream.peek(); - var esc = state.escaped; - state.escaped = false; - /* comments */ - if (ch == "#") { stream.skipToEnd(); return "comment"; } - if (state.literal && stream.indentation() > state.keyCol) { - stream.skipToEnd(); return "string"; - } else if (state.literal) { state.literal = false; } - if (stream.sol()) { - state.keyCol = 0; - state.pair = false; - state.pairStart = false; - /* document start */ - if(stream.match(/---/)) { return "def"; } - /* document end */ - if (stream.match(/\.\.\./)) { return "def"; } - /* array list item */ - if (stream.match(/\s*-\s+/)) { return 'meta'; } - } - /* pairs (associative arrays) -> key */ - if (!state.pair && stream.match(/^\s*([a-z0-9\._-])+(?=\s*:)/i)) { - state.pair = true; - state.keyCol = stream.indentation(); - return "atom"; - } - if (state.pair && stream.match(/^:\s*/)) { state.pairStart = true; return 'meta'; } - - /* inline pairs/lists */ - if (stream.match(/^(\{|\}|\[|\])/)) { - if (ch == '{') - state.inlinePairs++; - else if (ch == '}') - state.inlinePairs--; - else if (ch == '[') - state.inlineList++; - else - state.inlineList--; - return 'meta'; - } - - /* list seperator */ - if (state.inlineList > 0 && !esc && ch == ',') { - stream.next(); - return 'meta'; - } - /* pairs seperator */ - if (state.inlinePairs > 0 && !esc && ch == ',') { - state.keyCol = 0; - state.pair = false; - state.pairStart = false; - stream.next(); - return 'meta'; - } - - /* start of value of a pair */ - if (state.pairStart) { - /* block literals */ - if (stream.match(/^\s*(\||\>)\s*/)) { state.literal = true; return 'meta'; }; - /* references */ - if (stream.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i)) { return 'variable-2'; } - /* numbers */ - if (state.inlinePairs == 0 && stream.match(/^\s*-?[0-9\.\,]+\s?$/)) { return 'number'; } - if (state.inlinePairs > 0 && stream.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/)) { return 'number'; } - /* keywords */ - if (stream.match(keywordRegex)) { return 'keyword'; } - } - /* nothing found, continue */ - state.pairStart = false; - state.escaped = (ch == '\\'); - stream.next(); - return null; - }, - startState: function() { - return { - pair: false, - pairStart: false, - keyCol: 0, - inlinePairs: 0, - inlineList: 0, - literal: false, - escaped: false - }; - } - }; + var cons = ['true', 'false', 'on', 'off', 'yes', 'no']; + var keywordRegex = new RegExp("\\b(("+cons.join(")|(")+"))$", 'i'); + + return { + token: function(stream, state) { + var ch = stream.peek(); + var esc = state.escaped; + state.escaped = false; + /* comments */ + if (ch == "#") { stream.skipToEnd(); return "comment"; } + if (state.literal && stream.indentation() > state.keyCol) { + stream.skipToEnd(); return "string"; + } else if (state.literal) { state.literal = false; } + if (stream.sol()) { + state.keyCol = 0; + state.pair = false; + state.pairStart = false; + /* document start */ + if(stream.match(/---/)) { return "def"; } + /* document end */ + if (stream.match(/\.\.\./)) { return "def"; } + /* array list item */ + if (stream.match(/\s*-\s+/)) { return 'meta'; } + } + /* pairs (associative arrays) -> key */ + if (!state.pair && stream.match(/^\s*([a-z0-9\._-])+(?=\s*:)/i)) { + state.pair = true; + state.keyCol = stream.indentation(); + return "atom"; + } + if (state.pair && stream.match(/^:\s*/)) { state.pairStart = true; return 'meta'; } + + /* inline pairs/lists */ + if (stream.match(/^(\{|\}|\[|\])/)) { + if (ch == '{') + state.inlinePairs++; + else if (ch == '}') + state.inlinePairs--; + else if (ch == '[') + state.inlineList++; + else + state.inlineList--; + return 'meta'; + } + + /* list seperator */ + if (state.inlineList > 0 && !esc && ch == ',') { + stream.next(); + return 'meta'; + } + /* pairs seperator */ + if (state.inlinePairs > 0 && !esc && ch == ',') { + state.keyCol = 0; + state.pair = false; + state.pairStart = false; + stream.next(); + return 'meta'; + } + + /* start of value of a pair */ + if (state.pairStart) { + /* block literals */ + if (stream.match(/^\s*(\||\>)\s*/)) { state.literal = true; return 'meta'; }; + /* references */ + if (stream.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i)) { return 'variable-2'; } + /* numbers */ + if (state.inlinePairs == 0 && stream.match(/^\s*-?[0-9\.\,]+\s?$/)) { return 'number'; } + if (state.inlinePairs > 0 && stream.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/)) { return 'number'; } + /* keywords */ + if (stream.match(keywordRegex)) { return 'keyword'; } + } + + /* nothing found, continue */ + state.pairStart = false; + state.escaped = (ch == '\\'); + stream.next(); + return null; + }, + startState: function() { + return { + pair: false, + pairStart: false, + keyCol: 0, + inlinePairs: 0, + inlineList: 0, + literal: false, + escaped: false + }; + } + }; }); CodeMirror.defineMIME("text/x-yaml", "yaml"); diff --git a/mode/z80/z80.js b/mode/z80/z80.js index c026790dc7..ff43d32b52 100644 --- a/mode/z80/z80.js +++ b/mode/z80/z80.js @@ -1,113 +1,85 @@ -CodeMirror.defineMode('z80', function() -{ - var keywords1 = /^(exx?|(ld|cp|in)([di]r?)?|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|rst|[de]i|halt|im|ot[di]r|out[di]?)\b/i; - var keywords2 = /^(call|j[pr]|ret[in]?)\b/i; - var keywords3 = /^b_?(call|jump)\b/i; - var variables1 = /^(af?|bc?|c|de?|e|hl?|l|i[xy]?|r|sp)\b/i; - var variables2 = /^(n?[zc]|p[oe]?|m)\b/i; - var errors = /^([hl][xy]|i[xy][hl]|slia|sll)\b/i; - var numbers = /^([\da-f]+h|[0-7]+o|[01]+b|\d+)\b/i; - - return {startState: function() - { - return {context: 0}; - }, token: function(stream, state) - { - if (!stream.column()) - state.context = 0; - - if (stream.eatSpace()) - return null; - - var w; - - if (stream.eatWhile(/\w/)) - { - w = stream.current(); - - if (stream.indentation()) - { - if (state.context == 1 && variables1.test(w)) - return 'variable-2'; - - if (state.context == 2 && variables2.test(w)) - return 'variable-3'; - - if (keywords1.test(w)) - { - state.context = 1; - return 'keyword'; - } - else if (keywords2.test(w)) - { - state.context = 2; - return 'keyword'; - } - else if (keywords3.test(w)) - { - state.context = 3; - return 'keyword'; - } - - if (errors.test(w)) - return 'error'; - } - else if (numbers.test(w)) - { - return 'number'; - } - else - { - return null; - } - } - else if (stream.eat(';')) - { - stream.skipToEnd(); - return 'comment'; - } - else if (stream.eat('"')) - { - while (w = stream.next()) - { - if (w == '"') - break; - - if (w == '\\') - stream.next(); - } - - return 'string'; - } - else if (stream.eat('\'')) - { - if (stream.match(/\\?.'/)) - return 'number'; - } - else if (stream.eat('.') || stream.sol() && stream.eat('#')) - { - state.context = 4; - - if (stream.eatWhile(/\w/)) - return 'def'; - } - else if (stream.eat('$')) - { - if (stream.eatWhile(/[\da-f]/i)) - return 'number'; - } - else if (stream.eat('%')) - { - if (stream.eatWhile(/[01]/)) - return 'number'; - } - else - { - stream.next(); - } - - return null; - }}; +CodeMirror.defineMode('z80', function() { + var keywords1 = /^(exx?|(ld|cp|in)([di]r?)?|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|rst|[de]i|halt|im|ot[di]r|out[di]?)\b/i; + var keywords2 = /^(call|j[pr]|ret[in]?)\b/i; + var keywords3 = /^b_?(call|jump)\b/i; + var variables1 = /^(af?|bc?|c|de?|e|hl?|l|i[xy]?|r|sp)\b/i; + var variables2 = /^(n?[zc]|p[oe]?|m)\b/i; + var errors = /^([hl][xy]|i[xy][hl]|slia|sll)\b/i; + var numbers = /^([\da-f]+h|[0-7]+o|[01]+b|\d+)\b/i; + + return { + startState: function() { + return {context: 0}; + }, + token: function(stream, state) { + if (!stream.column()) + state.context = 0; + + if (stream.eatSpace()) + return null; + + var w; + + if (stream.eatWhile(/\w/)) { + w = stream.current(); + + if (stream.indentation()) { + if (state.context == 1 && variables1.test(w)) + return 'variable-2'; + + if (state.context == 2 && variables2.test(w)) + return 'variable-3'; + + if (keywords1.test(w)) { + state.context = 1; + return 'keyword'; + } else if (keywords2.test(w)) { + state.context = 2; + return 'keyword'; + } else if (keywords3.test(w)) { + state.context = 3; + return 'keyword'; + } + + if (errors.test(w)) + return 'error'; + } else if (numbers.test(w)) { + return 'number'; + } else { + return null; + } + } else if (stream.eat(';')) { + stream.skipToEnd(); + return 'comment'; + } else if (stream.eat('"')) { + while (w = stream.next()) { + if (w == '"') + break; + + if (w == '\\') + stream.next(); + } + return 'string'; + } else if (stream.eat('\'')) { + if (stream.match(/\\?.'/)) + return 'number'; + } else if (stream.eat('.') || stream.sol() && stream.eat('#')) { + state.context = 4; + + if (stream.eatWhile(/\w/)) + return 'def'; + } else if (stream.eat('$')) { + if (stream.eatWhile(/[\da-f]/i)) + return 'number'; + } else if (stream.eat('%')) { + if (stream.eatWhile(/[01]/)) + return 'number'; + } else { + stream.next(); + } + return null; + } + }; }); CodeMirror.defineMIME("text/x-z80", "z80"); From 86c6b6afd965e36ed71562111ad573433a8c8b6f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 11:53:13 +0200 Subject: [PATCH 0436/5273] Make the linter complain about trailing whitespace --- test/lint/lint.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/test/lint/lint.js b/test/lint/lint.js index 60b63a2d15..5f808922f2 100644 --- a/test/lint/lint.js +++ b/test/lint/lint.js @@ -19,11 +19,15 @@ var scopePasser = walk.make({ }); function checkFile(fileName) { - var file = fs.readFileSync(fileName, "utf8"); - var badChar = file.match(/[\x00-\x08\x0b\x0c\x0e-\x19\uFEFF\t]/); - if (badChar) - fail("Undesirable character " + badChar[0].charCodeAt(0) + " at position " + badChar.index, - {source: fileName}); + var file = fs.readFileSync(fileName, "utf8"), notAllowed; + if (notAllowed = file.match(/[\x00-\x08\x0b\x0c\x0e-\x19\uFEFF\t]|[ \t]\n/)) { + var msg; + if (notAllowed[0] == "\t") msg = "Found tab character"; + else if (notAllowed[0].indexOf("\n") > -1) msg = "Trailing whitespace"; + else msg = "Undesirable character " + notAllowed[0].charCodeAt(0); + var info = acorn.getLineInfo(file, notAllowed.index); + fail(msg + " at line " + info.line + ", column " + info.column, {source: fileName}); + } try { var parsed = acorn.parse(file, { @@ -91,7 +95,7 @@ function checkFile(fileName) { var failed = false; function fail(msg, pos) { if (pos.start) msg += " (" + pos.start.line + ":" + pos.start.column + ")"; - console.log(pos.source.match(/[^\/]+$/)[0] + ": " + msg); + console.log(pos.source + ": " + msg); failed = true; } From 2700c8cdbffb861508911f4af15e5fc159902c8d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 11:53:23 +0200 Subject: [PATCH 0437/5273] Remove a whole lot of trailing whitespace --- addon/edit/matchbrackets.js | 2 +- addon/hint/pig-hint.js | 34 ++++----- addon/mode/multiplex.js | 2 +- addon/mode/overlay.js | 4 +- addon/search/match-highlighter.js | 2 +- addon/selection/active-line.js | 2 +- mode/asterisk/asterisk.js | 12 ++-- mode/clike/clike.js | 28 ++++---- mode/clojure/clojure.js | 2 +- mode/coffeescript/coffeescript.js | 2 +- mode/erlang/erlang.js | 2 +- mode/gas/gas.js | 2 +- mode/haskell/haskell.js | 52 +++++++------- mode/haxe/haxe.js | 30 ++++---- mode/htmlembedded/htmlembedded.js | 12 ++-- mode/javascript/javascript.js | 8 +-- mode/jinja2/jinja2.js | 4 +- mode/less/less.js | 30 ++++---- mode/markdown/markdown.js | 78 ++++++++++----------- mode/markdown/test.js | 22 +++--- mode/ntriples/ntriples.js | 44 ++++++------ mode/ocaml/ocaml.js | 2 +- mode/python/python.js | 48 ++++++------- mode/q/q.js | 2 +- mode/shell/shell.js | 2 +- mode/sieve/sieve.js | 20 +++--- mode/sparql/sparql.js | 2 +- mode/sql/sql.js | 4 +- mode/tcl/tcl.js | 2 +- mode/vb/vb.js | 61 ++++++++--------- mode/xml/xml.js | 2 +- mode/xquery/xquery.js | 110 +++++++++++++++--------------- 32 files changed, 314 insertions(+), 315 deletions(-) diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js index f4925b7256..72bca57091 100644 --- a/addon/edit/matchbrackets.js +++ b/addon/edit/matchbrackets.js @@ -3,7 +3,7 @@ (document.documentMode == null || document.documentMode < 8); var Pos = CodeMirror.Pos; - // Disable brace matching in long lines, since it'll cause hugely slow updates + // Disable brace matching in long lines, since it'll cause hugely slow updates var maxLineLen = 1000; var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"}; diff --git a/addon/hint/pig-hint.js b/addon/hint/pig-hint.js index 9847996be9..d831ccfe93 100644 --- a/addon/hint/pig-hint.js +++ b/addon/hint/pig-hint.js @@ -2,7 +2,7 @@ function forEach(arr, f) { for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); } - + function arrayContains(arr, item) { if (!Array.prototype.indexOf) { var i = arr.length; @@ -25,11 +25,11 @@ token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state, className: token.string == ":" ? "pig-type" : null}; } - + if (!context) var context = []; context.push(tprop); - - var completionList = getCompletions(token, context); + + var completionList = getCompletions(token, context); completionList = completionList.sort(); //prevent autocomplete for last word, instead show dropdown with one word if(completionList.length == 1) { @@ -40,24 +40,24 @@ from: CodeMirror.Pos(cur.line, token.start), to: CodeMirror.Pos(cur.line, token.end)}; } - + CodeMirror.pigHint = function(editor) { return scriptHint(editor, pigKeywordsU, function (e, cur) {return e.getTokenAt(cur);}); }; - + var pigKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP " + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL " + "PARTITION GROUP AND OR NOT GENERATE FLATTEN ASC DESC IS STREAM THROUGH STORE MAPREDUCE " - + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE " + + "SHIP CACHE INPUT OUTPUT STDERROR STDIN STDOUT LIMIT SAMPLE LEFT RIGHT FULL EQ GT LT GTE LTE " + "NEQ MATCHES TRUE FALSE"; var pigKeywordsU = pigKeywords.split(" "); var pigKeywordsL = pigKeywords.toLowerCase().split(" "); - + var pigTypes = "BOOLEAN INT LONG FLOAT DOUBLE CHARARRAY BYTEARRAY BAG TUPLE MAP"; var pigTypesU = pigTypes.split(" "); var pigTypesL = pigTypes.toLowerCase().split(" "); - - var pigBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL " + + var pigBuiltins = "ABS ACOS ARITY ASIN ATAN AVG BAGSIZE BINSTORAGE BLOOM BUILDBLOOM CBRT CEIL " + "CONCAT COR COS COSH COUNT COUNT_STAR COV CONSTANTSIZE CUBEDIMENSIONS DIFF DISTINCT DOUBLEABS " + "DOUBLEAVG DOUBLEBASE DOUBLEMAX DOUBLEMIN DOUBLEROUND DOUBLESUM EXP FLOOR FLOATABS FLOATAVG " + "FLOATMAX FLOATMIN FLOATROUND FLOATSUM GENERICINVOKER INDEXOF INTABS INTAVG INTMAX INTMIN " @@ -66,9 +66,9 @@ + "LONGAVG LONGMAX LONGMIN LONGSUM MAX MIN MAPSIZE MONITOREDUDF NONDETERMINISTIC OUTPUTSCHEMA " + "PIGSTORAGE PIGSTREAMING RANDOM REGEX_EXTRACT REGEX_EXTRACT_ALL REPLACE ROUND SIN SINH SIZE " + "SQRT STRSPLIT SUBSTRING SUM STRINGCONCAT STRINGMAX STRINGMIN STRINGSIZE TAN TANH TOBAG " - + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER"; - var pigBuiltinsU = pigBuiltins.split(" ").join("() ").split(" "); - var pigBuiltinsL = pigBuiltins.toLowerCase().split(" ").join("() ").split(" "); + + "TOKENIZE TOMAP TOP TOTUPLE TRIM TEXTLOADER TUPLESIZE UCFIRST UPPER UTF8STORAGECONVERTER"; + var pigBuiltinsU = pigBuiltins.split(" ").join("() ").split(" "); + var pigBuiltinsL = pigBuiltins.toLowerCase().split(" ").join("() ").split(" "); var pigBuiltinsC = ("BagSize BinStorage Bloom BuildBloom ConstantSize CubeDimensions DoubleAbs " + "DoubleAvg DoubleBase DoubleMax DoubleMin DoubleRound DoubleSum FloatAbs FloatAvg FloatMax " + "FloatMin FloatRound FloatSum GenericInvoker IntAbs IntAvg IntMax IntMin IntSum " @@ -76,13 +76,13 @@ + "IsEmpty JsonLoader JsonMetadata JsonStorage LongAbs LongAvg LongMax LongMin LongSum MapSize " + "MonitoredUDF Nondeterministic OutputSchema PigStorage PigStreaming StringConcat StringMax " + "StringMin StringSize TextLoader TupleSize Utf8StorageConverter").split(" ").join("() ").split(" "); - + function getCompletions(token, context) { var found = [], start = token.string; function maybeAdd(str) { if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str); } - + function gatherCompletions(obj) { if(obj == ":") { forEach(pigTypesL, maybeAdd); @@ -103,11 +103,11 @@ // find in the current environment. var obj = context.pop(), base; - if (obj.type == "variable") + if (obj.type == "variable") base = obj.string; else if(obj.type == "variable-3") base = ":" + obj.string; - + while (base != null && context.length) base = base[context.pop().string]; if (base != null) gatherCompletions(base); diff --git a/addon/mode/multiplex.js b/addon/mode/multiplex.js index 459a918ea5..3ff3a929ed 100644 --- a/addon/mode/multiplex.js +++ b/addon/mode/multiplex.js @@ -61,7 +61,7 @@ CodeMirror.multiplexingMode = function(outer /*, others */) { return innerToken; } }, - + indent: function(state, textAfter) { var mode = state.innerActive ? state.innerActive.mode : outer; if (!mode.indent) return CodeMirror.Pass; diff --git a/addon/mode/overlay.js b/addon/mode/overlay.js index fba38987bb..b7928a7bbf 100644 --- a/addon/mode/overlay.js +++ b/addon/mode/overlay.js @@ -43,14 +43,14 @@ CodeMirror.overlayMode = CodeMirror.overlayParser = function(base, overlay, comb if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur; else return state.overlayCur; }, - + indent: base.indent && function(state, textAfter) { return base.indent(state.base, textAfter); }, electricChars: base.electricChars, 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); diff --git a/addon/search/match-highlighter.js b/addon/search/match-highlighter.js index c6e35cd97e..14c1dab5b6 100644 --- a/addon/search/match-highlighter.js +++ b/addon/search/match-highlighter.js @@ -14,7 +14,7 @@ (function() { var DEFAULT_MIN_CHARS = 2; var DEFAULT_TOKEN_STYLE = "matchhighlight"; - + function State(options) { this.minChars = typeof options == "object" && options.minChars || DEFAULT_MIN_CHARS; this.style = typeof options == "object" && options.style || DEFAULT_TOKEN_STYLE; diff --git a/addon/selection/active-line.js b/addon/selection/active-line.js index 988a0ffbf7..211de0fefd 100644 --- a/addon/selection/active-line.js +++ b/addon/selection/active-line.js @@ -20,7 +20,7 @@ delete cm._activeLine; } }); - + function clearActiveLine(cm) { if ("_activeLine" in cm) { cm.removeLineClass(cm._activeLine, "wrap", WRAP_CLASS); diff --git a/mode/asterisk/asterisk.js b/mode/asterisk/asterisk.js index d491857e92..60b689d1d5 100644 --- a/mode/asterisk/asterisk.js +++ b/mode/asterisk/asterisk.js @@ -8,7 +8,7 @@ * Created: 05/17/2012 09:20:25 PM * Revision: none * - * Author: Stas Kobzar (stas@modulis.ca), + * Author: Stas Kobzar (stas@modulis.ca), * Company: Modulis.ca Inc. * * ===================================================================================== @@ -99,9 +99,9 @@ CodeMirror.defineMode("asterisk", function() { state.extenStart = true; switch(cur) { case 'same': state.extenSame = true; break; - case 'include': - case 'switch': - case 'ignorepat': + case 'include': + case 'switch': + case 'ignorepat': state.extenInclude = true;break; default:break; } @@ -121,7 +121,7 @@ CodeMirror.defineMode("asterisk", function() { }; }, token: function(stream, state) { - + var cur = ''; var ch = ''; if(stream.eatSpace()) return null; @@ -174,7 +174,7 @@ CodeMirror.defineMode("asterisk", function() { } else{ return basicToken(stream,state); } - + return null; } }; diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 1b350aeb8c..c14d7b4006 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -222,7 +222,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { }); CodeMirror.defineMIME("text/x-java", { name: "clike", - keywords: words("abstract assert boolean break byte case catch char class const continue default " + + keywords: words("abstract assert boolean break byte case catch char class const continue default " + "do double else enum extends final finally float for goto if implements import " + "instanceof int interface long native new package private protected public " + "return short static strictfp super switch synchronized this throw throws transient " + @@ -238,12 +238,12 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { }); CodeMirror.defineMIME("text/x-csharp", { name: "clike", - keywords: words("abstract as 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" + - " sizeof stackalloc static struct switch this throw try typeof unchecked" + - " unsafe using virtual void volatile while add alias ascending descending dynamic from get" + + keywords: words("abstract as 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" + + " 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"), blockKeywords: words("catch class do else finally for foreach if struct switch try while"), builtin: words("Boolean Byte Char DateTime DateTimeOffset Decimal Double" + @@ -265,30 +265,30 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { CodeMirror.defineMIME("text/x-scala", { name: "clike", keywords: words( - + /* scala */ "abstract case catch class def do else extends false final finally for forSome if " + "implicit import lazy match new null object override package private protected return " + "sealed super this throw trait try trye type val var while with yield _ : = => <- <: " + "<% >: # @ " + - + /* package scala */ "assert assume require print println printf readLine readBoolean readByte readShort " + "readChar readInt readLong readFloat readDouble " + - + "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " + "Enumeration Equiv Error Exception Fractional Function IndexedSeq Integral Iterable " + "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " + "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " + "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector :: #:: " + - - /* package java.lang */ + + /* package java.lang */ "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void" - - + + ), blockKeywords: words("catch class do else finally for forSome if match switch try while"), atoms: words("true false null"), diff --git a/mode/clojure/clojure.js b/mode/clojure/clojure.js index 658ff140e0..7751212632 100644 --- a/mode/clojure/clojure.js +++ b/mode/clojure/clojure.js @@ -14,7 +14,7 @@ CodeMirror.defineMode("clojure", function () { } var atoms = makeKeywords("true false nil"); - + var keywords = makeKeywords( "defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle"); diff --git a/mode/coffeescript/coffeescript.js b/mode/coffeescript/coffeescript.js index 4d925037ce..cf1cf4f246 100644 --- a/mode/coffeescript/coffeescript.js +++ b/mode/coffeescript/coffeescript.js @@ -158,7 +158,7 @@ CodeMirror.defineMode('coffeescript', function(conf) { if (stream.match(identifiers)) { return 'variable'; } - + if (stream.match(properties)) { return 'property'; } diff --git a/mode/erlang/erlang.js b/mode/erlang/erlang.js index accf24e670..029b8e5561 100644 --- a/mode/erlang/erlang.js +++ b/mode/erlang/erlang.js @@ -247,7 +247,7 @@ CodeMirror.defineMode("erlang", function(cmCfg) { return rval(state,stream,"function"); } } - return rval(state,stream,"atom"); + return rval(state,stream,"atom"); } // number diff --git a/mode/gas/gas.js b/mode/gas/gas.js index 5ef4bb04ed..6604f01820 100644 --- a/mode/gas/gas.js +++ b/mode/gas/gas.js @@ -241,7 +241,7 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) { return "comment"; } - return { + return { startState: function() { return { tokenize: null diff --git a/mode/haskell/haskell.js b/mode/haskell/haskell.js index 71235f4ee9..faec08dc33 100644 --- a/mode/haskell/haskell.js +++ b/mode/haskell/haskell.js @@ -4,7 +4,7 @@ CodeMirror.defineMode("haskell", function() { setState(f); return f(source, setState); } - + // These should all be Unicode extended, as per the Haskell 2010 report var smallRE = /[a-z_]/; var largeRE = /[A-Z]/; @@ -15,12 +15,12 @@ CodeMirror.defineMode("haskell", function() { var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/; var specialRE = /[(),;[\]`{}]/; var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer - + function normal(source, setState) { if (source.eatWhile(whiteCharRE)) { return null; } - + var ch = source.next(); if (specialRE.test(ch)) { if (ch == '{' && source.eat('-')) { @@ -32,7 +32,7 @@ CodeMirror.defineMode("haskell", function() { } return null; } - + if (ch == '\'') { if (source.eat('\\')) { source.next(); // should handle other escapes here @@ -45,11 +45,11 @@ CodeMirror.defineMode("haskell", function() { } return "error"; } - + if (ch == '"') { return switchState(source, setState, stringLiteral); } - + if (largeRE.test(ch)) { source.eatWhile(idRE); if (source.eat('.')) { @@ -57,12 +57,12 @@ CodeMirror.defineMode("haskell", function() { } return "variable-2"; } - + if (smallRE.test(ch)) { source.eatWhile(idRE); return "variable"; } - + if (digitRE.test(ch)) { if (ch == '0') { if (source.eat(/[xX]/)) { @@ -87,7 +87,7 @@ CodeMirror.defineMode("haskell", function() { } return t; } - + if (symbolRE.test(ch)) { if (ch == '-' && source.eat(/-/)) { source.eatWhile(/-/); @@ -101,12 +101,12 @@ CodeMirror.defineMode("haskell", function() { t = "variable-2"; } source.eatWhile(symbolRE); - return t; + return t; } - + return "error"; } - + function ncomment(type, nest) { if (nest == 0) { return normal; @@ -130,7 +130,7 @@ CodeMirror.defineMode("haskell", function() { return type; }; } - + function stringLiteral(source, setState) { while (!source.eol()) { var ch = source.next(); @@ -153,7 +153,7 @@ CodeMirror.defineMode("haskell", function() { setState(normal); return "error"; } - + function stringGap(source, setState) { if (source.eat('\\')) { return switchState(source, setState, stringLiteral); @@ -162,8 +162,8 @@ CodeMirror.defineMode("haskell", function() { setState(normal); return "error"; } - - + + var wellKnownWords = (function() { var wkw = {}; function setType(t) { @@ -172,19 +172,19 @@ CodeMirror.defineMode("haskell", function() { wkw[arguments[i]] = t; }; } - + setType("keyword")( "case", "class", "data", "default", "deriving", "do", "else", "foreign", "if", "import", "in", "infix", "infixl", "infixr", "instance", "let", "module", "newtype", "of", "then", "type", "where", "_"); - + setType("keyword")( "\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>"); - + setType("builtin")( "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<", "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**"); - + setType("builtin")( "Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum", "Eq", "False", "FilePath", "Float", "Floating", "Fractional", "Functor", "GT", @@ -192,7 +192,7 @@ CodeMirror.defineMode("haskell", function() { "Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read", "ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS", "String", "True"); - + setType("builtin")( "abs", "acos", "acosh", "all", "and", "any", "appendFile", "asTypeOf", "asin", "asinh", "atan", "atan2", "atanh", "break", "catch", "ceiling", @@ -220,16 +220,16 @@ CodeMirror.defineMode("haskell", function() { "toRational", "truncate", "uncurry", "undefined", "unlines", "until", "unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip", "zip3", "zipWith", "zipWith3"); - + return wkw; })(); - - - + + + return { startState: function () { return { f: normal }; }, copyState: function (s) { return { f: s.f }; }, - + token: function(stream, state) { var t = state.f(stream, function(s) { state.f = s; }); var w = stream.current(); diff --git a/mode/haxe/haxe.js b/mode/haxe/haxe.js index 786fe92d06..28f9b00ec3 100644 --- a/mode/haxe/haxe.js +++ b/mode/haxe/haxe.js @@ -1,6 +1,6 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) { var indentUnit = config.indentUnit; - + // Tokenizer var keywords = function(){ @@ -12,10 +12,10 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) { "if": A, "while": A, "else": B, "do": B, "try": B, "return": C, "break": C, "continue": C, "new": C, "throw": C, "var": kw("var"), "inline":attribute, "static": attribute, "using":kw("import"), - "public": attribute, "private": attribute, "cast": kw("cast"), "import": kw("import"), "macro": kw("macro"), + "public": attribute, "private": attribute, "cast": kw("cast"), "import": kw("import"), "macro": kw("macro"), "function": kw("function"), "catch": kw("catch"), "untyped": kw("untyped"), "callback": kw("cb"), "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"), - "in": operator, "never": kw("property_access"), "trace":kw("trace"), + "in": operator, "never": kw("property_access"), "trace":kw("trace"), "class": type, "enum":type, "interface":type, "typedef":type, "extends":type, "implements":type, "dynamic":type, "true": atom, "false": atom, "null": atom }; @@ -55,14 +55,14 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) { else if (ch == "0" && stream.eat(/x/i)) { stream.eatWhile(/[\da-f]/i); return ret("number", "number"); - } + } else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) { stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); return ret("number", "number"); } else if (state.reAllowed && (ch == "~" && stream.eat(/\//))) { nextUntilUnescaped(stream, "/"); - stream.eatWhile(/[gimsu]/); + stream.eatWhile(/[gimsu]/); return ret("regexp", "string-2"); } else if (ch == "/") { @@ -146,13 +146,13 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) { for (var v = state.localVars; v; v = v.next) if (v.name == varname) return true; } - + function parseHaxe(state, style, type, content, stream) { var cc = state.cc; // Communicate our context to the combinators. // (Less wasteful than consing up a hundred closures on every call.) cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; - + if (!state.lexical.hasOwnProperty("align")) state.lexical.align = true; @@ -168,7 +168,7 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) { } } } - + function imported(state, typename) { if (/[a-z]/.test(typename.charAt(0))) @@ -177,8 +177,8 @@ CodeMirror.defineMode("haxe", function(config, parserConfig) { for (var i = 0; i/i; - + //inner modes var scriptingMode, htmlMixedMode; - + //tokenizer when in html mode function htmlDispatch(stream, state) { if (stream.match(scriptStartRegex, false)) { @@ -32,7 +32,7 @@ CodeMirror.defineMode("htmlembedded", function(config, parserConfig) { startState: function() { scriptingMode = scriptingMode || CodeMirror.getMode(config, parserConfig.scriptingModeSpec); htmlMixedMode = htmlMixedMode || CodeMirror.getMode(config, "htmlmixed"); - return { + return { token : parserConfig.startOpen ? scriptingDispatch : htmlDispatch, htmlState : CodeMirror.startState(htmlMixedMode), scriptState : CodeMirror.startState(scriptingMode) @@ -49,7 +49,7 @@ CodeMirror.defineMode("htmlembedded", function(config, parserConfig) { else if (scriptingMode.indent) return scriptingMode.indent(state.scriptState, textAfter); }, - + copyState: function(state) { return { token : state.token, @@ -57,7 +57,7 @@ CodeMirror.defineMode("htmlembedded", function(config, parserConfig) { scriptState : CodeMirror.copyState(scriptingMode, state.scriptState) }; }, - + electricChars: "/{}:", innerMode: function(state) { diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index bfbf78378b..6f7c33c2ac 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -11,7 +11,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function kw(type) {return {type: type, style: "keyword"};} var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"); var operator = kw("operator"), atom = {type: "atom", style: "atom"}; - + var jsKeywords = { "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, @@ -87,7 +87,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { else if (ch == "0" && stream.eat(/x/i)) { stream.eatWhile(/[\da-f]/i); return ret("number", "number"); - } + } else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) { stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); return ret("number", "number"); @@ -170,7 +170,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { // Communicate our context to the combinators. // (Less wasteful than consing up a hundred closures on every call.) cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; - + if (!state.lexical.hasOwnProperty("align")) state.lexical.align = true; @@ -282,7 +282,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type.match(/[;\}\)\],]/)) return pass(); return pass(expression); } - + function maybeoperator(type, value) { if (type == "operator") { if (/\+\+|--/.test(value)) return cont(maybeoperator); diff --git a/mode/jinja2/jinja2.js b/mode/jinja2/jinja2.js index 1472d398f2..16b06c48ef 100644 --- a/mode/jinja2/jinja2.js +++ b/mode/jinja2/jinja2.js @@ -1,5 +1,5 @@ CodeMirror.defineMode("jinja2", function() { - var keywords = ["block", "endblock", "for", "endfor", "in", "true", "false", + var keywords = ["block", "endblock", "for", "endfor", "in", "true", "false", "loop", "none", "self", "super", "if", "as", "not", "and", "else", "import", "with", "without", "context"]; keywords = new RegExp("^((" + keywords.join(")|(") + "))\\b"); @@ -38,5 +38,5 @@ CodeMirror.defineMode("jinja2", function() { token: function (stream, state) { return state.tokenize(stream, state); } - }; + }; }); diff --git a/mode/less/less.js b/mode/less/less.js index 4f6214363a..6df4790995 100644 --- a/mode/less/less.js +++ b/mode/less/less.js @@ -9,16 +9,16 @@ CodeMirror.defineMode("less", function(config) { function ret(style, tp) {type = tp; return style;} //html tags var tags = "a abbr acronym address applet area article aside audio b base basefont bdi bdo big blockquote body br button canvas caption cite code col colgroup command datalist dd del details dfn dir div dl dt em embed fieldset figcaption figure font footer form frame frameset h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins keygen kbd label legend li link map mark menu meta meter nav noframes noscript object ol optgroup option output p param pre progress q rp rt ruby s samp script section select small source span strike strong style sub summary sup table tbody td textarea tfoot th thead time title tr track tt u ul var video wbr".split(' '); - + function inTagsArray(val){ for(var i=0; i= 0) { // Continued list if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block @@ -123,7 +123,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.list = false; state.listDepth = 0; } - + if (state.indentationDiff >= 4) { state.indentation -= 4; stream.skipToEnd(); @@ -158,7 +158,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { switchBlock(stream, state, local); return code; } - + return switchInline(stream, state, state.inline); } @@ -193,17 +193,17 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { // Inline function getType(state) { var styles = []; - + if (state.taskOpen) { return "meta"; } if (state.taskClosed) { return "property"; } - + if (state.strong) { styles.push(strong); } if (state.em) { styles.push(em); } - + if (state.linkText) { styles.push(linktext); } - + if (state.code) { styles.push(code); } - + if (state.header) { styles.push(header); } if (state.quote) { styles.push(state.quote % 2 ? quote1 : quote2); } if (state.list !== false) { @@ -224,19 +224,19 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { if (stream.match(textRE, true)) { return getType(state); } - return undefined; + return undefined; } function inlineNormal(stream, state) { var style = state.text(stream, state); if (typeof style !== 'undefined') return style; - + if (state.list) { // List marker (*, +, -, 1., etc) state.list = null; return getType(state); } - + if (state.taskList) { var taskOpen = stream.match(taskListRE, true)[1] !== "x"; if (taskOpen) state.taskOpen = true; @@ -244,17 +244,17 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.taskList = false; return getType(state); } - + state.taskOpen = false; state.taskClosed = false; - + var ch = stream.next(); - + if (ch === '\\') { stream.next(); return getType(state); } - + // Matches link titles present on next line if (state.linkTitle) { state.linkTitle = false; @@ -268,7 +268,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return linkhref; } } - + // If this block is changed, it may need to be updated in GFM mode if (ch === '`') { var t = getType(state); @@ -289,7 +289,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } else if (state.code) { return getType(state); } - + if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) { stream.match(/\[[^\]]*\]/); state.inline = state.f = linkHref; @@ -307,15 +307,15 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.inline = state.f = linkHref; return type; } - + if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, true)) { return switchInline(stream, state, inlineElement(linkinline, '>')); } - + if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, true)) { return switchInline(stream, state, inlineElement(linkemail, '>')); } - + if (ch === '<' && stream.match(/^\w/, false)) { if (stream.string.indexOf(">")!=-1) { var atts = stream.string.substring(1,stream.string.indexOf(">")); @@ -326,12 +326,12 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { stream.backUp(1); return switchBlock(stream, state, htmlBlock); } - + if (ch === '<' && stream.match(/^\/\w*?>/)) { state.md_inside = false; return "tag"; } - + var ignoreUnderscore = false; if (!modeCfg.underscoresBreakWords) { if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) { @@ -368,7 +368,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } } } - + return getType(state); } @@ -414,7 +414,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { if (!savedInlineRE[endChar]) { // Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741) endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); - // Match any non-endChar, escaped character, as well as the closing + // Match any non-endChar, escaped character, as well as the closing // endChar. savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')'); } @@ -434,17 +434,17 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { startState: function() { return { f: blockNormal, - + prevLineHasContent: false, thisLineHasContent: false, - + block: blockNormal, htmlState: CodeMirror.startState(htmlMode), indentation: 0, - + inline: inlineNormal, text: handleText, - + linkText: false, linkTitle: false, em: false, @@ -460,17 +460,17 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { copyState: function(s) { return { f: s.f, - + prevLineHasContent: s.prevLineHasContent, thisLineHasContent: s.thisLineHasContent, - + block: s.block, htmlState: CodeMirror.copyState(htmlMode, s.htmlState), indentation: s.indentation, - + localMode: s.localMode, localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null, - + inline: s.inline, text: s.text, linkTitle: s.linkTitle, @@ -497,10 +497,10 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { // Reset state.header state.header = false; - + // Reset state.taskList state.taskList = false; - + // Reset state.code state.code = false; diff --git a/mode/markdown/test.js b/mode/markdown/test.js index cfc229bc3f..c451412fee 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -39,20 +39,20 @@ "[comment `]"); // Unclosed backticks - // Instead of simply marking as CODE, it would be nice to have an + // Instead of simply marking as CODE, it would be nice to have an // incomplete flag for CODE, that is styled slightly different. MT("unclosedBackticks", "foo [comment `bar]"); - // Per documentation: "To include a literal backtick character within a - // code span, you can use multiple backticks as the opening and closing + // Per documentation: "To include a literal backtick character within a + // code span, you can use multiple backticks as the opening and closing // delimiters" MT("doubleBackticks", "[comment ``foo ` bar``]"); // Tests based on Dingus // http://daringfireball.net/projects/markdown/dingus - // + // // Multiple backticks within an inline code block MT("consecutiveBackticks", "[comment `foo```bar`]"); @@ -98,10 +98,10 @@ // Setext headers - H1, H2 // Per documentation, "Any number of underlining =’s or -’s will work." // http://daringfireball.net/projects/markdown/syntax#header - // Ideally, the text would be marked as `header` as well, but this is - // not really feasible at the moment. So, instead, we're testing against + // Ideally, the text would be marked as `header` as well, but this is + // not really feasible at the moment. So, instead, we're testing against // what works today, to avoid any regressions. - // + // // Check if single underlining = works MT("setextH1", "foo", @@ -368,7 +368,7 @@ " [comment world]", " [comment foo]", " [variable-2 bar]"); - + // List nesting edge cases MT("listNested", "[variable-2 * foo]", @@ -548,7 +548,7 @@ MT("emInWordUnderscore", "foo[em _bar_]hello"); - // Per documentation: "...surround an * or _ with spaces, it’ll be + // Per documentation: "...surround an * or _ with spaces, it’ll be // treated as a literal asterisk or underscore." MT("emEscapedBySpaceIn", @@ -558,7 +558,7 @@ "foo _ bar[em _hello_]world"); // Unclosed emphasis characters - // Instead of simply marking as EM / STRONG, it would be nice to have an + // Instead of simply marking as EM / STRONG, it would be nice to have an // incomplete flag for EM and STRONG, that is styled slightly different. MT("emIncompleteAsterisk", "foo [em *bar]"); @@ -625,7 +625,7 @@ // Tests to make sure GFM-specific things aren't getting through - + MT("taskList", "[variable-2 * [ ]] bar]"); diff --git a/mode/ntriples/ntriples.js b/mode/ntriples/ntriples.js index ced8645169..ed0cee34b0 100644 --- a/mode/ntriples/ntriples.js +++ b/mode/ntriples/ntriples.js @@ -1,22 +1,22 @@ /********************************************************** -* This script provides syntax highlighting support for +* This script provides syntax highlighting support for * the Ntriples format. -* Ntriples format specification: +* Ntriples format specification: * http://www.w3.org/TR/rdf-testcases/#ntriples ***********************************************************/ -/* +/* The following expression defines the defined ASF grammar transitions. pre_subject -> { ( writing_subject_uri | writing_bnode_uri ) - -> pre_predicate - -> writing_predicate_uri - -> pre_object - -> writing_object_uri | writing_object_bnode | - ( - writing_object_literal + -> pre_predicate + -> writing_predicate_uri + -> pre_object + -> writing_object_uri | writing_object_bnode | + ( + writing_object_literal -> writing_literal_lang | writing_literal_type ) -> post_object @@ -25,7 +25,7 @@ -> ERROR } */ -CodeMirror.defineMode("ntriples", function() { +CodeMirror.defineMode("ntriples", function() { var Location = { PRE_SUBJECT : 0, @@ -45,7 +45,7 @@ CodeMirror.defineMode("ntriples", function() { function transitState(currState, c) { var currLocation = currState.location; var ret; - + // Opening. if (currLocation == Location.PRE_SUBJECT && c == '<') ret = Location.WRITING_SUB_URI; else if(currLocation == Location.PRE_SUBJECT && c == '_') ret = Location.WRITING_BNODE_URI; @@ -53,7 +53,7 @@ CodeMirror.defineMode("ntriples", function() { else if(currLocation == Location.PRE_OBJ && c == '<') ret = Location.WRITING_OBJ_URI; else if(currLocation == Location.PRE_OBJ && c == '_') ret = Location.WRITING_OBJ_BNODE; else if(currLocation == Location.PRE_OBJ && c == '"') ret = Location.WRITING_OBJ_LITERAL; - + // Closing. else if(currLocation == Location.WRITING_SUB_URI && c == '>') ret = Location.PRE_PRED; else if(currLocation == Location.WRITING_BNODE_URI && c == ' ') ret = Location.PRE_PRED; @@ -63,33 +63,33 @@ CodeMirror.defineMode("ntriples", function() { else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '"') ret = Location.POST_OBJ; else if(currLocation == Location.WRITING_LIT_LANG && c == ' ') ret = Location.POST_OBJ; else if(currLocation == Location.WRITING_LIT_TYPE && c == '>') ret = Location.POST_OBJ; - + // Closing typed and language literal. else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '@') ret = Location.WRITING_LIT_LANG; else if(currLocation == Location.WRITING_OBJ_LITERAL && c == '^') ret = Location.WRITING_LIT_TYPE; // Spaces. - else if( c == ' ' && + else if( c == ' ' && ( - currLocation == Location.PRE_SUBJECT || - currLocation == Location.PRE_PRED || - currLocation == Location.PRE_OBJ || + currLocation == Location.PRE_SUBJECT || + currLocation == Location.PRE_PRED || + currLocation == Location.PRE_OBJ || currLocation == Location.POST_OBJ ) ) ret = currLocation; - + // Reset. - else if(currLocation == Location.POST_OBJ && c == '.') ret = Location.PRE_SUBJECT; - + else if(currLocation == Location.POST_OBJ && c == '.') ret = Location.PRE_SUBJECT; + // Error else ret = Location.ERROR; - + currState.location=ret; } return { startState: function() { - return { + return { location : Location.PRE_SUBJECT, uris : [], anchors : [], diff --git a/mode/ocaml/ocaml.js b/mode/ocaml/ocaml.js index 2ce3fb8f0c..7dc3d283b2 100644 --- a/mode/ocaml/ocaml.js +++ b/mode/ocaml/ocaml.js @@ -109,5 +109,5 @@ CodeMirror.defineMode('ocaml', function() { } }; }); - + CodeMirror.defineMIME('text/x-ocaml', 'ocaml'); diff --git a/mode/python/python.js b/mode/python/python.js index 951aaf8197..d69ef8389b 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -4,7 +4,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) { function wordRegexp(words) { return new RegExp("^((" + words.join(")|(") + "))\\b"); } - + var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!]"); var singleDelimiters = parserConf.singleDelimiters || new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]'); var doubleOperators = parserConf.doubleOperators || new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"); @@ -72,15 +72,15 @@ CodeMirror.defineMode("python", function(conf, parserConf) { if (stream.eatSpace()) { return null; } - + var ch = stream.peek(); - + // Handle Comments if (ch === '#') { stream.skipToEnd(); return 'comment'; } - + // Handle Number Literals if (stream.match(/^[0-9\.]/, false)) { var floatLiteral = false; @@ -116,13 +116,13 @@ CodeMirror.defineMode("python", function(conf, parserConf) { return 'number'; } } - + // Handle Strings if (stream.match(stringPrefixes)) { state.tokenize = tokenStringFactory(stream.current()); return state.tokenize(stream, state); } - + // Handle operators and Delimiters if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) { return null; @@ -135,31 +135,31 @@ CodeMirror.defineMode("python", function(conf, parserConf) { if (stream.match(singleDelimiters)) { return null; } - + if (stream.match(keywords)) { return 'keyword'; } - + if (stream.match(builtins)) { return 'builtin'; } - + if (stream.match(identifiers)) { return 'variable'; } - + // Handle non-detected items stream.next(); return ERRORCLASS; } - + function tokenStringFactory(delimiter) { while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) { delimiter = delimiter.substr(1); } var singleline = delimiter.length == 1; var OUTCLASS = 'string'; - + function tokenString(stream, state) { while (!stream.eol()) { stream.eatWhile(/[^'"\\]/); @@ -187,7 +187,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) { tokenString.isString = true; return tokenString; } - + function indent(stream, state, type) { type = type || 'py'; var indentUnit = 0; @@ -210,7 +210,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) { type: type }); } - + function dedent(stream, state, type) { type = type || 'py'; if (state.scopes.length == 1) return; @@ -259,7 +259,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) { } return style; } - + // Handle decorators if (current === '@') { return stream.match(identifiers, false) ? 'meta' : ERRORCLASS; @@ -269,7 +269,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) { && state.lastToken === 'meta') { style = 'meta'; } - + // Handle scope changes. if (current === 'pass' || current === 'return') { state.dedent += 1; @@ -298,7 +298,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) { if (state.scopes.length > 1) state.scopes.shift(); state.dedent -= 1; } - + return style; } @@ -312,27 +312,27 @@ CodeMirror.defineMode("python", function(conf, parserConf) { dedent: 0 }; }, - + token: function(stream, state) { var style = tokenLexer(stream, state); - + state.lastToken = style; - + if (stream.eol() && stream.lambda) { state.lambda = false; } - + return style; }, - + indent: function(state) { if (state.tokenize != tokenBase) { return state.tokenize.isString ? CodeMirror.Pass : 0; } - + return state.scopes[0].offset; } - + }; return external; }); diff --git a/mode/q/q.js b/mode/q/q.js index 6fc4e65a9c..56017e30ad 100644 --- a/mode/q/q.js +++ b/mode/q/q.js @@ -17,7 +17,7 @@ CodeMirror.defineMode("q",function(config){ return state.tokenize=tokenBase,"builtin"; } if(/\s/.test(c)) - return stream.peek()=="/"?(stream.skipToEnd(),"comment"):"whitespace"; + return stream.peek()=="/"?(stream.skipToEnd(),"comment"):"whitespace"; if(c=='"') return(state.tokenize=tokenString)(stream,state); if(c=='`') diff --git a/mode/shell/shell.js b/mode/shell/shell.js index 9ce139b411..ed09284f29 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -114,5 +114,5 @@ CodeMirror.defineMode('shell', function() { } }; }); - + CodeMirror.defineMIME('text/x-sh', 'shell'); diff --git a/mode/sieve/sieve.js b/mode/sieve/sieve.js index b1bba53e05..8ca2a4cb82 100644 --- a/mode/sieve/sieve.js +++ b/mode/sieve/sieve.js @@ -31,7 +31,7 @@ CodeMirror.defineMode("sieve", function(config) { state.tokenize = tokenString(ch); return state.tokenize(stream, state); } - + if (ch == "(") { state._indent.push("("); // add virtual angel wings so that editor behaves... @@ -44,24 +44,24 @@ CodeMirror.defineMode("sieve", function(config) { state._indent.push("{"); return null; } - + if (ch == ")") { state._indent.pop(); - state._indent.pop(); + state._indent.pop(); } if (ch === "}") { state._indent.pop(); return null; } - + if (ch == ",") return null; - + if (ch == ";") return null; - - + + if (/[{}\(\),;]/.test(ch)) return null; @@ -97,7 +97,7 @@ CodeMirror.defineMode("sieve", function(config) { if (atoms.propertyIsEnumerable(cur)) return "atom"; - + return null; } @@ -169,10 +169,10 @@ CodeMirror.defineMode("sieve", function(config) { var length = state._indent.length; if (_textAfter && (_textAfter[0] == "}")) length--; - + if (length <0) length = 0; - + return length * indentUnit; }, diff --git a/mode/sparql/sparql.js b/mode/sparql/sparql.js index 0b367b2a80..f7237698d3 100644 --- a/mode/sparql/sparql.js +++ b/mode/sparql/sparql.js @@ -117,7 +117,7 @@ CodeMirror.defineMode("sparql", function(config) { state.context.col = stream.column(); } } - + return style; }, diff --git a/mode/sql/sql.js b/mode/sql/sql.js index 78f8d7fbad..15f65920ca 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -9,7 +9,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { support = parserConfig.support || {}, hooks = parserConfig.hooks || {}, dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true}; - + function tokenBase(stream, state) { var ch = stream.next(); @@ -163,7 +163,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { (function() { "use strict"; - + // `identifier` function hookIdentifier(stream) { var escaped = false, ch; diff --git a/mode/tcl/tcl.js b/mode/tcl/tcl.js index 58ca709e4c..ed2c697217 100644 --- a/mode/tcl/tcl.js +++ b/mode/tcl/tcl.js @@ -56,7 +56,7 @@ CodeMirror.defineMode("tcl", function() { else if (ch == "$") { stream.eatWhile(/[$_a-z0-9A-Z\.{:]/); stream.eatWhile(/}/); - state.beforeParams = true; + state.beforeParams = true; return "builtin"; } else if (isOperatorChar.test(ch)) { diff --git a/mode/vb/vb.js b/mode/vb/vb.js index 764c07101a..27b2271951 100644 --- a/mode/vb/vb.js +++ b/mode/vb/vb.js @@ -1,10 +1,10 @@ CodeMirror.defineMode("vb", function(conf, parserConf) { var ERRORCLASS = 'error'; - + function wordRegexp(words) { return new RegExp("^((" + words.join(")|(") + "))\\b", "i"); } - + var singleOperators = new RegExp("^[\\+\\-\\*/%&\\\\|\\^~<>!]"); var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]'); var doubleOperators = new RegExp("^((==)|(<>)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"); @@ -15,9 +15,9 @@ CodeMirror.defineMode("vb", function(conf, parserConf) { var openingKeywords = ['class','module', 'sub','enum','select','while','if','function', 'get','set','property', 'try']; var middleKeywords = ['else','elseif','case', 'catch']; var endKeywords = ['next','loop']; - + var wordOperators = wordRegexp(['and', 'or', 'not', 'xor', 'in']); - var commonkeywords = ['as', 'dim', 'break', 'continue','optional', 'then', 'until', + var commonkeywords = ['as', 'dim', 'break', 'continue','optional', 'then', 'until', 'goto', 'byval','byref','new','handles','property', 'return', 'const','private', 'protected', 'friend', 'public', 'shared', 'static', 'true','false']; var commontypes = ['integer','string','double','decimal','boolean','short','char', 'float','single']; @@ -34,13 +34,13 @@ CodeMirror.defineMode("vb", function(conf, parserConf) { var indentInfo = null; - + function indent(_stream, state) { state.currentIndent++; } - + function dedent(_stream, state) { state.currentIndent--; } @@ -49,16 +49,16 @@ CodeMirror.defineMode("vb", function(conf, parserConf) { if (stream.eatSpace()) { return null; } - + var ch = stream.peek(); - + // Handle Comments if (ch === "'") { stream.skipToEnd(); return 'comment'; } - - + + // Handle Number Literals if (stream.match(/^((&H)|(&O))?[0-9\.a-f]/i, false)) { var floatLiteral = false; @@ -66,7 +66,7 @@ CodeMirror.defineMode("vb", function(conf, parserConf) { if (stream.match(/^\d*\.\d+F?/i)) { floatLiteral = true; } else if (stream.match(/^\d+\.\d*F?/)) { floatLiteral = true; } else if (stream.match(/^\.\d+F?/)) { floatLiteral = true; } - + if (floatLiteral) { // Float literals may be "imaginary" stream.eat(/J/i); @@ -93,13 +93,13 @@ CodeMirror.defineMode("vb", function(conf, parserConf) { return 'number'; } } - + // Handle Strings if (stream.match(stringPrefixes)) { state.tokenize = tokenStringFactory(stream.current()); return state.tokenize(stream, state); } - + // Handle operators and Delimiters if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) { return null; @@ -137,28 +137,28 @@ CodeMirror.defineMode("vb", function(conf, parserConf) { dedent(stream,state); return 'keyword'; } - + if (stream.match(types)) { return 'keyword'; } - + if (stream.match(keywords)) { return 'keyword'; } - + if (stream.match(identifiers)) { return 'variable'; } - + // Handle non-detected items stream.next(); return ERRORCLASS; } - + function tokenStringFactory(delimiter) { var singleline = delimiter.length == 1; var OUTCLASS = 'string'; - + return function(stream, state) { while (!stream.eol()) { stream.eatWhile(/[^'"]/); @@ -179,7 +179,7 @@ CodeMirror.defineMode("vb", function(conf, parserConf) { return OUTCLASS; }; } - + function tokenLexer(stream, state) { var style = state.tokenize(stream, state); @@ -195,8 +195,8 @@ CodeMirror.defineMode("vb", function(conf, parserConf) { return ERRORCLASS; } } - - + + var delimiter_index = '[({'.indexOf(current); if (delimiter_index !== -1) { indent(stream, state ); @@ -212,7 +212,7 @@ CodeMirror.defineMode("vb", function(conf, parserConf) { return ERRORCLASS; } } - + return style; } @@ -229,7 +229,7 @@ CodeMirror.defineMode("vb", function(conf, parserConf) { }; }, - + token: function(stream, state) { if (stream.sol()) { state.currentIndent += state.nextLineIndent; @@ -237,24 +237,23 @@ CodeMirror.defineMode("vb", function(conf, parserConf) { state.doInCurrentLine = 0; } var style = tokenLexer(stream, state); - + state.lastToken = {style:style, content: stream.current()}; - - - + + + return style; }, - + indent: function(state, textAfter) { var trueText = textAfter.replace(/^\s+|\s+$/g, '') ; if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1); if(state.currentIndent < 0) return 0; return state.currentIndent * conf.indentUnit; } - + }; return external; }); CodeMirror.defineMIME("text/x-vb", "vb"); - diff --git a/mode/xml/xml.js b/mode/xml/xml.js index a68b033841..440343bbe7 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -86,7 +86,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { var ok; if (stream.eat("#")) { if (stream.eat("x")) { - ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); + ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); } else { ok = stream.eatWhile(/[\d]/) && stream.eat(";"); } diff --git a/mode/xquery/xquery.js b/mode/xquery/xquery.js index d5c859e00a..95decc11b7 100644 --- a/mode/xquery/xquery.js +++ b/mode/xquery/xquery.js @@ -35,18 +35,18 @@ CodeMirror.defineMode("xquery", function() { , atom = {type: "atom", style: "atom"} , punctuation = {type: "punctuation", style: null} , qualifier = {type: "axis_specifier", style: "qualifier"}; - + // kwObj is what is return from this function at the end var kwObj = { 'if': A, 'switch': A, 'while': A, 'for': A, 'else': B, 'then': B, 'try': B, 'finally': B, 'catch': B, - 'element': C, 'attribute': C, 'let': C, 'implements': C, 'import': C, 'module': C, 'namespace': C, - 'return': C, 'super': C, 'this': C, 'throws': C, 'where': C, 'private': C, + 'element': C, 'attribute': C, 'let': C, 'implements': C, 'import': C, 'module': C, 'namespace': C, + 'return': C, 'super': C, 'this': C, 'throws': C, 'where': C, 'private': C, ',': punctuation, 'null': atom, 'fn:false()': atom, 'fn:true()': atom }; - - // a list of 'basic' keywords. For each add a property to kwObj with the value of + + // a list of 'basic' keywords. For each add a property to kwObj with the value of // {type: basic[i], style: "keyword"} e.g. 'after' --> {type: "after", style: "keyword"} var basic = ['after','ancestor','ancestor-or-self','and','as','ascending','assert','attribute','before', 'by','case','cast','child','comment','declare','default','define','descendant','descendant-or-self', @@ -57,20 +57,20 @@ CodeMirror.defineMode("xquery", function() { 'self','some','sortby','stable','text','then','to','treat','typeswitch','union','variable','version','where', 'xquery', 'empty-sequence']; for(var i=0, l=basic.length; i < l; i++) { kwObj[basic[i]] = kw(basic[i]);}; - - // a list of types. For each add a property to kwObj with the value of + + // a list of types. For each add a property to kwObj with the value of // {type: "atom", style: "atom"} - var types = ['xs:string', 'xs:float', 'xs:decimal', 'xs:double', 'xs:integer', 'xs:boolean', 'xs:date', 'xs:dateTime', - 'xs:time', 'xs:duration', 'xs:dayTimeDuration', 'xs:time', 'xs:yearMonthDuration', 'numeric', 'xs:hexBinary', + var types = ['xs:string', 'xs:float', 'xs:decimal', 'xs:double', 'xs:integer', 'xs:boolean', 'xs:date', 'xs:dateTime', + 'xs:time', 'xs:duration', 'xs:dayTimeDuration', 'xs:time', 'xs:yearMonthDuration', 'numeric', 'xs:hexBinary', 'xs:base64Binary', 'xs:anyURI', 'xs:QName', 'xs:byte','xs:boolean','xs:anyURI','xf:yearMonthDuration']; for(var i=0, l=types.length; i < l; i++) { kwObj[types[i]] = atom;}; - + // each operator will add a property to kwObj with value of {type: "operator", style: "keyword"} var operators = ['eq', 'ne', 'lt', 'le', 'gt', 'ge', ':=', '=', '>', '>=', '<', '<=', '.', '|', '?', 'and', 'or', 'div', 'idiv', 'mod', '*', '/', '+', '-']; for(var i=0, l=operators.length; i < l; i++) { kwObj[operators[i]] = operator;}; - + // each axis_specifiers will add a property to kwObj with value of {type: "axis_specifier", style: "qualifier"} - var axis_specifiers = ["self::", "attribute::", "child::", "descendant::", "descendant-or-self::", "parent::", + var axis_specifiers = ["self::", "attribute::", "child::", "descendant::", "descendant-or-self::", "parent::", "ancestor::", "ancestor-or-self::", "following::", "preceding::", "following-sibling::", "preceding-sibling::"]; for(var i=0, l=axis_specifiers.length; i < l; i++) { kwObj[axis_specifiers[i]] = qualifier; }; @@ -80,42 +80,42 @@ CodeMirror.defineMode("xquery", function() { // Used as scratch variables to communicate multiple values without // consing up tons of objects. var type, content; - + function ret(tp, style, cont) { type = tp; content = cont; return style; } - + function chain(stream, state, f) { state.tokenize = f; return f(stream, state); } - + // the primary mode tokenizer function tokenBase(stream, state) { - var ch = stream.next(), + var ch = stream.next(), mightBeFunction = false, isEQName = isEQNameAhead(stream); - + // an XML tag (if not in some sub, chained tokenizer) if (ch == "<") { if(stream.match("!--", true)) return chain(stream, state, tokenXMLComment); - + if(stream.match("![CDATA", false)) { state.tokenize = tokenCDATA; return ret("tag", "tag"); } - + if(stream.match("?", false)) { return chain(stream, state, tokenPreProcessing); } - + var isclose = stream.eat("/"); stream.eatSpace(); var tagName = "", c; while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c; - + return chain(stream, state, tokenTag(tagName, isclose)); } // start code block @@ -136,7 +136,7 @@ CodeMirror.defineMode("xquery", function() { popStateStack(state); return ret("tag", "tag"); } - else + else return ret("word", "variable"); } // if a number @@ -186,13 +186,13 @@ CodeMirror.defineMode("xquery", function() { // if there's a EQName ahead, consume the rest of the string portion, it's likely a function if(isEQName && ch === '\"') while(stream.next() !== '"'){} if(isEQName && ch === '\'') while(stream.next() !== '\''){} - + // gobble up a word if the character is not known if(!known) stream.eatWhile(/[\w\$_-]/); - + // gobble a colon in the case that is a lib func type call fn:doc var foundColon = stream.eat(":"); - + // if there's not a second colon, gobble another word. Otherwise, it's probably an axis specifier // which should get matched as a keyword if(!stream.eat(":") && foundColon) { @@ -205,27 +205,27 @@ CodeMirror.defineMode("xquery", function() { // is the word a keyword? var word = stream.current(); known = keywords.propertyIsEnumerable(word) && keywords[word]; - - // if we think it's a function call but not yet known, + + // if we think it's a function call but not yet known, // set style to variable for now for lack of something better if(mightBeFunction && !known) known = {type: "function_call", style: "variable def"}; - + // if the previous word was element, attribute, axis specifier, this word should be the name of that if(isInXmlConstructor(state)) { popStateStack(state); return ret("word", "variable", word); } - // as previously checked, if the word is element,attribute, axis specifier, call it an "xmlconstructor" and + // as previously checked, if the word is element,attribute, axis specifier, call it an "xmlconstructor" and // push the stack so we know to look for it on the next word if(word == "element" || word == "attribute" || known.type == "axis_specifier") pushStateStack(state, {type: "xmlconstructor"}); - + // if the word is known, return the details of that else just call this a generic 'word' return known ? ret(known.type, known.style, word) : ret("word", "variable", word); } } - // handle comments, including nested + // handle comments, including nested function tokenComment(stream, state) { var maybeEnd = false, maybeNested = false, nestedCount = 0, ch; while (ch = stream.next()) { @@ -243,7 +243,7 @@ CodeMirror.defineMode("xquery", function() { maybeEnd = (ch == ":"); maybeNested = (ch == "("); } - + return ret("comment", "comment"); } @@ -264,10 +264,10 @@ CodeMirror.defineMode("xquery", function() { // if we're in a string and in an XML block, allow an embedded code block if(stream.match("{", false) && isInXmlAttributeBlock(state)) { state.tokenize = tokenBase; - return ret("string", "string"); + return ret("string", "string"); } - + while (ch = stream.next()) { if (ch == quote) { popStateStack(state); @@ -278,16 +278,16 @@ CodeMirror.defineMode("xquery", function() { // if we're in a string and in an XML block, allow an embedded code block in an attribute if(stream.match("{", false) && isInXmlAttributeBlock(state)) { state.tokenize = tokenBase; - return ret("string", "string"); + return ret("string", "string"); } } } - + return ret("string", "string"); }; } - + // tokenizer for variables function tokenVariable(stream, state) { var isVariableChar = /[\w\$_-]/; @@ -304,7 +304,7 @@ CodeMirror.defineMode("xquery", function() { state.tokenize = tokenBase; return ret("variable", "variable"); } - + // tokenizer for XML tags function tokenTag(name, isclose) { return function(stream, state) { @@ -322,7 +322,7 @@ CodeMirror.defineMode("xquery", function() { return ret("tag", "tag"); } else { - state.tokenize = tokenBase; + state.tokenize = tokenBase; } return ret("tag", "tag"); }; @@ -331,7 +331,7 @@ CodeMirror.defineMode("xquery", function() { // tokenizer for XML attributes function tokenAttribute(stream, state) { var ch = stream.next(); - + if(ch == "/" && stream.eat(">")) { if(isInXmlAttributeBlock(state)) popStateStack(state); if(isInXmlBlock(state)) popStateStack(state); @@ -347,7 +347,7 @@ CodeMirror.defineMode("xquery", function() { if (ch == '"' || ch == "'") return chain(stream, state, tokenString(ch, tokenAttribute)); - if(!isInXmlAttributeBlock(state)) + if(!isInXmlAttributeBlock(state)) pushStateStack(state, { type: "attribute", name: name, tokenize: tokenAttribute}); stream.eat(/[a-zA-Z_:]/); @@ -357,18 +357,18 @@ CodeMirror.defineMode("xquery", function() { // the case where the attribute has not value and the tag was closed if(stream.match(">", false) || stream.match("/", false)) { popStateStack(state); - state.tokenize = tokenBase; + state.tokenize = tokenBase; } return ret("attribute", "attribute"); } - - // handle comments, including nested + + // handle comments, including nested function tokenXMLComment(stream, state) { var ch; while (ch = stream.next()) { if (ch == "-" && stream.match("->", true)) { - state.tokenize = tokenBase; + state.tokenize = tokenBase; return ret("comment", "comment"); } } @@ -380,7 +380,7 @@ CodeMirror.defineMode("xquery", function() { var ch; while (ch = stream.next()) { if (ch == "]" && stream.match("]", true)) { - state.tokenize = tokenBase; + state.tokenize = tokenBase; return ret("comment", "comment"); } } @@ -391,20 +391,20 @@ CodeMirror.defineMode("xquery", function() { var ch; while (ch = stream.next()) { if (ch == "?" && stream.match(">", true)) { - state.tokenize = tokenBase; + state.tokenize = tokenBase; return ret("comment", "comment meta"); } } } - - + + // functions to test the current context of the state function isInXmlBlock(state) { return isIn(state, "tag"); } function isInXmlAttributeBlock(state) { return isIn(state, "attribute"); } function isInXmlConstructor(state) { return isIn(state, "xmlconstructor"); } function isInString(state) { return isIn(state, "string"); } - function isEQNameAhead(stream) { + function isEQNameAhead(stream) { // assume we've already eaten a quote (") if(stream.current() === '"') return stream.match(/^[^\"]+\"\:/, false); @@ -413,21 +413,21 @@ CodeMirror.defineMode("xquery", function() { else return false; } - + function isIn(state, type) { - return (state.stack.length && state.stack[state.stack.length - 1].type == type); + return (state.stack.length && state.stack[state.stack.length - 1].type == type); } - + function pushStateStack(state, newState) { state.stack.push(newState); } - + function popStateStack(state) { state.stack.pop(); var reinstateTokenize = state.stack.length && state.stack[state.stack.length-1].tokenize; state.tokenize = reinstateTokenize || tokenBase; } - + // the interface for the mode API return { startState: function() { From d8a762c4276e7b330d3d0051e2b6a0dc063af287 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 12:04:11 +0200 Subject: [PATCH 0438/5273] Add a bin/lint for easy running of the linter --- CONTRIBUTING.md | 8 +++++--- bin/lint | 11 +++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100755 bin/lint diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index afc18373cc..4e040ff193 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -56,6 +56,8 @@ should be asked on the test suite under `mode/XXX/test.js`. Feel free to add new test suites to modes that don't have one yet (be sure to link the new tests into `test/index.html`). +- Follow the general code style of the rest of the project (see + below). Run `bin/lint` to verify that the linter is happy. - Make sure all tests pass. Visit `test/index.html` in your browser to run them. - Submit a pull request @@ -65,6 +67,6 @@ should be asked on the - 2 spaces per indentation level, no tabs. - Include semicolons after statements. -- Note that the linter (`test/lint/lint.js`) which is run after each - commit complains about unused variables and functions. Prefix their - names with an underscore to muffle it. +- Note that the linter (`bin/lint`) which is run after each commit + complains about unused variables and functions. Prefix their names + with an underscore to muffle it. diff --git a/bin/lint b/bin/lint new file mode 100755 index 0000000000..3b6338691e --- /dev/null +++ b/bin/lint @@ -0,0 +1,11 @@ +#!/usr/bin/env node + +var lint = require("../test/lint/lint"); + +process.chdir(__dirname.slice(0, __dirname.lastIndexOf("/"))); + +lint.checkDir("mode"); +lint.checkDir("lib"); +lint.checkDir("addon"); + +process.exit(lint.success() ? 0 : 1); From 164bc920784320383f98916fd9a6eabe1f6f81a7 Mon Sep 17 00:00:00 2001 From: Hocdoc Date: Fri, 29 Mar 2013 11:08:36 +0100 Subject: [PATCH 0439/5273] Remove double semicolon from eclipse theme. The double semicolon prevents LESS to compile the CSS file. --- theme/eclipse.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/eclipse.css b/theme/eclipse.css index 4807e45156..4137bbe26e 100644 --- a/theme/eclipse.css +++ b/theme/eclipse.css @@ -21,5 +21,5 @@ .cm-s-eclipse .CodeMirror-matchingbracket { outline:1px solid grey; - color:black !important;; + color:black !important; } From ab6d9193ea512ab84e1f7936cf25c5239feb78e3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 12:09:51 +0200 Subject: [PATCH 0440/5273] Leave selection positions at start of changed range alone --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 493bd71b08..ef7a9c2fdb 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2140,7 +2140,7 @@ window.CodeMirror = (function() { // hint is null, leave the selection alone as much as possible var adjustPos = function(pos) { - if (posLess(pos, change.from)) return pos; + if (!posLess(change.from, pos)) return pos; if (!posLess(change.to, pos)) return end; var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; From f15a14eed1d658957e756fa7dce13c80d0698b51 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 12:14:42 +0200 Subject: [PATCH 0441/5273] Disable another test on Phantom --- test/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.js b/test/test.js index 96f37353aa..a334c5a59c 100644 --- a/test/test.js +++ b/test/test.js @@ -858,7 +858,7 @@ testCM("verticalScroll", function(cm) { cm.setLine(0, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah"); is(sc.scrollWidth > baseWidth, "scrollbar present"); cm.setLine(0, "foo"); - eq(sc.scrollWidth, baseWidth, "scrollbar gone"); + if (!phantom) eq(sc.scrollWidth, baseWidth, "scrollbar gone"); cm.setLine(0, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaah"); cm.setLine(1, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbh"); is(sc.scrollWidth > baseWidth, "present again"); From 6cf4289de7e5295bd8dc5ee796d0e2bce8f4cbb1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 12:30:26 +0200 Subject: [PATCH 0442/5273] Make calculateScrollPos behave sanely when object doesn't fit into view --- lib/codemirror.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index ef7a9c2fdb..8f950f3f0a 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2530,11 +2530,16 @@ window.CodeMirror = (function() { function calculateScrollPos(cm, x1, y1, x2, y2) { var display = cm.display, pt = paddingTop(display); y1 += pt; y2 += pt; + if (y1 < 0) y1 = 0; var screen = display.scroller.clientHeight - scrollerCutOff, screentop = display.scroller.scrollTop, result = {}; var docBottom = cm.doc.height + paddingVert(display); var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10; - if (y1 < screentop) result.scrollTop = atTop ? 0 : Math.max(0, y1); - else if (y2 > screentop + screen) result.scrollTop = (atBottom ? docBottom : y2) - screen; + if (y1 < screentop) { + 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 screenw = display.scroller.clientWidth - scrollerCutOff, screenleft = display.scroller.scrollLeft; x1 += display.gutters.offsetWidth; x2 += display.gutters.offsetWidth; From 00d0c0b2eb98ebcd4c1a043f5f3aeb43fff9a8bb Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 12:32:37 +0200 Subject: [PATCH 0443/5273] Add Code per Node to real-world uses --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index d1769559f7..6bebfebc18 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -27,6 +27,7 @@

    { } CodeMi
  • APEye (tool for testing & documenting APIs)
  • BlueGriffon (HTML editor)
  • Cargo Collective (creative publishing platform)
  • +
  • Code per Node (Drupal module)
  • Codebug (PHP Xdebug front-end)
  • CodeMirror movie (scripted editing demos)
  • CodeMirror2-GWT (Google Web Toolkit wrapper)
  • From 4d63c15295b15c54af8fb2ac6193e81d5366d46b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 12:44:05 +0200 Subject: [PATCH 0444/5273] [matchbrackets addon] Skip scanning of huge lines, allow passing of config options Issue #1408 --- addon/edit/matchbrackets.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js index 72bca57091..167eece3d5 100644 --- a/addon/edit/matchbrackets.js +++ b/addon/edit/matchbrackets.js @@ -3,11 +3,11 @@ (document.documentMode == null || document.documentMode < 8); var Pos = CodeMirror.Pos; - // Disable brace matching in long lines, since it'll cause hugely slow updates - var maxLineLen = 1000; var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"}; function findMatchingBracket(cm) { + var maxScanLen = cm.state._matchBrackets.maxScanLineLength || 10000; + var cur = cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1; var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)]; if (!match) return null; @@ -18,6 +18,7 @@ function scan(line, lineNo, start) { if (!line.text) return; var pos = forward ? 0 : line.text.length - 1, end = forward ? line.text.length : -1; + if (line.text.length > maxScanLen) return null; if (start != null) pos = start + d; for (; pos != end; pos += d) { var ch = line.text.charAt(pos); @@ -38,9 +39,11 @@ } function matchBrackets(cm, autoclear) { + // Disable brace matching in long lines, since it'll cause hugely slow updates + var maxHighlightLen = cm.state._matchBrackets.maxHighlightLineLength || 1000; var found = findMatchingBracket(cm); - if (!found || cm.getLine(found.from.line).length > maxLineLen || - found.to && cm.getLine(found.to.line).length > maxLineLen) + if (!found || cm.getLine(found.from.line).length > maxHighlightLen || + found.to && cm.getLine(found.to.line).length > maxHighlightLen) return; var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; @@ -64,9 +67,13 @@ }); } - CodeMirror.defineOption("matchBrackets", false, function(cm, val) { - if (val) cm.on("cursorActivity", doMatchBrackets); - else cm.off("cursorActivity", doMatchBrackets); + CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) + cm.off("cursorActivity", doMatchBrackets); + if (val) { + cm.state._matchBrackets = typeof val == "object" ? val : {}; + cm.on("cursorActivity", doMatchBrackets); + } }); CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);}); From bcade67000aace1fefc7d5712ec8ed608a6bed16 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 12:49:41 +0200 Subject: [PATCH 0445/5273] [matchbrackets addon] Don't fetch tokens on long lines Without a bunch of more involved code, it has quadratic complexity, which gets slow rather fast. Closes #1408 --- addon/edit/matchbrackets.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js index 167eece3d5..e4ff914c6b 100644 --- a/addon/edit/matchbrackets.js +++ b/addon/edit/matchbrackets.js @@ -19,10 +19,11 @@ if (!line.text) return; var pos = forward ? 0 : line.text.length - 1, end = forward ? line.text.length : -1; if (line.text.length > maxScanLen) return null; + var checkTokenStyles = line.text.length < 1000; if (start != null) pos = start + d; for (; pos != end; pos += d) { var ch = line.text.charAt(pos); - if (re.test(ch) && cm.getTokenAt(Pos(lineNo, pos + 1)).type == style) { + if (re.test(ch) && (!checkTokenStyles || cm.getTokenAt(Pos(lineNo, pos + 1)).type == style)) { var match = matching[ch]; if (match.charAt(1) == ">" == forward) stack.push(ch); else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false}; From 5f25446d8f5fad8604d7c87bf4d0663d2fd6d134 Mon Sep 17 00:00:00 2001 From: Hasan Karahan Date: Sat, 30 Mar 2013 16:02:29 +0500 Subject: [PATCH 0446/5273] [rst-mode] Fixed strong, emphasis & literal rST rST does not allow mixing strong with simple emphasis, further it requires the stars to have a preceding and trailing whitespaces. Same for literal text; e.g. **strong** is correct, but **strong* is not, or *emphasis* is correct, but *emphasis** is not. --- mode/rst/rst.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mode/rst/rst.js b/mode/rst/rst.js index 5fed967a67..8de9d75415 100644 --- a/mode/rst/rst.js +++ b/mode/rst/rst.js @@ -501,9 +501,9 @@ CodeMirror.defineMode('rst', function (config, options) { rx_uri_protocol + rx_uri_domain + rx_uri_path ); - var rx_strong = /^\*\*[^\*\s](?:[^\*]*[^\*\s])?\*\*/; - var rx_emphasis = /^\*[^\*\s](?:[^\*]*[^\*\s])?\*/; - var rx_literal = /^``[^`\s](?:[^`]*[^`\s])``/; + var rx_strong = /^\*\*[^\*\s](?:[^\*]*[^\*\s])?\*\*(\s+|$)/; + var rx_emphasis = /^[^\*]\*[^\*\s](?:[^\*]*[^\*\s])?\*(\s+|$)/; + var rx_literal = /^``[^`\s](?:[^`]*[^`\s])``(\s+|$)/; var rx_number = /^(?:[\d]+(?:[\.,]\d+)*)/; var rx_positive = /^(?:\s\+[\d]+(?:[\.,]\d+)*)/; From 6139ad9d45da4c786a7958fdc2eb33198903a102 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 13:11:19 +0200 Subject: [PATCH 0447/5273] Ensure cursorActivity event is fired when the cursor is in changed range Closes #1411 --- lib/codemirror.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 8f950f3f0a..e1c79976c6 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1274,6 +1274,7 @@ window.CodeMirror = (function() { userSelChange: null, textChanged: null, selectionChanged: false, + cursorActivity: false, updateMaxLine: false, updateScrollPos: false, id: ++nextOpId @@ -1333,7 +1334,7 @@ window.CodeMirror = (function() { } if (op.textChanged) signal(cm, "change", cm, op.textChanged); - if (op.selectionChanged) signal(cm, "cursorActivity", cm); + if (op.cursorActivity) signal(cm, "cursorActivity", cm); if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i](); } @@ -2298,6 +2299,9 @@ window.CodeMirror = (function() { }); } + if (!posLess(doc.sel.head, change.from) && !posLess(change.to, doc.sel.head)) + cm.curOp.cursorActivity = true; + updateDoc(doc, change, spans, selAfter, estimateHeight(cm)); if (!cm.options.lineWrapping) { @@ -2424,7 +2428,8 @@ window.CodeMirror = (function() { sel.to = inv ? anchor : head; if (doc.cm) - doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; + doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = + doc.cm.curOp.cursorActivity = true; signalLater(doc, "cursorActivity", doc); } From 01c0c777a3a5f617d89b0759ad45c35d1ec9f6f8 Mon Sep 17 00:00:00 2001 From: Andy Li Date: Sun, 31 Mar 2013 22:52:40 +0800 Subject: [PATCH 0448/5273] Fix various HTML mistakes in docs --- doc/compress.html | 2 +- doc/internals.html | 2 +- doc/manual.html | 1 + doc/oldrelease.html | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index a100f9b965..cd4d41bac8 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -170,7 +170,7 @@

    { } CodeMi -

    +

    with UglifyJS diff --git a/doc/internals.html b/doc/internals.html index 9139528f3d..4336ba4d1c 100644 --- a/doc/internals.html +++ b/doc/internals.html @@ -50,7 +50,7 @@

    { } CodeMi integrated into about a thousand systems by now. The most prominent one, since a few weeks, being Google -code's project hosting. It works, and it's being used widely. +code's project hosting. It works, and it's being used widely.

    Still, I did not start replacing it because I was bored. CodeMirror 1 was heavily reliant on designMode diff --git a/doc/manual.html b/doc/manual.html index 4a601f2709..5244fce777 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1177,6 +1177,7 @@

    Widget, gutter, and decoration methods

    the height of the line that contains the widget.

  • +

    Sizing, scrolling and positioning methods

    diff --git a/doc/oldrelease.html b/doc/oldrelease.html index f97a65a8cb..b51e93c328 100644 --- a/doc/oldrelease.html +++ b/doc/oldrelease.html @@ -335,7 +335,7 @@

    { } CodeMi faster, smaller, simpler to use, and less dependent on browser quirks. See this and this - for more information. + for more information.

    28-03-2011: Version 1.0:

    22-02-2011: Version 2.0 beta 2:

    -

    Somewhat more mature API, lots of bugs shaken out. +

    Somewhat more mature API, lots of bugs shaken out.

    17-02-2011: Version 0.94:

      From f0d055b1d4972d5a8347a3b654cb7842e742eb76 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Tue, 2 Apr 2013 00:58:37 -0400 Subject: [PATCH 0449/5273] Implement custom scrolling Ctrl-D/U. --- keymap/vim.js | 38 +++++++++++++++++++++++++++++++++++++- test/vim_test.js | 27 +++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/keymap/vim.js b/keymap/vim.js index 77b696d93b..ba0e0942c1 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -131,6 +131,12 @@ motion: 'moveByPage', motionArgs: { forward: true }}, { keys: ['Ctrl-b'], type: 'motion', motion: 'moveByPage', motionArgs: { forward: false }}, + { keys: ['Ctrl-d'], type: 'motion', + motion: 'moveByScroll', + motionArgs: { forward: true, explicitRepeat: true }}, + { keys: ['Ctrl-u'], type: 'motion', + motion: 'moveByScroll', + motionArgs: { forward: false, explicitRepeat: true }}, { keys: ['g', 'g'], type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, linewise: true }}, @@ -1068,6 +1074,7 @@ switch (vim.lastMotion) { case this.moveByLines: case this.moveByDisplayLines: + case this.moveByScroll: case this.moveToColumn: case this.moveToEol: endCh = vim.lastHPos; @@ -1091,6 +1098,7 @@ var cur = cm.getCursor(); switch (vim.lastMotion) { case this.moveByDisplayLines: + case this.moveByScroll: case this.moveByLines: case this.moveToColumn: case this.moveToEol: @@ -1100,7 +1108,17 @@ } var repeat = motionArgs.repeat; var res=cm.findPosV(cur,(motionArgs.forward ? repeat : -repeat),"line",vim.lastHSPos); - if(res.hitSide)return null; + if (res.hitSide) { + if (motionArgs.forward) { + var lastCharCoords = cm.charCoords(res, 'div'); + var goalCoords = { top: lastCharCoords.top + 8, left: vim.lastHSPos }; + var res = cm.coordsChar(goalCoords, 'div'); + } else { + var resCoords = cm.charCoords({ line: cm.firstLine(), ch: 0}, 'div'); + resCoords.left = vim.lastHSPos; + res = cm.coordsChar(resCoords, 'div'); + } + } vim.lastHPos = res.ch; return res; }, @@ -1131,6 +1149,24 @@ } return { line: line, ch: 0 }; }, + moveByScroll: function(cm, motionArgs, vim) { + var globalState = getVimGlobalState(); + var scrollbox = cm.getScrollInfo(); + var curEnd = null; + var repeat = motionArgs.repeat; + if (!repeat) { + repeat = scrollbox.clientHeight / (2 * cm.defaultTextHeight()); + } + var orig = cm.charCoords(cm.getCursor(), 'local'); + motionArgs.repeat = repeat; + var curEnd = motions.moveByDisplayLines(cm, motionArgs, vim); + if (!curEnd) { + return null; + } + var dest = cm.charCoords(curEnd, 'local'); + cm.scrollTo(null, scrollbox.top + dest.top - orig.top); + return curEnd; + }, moveByWords: function(cm, motionArgs) { return moveToWord(cm, motionArgs.repeat, !!motionArgs.forward, !!motionArgs.wordEnd, !!motionArgs.bigWord); diff --git a/test/vim_test.js b/test/vim_test.js index f91be02f9e..fb0254a9ba 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -304,6 +304,33 @@ testVim('j_k_and_gj_gk', function(cm,vim,helpers){ helpers.doKeys('k'); helpers.assertCursorAt(0, 176); },{ lineWrapping:true, value: 'This line is intentially long to test movement of gj and gk over wrapped lines. I will start on the end of this line, then make a step up and back to set the origin for j and k.\nThis line is supposed to be even longer than the previous. I will jump here and make another wiggle with gj and gk, before I jump back to the line above. Both wiggles should not change my cursor\'s target character but both j/k and gj/gk change each other\'s reference position.'}); +testVim('gj_gk', function(cm, vim, helpers) { + cm.setSize(120); + // Test top of document edge case. + cm.setCursor(0, 4); + helpers.doKeys('g', 'j'); + helpers.doKeys('10', 'g', 'k'); + helpers.assertCursorAt(0, 4); + + // Test moving down preserves column position. + helpers.doKeys('g', 'j'); + var pos1 = cm.getCursor(); + var expectedPos2 = { line: 0, ch: (pos1.ch - 4) * 2 + 4}; + helpers.doKeys('g', 'j'); + helpers.assertCursorAt(expectedPos2); + + // Move to the last character + cm.setCursor(0, 0); + // Move left to reset HSPos + helpers.doKeys('h'); + // Test bottom of document edge case. + helpers.doKeys('100', 'g', 'j'); + var endingPos = cm.getCursor(); + is(endingPos != 0, 'gj should not be on wrapped line 0'); + var topLeftCharCoords = cm.charCoords(makeCursor(0, 0)); + var endingCharCoords = cm.charCoords(endingPos); + is(topLeftCharCoords.left == endingCharCoords.left, 'gj should end up on column 0'); +},{ lineNumbers: false, lineWrapping:true, value: 'Thislineisintentiallylongtotestmovementofgjandgkoverwrappedlines.' }); testVim('}', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('}'); From 37456d086e9da30b21493f20b901f0e890f31590 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 13:21:14 +0200 Subject: [PATCH 0450/5273] Disable another test that fails on Phantom but not on real Webkit --- test/vim_test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/vim_test.js b/test/vim_test.js index fb0254a9ba..bc04b7fc70 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -305,6 +305,7 @@ testVim('j_k_and_gj_gk', function(cm,vim,helpers){ helpers.assertCursorAt(0, 176); },{ lineWrapping:true, value: 'This line is intentially long to test movement of gj and gk over wrapped lines. I will start on the end of this line, then make a step up and back to set the origin for j and k.\nThis line is supposed to be even longer than the previous. I will jump here and make another wiggle with gj and gk, before I jump back to the line above. Both wiggles should not change my cursor\'s target character but both j/k and gj/gk change each other\'s reference position.'}); testVim('gj_gk', function(cm, vim, helpers) { + if (phantom) return; cm.setSize(120); // Test top of document edge case. cm.setCursor(0, 4); From 11805dda45b8432d852831ae3bf874c83e037d8b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Apr 2013 23:40:45 +0200 Subject: [PATCH 0451/5273] Fix newlineAndIndent command Closes #1415 --- lib/codemirror.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index e1c79976c6..e4171e82a5 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2609,6 +2609,7 @@ window.CodeMirror = (function() { if (indentString != curSpaceString) replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); line.stateAfter = null; + return indentString.length; } function changeLine(cm, handle, op) { @@ -2756,7 +2757,7 @@ window.CodeMirror = (function() { 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)) return indentLine(this, n, dir, aggressive); }), indentSelection: operation(null, function(how) { var sel = this.doc.sel; @@ -3296,7 +3297,8 @@ window.CodeMirror = (function() { newlineAndIndent: function(cm) { operation(cm, function() { cm.replaceSelection("\n", "end", "+input"); - cm.indentLine(cm.getCursor().line, null, true); + var line = cm.getCursor().line, indented = cm.indentLine(line, null, true); + if (indented) cm.setCursor(line, indented); })(); }, toggleOverwrite: function(cm) {cm.toggleOverwrite();} From 28b85eef53741aae9c9acaaee104bd18bf981a9f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Apr 2013 08:52:54 +0200 Subject: [PATCH 0452/5273] Document second argument to replaceSelection --- doc/manual.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 5244fce777..fd1a49f360 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -773,8 +773,13 @@

      Cursor and selection methods

      doc.getSelection() → string
      Get the currently selected code.
      -
      doc.replaceSelection(string)
      -
      Replace the selection with the given string.
      +
      doc.replaceSelection(string, collapse)
      +
      Replace the selection with the given string. By default, the + new selection will span the inserted text. The + optional collapse argument can be used to change + this—passing "start" or "end" will + collapse the selection to the start or end of the inserted + text.
      doc.getCursor(start) → object
      start is a an optional string indicating which From 90209f8cb05f815adc94b0b67a36c18c9eacbaa1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Apr 2013 09:05:36 +0200 Subject: [PATCH 0453/5273] [javascript mode] Handle non-typical for-initializers properly Closes #1418 --- 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 6f7c33c2ac..b2df95f639 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -358,7 +358,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "var") return cont(vardef1, expect(";"), forspec2); if (type == ";") return cont(forspec2); if (type == "variable") return cont(formaybein); - return cont(forspec2); + return pass(expression, expect(";"), forspec2); } function formaybein(_type, value) { if (value == "in") return cont(expression); From c1b7ea430aca76aaad9ce1c79990086f10a14c04 Mon Sep 17 00:00:00 2001 From: Albert Xing Date: Tue, 2 Apr 2013 16:26:20 -0700 Subject: [PATCH 0454/5273] [closebrackets addon] Do not auto-close single apostrophes in comments Make exception for auto-closing single apostrophes in comments, as per adobe/brackets#3246 --- addon/edit/closebrackets.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index b46caca02a..5e78ba2f03 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -17,7 +17,7 @@ if (cm.somethingSelected()) return CodeMirror.Pass; var cur = cm.getCursor(), line = cm.getLine(cur.line); if (cur.ch && cur.ch < line.length && - pairs.indexOf(line.slice(cur.ch - 1, cur.ch + 1)) % 2 == 0) + pairs.indexOf(line.slice(cur.ch - 1, cur.ch + 1)) % 2 == 0) cm.replaceRange("", CodeMirror.Pos(cur.line, cur.ch - 1), CodeMirror.Pos(cur.line, cur.ch + 1)); else return CodeMirror.Pass; @@ -27,8 +27,8 @@ for (var i = 0; i < pairs.length; i += 2) (function(left, right) { if (left != right) closingBrackets.push(right); function surround(cm) { - var selection = cm.getSelection(); - cm.replaceSelection(left + selection + right); + var selection = cm.getSelection(); + cm.replaceSelection(left + selection + right); } function maybeOverwrite(cm) { var cur = cm.getCursor(), ahead = cm.getRange(cur, CodeMirror.Pos(cur.line, cur.ch + 1)); @@ -36,6 +36,11 @@ else cm.execCommand("goCharRight"); } map["'" + left + "'"] = function(cm) { + var type = cm.getTokenAt(cm.getCursor()).type; + if (left === "'" && type === "comment") { + cm.replaceSelection("'", {head: ahead, anchor: ahead}); + return; + } if (cm.somethingSelected()) return surround(cm); if (left == right && maybeOverwrite(cm) != CodeMirror.Pass) return; var cur = cm.getCursor(), ahead = CodeMirror.Pos(cur.line, cur.ch + 1); From de0d4ebad64dd07695e23421e577e4219980cc40 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Apr 2013 09:15:30 +0200 Subject: [PATCH 0455/5273] [closebrackets addon] Clean up c1b7ea430aca76aaad9ce1c79990086f10a14c04 --- addon/edit/closebrackets.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 5e78ba2f03..43902aee68 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -36,11 +36,8 @@ else cm.execCommand("goCharRight"); } map["'" + left + "'"] = function(cm) { - var type = cm.getTokenAt(cm.getCursor()).type; - if (left === "'" && type === "comment") { - cm.replaceSelection("'", {head: ahead, anchor: ahead}); - return; - } + if (left == "'" && cm.getTokenAt(cm.getCursor()).type == "comment") + return CodeMirror.Pass; if (cm.somethingSelected()) return surround(cm); if (left == right && maybeOverwrite(cm) != CodeMirror.Pass) return; var cur = cm.getCursor(), ahead = CodeMirror.Pos(cur.line, cur.ch + 1); From f50582c497c21507f029f919ecd4d6ca99434de3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Apr 2013 16:44:05 +0200 Subject: [PATCH 0456/5273] Use a slightly more complicated heuristic for adjusting cursor pos at start of change Issue #1415 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index e4171e82a5..ac8b41a0ae 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2141,7 +2141,7 @@ window.CodeMirror = (function() { // hint is null, leave the selection alone as much as possible var adjustPos = function(pos) { - if (!posLess(change.from, pos)) return pos; + if (posEq(change.from, change.to) ? posLess(pos, change.from) : !posLess(change.from, pos)) return pos; if (!posLess(change.to, pos)) return end; var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; From c984988179f8093528eac125b1cdd4f5e67ee7da Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 4 Apr 2013 10:45:30 +0200 Subject: [PATCH 0457/5273] [javascript-hint addon] Fix undefined variable bug --- addon/hint/javascript-hint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/hint/javascript-hint.js b/addon/hint/javascript-hint.js index e3366147e3..b961c5abe9 100644 --- a/addon/hint/javascript-hint.js +++ b/addon/hint/javascript-hint.js @@ -25,7 +25,7 @@ // If it's not a 'word-style' token, ignore the token. if (!/^[\w$_]*$/.test(token.string)) { - token = tprop = {start: cur.ch, end: cur.ch, string: "", state: state, + token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state, type: token.string == "." ? "property" : null}; } // If it is a property, find out what it is a property of. From 58e59e3acf651a3f32a58333e5f6a0412c819eb9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 4 Apr 2013 10:56:45 +0200 Subject: [PATCH 0458/5273] [javascript mode] Another fix to parsing for-loop specs Issue #1418 --- 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 b2df95f639..89f1220369 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -367,7 +367,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function forspec2(type, value) { if (type == ";") return cont(forspec3); if (value == "in") return cont(expression); - return cont(expression, expect(";"), forspec3); + return pass(expression, expect(";"), forspec3); } function forspec3(type) { if (type != ")") cont(expression); From 17d836adebf1ddbbeb9635b4f1e55690c1935876 Mon Sep 17 00:00:00 2001 From: Andy Li Date: Thu, 4 Apr 2013 03:26:50 +0800 Subject: [PATCH 0459/5273] Standardized the type format used in manual. --- doc/manual.html | 373 ++++++++++++++++++++++++++---------------------- 1 file changed, 200 insertions(+), 173 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index fd1a49f360..fbf30573d2 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -119,11 +119,11 @@

      Configuration

      These are the supported options:

      -
      value (string or Doc)
      +
      value: string|CodeMirror.Doc
      The starting value of the editor. Can be a string, or a document object.
      -
      mode (string or object)
      +
      mode: string|object
      The mode to use. When not given, this will default to the first mode that was loaded. It may be a string, which either simply names the mode or is @@ -140,7 +140,7 @@

      Configuration

      mode names to their constructors, and the second maps MIME types to mode specs.
      -
      theme (string)
      +
      theme: string
      The theme to style the editor with. You must make sure the CSS file defining the corresponding .cm-s-[name] styles is loaded (see @@ -152,29 +152,29 @@

      Configuration

      the cm-s-foo and the cm-s-bar classes to the editor.
      -
      indentUnit (integer)
      +
      indentUnit: integer
      How many spaces a block (whatever that means in the edited language) should be indented. The default is 2.
      -
      smartIndent (boolean)
      +
      smartIndent: boolean
      Whether to use the context-sensitive indentation that the mode provides (or just indent the same as the line before). Defaults to true.
      -
      tabSize (integer)
      +
      tabSize: integer
      The width of a tab character. Defaults to 4.
      -
      indentWithTabs (boolean)
      +
      indentWithTabs: boolean
      Whether, when indenting, the first N*tabSize spaces should be replaced by N tabs. Default is false.
      -
      electricChars (boolean)
      +
      electricChars: boolean
      Configures whether the editor should re-indent the current line when a character is typed that might change its proper indentation (only works if the mode supports indentation). Default is true.
      -
      rtlMoveVisually (boolean)
      +
      rtlMoveVisually: boolean
      Determines whether horizontal cursor movement through right-to-left (Arabic, Hebrew) text is visual (pressing the left arrow moves the cursor left) or logical (pressing the left arrow @@ -182,7 +182,7 @@

      Configuration

      right in right-to-left text). The default is false on Windows, and true on other platforms.
      -
      keyMap (string)
      +
      keyMap: string
      Configures the keymap to use. The default is "default", which is the only keymap defined in codemirror.js itself. Extra keymaps are found in @@ -190,28 +190,28 @@

      Configuration

      the section on keymaps for more information.
      -
      extraKeys (object)
      +
      extraKeys: object
      Can be used to specify extra keybindings for the editor, alongside the ones defined by keyMap. Should be either null, or a valid keymap value.
      -
      lineWrapping (boolean)
      +
      lineWrapping: boolean
      Whether CodeMirror should scroll or wrap for long lines. Defaults to false (scroll).
      -
      lineNumbers (boolean)
      +
      lineNumbers: boolean
      Whether to show line numbers to the left of the editor.
      -
      firstLineNumber (integer)
      +
      firstLineNumber: integer
      At which number to start counting lines. Default is 1.
      -
      lineNumberFormatter (function)
      +
      lineNumberFormatter: (line: integer) → string
      A function used to format line numbers. The function is passed the line number, and should return a string that will be shown in the gutter.
      -
      gutters (array)
      +
      gutters: array<string>
      Can be used to add extra gutters (beyond or instead of the line number gutter). Should be an array of CSS class names, each of which defines a width (and optionally a @@ -223,31 +223,31 @@

      Configuration

      names are the keys passed to setGutterMarker.
      -
      fixedGutter (boolean)
      +
      fixedGutter: boolean
      Determines whether the gutter scrolls along with the content horizontally (false) or whether it stays fixed during horizontal scrolling (true, the default).
      -
      readOnly (boolean)
      +
      readOnly: boolean|string
      This disables editing of the editor content by the user. If the special value "nocursor" is given (instead of simply true), focusing of the editor is also disallowed.
      -
      showCursorWhenSelecting (boolean)
      +
      showCursorWhenSelecting: boolean
      Whether the cursor should be drawn when a selection is active. Defaults to false.
      -
      undoDepth (integer)
      +
      undoDepth: integer
      The maximum number of undo levels that the editor stores. Defaults to 40.
      -
      tabindex (integer)
      +
      tabindex: integer
      The tab index to assign to the editor. If not given, no tab index will be assigned.
      -
      autofocus (boolean)
      +
      autofocus: boolean
      Can be used to make CodeMirror focus itself on initialization. Defaults to off. When fromTextArea is @@ -262,10 +262,10 @@

      Configuration

      might want to skip them the first time you read this manual.

      -
      dragDrop (boolean)
      +
      dragDrop: boolean
      Controls whether drag-and-drop is enabled. On by default.
      -
      onDragEvent (function)
      +
      onDragEvent: (instance: CodeMirror, event: Event) → boolean
      When given, this will be called when the editor is handling a dragenter, dragover, or drop event. It will be passed the editor instance @@ -274,7 +274,7 @@

      Configuration

      return true to indicate that CodeMirror should not do anything further.
      -
      onKeyEvent (function)
      +
      onKeyEvent: (instance: CodeMirror, event: Event) → boolean
      This provides a rather low-level hook into CodeMirror's key handling. If provided, this function will be called on every keydown, keyup, @@ -293,32 +293,35 @@

      Configuration

      is keydown (or keypress for actions that need character data).
      -
      cursorBlinkRate (number)
      +
      cursorBlinkRate: number
      Half-period in milliseconds used for cursor blinking. The default blink rate is 530ms.
      -
      cursorHeight (number)
      +
      cursorHeight: number
      Determines the height of the cursor. Default is 1, meaning it spans the whole height of the line. For some fonts (and by some tastes) a smaller height (for example 0.85), which causes the cursor to not reach all the way to the bottom of the line, looks better
      -
      workTime, workDelay (number)
      +
      workTime: number
      Highlighting is done by a pseudo background-thread that will work for workTime milliseconds, and then use timeout to sleep for workDelay milliseconds. The defaults are 200 and 300, you can change these options to make the highlighting more or less aggressive.
      -
      pollInterval (number)
      +
      workDelay: number
      +
      See workTime.
      + +
      pollInterval: number
      Indicates how quickly CodeMirror should poll its input textarea for changes (when focused). Most input is captured by events, but some things, like IME input on some browsers, don't generate events that allow CodeMirror to properly detect it. Thus, it polls. Default is 100 milliseconds.
      -
      flattenSpans (boolean)
      +
      flattenSpans: boolean
      By default, CodeMirror will combine adjacent tokens into a single span if they have the same class. This will result in a simpler DOM tree, and thus perform better. With some kinds of @@ -326,14 +329,14 @@

      Configuration

      document looks. You can set this option to false to disable this behavior.
      -
      maxHighlightLength (number)
      +
      maxHighlightLength: number
      When highlighting long lines, in order to stay responsive, the editor will give up and simply style the rest of the line as plain text when it reaches a certain position. The default is 10000. You can set this to Infinity to turn off this behavior.
      -
      viewportMargin (integer)
      +
      viewportMargin: integer
      Specifies the amount of lines that are rendered above and below the part of the document that's currently scrolled into view. This affects the amount of updates needed when scrolling, @@ -357,7 +360,8 @@

      Events

      refers to the editor instance.

      -
      "change" (instance, changeObj)
      +
      "change" (instance: CodeMirror, changeObj: { from: {line, ch}, to: {line, ch}, text: array<string>, removed: string, + ?next:changeObj })
      Fires every time the content of the editor is changed. The changeObj is a {from, to, text, removed, next} object containing information about the changes @@ -374,7 +378,7 @@

      Events

      a next property pointing to another change object (which may point to another, etc).
      -
      "beforeChange" (instance, change)
      +
      "beforeChange" (instance: CodeMirror, change: { from: {line, ch}, to: {line, ch}, text: array<string>, removed: string, update: (?from: {line, ch}, ?to: {line, ch}, ?text: array<string>) → void, cancel: () → void })
      This event is fired before a change is applied, and its handler may choose to modify or cancel the change. The change object @@ -394,11 +398,11 @@

      Events

      the CodeMirror implementation, probably cause the editor to become corrupted.
      -
      "cursorActivity" (instance)
      +
      "cursorActivity" (instance: CodeMirror)
      Will be fired when the cursor or selection moves, or any change is made to the editor content.
      -
      "beforeSelectionChange" (instance, selection)
      +
      "beforeSelectionChange" (instance: CodeMirror, selection: { head: {line, ch}, anchor: {line, ch} })
      This event is fired before the selection is moved. Its handler may modify the resulting selection head and anchor. The selection parameter is an object @@ -410,13 +414,13 @@

      Events

      handlers — they should not do anything to directly update the state of the editor.
      -
      "viewportChange" (instance, from, to)
      +
      "viewportChange" (instance: CodeMirror, from: number, to: number)
      Fires whenever the view port of the editor changes (due to scrolling, editing, or any other factor). The from and to arguments give the new start and end of the viewport.
      -
      "gutterClick" (instance, line, gutter, clickEvent)
      +
      "gutterClick" (instance: CodeMirror, line: integer, gutter: string, clickEvent: Event)
      Fires when the editor gutter (the line-number area) is clicked. Will pass the editor instance as first argument, the (zero-based) number of the line that was clicked as second @@ -424,16 +428,19 @@

      Events

      argument, and the raw mousedown event object as fourth argument.
      -
      "focus", "blur" (instance)
      -
      These fire whenever the editor is focused or unfocused.
      +
      "focus" (instance: CodeMirror)
      +
      Fires whenever the editor is focused.
      + +
      "blur" (instance: CodeMirror)
      +
      Fires whenever the editor is unfocused.
      -
      "scroll" (instance)
      +
      "scroll" (instance: CodeMirror)
      Fires when the editor is scrolled.
      -
      "update" (instance)
      +
      "update" (instance: CodeMirror)
      Will be fired whenever CodeMirror updates its DOM display.
      -
      "renderLine" (instance, line, element)
      +
      "renderLine" (instance: CodeMirror, line: integer, element: Element)
      Fired whenever a line is (re-)rendered to the DOM. Fired right after the DOM element is built, before it is added to the document. The handler may mess with the style of @@ -449,7 +456,7 @@

      Events

      following events:

      -
      "change" (doc, changeObj)
      +
      "change" (doc: CodeMirror.Doc, changeObj: { from: {line, ch}, to: {line, ch}, text: array<string>, removed: string })
      Fired whenever a change occurs to the document. changeObj has a similar type as the object passed to the @@ -458,15 +465,15 @@

      Events

      document change events are not batched (whereas editor change events are).
      -
      "beforeChange" (doc, change)
      +
      "beforeChange" (doc: CodeMirror.Doc, change: { from: {line, ch}, to: {line, ch}, text: array<string>, removed: string })
      See the description of the same event on editor instances.
      -
      "cursorActivity" (doc)
      +
      "cursorActivity" (doc: CodeMirror.Doc)
      Fired whenever the cursor or selection in this document changes.
      -
      "beforeSelectionChange" (doc, selection)
      +
      "beforeSelectionChange" (doc: CodeMirror.Doc, selection: { head: {line, ch}, anchor: {line, ch} })
      Equivalent to the event by the same name as fired on editor instances.
      @@ -482,7 +489,7 @@

      Events

      is associated with the start of the line. Mostly useful when you need to find out when your gutter markers on a given line are removed.
      -
      "change" (line, changeObj)
      +
      "change" (line: LineHandle, changeObj: { from: {line, ch}, to: {line, ch}, text: array<string>, removed: string })
      Fires when the line's text content is changed in any way (but the line is not deleted outright). The change object is similar to the one passed @@ -490,7 +497,7 @@

      Events

      object.
      -

      Marked range handles, as returned +

      Marked range handles (CodeMirror.TextMarker), as returned by markText and setBookmark, emit the following events:

      @@ -517,7 +524,7 @@

      Events

      operation brought the marker back.
      -

      Line widgets, returned +

      Line widgets (CodeMirror.LineWidget), returned by addLineWidget, fire these events:

      @@ -704,49 +711,55 @@

      Programming API

      Content manipulation methods

      -
      doc.getValue() → string
      +
      doc.getValue(?seperator: string): string
      Get the current editor content. You can pass it an optional argument to specify the string to be used to separate lines (defaults to "\n").
      -
      doc.setValue(string)
      +
      doc.setValue(content: string): void
      Set the editor content.
      -
      doc.getRange(from, to) → string
      +
      doc.getRange(from: {line, ch}, to: {line, ch}, ?seperator: string): string
      Get the text between the given points in the editor, which should be {line, ch} objects. An optional third argument can be given to indicate the line separator string to use (defaults to "\n").
      -
      doc.replaceRange(string, from, to)
      +
      doc.replaceRange(replacement: string, from: {line, ch}, to: {line, ch}): void
      Replace the part of the document between from and to with the given string. from and to must be {line, ch} objects. to can be left off to simply insert the string at position from.
      -
      doc.getLine(n) → string
      +
      doc.getLine(n: integer): string
      Get the content of line n.
      -
      doc.setLine(n, text)
      +
      doc.setLine(n: integer, text: string): void
      Set the content of line n.
      -
      doc.removeLine(n)
      +
      doc.removeLine(n: integer): void
      Remove the given line from the document.
      -
      doc.lineCount() → number
      +
      doc.lineCount(): integer
      Get the number of lines in the editor.
      -
      doc.firstLine() → number
      -
      doc.lastLine() → number
      -
      Get the first and last lines of the editor. This will - usually be zero and doc.lineCount() - 1 respectively, - but for linked sub-views, +
      doc.firstLine(): integer
      +
      Get the first line of the editor. This will + usually be zero but for linked sub-views, or documents instantiated with a non-zero first line, it might return other values.
      +
      doc.lastLine(): integer
      +
      Get the last line of the editor. This will + usually be doc.lineCount() - 1, + but for linked sub-views, + it might return other values.
      -
      doc.getLineHandle(num) → lineHandle
      +
      doc.getLineHandle(num: integer): LineHandle
      Fetches the line handle for the given line number.
      -
      doc.getLineNumber(handle) → integer
      +
      doc.getLineNumber(handle: LineHandle): integer
      Given a line handle, returns the current position of that line (or null when it is no longer in the document).
      -
      doc.eachLine(f) | doc.eachLine(start, end, f)
      +
      + doc.eachLine(f: (line:LineHandle) → void): void
      + doc.eachLine(start: integer, end: integer, f: (line:LineHandle) → void): void +
      Iterate over the whole document, or if start and end line numbers are given, the range from start up to (not including) end, @@ -757,12 +770,12 @@

      Content manipulation methods

      a text property containing the line's content (as a string).
      -
      doc.markClean()
      +
      doc.markClean(): void
      Set the editor content as 'clean', a flag that it will retain until it is edited, and which will be set again when such an edit is undone again. Useful to track whether the content needs to be saved.
      -
      doc.isClean() → boolean
      +
      doc.isClean(): boolean
      Returns whether the document is currently clean (not modified since initialization or the last call to markClean).
      @@ -771,9 +784,9 @@

      Content manipulation methods

      Cursor and selection methods

      -
      doc.getSelection() → string
      +
      doc.getSelection(): string
      Get the currently selected code.
      -
      doc.replaceSelection(string, collapse)
      +
      doc.replaceSelection(replacement: string, ?collapse: string): void
      Replace the selection with the given string. By default, the new selection will span the inserted text. The optional collapse argument can be used to change @@ -781,7 +794,7 @@

      Cursor and selection methods

      collapse the selection to the start or end of the inserted text.
      -
      doc.getCursor(start) → object
      +
      doc.getCursor(?start: string): {line, ch}
      start is a an optional string indicating which end of the selection to return. It may be "start", "end", "head" @@ -790,18 +803,18 @@

      Cursor and selection methods

      selection). Omitting the argument is the same as passing "head". A {line, ch} object will be returned.
      -
      doc.somethingSelected() → boolean
      +
      doc.somethingSelected(): boolean
      Return true if any text is selected.
      -
      doc.setCursor(pos)
      +
      doc.setCursor(pos: {line, ch}): void
      Set the cursor position. You can either pass a single {line, ch} object, or the line and the character as two separate parameters.
      -
      doc.setSelection(anchor, head)
      +
      doc.setSelection(anchor: {line, ch}, head: {line, ch}): void
      Set the selection range. anchor and head should be {line, ch} objects. head defaults to anchor when not given.
      -
      doc.extendSelection(pos, pos2)
      +
      doc.extendSelection(pos: {line, ch}, ?pos2: {line, ch}): void
      Similar to setSelection, but will, if shift is held or @@ -811,16 +824,16 @@

      Cursor and selection methods

      ensure a region (for example a word or paragraph) will end up selected (in addition to whatever lies between that region and the current anchor).
      -
      doc.setExtending(bool)
      +
      doc.setExtending(value: boolean): void
      Sets or clears the 'extending' flag, which acts similar to the shift key, in that it will cause cursor movement and calls to extendSelection to leave the selection anchor in place.
      -
      cm.hasFocus() → bool
      +
      cm.hasFocus(): boolean
      Tells you whether the editor currently has focus.
      -
      cm.findPosH(start, amount, unit, visually) → object
      +
      cm.findPosH(start: {line, ch}, amount: integer, unit: string, visually: boolean): {line, ch, ?hitSide: boolean}
      Used to find the target position for horizontal cursor motion. start is a {line, ch} object, amount an integer (may be negative), @@ -833,7 +846,7 @@

      Cursor and selection methods

      the motion was clipped by hitting the end or start of the document, the returned value will have a hitSide property set to true.
      -
      cm.findPosV(start, amount, unit) → object
      +
      cm.findPosV(start: {line, ch}, amount: integer, unit: string): {line, ch, ?hitSide: boolean}
      Similar to findPosH, but used for vertical motion. unit may be "line" or "page". The other @@ -844,16 +857,16 @@

      Cursor and selection methods

      Configuration methods

      -
      cm.setOption(option, value)
      +
      cm.setOption(option: string, value: any): void
      Change the configuration of the editor. option should the name of an option, and value should be a valid value for that option.
      -
      cm.getOption(option) → value
      +
      cm.getOption(option: string) → any
      Retrieves the current value of the given option for this editor instance.
      -
      cm.addKeyMap(map, bottom)
      +
      cm.addKeyMap(map: object, bottom: boolean): void
      Attach an additional keymap to the editor. This is mostly useful for add-ons that need to register some key handlers without trampling on @@ -865,14 +878,14 @@

      Configuration methods

      than those added later, unless the bottom argument was passed, in which case they end up below other keymaps added with this method.
      -
      cm.removeKeyMap(map)
      +
      cm.removeKeyMap(map: object): void
      Disable a keymap added with addKeyMap. Either pass in the keymap object itself, or a string, which will be compared against the name property of the active keymaps.
      -
      cm.addOverlay(mode, options)
      +
      cm.addOverlay(mode: string|object, ?options: object): void
      Enable a highlighting overlay. This is a stateless mini-mode that can be used to add extra highlighting. For example, the search add-on uses it to @@ -886,18 +899,18 @@

      Configuration methods

      allow the overlay styling, when not null, to override the styling of the base mode entirely, instead of the two being applied together.
      -
      cm.removeOverlay(mode)
      +
      cm.removeOverlay(mode: string|object): void
      Pass this the exact argument passed for the mode parameter to addOverlay to remove an overlay again.
      -
      cm.on(type, func)
      +
      cm.on(type: string, func: (...args) → void): void
      Register an event handler for the given event type (a string) on the editor instance. There is also a CodeMirror.on(object, type, func) version that allows registering of events on any object.
      -
      cm.off(type, func)
      +
      cm.off(type: string, func: (...args) → void): void
      Remove an event handler on the editor instance. An equivalent CodeMirror.off(object, type, func) also exists.
      @@ -916,50 +929,53 @@

      Document management methods

      it start at a line number other than 0, respectively.

      -
      cm.getDoc() → doc
      +
      cm.getDoc(): CodeMirror.Doc
      Retrieve the currently active document from an editor.
      -
      doc.getEditor() → editor
      +
      doc.getEditor(): CodeMirror
      Retrieve the editor associated with a document. May return null.
      -
      cm.swapDoc(doc) → doc
      +
      cm.swapDoc(doc: CodeMirror.Doc): CodeMirror.Doc
      Attach a new document to the editor. Returns the old document, which is now no longer associated with an editor.
      -
      doc.copy(copyHistory) → doc
      +
      doc.copy(copyHistory: boolean): CodeMirror.Doc
      Create an identical copy of the given doc. When copyHistory is true, the history will also be copied. Can not be called directly on an editor.
      -
      doc.linkedDoc(options) → doc
      +
      doc.linkedDoc(options: object): CodeMirror.Doc
      Create a new document that's linked to the target document. Linked documents will stay in sync (changes to one are also applied to the other) until unlinked. These are the options that are supported:
      -
      sharedHist (boolean)
      +
      sharedHist: boolean
      When turned on, the linked copy will share an undo history with the original. Thus, something done in one of the two can be undone in the other, and vice versa.
      -
      from, to (integer)
      +
      + from: integer
      + to: integer +
      Can be given to make the new document a subview of the original. Subviews only show a given range of lines. Note that line coordinates inside the subview will be consistent with those of the parent, so that for example a subview starting at line 10 will refer to its first line as line 10, not 0.
      -
      mode (mode spec)
      +
      mode: string|object
      By default, the new document inherits the mode of the parent. This option can be set to a mode spec to give it a different mode.
      -
      doc.unlinkDoc(doc)
      +
      doc.unlinkDoc(doc: CodeMirror.Doc): void
      Break the link between two documents. After calling this, changes will no longer propagate between the documents, and, if they had a shared history, the history will become separate.
      -
      doc.iterLinkedDocs(function)
      +
      doc.iterLinkedDocs(function: (doc: CodeMirror.Doc, sharedHist: boolean) → void): void
      Will call the given function for all documents linked to the target document. It will be passed two arguments, the linked document and a boolean indicating whether that document shares history @@ -969,20 +985,20 @@

      Document management methods

      History-related methods

      -
      doc.undo()
      +
      doc.undo(): void
      Undo one edit (if any undo events are stored).
      -
      doc.redo()
      +
      doc.redo(): void
      Redo one undone edit.
      -
      doc.historySize() → object
      +
      doc.historySize(): { undo: integer, redo: integer }
      Returns an object with {undo, redo} properties, both of which hold integers, indicating the amount of stored undo and redo operations.
      -
      doc.clearHistory()
      +
      doc.clearHistory(): void
      Clears the editor's undo history.
      -
      doc.getHistory() → object
      +
      doc.getHistory(): object
      Get a (JSON-serializeable) representation of the undo history.
      -
      doc.setHistory(object)
      +
      doc.setHistory(history: object): void
      Replace the editor's undo history with the one provided, which must be a value as returned by getHistory. Note that @@ -994,31 +1010,33 @@

      History-related methods

      Text-marking methods

      -
      doc.markText(from, to, options) → object
      +
      doc.markText(from: {line, ch}, to: {line, ch}, ?options: object): CodeMirror.TextMarker
      Can be used to mark a range of text with a specific CSS class name. from and to should be {line, ch} objects. The options parameter is optional. When given, it should be an object that may contain the following configuration options:
      -
      className (string)
      +
      className: string
      Assigns a CSS class to the marked stretch of text.
      -
      inclusiveLeft (boolean)
      Determines whether +
      inclusiveLeft: boolean
      +
      Determines whether text inserted on the left of the marker will end up inside or outside of it.
      -
      inclusiveRight (boolean)
      Like inclusiveLeft, +
      inclusiveRight: boolean
      +
      Like inclusiveLeft, but for the right side.
      -
      atomic (boolean)
      +
      atomic: boolean
      Atomic ranges act as a single unit when cursor movement is concerned—i.e. it is impossible to place the cursor inside of them. In atomic ranges, inclusiveLeft and inclusiveRight have a different meaning—they will prevent the cursor from being placed respectively directly before and directly after the range.
      -
      collapsed (boolean)
      +
      collapsed: boolean
      Collapsed ranges do not show up in the display. Setting a range to be collapsed will automatically make it atomic.
      -
      clearOnEnter (boolean)
      +
      clearOnEnter: boolean
      When enabled, will cause the mark to clear itself whenever the cursor enters its range. This is mostly useful for text-replacement widgets that need to 'snap open' when the @@ -1026,11 +1044,11 @@

      Text-marking methods

      the "clear" event fired on the range handle can be used to be notified when this happens.
      -
      replacedWith (dom node)
      +
      replacedWith: Element
      Use a given node to display this range. Implies both collapsed and atomic. The given DOM node must be an inline element (as opposed to a block element).
      -
      readOnly
      +
      readOnly: boolean|string
      A read-only span can, as long as it is not cleared, not be modified except by calling setValue to reset @@ -1039,12 +1057,12 @@

      Text-marking methods

      existing undo events being partially nullified by read-only spans would corrupt the history (in the current implementation).
      -
      startStyle
      Can be used to specify +
      startStyle: string
      Can be used to specify an extra CSS class to be applied to the leftmost span that is part of the marker.
      -
      endStyle
      Equivalent +
      endStyle: string
      Equivalent to startStyle, but for the rightmost span.
      -
      shared
      When the +
      shared: boolean
      When the target document is linked to other documents, you can set shared to true to make the marker appear in all documents. By default, a marker appears @@ -1065,7 +1083,7 @@

      Text-marking methods

      the replacedWith option, if any.
      -
      doc.setBookmark(pos, options) → object
      +
      doc.setBookmark(pos: {line, ch}, ?options: object): CodeMirror.TextMarker
      Inserts a bookmark, a handle that follows the text around it as it is being edited, at the given position. A bookmark has two methods find() and clear(). The first @@ -1074,27 +1092,27 @@

      Text-marking methods

      The options argument is optional. If given, the following properties are recognized:
      -
      widget
      Can be used to display a DOM +
      widget: Element
      Can be used to display a DOM node at the current location of the bookmark (analogous to the replacedWith option to markText).
      -
      insertLeft
      By default, text typed +
      insertLeft: boolean
      By default, text typed when the cursor is on top of the bookmark will end up to the right of the bookmark. Set this option to true to make it go to the left instead.
      -
      doc.findMarksAt(pos) → array
      +
      doc.findMarksAt(pos: {line, ch}): array<CodeMirror.TextMarker>
      Returns an array of all the bookmarks and marked ranges present at the given position.
      -
      doc.getAllMarks() → array
      +
      doc.getAllMarks(): array<CodeMirror.TextMarker>
      Returns an array containing all marked ranges in the document.

      Widget, gutter, and decoration methods

      -
      cm.setGutterMarker(line, gutterID, value) → lineHandle
      +
      cm.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) @@ -1103,11 +1121,11 @@

      Widget, gutter, and decoration methods

      will be shown in the specified gutter next to the specified line.
      -
      cm.clearGutter(gutterID)
      +
      cm.clearGutter(gutterID: string): void
      Remove all gutter markers in the gutter with the given ID.
      -
      cm.addLineClass(line, where, class) → lineHandle
      +
      cm.addLineClass(line: integer|LineHandle, where: string, class: string): LineHandle
      Set a CSS class name for the given line. line can be a number or a line handle. where determines to which element this class should be applied, can can be one @@ -1118,7 +1136,7 @@

      Widget, gutter, and decoration methods

      gutter elements). class should be the name of the class to apply.
      -
      cm.removeLineClass(line, where, class) → lineHandle
      +
      cm.removeLineClass(line: integer|LineHandle, where: string, class: string): LineHandle
      Remove a CSS class from a line. line can be a line handle or number. where should be one of "text", "background", @@ -1127,7 +1145,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) → object
      +
      cm.lineInfo(line: integer|LineHandle): {line: integer, handle: LineHandle, text: string, gutterMarkers: object<Element>, textClass: string, bgClass: string, wrapClass: string, widgets: array<CodeMirror.LineWidget>}
      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, @@ -1138,7 +1156,7 @@

      Widget, gutter, and decoration methods

      line, and the various class properties refer to classes added with addLineClass.
      -
      cm.addWidget(pos, node, scrollIntoView)
      +
      cm.addWidget(pos: {line, ch}, node: Element, scrollIntoView: boolean): void
      Puts node, which should be an absolutely positioned DOM node, into the editor, positioned right below the given {line, ch} position. @@ -1147,7 +1165,7 @@

      Widget, gutter, and decoration methods

      widget again, simply use DOM methods (move it somewhere else, or call removeChild on its parent).
      -
      cm.addLineWidget(line, node, options) → object
      +
      cm.addLineWidget(line: integer|LineHandle, node: Element, ?options: object): CodeMirror.LineWidget
      Adds a line widget, an element shown below a line, spanning the whole of the editor's width, and moving the lines below it downwards. line should be either an integer or a @@ -1157,15 +1175,15 @@

      Widget, gutter, and decoration methods

      the widget. The following options are supported (all default to false):
      -
      coverGutter (boolean)
      +
      coverGutter: boolean
      Whether the widget should cover the gutter.
      -
      noHScroll (boolean)
      +
      noHScroll: boolean
      Whether the widget should stay fixed in the face of horizontal scrolling.
      -
      above (boolean)
      +
      above: boolean
      Causes the widget to be placed above instead of below the text of the line.
      -
      showIfHidden (boolean)
      +
      showIfHidden: boolean
      When true, will cause the widget to be rendered even if the line it is associated with is hidden.
      @@ -1175,8 +1193,8 @@

      Widget, gutter, and decoration methods

      the widget placement. It'll have a line property pointing at the line handle that it is associated with, and the following methods:
      -
      clear()
      Removes the widget.
      -
      changed()
      Call +
      clear(): void
      Removes the widget.
      +
      changed(): void
      Call this if you made some change to the widget's DOM node that might affect its height. It'll force CodeMirror to update the height of the line that contains the widget.
      @@ -1187,7 +1205,7 @@

      Widget, gutter, and decoration methods

      Sizing, scrolling and positioning methods

      -
      cm.setSize(width, height)
      +
      cm.setSize(width: number|string, height: number|string): void
      Programatically set the size of the editor (overriding the applicable CSS rules). width and height height @@ -1196,16 +1214,16 @@

      Sizing, scrolling and positioning methods

      pass null for either of them to indicate that that dimension should not be changed.
      -
      cm.scrollTo(x, y)
      +
      cm.scrollTo(x: number, y: number): void
      Scroll the editor to a given (pixel) position. Both arguments may be left as null or undefined to have no effect.
      -
      cm.getScrollInfo()
      +
      cm.getScrollInfo(): {left: number, top: number, width: number, height: number, clientWidth: number, clientHeight: number}
      Get an {left, top, width, height, clientWidth, clientHeight} object that represents the current scroll position, the size of the scrollable area, and the size of the visible area (minus scrollbars).
      -
      cm.scrollIntoView(pos, margin)
      +
      cm.scrollIntoView(pos: {line, ch}|{left: number, top: number, right: number, bottom: number}, ?margin: number): void
      Scrolls the given element into view. pos may be either a {line, ch} position, referring to a given character, null, to refer to the cursor, or @@ -1214,7 +1232,7 @@

      Sizing, scrolling and positioning methods

      optional. When given, it indicates the amount of pixels around the given area that should be made visible as well.
      -
      cm.cursorCoords(where, mode) → object
      +
      cm.cursorCoords(where: boolean|{line, ch}, mode: string): {left: number, top: number, bottom: number}
      Returns an {left, top, bottom} object containing the coordinates of the cursor position. If mode is "local", they will be @@ -1225,29 +1243,29 @@

      Sizing, scrolling and positioning methods

      end (false) of the selection, or, if a {line, ch} object is given, it specifies the precise position at which you want to measure.
      -
      cm.charCoords(pos, mode) → object
      +
      cm.charCoords(pos: {line, ch}, mode: string): {left: number, top: number, bottom: number}
      Returns the position and dimensions of an arbitrary character. pos should be a {line, ch} object. This differs from cursorCoords in that it'll give the size of the whole character, rather than just the position that the cursor would have when it would sit at that position.
      -
      cm.coordsChar(object, mode) → pos
      +
      cm.coordsChar(object: {left: number, top: number}, ?mode: string): {line, ch}
      Given an {left, top} object, returns the {line, ch} position that corresponds to it. The optional mode parameter determines relative to what the coordinates are interpreted. It may be "window", "page" (the default), or "local".
      -
      cm.defaultTextHeight() → number
      +
      cm.defaultTextHeight(): number
      Returns the line height of the default font for the editor.
      -
      cm.defaultCharWidth() → number
      +
      cm.defaultCharWidth(): number
      Returns the pixel width of an 'x' in the default font for the editor. (Note that for non-monospace fonts, this is mostly useless, and even for monospace fonts, non-ascii characters might have a different width).
      -
      cm.getViewport() → object
      +
      cm.getViewport(): {from: number, to: number}
      Returns a {from, to} object indicating the start (inclusive) and end (exclusive) of the currently rendered part of the document. In big documents, when most content is @@ -1256,7 +1274,7 @@

      Sizing, scrolling and positioning methods

      the viewportChange event.
      -
      cm.refresh()
      +
      cm.refresh(): void
      If your code does something to change the size of the editor element (window resizes are already listened for), or unhides it, you should probably follow up by calling this method to @@ -1271,13 +1289,13 @@

      Mode, state, and token-related methods

      more detailed description of how these work.

      -
      doc.getMode() → object
      +
      doc.getMode(): object
      Gets the mode object for the editor. Note that this is distinct from getOption("mode"), which gives you the mode specification, rather than the resolved, instantiated mode object.
      -
      cm.getTokenAt(pos) → object
      +
      cm.getTokenAt(pos: {line, ch}): { start: string, end: string, string: string, type: string, state: string }
      Retrieves information about the token the current mode found before the given position (a {line, ch} object). The returned object has the following properties: @@ -1291,7 +1309,7 @@

      Mode, state, and token-related methods

      state
      The mode's state at the end of this token.
      -
      cm.getStateAfter(line) → state
      +
      cm.getStateAfter(?line: integer): object
      Returns the mode's parser state, if any, at the end of the given line number. If no line number is given, the state at the end of the document is returned. This can be useful for storing @@ -1302,7 +1320,7 @@

      Mode, state, and token-related methods

      Miscellaneous methods

      -
      cm.operation(func) → result
      +
      cm.operation(func: () → any): any
      CodeMirror internally buffers changes and only updates its DOM structure after it has finished performing some operation. If you need to perform a lot of operations on a CodeMirror @@ -1312,7 +1330,7 @@

      Miscellaneous methods

      lot faster. The return value from this method will be the return value of your function.
      -
      cm.indentLine(line, dir)
      +
      cm.indentLine(line: integer|LineHandle, ?dir: string): void
      Adjust the indentation of the given line. The second argument (which defaults to "smart") may be one of:
      @@ -1328,28 +1346,28 @@

      Miscellaneous methods

      Reduce the indentation of the line.
      -
      doc.posFromIndex(index) → object
      +
      doc.posFromIndex(index: integer): {line, ch}
      Calculates and returns a {line, ch} object for a zero-based index who's value is relative to the start of the editor's text. If the index is out of range of the text then the returned object is clipped to start or end of the text respectively.
      -
      doc.indexFromPos(object) → number
      +
      doc.indexFromPos(object: {line, ch}): integer
      The reverse of posFromIndex.
      -
      cm.focus()
      +
      cm.focus(): void
      Give the editor focus.
      -
      cm.getInputField() → textarea
      +
      cm.getInputField(): TextAreaElement
      Returns the hidden textarea used to read input.
      -
      cm.getWrapperElement() → node
      +
      cm.getWrapperElement(): Element
      Returns the DOM node that represents the editor, and controls its size. Remove this from your tree to delete an editor instance.
      -
      cm.getScrollerElement() → node
      +
      cm.getScrollerElement(): Element
      Returns the DOM node that is responsible for the scrolling of the editor.
      -
      cm.getGutterElement() → node
      +
      cm.getGutterElement(): Element
      Fetches the DOM node that contains the editor gutters.
      @@ -1432,18 +1450,24 @@

      Add-ons

      relevant when matching a string. It will cause the search to be case-insensitive. A search cursor has the following methods:
      -
      findNext(), findPrevious() → boolean
      +
      + findNext(): boolean
      + findPrevious(): boolean +
      Search forward or backward from the current position. The return value indicates whether a match was found. If matching a regular expression, the return value will be the array returned by the match method, in case you want to extract matched groups.
      -
      from(), to() → object
      +
      + from(): {line, ch}
      + to(): {line, ch} +
      These are only valid when the last call to findNext or findPrevious did not return false. They will return {line, ch} objects pointing at the start and end of the match.
      -
      replace(text)
      +
      replace(text: string): void
      Replaces the currently found match with the given text and adjusts the cursor position to reflect the replacement.
      @@ -1651,42 +1675,45 @@

      Writing CodeMirror Modes

      the following API:

      -
      eol() → boolean
      +
      eol(): boolean
      Returns true only if the stream is at the end of the line.
      -
      sol() → boolean
      +
      sol(): boolean
      Returns true only if the stream is at the start of the line.
      -
      peek() → character
      +
      peek(): string
      Returns the next character in the stream without advancing it. Will return an null at the end of the line.
      -
      next() → character
      +
      next(): string
      Returns the next character in the stream and advances it. Also returns null when no more characters are available.
      -
      eat(match) → character
      +
      eat(match: string|regexp|(char:string) → boolean): string
      match can be a character, a regular expression, or a function that takes a character and returns a boolean. If the next character in the stream 'matches' the given argument, it is consumed and returned. Otherwise, undefined is returned.
      -
      eatWhile(match) → boolean
      +
      eatWhile(match: string|regexp|(char:string) → boolean): boolean
      Repeatedly calls eat with the given argument, until it fails. Returns true if any characters were eaten.
      -
      eatSpace() → boolean
      +
      eatSpace(): boolean
      Shortcut for eatWhile when matching white-space.
      -
      skipToEnd()
      +
      skipToEnd(): void
      Moves the position to the end of the line.
      -
      skipTo(ch) → boolean
      +
      skipTo(ch: string): boolean
      Skips to the next occurrence of the given character, if found on the current line (doesn't advance the stream if the character does not occur on the line). Returns true if the character was found.
      -
      match(pattern, consume, caseFold) → boolean
      +
      + match(pattern: string, ?consume: boolean, ?caseFold: boolean): boolean
      + match(pattern: regexp, ?consume: boolean): array<string> +
      Act like a multi-character eat—if consume is true or not given—or a look-ahead that doesn't update the stream @@ -1698,18 +1725,18 @@

      Writing CodeMirror Modes

      returned by match, in case you need to extract matched groups.
      -
      backUp(n)
      +
      backUp(n: integer): void
      Backs up the stream n characters. Backing it up further than the start of the current token will cause things to break, so be careful.
      -
      column() → integer
      +
      column(): integer
      Returns the column (taking into account tabs) at which the current token starts.
      -
      indentation() → integer
      +
      indentation(): integer
      Tells you how far the current line has been indented, in spaces. Corrects for tab characters.
      -
      current() → string
      +
      current(): string
      Get the string between the start of the current token and the current stream position.
      From 7f17d0857889003b0c6f885cb246b88e848fbaf4 Mon Sep 17 00:00:00 2001 From: Andy Li Date: Thu, 4 Apr 2013 04:20:00 +0800 Subject: [PATCH 0460/5273] Manual: Constructor method is added to miscellaneous, static members are put inside a
      . --- doc/manual.html | 104 ++++++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 47 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index fbf30573d2..fc0eab5e33 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -431,7 +431,7 @@

      Events

      "focus" (instance: CodeMirror)
      Fires whenever the editor is focused.
      -
      "blur" (instance: CodeMirror)
      +
      "blur" (instance: CodeMirror)
      Fires whenever the editor is unfocused.
      "scroll" (instance: CodeMirror)
      @@ -1320,6 +1320,9 @@

      Mode, state, and token-related methods

      Miscellaneous methods

      +
      CodeMirror(elt:Element|(elt:Element) → void, ?config: object): void
      +
      The constructor. See Basic Usage.
      +
      cm.operation(func: () → any): any
      CodeMirror internally buffers changes and only updates its DOM structure after it has finished performing some operation. @@ -1372,57 +1375,64 @@

      Miscellaneous methods

      Static properties

      - -

      The CodeMirror object itself provides - several useful properties. Firstly, its version - property contains a string that indicates the version of the - library. For releases, this simply - contains "major.minor" (for - example "2.33". For beta versions, " B" - (space, capital B) is added at the end of the string, for - development snapshots, " +" (space, plus) is - added.

      - -

      The CodeMirror.fromTextArea - method provides another way to initialize an editor. It takes a - textarea DOM node as first argument and an optional configuration - object as second. It will replace the textarea with a CodeMirror - instance, and wire up the form of that textarea (if any) to make - sure the editor contents are put into the textarea when the form - is submitted. A CodeMirror instance created this way has three - additional methods:

      +

      The CodeMirror object itself provides + several useful properties.

      -
      cm.save()
      -
      Copy the content of the editor into the textarea.
      +
      CodeMirror.version: string
      +
      It contains a string that indicates the version of the + library. For releases, this simply + contains "major.minor" (for + example "2.33". For beta versions, " B" + (space, capital B) is added at the end of the string, for + development snapshots, " +" (space, plus) is + added.
      + +
      CodeMirror.fromTextArea(textArea: TextAreaElement, ?config: object)
      +
      + The method provides another way to initialize an editor. It takes a + textarea DOM node as first argument and an optional configuration + object as second. It will replace the textarea with a CodeMirror + instance, and wire up the form of that textarea (if any) to make + sure the editor contents are put into the textarea when the form + is submitted. A CodeMirror instance created this way has three + additional methods: +
      +
      cm.save(): void
      +
      Copy the content of the editor into the textarea.
      -
      cm.toTextArea()
      -
      Remove the editor, and restore the original textarea (with - the editor's current content).
      +
      cm.toTextArea(): void
      +
      Remove the editor, and restore the original textarea (with + the editor's current content).
      -
      cm.getTextArea() → textarea
      -
      Returns the textarea that the instance was based on.
      -
      +
      cm.getTextArea(): TextAreaElement
      +
      Returns the textarea that the instance was based on.
      +
      +
      -

      If you want to define extra methods in terms - of the CodeMirror API, it is possible to - use CodeMirror.defineExtension(name, value). This - will cause the given value (usually a method) to be added to all - CodeMirror instances created from then on.

      - -

      Similarly, CodeMirror.defineOption(name, - default, updateFunc) can be used to define new options for - CodeMirror. The updateFunc will be called with the - editor instance and the new value when an editor is initialized, - and whenever the option is modified - through setOption.

      - -

      If your extention just needs to run some - code whenever a CodeMirror instance is initialized, - use CodeMirror.defineInitHook. Give it a function as - its only argument, and from then on, that function will be called - (with the instance as argument) whenever a new CodeMirror instance - is initialized.

      +
      CodeMirror.defineExtension(name: string, value: any): void
      +
      If you want to define extra methods in terms + of the CodeMirror API, it is possible to + use defineExtension. This + will cause the given value (usually a method) to be added to all + CodeMirror instances created from then on.
      + +
      CodeMirror.defineOption(name: string, + default: any, updateFunc: (instance: CodeMirror, value: any, setOption: boolean) → void): void
      +
      Similarly, defineOption can be used to define new options for + CodeMirror. The updateFunc will be called with the + editor instance and the new value when an editor is initialized, + and whenever the option is modified + through setOption.
      + +
      CodeMirror.defineInitHook(func: (instance: CodeMirror) → void): void
      +
      If your extention just needs to run some + code whenever a CodeMirror instance is initialized, + use CodeMirror.defineInitHook. Give it a function as + its only argument, and from then on, that function will be called + (with the instance as argument) whenever a new CodeMirror instance + is initialized.
      +

      Add-ons

      From 7683ff625be45ebea5a020da61ce1e019b6c5717 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 4 Apr 2013 11:20:05 +0200 Subject: [PATCH 0461/5273] Go over manual changes, try to preserve readability --- doc/manual.html | 247 ++++++++++++++++++++++++------------------------ 1 file changed, 123 insertions(+), 124 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index fc0eab5e33..d805185f15 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -206,7 +206,7 @@

      Configuration

      firstLineNumber: integer
      At which number to start counting lines. Default is 1.
      -
      lineNumberFormatter: (line: integer) → string
      +
      lineNumberFormatter: function(line: integer) → string
      A function used to format line numbers. The function is passed the line number, and should return a string that will be shown in the gutter.
      @@ -265,7 +265,7 @@

      Configuration

      dragDrop: boolean
      Controls whether drag-and-drop is enabled. On by default.
      -
      onDragEvent: (instance: CodeMirror, event: Event) → boolean
      +
      onDragEvent: function(instance: CodeMirror, event: Event) → boolean
      When given, this will be called when the editor is handling a dragenter, dragover, or drop event. It will be passed the editor instance @@ -274,7 +274,7 @@

      Configuration

      return true to indicate that CodeMirror should not do anything further.
      -
      onKeyEvent: (instance: CodeMirror, event: Event) → boolean
      +
      onKeyEvent: function(instance: CodeMirror, event: Event) → boolean
      This provides a rather low-level hook into CodeMirror's key handling. If provided, this function will be called on every keydown, keyup, @@ -304,7 +304,7 @@

      Configuration

      which causes the cursor to not reach all the way to the bottom of the line, looks better
      -
      workTime: number
      +
      workTime, workDelay: number
      Highlighting is done by a pseudo background-thread that will work for workTime milliseconds, and then use timeout to sleep for workDelay milliseconds. The @@ -360,8 +360,7 @@

      Events

      refers to the editor instance.

      -
      "change" (instance: CodeMirror, changeObj: { from: {line, ch}, to: {line, ch}, text: array<string>, removed: string, - ?next:changeObj })
      +
      "change" (instance: CodeMirror, changeObj: object)
      Fires every time the content of the editor is changed. The changeObj is a {from, to, text, removed, next} object containing information about the changes @@ -378,10 +377,10 @@

      Events

      a next property pointing to another change object (which may point to another, etc).
      -
      "beforeChange" (instance: CodeMirror, change: { from: {line, ch}, to: {line, ch}, text: array<string>, removed: string, update: (?from: {line, ch}, ?to: {line, ch}, ?text: array<string>) → void, cancel: () → void })
      +
      "beforeChange" (instance: CodeMirror, changeObj: object)
      This event is fired before a change is applied, and its handler may choose to modify or cancel the change. - The change object + The changeObj object has from, to, and text properties, as with the "change" event, but @@ -402,7 +401,7 @@

      Events

      Will be fired when the cursor or selection moves, or any change is made to the editor content.
      -
      "beforeSelectionChange" (instance: CodeMirror, selection: { head: {line, ch}, anchor: {line, ch} })
      +
      "beforeSelectionChange" (instance: CodeMirror, selection: {head, anchor})
      This event is fired before the selection is moved. Its handler may modify the resulting selection head and anchor. The selection parameter is an object @@ -456,7 +455,7 @@

      Events

      following events:

      -
      "change" (doc: CodeMirror.Doc, changeObj: { from: {line, ch}, to: {line, ch}, text: array<string>, removed: string })
      +
      "change" (doc: CodeMirror.Doc, changeObj: object)
      Fired whenever a change occurs to the document. changeObj has a similar type as the object passed to the @@ -465,7 +464,7 @@

      Events

      document change events are not batched (whereas editor change events are).
      -
      "beforeChange" (doc: CodeMirror.Doc, change: { from: {line, ch}, to: {line, ch}, text: array<string>, removed: string })
      +
      "beforeChange" (doc: CodeMirror.Doc, change: object)
      See the description of the same event on editor instances.
      @@ -473,7 +472,7 @@

      Events

      Fired whenever the cursor or selection in this document changes.
      -
      "beforeSelectionChange" (doc: CodeMirror.Doc, selection: { head: {line, ch}, anchor: {line, ch} })
      +
      "beforeSelectionChange" (doc: CodeMirror.Doc, selection: {head, anchor})
      Equivalent to the event by the same name as fired on editor instances.
      @@ -489,7 +488,7 @@

      Events

      is associated with the start of the line. Mostly useful when you need to find out when your gutter markers on a given line are removed.
      -
      "change" (line: LineHandle, changeObj: { from: {line, ch}, to: {line, ch}, text: array<string>, removed: string })
      +
      "change" (line: LineHandle, changeObj: object)
      Fires when the line's text content is changed in any way (but the line is not deleted outright). The change object is similar to the one passed @@ -711,54 +710,54 @@

      Programming API

      Content manipulation methods

      -
      doc.getValue(?seperator: string): string
      +
      doc.getValue(?seperator: string) → string
      Get the current editor content. You can pass it an optional argument to specify the string to be used to separate lines (defaults to "\n").
      -
      doc.setValue(content: string): void
      +
      doc.setValue(content: string)
      Set the editor content.
      -
      doc.getRange(from: {line, ch}, to: {line, ch}, ?seperator: string): string
      +
      doc.getRange(from: {line, ch}, to: {line, ch}, ?seperator: string) → string
      Get the text between the given points in the editor, which should be {line, ch} objects. An optional third argument can be given to indicate the line separator string to use (defaults to "\n").
      -
      doc.replaceRange(replacement: string, from: {line, ch}, to: {line, ch}): void
      +
      doc.replaceRange(replacement: string, from: {line, ch}, to: {line, ch})
      Replace the part of the document between from and to with the given string. from and to must be {line, ch} objects. to can be left off to simply insert the string at position from.
      -
      doc.getLine(n: integer): string
      +
      doc.getLine(n: integer) → string
      Get the content of line n.
      -
      doc.setLine(n: integer, text: string): void
      +
      doc.setLine(n: integer, text: string)
      Set the content of line n.
      -
      doc.removeLine(n: integer): void
      +
      doc.removeLine(n: integer)
      Remove the given line from the document.
      -
      doc.lineCount(): integer
      +
      doc.lineCount() → integer
      Get the number of lines in the editor.
      -
      doc.firstLine(): integer
      +
      doc.firstLine() → integer
      Get the first line of the editor. This will usually be zero but for linked sub-views, or documents instantiated with a non-zero first line, it might return other values.
      -
      doc.lastLine(): integer
      +
      doc.lastLine() → integer
      Get the last line of the editor. This will usually be doc.lineCount() - 1, but for linked sub-views, it might return other values.
      -
      doc.getLineHandle(num: integer): LineHandle
      +
      doc.getLineHandle(num: integer) → LineHandle
      Fetches the line handle for the given line number.
      -
      doc.getLineNumber(handle: LineHandle): integer
      +
      doc.getLineNumber(handle: LineHandle) → integer
      Given a line handle, returns the current position of that line (or null when it is no longer in the document).
      - doc.eachLine(f: (line:LineHandle) → void): void
      - doc.eachLine(start: integer, end: integer, f: (line:LineHandle) → void): void + doc.eachLine(f: (line: LineHandle))
      + doc.eachLine(start: integer, end: integer, f: (line: LineHandle))
      Iterate over the whole document, or if start and end line numbers are given, the range @@ -770,12 +769,12 @@

      Content manipulation methods

      a text property containing the line's content (as a string).
      -
      doc.markClean(): void
      +
      doc.markClean()
      Set the editor content as 'clean', a flag that it will retain until it is edited, and which will be set again when such an edit is undone again. Useful to track whether the content needs to be saved.
      -
      doc.isClean(): boolean
      +
      doc.isClean() → boolean
      Returns whether the document is currently clean (not modified since initialization or the last call to markClean).
      @@ -784,9 +783,9 @@

      Content manipulation methods

      Cursor and selection methods

      -
      doc.getSelection(): string
      +
      doc.getSelection() → string
      Get the currently selected code.
      -
      doc.replaceSelection(replacement: string, ?collapse: string): void
      +
      doc.replaceSelection(replacement: string, ?collapse: string)
      Replace the selection with the given string. By default, the new selection will span the inserted text. The optional collapse argument can be used to change @@ -794,7 +793,7 @@

      Cursor and selection methods

      collapse the selection to the start or end of the inserted text.
      -
      doc.getCursor(?start: string): {line, ch}
      +
      doc.getCursor(?start: string) → {line, ch}
      start is a an optional string indicating which end of the selection to return. It may be "start", "end", "head" @@ -803,18 +802,18 @@

      Cursor and selection methods

      selection). Omitting the argument is the same as passing "head". A {line, ch} object will be returned.
      -
      doc.somethingSelected(): boolean
      +
      doc.somethingSelected() → boolean
      Return true if any text is selected.
      -
      doc.setCursor(pos: {line, ch}): void
      +
      doc.setCursor(pos: {line, ch})
      Set the cursor position. You can either pass a single {line, ch} object, or the line and the character as two separate parameters.
      -
      doc.setSelection(anchor: {line, ch}, head: {line, ch}): void
      +
      doc.setSelection(anchor: {line, ch}, head: {line, ch})
      Set the selection range. anchor and head should be {line, ch} objects. head defaults to anchor when not given.
      -
      doc.extendSelection(pos: {line, ch}, ?pos2: {line, ch}): void
      +
      doc.extendSelection(from: {line, ch}, ?to: {line, ch})
      Similar to setSelection, but will, if shift is held or @@ -824,16 +823,16 @@

      Cursor and selection methods

      ensure a region (for example a word or paragraph) will end up selected (in addition to whatever lies between that region and the current anchor).
      -
      doc.setExtending(value: boolean): void
      +
      doc.setExtending(value: boolean)
      Sets or clears the 'extending' flag, which acts similar to the shift key, in that it will cause cursor movement and calls to extendSelection to leave the selection anchor in place.
      -
      cm.hasFocus(): boolean
      +
      cm.hasFocus() → boolean
      Tells you whether the editor currently has focus.
      -
      cm.findPosH(start: {line, ch}, amount: integer, unit: string, visually: boolean): {line, ch, ?hitSide: boolean}
      +
      cm.findPosH(start: {line, ch}, amount: integer, unit: string, visually: boolean) → {line, ch, ?hitSide: boolean}
      Used to find the target position for horizontal cursor motion. start is a {line, ch} object, amount an integer (may be negative), @@ -846,7 +845,7 @@

      Cursor and selection methods

      the motion was clipped by hitting the end or start of the document, the returned value will have a hitSide property set to true.
      -
      cm.findPosV(start: {line, ch}, amount: integer, unit: string): {line, ch, ?hitSide: boolean}
      +
      cm.findPosV(start: {line, ch}, amount: integer, unit: string) → {line, ch, ?hitSide: boolean}
      Similar to findPosH, but used for vertical motion. unit may be "line" or "page". The other @@ -857,7 +856,7 @@

      Cursor and selection methods

      Configuration methods

      -
      cm.setOption(option: string, value: any): void
      +
      cm.setOption(option: string, value: any)
      Change the configuration of the editor. option should the name of an option, and value should be a valid value for that @@ -866,7 +865,7 @@

      Configuration methods

      Retrieves the current value of the given option for this editor instance.
      -
      cm.addKeyMap(map: object, bottom: boolean): void
      +
      cm.addKeyMap(map: object, bottom: boolean)
      Attach an additional keymap to the editor. This is mostly useful for add-ons that need to register some key handlers without trampling on @@ -878,14 +877,14 @@

      Configuration methods

      than those added later, unless the bottom argument was passed, in which case they end up below other keymaps added with this method.
      -
      cm.removeKeyMap(map: object): void
      +
      cm.removeKeyMap(map: object)
      Disable a keymap added with addKeyMap. Either pass in the keymap object itself, or a string, which will be compared against the name property of the active keymaps.
      -
      cm.addOverlay(mode: string|object, ?options: object): void
      +
      cm.addOverlay(mode: string|object, ?options: object)
      Enable a highlighting overlay. This is a stateless mini-mode that can be used to add extra highlighting. For example, the search add-on uses it to @@ -899,18 +898,18 @@

      Configuration methods

      allow the overlay styling, when not null, to override the styling of the base mode entirely, instead of the two being applied together.
      -
      cm.removeOverlay(mode: string|object): void
      +
      cm.removeOverlay(mode: string|object)
      Pass this the exact argument passed for the mode parameter to addOverlay to remove an overlay again.
      -
      cm.on(type: string, func: (...args) → void): void
      +
      cm.on(type: string, func: (...args))
      Register an event handler for the given event type (a string) on the editor instance. There is also a CodeMirror.on(object, type, func) version that allows registering of events on any object.
      -
      cm.off(type: string, func: (...args) → void): void
      +
      cm.off(type: string, func: (...args))
      Remove an event handler on the editor instance. An equivalent CodeMirror.off(object, type, func) also exists.
      @@ -929,22 +928,22 @@

      Document management methods

      it start at a line number other than 0, respectively.

      -
      cm.getDoc(): CodeMirror.Doc
      +
      cm.getDoc() → CodeMirror.Doc
      Retrieve the currently active document from an editor.
      -
      doc.getEditor(): CodeMirror
      +
      doc.getEditor() → CodeMirror
      Retrieve the editor associated with a document. May return null.
      -
      cm.swapDoc(doc: CodeMirror.Doc): CodeMirror.Doc
      +
      cm.swapDoc(doc: CodeMirror.Doc) → CodeMirror.Doc
      Attach a new document to the editor. Returns the old document, which is now no longer associated with an editor.
      -
      doc.copy(copyHistory: boolean): CodeMirror.Doc
      +
      doc.copy(copyHistory: boolean) → CodeMirror.Doc
      Create an identical copy of the given doc. When copyHistory is true, the history will also be copied. Can not be called directly on an editor.
      -
      doc.linkedDoc(options: object): CodeMirror.Doc
      +
      doc.linkedDoc(options: object) → CodeMirror.Doc
      Create a new document that's linked to the target document. Linked documents will stay in sync (changes to one are also applied to the other) until unlinked. @@ -970,12 +969,12 @@

      Document management methods

      a mode spec to give it a different mode.
      -
      doc.unlinkDoc(doc: CodeMirror.Doc): void
      +
      doc.unlinkDoc(doc: CodeMirror.Doc)
      Break the link between two documents. After calling this, changes will no longer propagate between the documents, and, if they had a shared history, the history will become separate.
      -
      doc.iterLinkedDocs(function: (doc: CodeMirror.Doc, sharedHist: boolean) → void): void
      +
      doc.iterLinkedDocs(function: (doc: CodeMirror.Doc, sharedHist: boolean))
      Will call the given function for all documents linked to the target document. It will be passed two arguments, the linked document and a boolean indicating whether that document shares history @@ -985,20 +984,20 @@

      Document management methods

      History-related methods

      -
      doc.undo(): void
      +
      doc.undo()
      Undo one edit (if any undo events are stored).
      -
      doc.redo(): void
      +
      doc.redo()
      Redo one undone edit.
      -
      doc.historySize(): { undo: integer, redo: integer }
      +
      doc.historySize() → {undo: integer, redo: integer}
      Returns an object with {undo, redo} properties, both of which hold integers, indicating the amount of stored undo and redo operations.
      -
      doc.clearHistory(): void
      +
      doc.clearHistory()
      Clears the editor's undo history.
      -
      doc.getHistory(): object
      +
      doc.getHistory() → object
      Get a (JSON-serializeable) representation of the undo history.
      -
      doc.setHistory(history: object): void
      +
      doc.setHistory(history: object)
      Replace the editor's undo history with the one provided, which must be a value as returned by getHistory. Note that @@ -1010,7 +1009,7 @@

      History-related methods

      Text-marking methods

      -
      doc.markText(from: {line, ch}, to: {line, ch}, ?options: object): CodeMirror.TextMarker
      +
      doc.markText(from: {line, ch}, to: {line, ch}, ?options: object) → CodeMirror.TextMarker
      Can be used to mark a range of text with a specific CSS class name. from and to should be {line, ch} objects. The options @@ -1083,7 +1082,7 @@

      Text-marking methods

      the replacedWith option, if any.
      -
      doc.setBookmark(pos: {line, ch}, ?options: object): CodeMirror.TextMarker
      +
      doc.setBookmark(pos: {line, ch}, ?options: object) → CodeMirror.TextMarker
      Inserts a bookmark, a handle that follows the text around it as it is being edited, at the given position. A bookmark has two methods find() and clear(). The first @@ -1102,17 +1101,17 @@

      Text-marking methods

      to the left instead.
      -
      doc.findMarksAt(pos: {line, ch}): array<CodeMirror.TextMarker>
      +
      doc.findMarksAt(pos: {line, ch}) → array<CodeMirror.TextMarker>
      Returns an array of all the bookmarks and marked ranges present at the given position.
      -
      doc.getAllMarks(): array<CodeMirror.TextMarker>
      +
      doc.getAllMarks() → array<CodeMirror.TextMarker>
      Returns an array containing all marked ranges in the document.

      Widget, gutter, and decoration methods

      -
      cm.setGutterMarker(line: integer|LineHandle, gutterID: string, value: Element): LineHandle
      +
      cm.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) @@ -1121,11 +1120,11 @@

      Widget, gutter, and decoration methods

      will be shown in the specified gutter next to the specified line.
      -
      cm.clearGutter(gutterID: string): void
      +
      cm.clearGutter(gutterID: string)
      Remove all gutter markers in the gutter with the given ID.
      -
      cm.addLineClass(line: integer|LineHandle, where: string, class: string): LineHandle
      +
      cm.addLineClass(line: integer|LineHandle, where: string, class: string) → LineHandle
      Set a CSS class name for the given line. line can be a number or a line handle. where determines to which element this class should be applied, can can be one @@ -1136,7 +1135,7 @@

      Widget, gutter, and decoration methods

      gutter elements). class should be the name of the class to apply.
      -
      cm.removeLineClass(line: integer|LineHandle, where: string, class: string): LineHandle
      +
      cm.removeLineClass(line: integer|LineHandle, where: string, class: string) → LineHandle
      Remove a CSS class from a line. line can be a line handle or number. where should be one of "text", "background", @@ -1145,7 +1144,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): {line: integer, handle: LineHandle, text: string, gutterMarkers: object<Element>, textClass: string, bgClass: string, wrapClass: string, widgets: array<CodeMirror.LineWidget>}
      +
      cm.lineInfo(line: integer|LineHandle) → {line: integer, handle: LineHandle, text: string, gutterMarkers: object<Element>, textClass: string, bgClass: string, wrapClass: string, widgets: array<CodeMirror.LineWidget>}
      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, @@ -1156,7 +1155,7 @@

      Widget, gutter, and decoration methods

      line, and the various class properties refer to classes added with addLineClass.
      -
      cm.addWidget(pos: {line, ch}, node: Element, scrollIntoView: boolean): void
      +
      cm.addWidget(pos: {line, ch}, node: Element, scrollIntoView: boolean)
      Puts node, which should be an absolutely positioned DOM node, into the editor, positioned right below the given {line, ch} position. @@ -1165,7 +1164,7 @@

      Widget, gutter, and decoration methods

      widget again, simply use DOM methods (move it somewhere else, or call removeChild on its parent).
      -
      cm.addLineWidget(line: integer|LineHandle, node: Element, ?options: object): CodeMirror.LineWidget
      +
      cm.addLineWidget(line: integer|LineHandle, node: Element, ?options: object) → CodeMirror.LineWidget
      Adds a line widget, an element shown below a line, spanning the whole of the editor's width, and moving the lines below it downwards. line should be either an integer or a @@ -1173,7 +1172,7 @@

      Widget, gutter, and decoration methods

      will be displayed below the given line. options, when given, should be an object that configures the behavior of the widget. The following options are supported (all default to - false): + false) →
      coverGutter: boolean
      Whether the widget should cover the gutter.
      @@ -1193,8 +1192,8 @@

      Widget, gutter, and decoration methods

      the widget placement. It'll have a line property pointing at the line handle that it is associated with, and the following methods:
      -
      clear(): void
      Removes the widget.
      -
      changed(): void
      Call +
      clear()
      Removes the widget.
      +
      changed()
      Call this if you made some change to the widget's DOM node that might affect its height. It'll force CodeMirror to update the height of the line that contains the widget.
      @@ -1205,7 +1204,7 @@

      Widget, gutter, and decoration methods

      Sizing, scrolling and positioning methods

      -
      cm.setSize(width: number|string, height: number|string): void
      +
      cm.setSize(width: number|string, height: number|string)
      Programatically set the size of the editor (overriding the applicable CSS rules). width and height height @@ -1214,16 +1213,16 @@

      Sizing, scrolling and positioning methods

      pass null for either of them to indicate that that dimension should not be changed.
      -
      cm.scrollTo(x: number, y: number): void
      +
      cm.scrollTo(x: number, y: number)
      Scroll the editor to a given (pixel) position. Both arguments may be left as null or undefined to have no effect.
      -
      cm.getScrollInfo(): {left: number, top: number, width: number, height: number, clientWidth: number, clientHeight: number}
      +
      cm.getScrollInfo() → {left, top, width, height, clientWidth, clientHeight}
      Get an {left, top, width, height, clientWidth, clientHeight} object that represents the current scroll position, the size of the scrollable area, and the size of the visible area (minus scrollbars).
      -
      cm.scrollIntoView(pos: {line, ch}|{left: number, top: number, right: number, bottom: number}, ?margin: number): void
      +
      cm.scrollIntoView(pos: {line, ch}|{left, top, right, bottom}, ?margin: number)
      Scrolls the given element into view. pos may be either a {line, ch} position, referring to a given character, null, to refer to the cursor, or @@ -1232,7 +1231,7 @@

      Sizing, scrolling and positioning methods

      optional. When given, it indicates the amount of pixels around the given area that should be made visible as well.
      -
      cm.cursorCoords(where: boolean|{line, ch}, mode: string): {left: number, top: number, bottom: number}
      +
      cm.cursorCoords(where: boolean|{line, ch}, mode: string) → {left, top, bottom}
      Returns an {left, top, bottom} object containing the coordinates of the cursor position. If mode is "local", they will be @@ -1243,29 +1242,29 @@

      Sizing, scrolling and positioning methods

      end (false) of the selection, or, if a {line, ch} object is given, it specifies the precise position at which you want to measure.
      -
      cm.charCoords(pos: {line, ch}, mode: string): {left: number, top: number, bottom: number}
      +
      cm.charCoords(pos: {line, ch}, mode: string) → {left, right, top, bottom}
      Returns the position and dimensions of an arbitrary character. pos should be a {line, ch} object. This differs from cursorCoords in that it'll give the size of the whole character, rather than just the position that the cursor would have when it would sit at that position.
      -
      cm.coordsChar(object: {left: number, top: number}, ?mode: string): {line, ch}
      +
      cm.coordsChar(object: {left, top}, ?mode: string) → {line, ch}
      Given an {left, top} object, returns the {line, ch} position that corresponds to it. The optional mode parameter determines relative to what the coordinates are interpreted. It may be "window", "page" (the default), or "local".
      -
      cm.defaultTextHeight(): number
      +
      cm.defaultTextHeight() → number
      Returns the line height of the default font for the editor.
      -
      cm.defaultCharWidth(): number
      +
      cm.defaultCharWidth() → number
      Returns the pixel width of an 'x' in the default font for the editor. (Note that for non-monospace fonts, this is mostly useless, and even for monospace fonts, non-ascii characters might have a different width).
      -
      cm.getViewport(): {from: number, to: number}
      +
      cm.getViewport() → {from: number, to: number}
      Returns a {from, to} object indicating the start (inclusive) and end (exclusive) of the currently rendered part of the document. In big documents, when most content is @@ -1274,7 +1273,7 @@

      Sizing, scrolling and positioning methods

      the viewportChange event.
      -
      cm.refresh(): void
      +
      cm.refresh()
      If your code does something to change the size of the editor element (window resizes are already listened for), or unhides it, you should probably follow up by calling this method to @@ -1289,13 +1288,13 @@

      Mode, state, and token-related methods

      more detailed description of how these work.

      -
      doc.getMode(): object
      +
      doc.getMode() → object
      Gets the mode object for the editor. Note that this is distinct from getOption("mode"), which gives you the mode specification, rather than the resolved, instantiated mode object.
      -
      cm.getTokenAt(pos: {line, ch}): { start: string, end: string, string: string, type: string, state: string }
      +
      cm.getTokenAt(pos: {line, ch}) → object
      Retrieves information about the token the current mode found before the given position (a {line, ch} object). The returned object has the following properties: @@ -1309,7 +1308,7 @@

      Mode, state, and token-related methods

      state
      The mode's state at the end of this token.
      -
      cm.getStateAfter(?line: integer): object
      +
      cm.getStateAfter(?line: integer) → object
      Returns the mode's parser state, if any, at the end of the given line number. If no line number is given, the state at the end of the document is returned. This can be useful for storing @@ -1320,10 +1319,10 @@

      Mode, state, and token-related methods

      Miscellaneous methods

      -
      CodeMirror(elt:Element|(elt:Element) → void, ?config: object): void
      +
      CodeMirror(elt: Element|function(elt: Element), ?config: object)
      The constructor. See Basic Usage.
      -
      cm.operation(func: () → any): any
      +
      cm.operation(func: () → any) → any
      CodeMirror internally buffers changes and only updates its DOM structure after it has finished performing some operation. If you need to perform a lot of operations on a CodeMirror @@ -1333,7 +1332,7 @@

      Miscellaneous methods

      lot faster. The return value from this method will be the return value of your function.
      -
      cm.indentLine(line: integer|LineHandle, ?dir: string): void
      +
      cm.indentLine(line: integer|LineHandle, ?dir: string)
      Adjust the indentation of the given line. The second argument (which defaults to "smart") may be one of:
      @@ -1349,28 +1348,28 @@

      Miscellaneous methods

      Reduce the indentation of the line.
      -
      doc.posFromIndex(index: integer): {line, ch}
      +
      doc.posFromIndex(index: integer) → {line, ch}
      Calculates and returns a {line, ch} object for a zero-based index who's value is relative to the start of the editor's text. If the index is out of range of the text then the returned object is clipped to start or end of the text respectively.
      -
      doc.indexFromPos(object: {line, ch}): integer
      +
      doc.indexFromPos(object: {line, ch}) → integer
      The reverse of posFromIndex.
      -
      cm.focus(): void
      +
      cm.focus()
      Give the editor focus.
      -
      cm.getInputField(): TextAreaElement
      +
      cm.getInputField() → TextAreaElement
      Returns the hidden textarea used to read input.
      -
      cm.getWrapperElement(): Element
      +
      cm.getWrapperElement() → Element
      Returns the DOM node that represents the editor, and controls its size. Remove this from your tree to delete an editor instance.
      -
      cm.getScrollerElement(): Element
      +
      cm.getScrollerElement() → Element
      Returns the DOM node that is responsible for the scrolling of the editor.
      -
      cm.getGutterElement(): Element
      +
      cm.getGutterElement() → Element
      Fetches the DOM node that contains the editor gutters.
      @@ -1398,19 +1397,19 @@

      Static properties

      is submitted. A CodeMirror instance created this way has three additional methods:
      -
      cm.save(): void
      +
      cm.save()
      Copy the content of the editor into the textarea.
      -
      cm.toTextArea(): void
      +
      cm.toTextArea()
      Remove the editor, and restore the original textarea (with the editor's current content).
      -
      cm.getTextArea(): TextAreaElement
      +
      cm.getTextArea() → TextAreaElement
      Returns the textarea that the instance was based on.
      -
      CodeMirror.defineExtension(name: string, value: any): void
      +
      CodeMirror.defineExtension(name: string, value: any)
      If you want to define extra methods in terms of the CodeMirror API, it is possible to use defineExtension. This @@ -1418,14 +1417,14 @@

      Static properties

      CodeMirror instances created from then on.
      CodeMirror.defineOption(name: string, - default: any, updateFunc: (instance: CodeMirror, value: any, setOption: boolean) → void): void
      + default: any, updateFunc: function)
      Similarly, defineOption can be used to define new options for CodeMirror. The updateFunc will be called with the editor instance and the new value when an editor is initialized, and whenever the option is modified through setOption.
      -
      CodeMirror.defineInitHook(func: (instance: CodeMirror) → void): void
      +
      CodeMirror.defineInitHook(func: function)
      If your extention just needs to run some code whenever a CodeMirror instance is initialized, use CodeMirror.defineInitHook. Give it a function as @@ -1461,8 +1460,8 @@

      Add-ons

      case-insensitive. A search cursor has the following methods:
      - findNext(): boolean
      - findPrevious(): boolean + findNext() → boolean
      + findPrevious() → boolean
      Search forward or backward from the current position. The return value indicates whether a match was found. If @@ -1470,14 +1469,14 @@

      Add-ons

      array returned by the match method, in case you want to extract matched groups.
      - from(): {line, ch}
      - to(): {line, ch} + from() → {line, ch}
      + to() → {line, ch}
      These are only valid when the last call to findNext or findPrevious did not return false. They will return {line, ch} objects pointing at the start and end of the match.
      -
      replace(text: string): void
      +
      replace(text: string)
      Replaces the currently found match with the given text and adjusts the cursor position to reflect the replacement.
      @@ -1685,44 +1684,44 @@

      Writing CodeMirror Modes

      the following API:

      -
      eol(): boolean
      +
      eol() → boolean
      Returns true only if the stream is at the end of the line.
      -
      sol(): boolean
      +
      sol() → boolean
      Returns true only if the stream is at the start of the line.
      -
      peek(): string
      +
      peek() → string
      Returns the next character in the stream without advancing it. Will return an null at the end of the line.
      -
      next(): string
      +
      next() → string
      Returns the next character in the stream and advances it. Also returns null when no more characters are available.
      -
      eat(match: string|regexp|(char:string) → boolean): string
      +
      eat(match: string|regexp|function(char: string) → boolean) → string
      match can be a character, a regular expression, or a function that takes a character and returns a boolean. If the next character in the stream 'matches' the given argument, it is consumed and returned. Otherwise, undefined is returned.
      -
      eatWhile(match: string|regexp|(char:string) → boolean): boolean
      +
      eatWhile(match: string|regexp|function(char: string) → boolean) → boolean
      Repeatedly calls eat with the given argument, until it fails. Returns true if any characters were eaten.
      -
      eatSpace(): boolean
      +
      eatSpace() → boolean
      Shortcut for eatWhile when matching white-space.
      -
      skipToEnd(): void
      +
      skipToEnd()
      Moves the position to the end of the line.
      -
      skipTo(ch: string): boolean
      +
      skipTo(ch: string) → boolean
      Skips to the next occurrence of the given character, if found on the current line (doesn't advance the stream if the character does not occur on the line). Returns true if the character was found.
      - match(pattern: string, ?consume: boolean, ?caseFold: boolean): boolean
      - match(pattern: regexp, ?consume: boolean): array<string> + match(pattern: string, ?consume: boolean, ?caseFold: boolean) → boolean
      + match(pattern: regexp, ?consume: boolean) → array<string>
      Act like a multi-character eat—if consume is true @@ -1735,18 +1734,18 @@

      Writing CodeMirror Modes

      returned by match, in case you need to extract matched groups.
      -
      backUp(n: integer): void
      +
      backUp(n: integer)
      Backs up the stream n characters. Backing it up further than the start of the current token will cause things to break, so be careful.
      -
      column(): integer
      +
      column() → integer
      Returns the column (taking into account tabs) at which the current token starts.
      -
      indentation(): integer
      +
      indentation() → integer
      Tells you how far the current line has been indented, in spaces. Corrects for tab characters.
      -
      current(): string
      +
      current() → string
      Get the string between the start of the current token and the current stream position.
      From 1cf23b4647b6864dac96debc4994284472fabad5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 4 Apr 2013 11:35:04 +0200 Subject: [PATCH 0462/5273] Do some styling in an attempt to make manual more readable --- doc/manual.html | 437 ++++++++++++++++++++++++------------------------ 1 file changed, 215 insertions(+), 222 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index d805185f15..45ea1a9225 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,10 +1,10 @@ - + CodeMirror: User Manual - - + + @@ -14,13 +14,16 @@ +

      { } CodeMirror

      - +
       /* User manual and
          reference guide */
      @@ -119,11 +122,11 @@ 

      Configuration

      These are the supported options:

      -
      value: string|CodeMirror.Doc
      +
      value: string|CodeMirror.Doc
      The starting value of the editor. Can be a string, or a document object.
      -
      mode: string|object
      +
      mode: string|object
      The mode to use. When not given, this will default to the first mode that was loaded. It may be a string, which either simply names the mode or is @@ -140,7 +143,7 @@

      Configuration

      mode names to their constructors, and the second maps MIME types to mode specs.
      -
      theme: string
      +
      theme: string
      The theme to style the editor with. You must make sure the CSS file defining the corresponding .cm-s-[name] styles is loaded (see @@ -152,29 +155,29 @@

      Configuration

      the cm-s-foo and the cm-s-bar classes to the editor.
      -
      indentUnit: integer
      +
      indentUnit: integer
      How many spaces a block (whatever that means in the edited language) should be indented. The default is 2.
      -
      smartIndent: boolean
      +
      smartIndent: boolean
      Whether to use the context-sensitive indentation that the mode provides (or just indent the same as the line before). Defaults to true.
      -
      tabSize: integer
      +
      tabSize: integer
      The width of a tab character. Defaults to 4.
      -
      indentWithTabs: boolean
      +
      indentWithTabs: boolean
      Whether, when indenting, the first N*tabSize spaces should be replaced by N tabs. Default is false.
      -
      electricChars: boolean
      +
      electricChars: boolean
      Configures whether the editor should re-indent the current line when a character is typed that might change its proper indentation (only works if the mode supports indentation). Default is true.
      -
      rtlMoveVisually: boolean
      +
      rtlMoveVisually: boolean
      Determines whether horizontal cursor movement through right-to-left (Arabic, Hebrew) text is visual (pressing the left arrow moves the cursor left) or logical (pressing the left arrow @@ -182,7 +185,7 @@

      Configuration

      right in right-to-left text). The default is false on Windows, and true on other platforms.
      -
      keyMap: string
      +
      keyMap: string
      Configures the keymap to use. The default is "default", which is the only keymap defined in codemirror.js itself. Extra keymaps are found in @@ -190,28 +193,28 @@

      Configuration

      the section on keymaps for more information.
      -
      extraKeys: object
      +
      extraKeys: object
      Can be used to specify extra keybindings for the editor, alongside the ones defined by keyMap. Should be either null, or a valid keymap value.
      -
      lineWrapping: boolean
      +
      lineWrapping: boolean
      Whether CodeMirror should scroll or wrap for long lines. Defaults to false (scroll).
      -
      lineNumbers: boolean
      +
      lineNumbers: boolean
      Whether to show line numbers to the left of the editor.
      -
      firstLineNumber: integer
      +
      firstLineNumber: integer
      At which number to start counting lines. Default is 1.
      -
      lineNumberFormatter: function(line: integer) → string
      +
      lineNumberFormatter: function(line: integer) → string
      A function used to format line numbers. The function is passed the line number, and should return a string that will be shown in the gutter.
      -
      gutters: array<string>
      +
      gutters: array<string>
      Can be used to add extra gutters (beyond or instead of the line number gutter). Should be an array of CSS class names, each of which defines a width (and optionally a @@ -223,31 +226,31 @@

      Configuration

      names are the keys passed to setGutterMarker.
      -
      fixedGutter: boolean
      +
      fixedGutter: boolean
      Determines whether the gutter scrolls along with the content horizontally (false) or whether it stays fixed during horizontal scrolling (true, the default).
      -
      readOnly: boolean|string
      +
      readOnly: boolean|string
      This disables editing of the editor content by the user. If the special value "nocursor" is given (instead of simply true), focusing of the editor is also disallowed.
      -
      showCursorWhenSelecting: boolean
      +
      showCursorWhenSelecting: boolean
      Whether the cursor should be drawn when a selection is active. Defaults to false.
      -
      undoDepth: integer
      +
      undoDepth: integer
      The maximum number of undo levels that the editor stores. Defaults to 40.
      -
      tabindex: integer
      +
      tabindex: integer
      The tab index to assign to the editor. If not given, no tab index will be assigned.
      -
      autofocus: boolean
      +
      autofocus: boolean
      Can be used to make CodeMirror focus itself on initialization. Defaults to off. When fromTextArea is @@ -262,10 +265,10 @@

      Configuration

      might want to skip them the first time you read this manual.

      -
      dragDrop: boolean
      +
      dragDrop: boolean
      Controls whether drag-and-drop is enabled. On by default.
      -
      onDragEvent: function(instance: CodeMirror, event: Event) → boolean
      +
      onDragEvent: function(instance: CodeMirror, event: Event) → boolean
      When given, this will be called when the editor is handling a dragenter, dragover, or drop event. It will be passed the editor instance @@ -274,7 +277,7 @@

      Configuration

      return true to indicate that CodeMirror should not do anything further.
      -
      onKeyEvent: function(instance: CodeMirror, event: Event) → boolean
      +
      onKeyEvent: function(instance: CodeMirror, event: Event) → boolean
      This provides a rather low-level hook into CodeMirror's key handling. If provided, this function will be called on every keydown, keyup, @@ -293,35 +296,35 @@

      Configuration

      is keydown (or keypress for actions that need character data).
      -
      cursorBlinkRate: number
      +
      cursorBlinkRate: number
      Half-period in milliseconds used for cursor blinking. The default blink rate is 530ms.
      -
      cursorHeight: number
      +
      cursorHeight: number
      Determines the height of the cursor. Default is 1, meaning it spans the whole height of the line. For some fonts (and by some tastes) a smaller height (for example 0.85), which causes the cursor to not reach all the way to the bottom of the line, looks better
      -
      workTime, workDelay: number
      +
      workTime, workDelay: number
      Highlighting is done by a pseudo background-thread that will work for workTime milliseconds, and then use timeout to sleep for workDelay milliseconds. The defaults are 200 and 300, you can change these options to make the highlighting more or less aggressive.
      -
      workDelay: number
      +
      workDelay: number
      See workTime.
      -
      pollInterval: number
      +
      pollInterval: number
      Indicates how quickly CodeMirror should poll its input textarea for changes (when focused). Most input is captured by events, but some things, like IME input on some browsers, don't generate events that allow CodeMirror to properly detect it. Thus, it polls. Default is 100 milliseconds.
      -
      flattenSpans: boolean
      +
      flattenSpans: boolean
      By default, CodeMirror will combine adjacent tokens into a single span if they have the same class. This will result in a simpler DOM tree, and thus perform better. With some kinds of @@ -329,14 +332,14 @@

      Configuration

      document looks. You can set this option to false to disable this behavior.
      -
      maxHighlightLength: number
      +
      maxHighlightLength: number
      When highlighting long lines, in order to stay responsive, the editor will give up and simply style the rest of the line as plain text when it reaches a certain position. The default is 10000. You can set this to Infinity to turn off this behavior.
      -
      viewportMargin: integer
      +
      viewportMargin: integer
      Specifies the amount of lines that are rendered above and below the part of the document that's currently scrolled into view. This affects the amount of updates needed when scrolling, @@ -360,7 +363,7 @@

      Events

      refers to the editor instance.

      -
      "change" (instance: CodeMirror, changeObj: object)
      +
      "change" (instance: CodeMirror, changeObj: object)
      Fires every time the content of the editor is changed. The changeObj is a {from, to, text, removed, next} object containing information about the changes @@ -377,7 +380,7 @@

      Events

      a next property pointing to another change object (which may point to another, etc).
      -
      "beforeChange" (instance: CodeMirror, changeObj: object)
      +
      "beforeChange" (instance: CodeMirror, changeObj: object)
      This event is fired before a change is applied, and its handler may choose to modify or cancel the change. The changeObj object @@ -397,11 +400,11 @@

      Events

      the CodeMirror implementation, probably cause the editor to become corrupted.
      -
      "cursorActivity" (instance: CodeMirror)
      +
      "cursorActivity" (instance: CodeMirror)
      Will be fired when the cursor or selection moves, or any change is made to the editor content.
      -
      "beforeSelectionChange" (instance: CodeMirror, selection: {head, anchor})
      +
      "beforeSelectionChange" (instance: CodeMirror, selection: {head, anchor})
      This event is fired before the selection is moved. Its handler may modify the resulting selection head and anchor. The selection parameter is an object @@ -413,13 +416,13 @@

      Events

      handlers — they should not do anything to directly update the state of the editor.
      -
      "viewportChange" (instance: CodeMirror, from: number, to: number)
      +
      "viewportChange" (instance: CodeMirror, from: number, to: number)
      Fires whenever the view port of the editor changes (due to scrolling, editing, or any other factor). The from and to arguments give the new start and end of the viewport.
      -
      "gutterClick" (instance: CodeMirror, line: integer, gutter: string, clickEvent: Event)
      +
      "gutterClick" (instance: CodeMirror, line: integer, gutter: string, clickEvent: Event)
      Fires when the editor gutter (the line-number area) is clicked. Will pass the editor instance as first argument, the (zero-based) number of the line that was clicked as second @@ -427,19 +430,19 @@

      Events

      argument, and the raw mousedown event object as fourth argument.
      -
      "focus" (instance: CodeMirror)
      +
      "focus" (instance: CodeMirror)
      Fires whenever the editor is focused.
      -
      "blur" (instance: CodeMirror)
      +
      "blur" (instance: CodeMirror)
      Fires whenever the editor is unfocused.
      -
      "scroll" (instance: CodeMirror)
      +
      "scroll" (instance: CodeMirror)
      Fires when the editor is scrolled.
      -
      "update" (instance: CodeMirror)
      +
      "update" (instance: CodeMirror)
      Will be fired whenever CodeMirror updates its DOM display.
      -
      "renderLine" (instance: CodeMirror, line: integer, element: Element)
      +
      "renderLine" (instance: CodeMirror, line: integer, element: Element)
      Fired whenever a line is (re-)rendered to the DOM. Fired right after the DOM element is built, before it is added to the document. The handler may mess with the style of @@ -455,7 +458,7 @@

      Events

      following events:

      -
      "change" (doc: CodeMirror.Doc, changeObj: object)
      +
      "change" (doc: CodeMirror.Doc, changeObj: object)
      Fired whenever a change occurs to the document. changeObj has a similar type as the object passed to the @@ -464,15 +467,15 @@

      Events

      document change events are not batched (whereas editor change events are).
      -
      "beforeChange" (doc: CodeMirror.Doc, change: object)
      +
      "beforeChange" (doc: CodeMirror.Doc, change: object)
      See the description of the same event on editor instances.
      -
      "cursorActivity" (doc: CodeMirror.Doc)
      +
      "cursorActivity" (doc: CodeMirror.Doc)
      Fired whenever the cursor or selection in this document changes.
      -
      "beforeSelectionChange" (doc: CodeMirror.Doc, selection: {head, anchor})
      +
      "beforeSelectionChange" (doc: CodeMirror.Doc, selection: {head, anchor})
      Equivalent to the event by the same name as fired on editor instances.
      @@ -483,12 +486,12 @@

      Events

      support these events:

      -
      "delete" ()
      +
      "delete" ()
      Will be fired when the line object is deleted. A line object is associated with the start of the line. Mostly useful when you need to find out when your gutter markers on a given line are removed.
      -
      "change" (line: LineHandle, changeObj: object)
      +
      "change" (line: LineHandle, changeObj: object)
      Fires when the line's text content is changed in any way (but the line is not deleted outright). The change object is similar to the one passed @@ -502,12 +505,12 @@

      Events

      following events:

      -
      "beforeCursorEnter" ()
      +
      "beforeCursorEnter" ()
      Fired when the cursor enters the marked range. From this event handler, the editor state may be inspected but not modified, with the exception that the range on which the event fires may be cleared.
      -
      "clear" ()
      +
      "clear" ()
      Fired when the range is cleared, either through cursor movement in combination with clearOnEnter @@ -515,10 +518,10 @@

      Events

      be fired once per handle. Note that deleting the range through text editing does not fire this event, because an undo action might bring the range back into existence.
      -
      "hide" ()
      +
      "hide" ()
      Fired when the last part of the marker is removed from the document by editing operations.
      -
      "unhide" ()
      +
      "unhide" ()
      Fired when, after the marker was removed by editing, a undo operation brought the marker back.
      @@ -528,7 +531,7 @@

      Events

      these events:

      -
      "redraw" ()
      +
      "redraw" ()
      Fired whenever the editor re-adds the widget to the DOM. This will happen once right after the widget is added (if it is scrolled into view), and then again whenever it is scrolled out @@ -622,13 +625,13 @@

      Customized Styling

      this file serve the following roles:

      -
      CodeMirror
      +
      CodeMirror
      The outer element of the editor. This should be used for the editor width, height, borders and positioning. Can also be used to set styles that should hold for everything inside the editor (such as font and font size), or to set a background.
      -
      CodeMirror-scroll
      +
      CodeMirror-scroll
      Whether the editor scrolls (overflow: auto + fixed height). By default, it does. Setting the CodeMirror class to have height: @@ -637,40 +640,40 @@

      Customized Styling

      to resize to fit its content.
      -
      CodeMirror-focused
      +
      CodeMirror-focused
      Whenever the editor is focused, the top element gets this class. This is used to hide the cursor and give the selection a different color when the editor is not focused.
      -
      CodeMirror-gutters
      +
      CodeMirror-gutters
      This is the backdrop for all gutters. Use it to set the default gutter background color, and optionally add a border on the right of the gutters.
      -
      CodeMirror-linenumbers
      +
      CodeMirror-linenumbers
      Use this for giving a background or width to the line number gutter.
      -
      CodeMirror-linenumber
      +
      CodeMirror-linenumber
      Used to style the actual individual line numbers. These won't be children of the CodeMirror-linenumbers (plural) element, but rather will be absolutely positioned to overlay it. Use this to set alignment and text properties for the line numbers.
      -
      CodeMirror-lines
      +
      CodeMirror-lines
      The visible lines. This is where you specify vertical padding for the editor content.
      -
      CodeMirror-cursor
      +
      CodeMirror-cursor
      The cursor is a block element that is absolutely positioned. You can make it look whichever way you want.
      -
      CodeMirror-selected
      +
      CodeMirror-selected
      The selection is represented by span elements with this class.
      -
      CodeMirror-matchingbracket, +
      CodeMirror-matchingbracket, CodeMirror-nonmatchingbracket
      These are used to style matched (or unmatched) brackets.
      @@ -710,55 +713,53 @@

      Programming API

      Content manipulation methods

      -
      doc.getValue(?seperator: string) → string
      +
      doc.getValue(?seperator: string) → string
      Get the current editor content. You can pass it an optional argument to specify the string to be used to separate lines (defaults to "\n").
      -
      doc.setValue(content: string)
      +
      doc.setValue(content: string)
      Set the editor content.
      -
      doc.getRange(from: {line, ch}, to: {line, ch}, ?seperator: string) → string
      +
      doc.getRange(from: {line, ch}, to: {line, ch}, ?seperator: string) → string
      Get the text between the given points in the editor, which should be {line, ch} objects. An optional third argument can be given to indicate the line separator string to use (defaults to "\n").
      -
      doc.replaceRange(replacement: string, from: {line, ch}, to: {line, ch})
      +
      doc.replaceRange(replacement: string, from: {line, ch}, to: {line, ch})
      Replace the part of the document between from and to with the given string. from and to must be {line, ch} objects. to can be left off to simply insert the string at position from.
      -
      doc.getLine(n: integer) → string
      +
      doc.getLine(n: integer) → string
      Get the content of line n.
      -
      doc.setLine(n: integer, text: string)
      +
      doc.setLine(n: integer, text: string)
      Set the content of line n.
      -
      doc.removeLine(n: integer)
      +
      doc.removeLine(n: integer)
      Remove the given line from the document.
      -
      doc.lineCount() → integer
      +
      doc.lineCount() → integer
      Get the number of lines in the editor.
      -
      doc.firstLine() → integer
      +
      doc.firstLine() → integer
      Get the first line of the editor. This will usually be zero but for linked sub-views, or documents instantiated with a non-zero first line, it might return other values.
      -
      doc.lastLine() → integer
      +
      doc.lastLine() → integer
      Get the last line of the editor. This will usually be doc.lineCount() - 1, but for linked sub-views, it might return other values.
      -
      doc.getLineHandle(num: integer) → LineHandle
      +
      doc.getLineHandle(num: integer) → LineHandle
      Fetches the line handle for the given line number.
      -
      doc.getLineNumber(handle: LineHandle) → integer
      +
      doc.getLineNumber(handle: LineHandle) → integer
      Given a line handle, returns the current position of that line (or null when it is no longer in the document).
      -
      - doc.eachLine(f: (line: LineHandle))
      - doc.eachLine(start: integer, end: integer, f: (line: LineHandle)) -
      +
      doc.eachLine(f: (line: LineHandle))
      +
      doc.eachLine(start: integer, end: integer, f: (line: LineHandle))
      Iterate over the whole document, or if start and end line numbers are given, the range from start up to (not including) end, @@ -769,12 +770,12 @@

      Content manipulation methods

      a text property containing the line's content (as a string).
      -
      doc.markClean()
      +
      doc.markClean()
      Set the editor content as 'clean', a flag that it will retain until it is edited, and which will be set again when such an edit is undone again. Useful to track whether the content needs to be saved.
      -
      doc.isClean() → boolean
      +
      doc.isClean() → boolean
      Returns whether the document is currently clean (not modified since initialization or the last call to markClean).
      @@ -783,9 +784,9 @@

      Content manipulation methods

      Cursor and selection methods

      -
      doc.getSelection() → string
      +
      doc.getSelection() → string
      Get the currently selected code.
      -
      doc.replaceSelection(replacement: string, ?collapse: string)
      +
      doc.replaceSelection(replacement: string, ?collapse: string)
      Replace the selection with the given string. By default, the new selection will span the inserted text. The optional collapse argument can be used to change @@ -793,7 +794,7 @@

      Cursor and selection methods

      collapse the selection to the start or end of the inserted text.
      -
      doc.getCursor(?start: string) → {line, ch}
      +
      doc.getCursor(?start: string) → {line, ch}
      start is a an optional string indicating which end of the selection to return. It may be "start", "end", "head" @@ -802,18 +803,18 @@

      Cursor and selection methods

      selection). Omitting the argument is the same as passing "head". A {line, ch} object will be returned.
      -
      doc.somethingSelected() → boolean
      +
      doc.somethingSelected() → boolean
      Return true if any text is selected.
      -
      doc.setCursor(pos: {line, ch})
      +
      doc.setCursor(pos: {line, ch})
      Set the cursor position. You can either pass a single {line, ch} object, or the line and the character as two separate parameters.
      -
      doc.setSelection(anchor: {line, ch}, head: {line, ch})
      +
      doc.setSelection(anchor: {line, ch}, head: {line, ch})
      Set the selection range. anchor and head should be {line, ch} objects. head defaults to anchor when not given.
      -
      doc.extendSelection(from: {line, ch}, ?to: {line, ch})
      +
      doc.extendSelection(from: {line, ch}, ?to: {line, ch})
      Similar to setSelection, but will, if shift is held or @@ -823,16 +824,16 @@

      Cursor and selection methods

      ensure a region (for example a word or paragraph) will end up selected (in addition to whatever lies between that region and the current anchor).
      -
      doc.setExtending(value: boolean)
      +
      doc.setExtending(value: boolean)
      Sets or clears the 'extending' flag, which acts similar to the shift key, in that it will cause cursor movement and calls to extendSelection to leave the selection anchor in place.
      -
      cm.hasFocus() → boolean
      +
      cm.hasFocus() → boolean
      Tells you whether the editor currently has focus.
      -
      cm.findPosH(start: {line, ch}, amount: integer, unit: string, visually: boolean) → {line, ch, ?hitSide: boolean}
      +
      cm.findPosH(start: {line, ch}, amount: integer, unit: string, visually: boolean) → {line, ch, ?hitSide: boolean}
      Used to find the target position for horizontal cursor motion. start is a {line, ch} object, amount an integer (may be negative), @@ -845,7 +846,7 @@

      Cursor and selection methods

      the motion was clipped by hitting the end or start of the document, the returned value will have a hitSide property set to true.
      -
      cm.findPosV(start: {line, ch}, amount: integer, unit: string) → {line, ch, ?hitSide: boolean}
      +
      cm.findPosV(start: {line, ch}, amount: integer, unit: string) → {line, ch, ?hitSide: boolean}
      Similar to findPosH, but used for vertical motion. unit may be "line" or "page". The other @@ -856,16 +857,16 @@

      Cursor and selection methods

      Configuration methods

      -
      cm.setOption(option: string, value: any)
      +
      cm.setOption(option: string, value: any)
      Change the configuration of the editor. option should the name of an option, and value should be a valid value for that option.
      -
      cm.getOption(option: string) → any
      +
      cm.getOption(option: string) → any
      Retrieves the current value of the given option for this editor instance.
      -
      cm.addKeyMap(map: object, bottom: boolean)
      +
      cm.addKeyMap(map: object, bottom: boolean)
      Attach an additional keymap to the editor. This is mostly useful for add-ons that need to register some key handlers without trampling on @@ -877,14 +878,14 @@

      Configuration methods

      than those added later, unless the bottom argument was passed, in which case they end up below other keymaps added with this method.
      -
      cm.removeKeyMap(map: object)
      +
      cm.removeKeyMap(map: object)
      Disable a keymap added with addKeyMap. Either pass in the keymap object itself, or a string, which will be compared against the name property of the active keymaps.
      -
      cm.addOverlay(mode: string|object, ?options: object)
      +
      cm.addOverlay(mode: string|object, ?options: object)
      Enable a highlighting overlay. This is a stateless mini-mode that can be used to add extra highlighting. For example, the search add-on uses it to @@ -898,18 +899,18 @@

      Configuration methods

      allow the overlay styling, when not null, to override the styling of the base mode entirely, instead of the two being applied together.
      -
      cm.removeOverlay(mode: string|object)
      +
      cm.removeOverlay(mode: string|object)
      Pass this the exact argument passed for the mode parameter to addOverlay to remove an overlay again.
      -
      cm.on(type: string, func: (...args))
      +
      cm.on(type: string, func: (...args))
      Register an event handler for the given event type (a string) on the editor instance. There is also a CodeMirror.on(object, type, func) version that allows registering of events on any object.
      -
      cm.off(type: string, func: (...args))
      +
      cm.off(type: string, func: (...args))
      Remove an event handler on the editor instance. An equivalent CodeMirror.off(object, type, func) also exists.
      @@ -928,53 +929,51 @@

      Document management methods

      it start at a line number other than 0, respectively.

      -
      cm.getDoc() → CodeMirror.Doc
      +
      cm.getDoc() → Doc
      Retrieve the currently active document from an editor.
      -
      doc.getEditor() → CodeMirror
      +
      doc.getEditor() → CodeMirror
      Retrieve the editor associated with a document. May return null.
      -
      cm.swapDoc(doc: CodeMirror.Doc) → CodeMirror.Doc
      +
      cm.swapDoc(doc: CodeMirror.Doc) → Doc
      Attach a new document to the editor. Returns the old document, which is now no longer associated with an editor.
      -
      doc.copy(copyHistory: boolean) → CodeMirror.Doc
      +
      doc.copy(copyHistory: boolean) → Doc
      Create an identical copy of the given doc. When copyHistory is true, the history will also be copied. Can not be called directly on an editor.
      -
      doc.linkedDoc(options: object) → CodeMirror.Doc
      +
      doc.linkedDoc(options: object) → Doc
      Create a new document that's linked to the target document. Linked documents will stay in sync (changes to one are also applied to the other) until unlinked. These are the options that are supported:
      -
      sharedHist: boolean
      +
      sharedHist: boolean
      When turned on, the linked copy will share an undo history with the original. Thus, something done in one of the two can be undone in the other, and vice versa.
      -
      - from: integer
      - to: integer -
      +
      from: integer
      +
      to: integer
      Can be given to make the new document a subview of the original. Subviews only show a given range of lines. Note that line coordinates inside the subview will be consistent with those of the parent, so that for example a subview starting at line 10 will refer to its first line as line 10, not 0.
      -
      mode: string|object
      +
      mode: string|object
      By default, the new document inherits the mode of the parent. This option can be set to a mode spec to give it a different mode.
      -
      doc.unlinkDoc(doc: CodeMirror.Doc)
      +
      doc.unlinkDoc(doc: CodeMirror.Doc)
      Break the link between two documents. After calling this, changes will no longer propagate between the documents, and, if they had a shared history, the history will become separate.
      -
      doc.iterLinkedDocs(function: (doc: CodeMirror.Doc, sharedHist: boolean))
      +
      doc.iterLinkedDocs(function: (doc: CodeMirror.Doc, sharedHist: boolean))
      Will call the given function for all documents linked to the target document. It will be passed two arguments, the linked document and a boolean indicating whether that document shares history @@ -984,20 +983,20 @@

      Document management methods

      History-related methods

      -
      doc.undo()
      +
      doc.undo()
      Undo one edit (if any undo events are stored).
      -
      doc.redo()
      +
      doc.redo()
      Redo one undone edit.
      -
      doc.historySize() → {undo: integer, redo: integer}
      +
      doc.historySize() → {undo: integer, redo: integer}
      Returns an object with {undo, redo} properties, both of which hold integers, indicating the amount of stored undo and redo operations.
      -
      doc.clearHistory()
      +
      doc.clearHistory()
      Clears the editor's undo history.
      -
      doc.getHistory() → object
      +
      doc.getHistory() → object
      Get a (JSON-serializeable) representation of the undo history.
      -
      doc.setHistory(history: object)
      +
      doc.setHistory(history: object)
      Replace the editor's undo history with the one provided, which must be a value as returned by getHistory. Note that @@ -1009,33 +1008,33 @@

      History-related methods

      Text-marking methods

      -
      doc.markText(from: {line, ch}, to: {line, ch}, ?options: object) → CodeMirror.TextMarker
      +
      doc.markText(from: {line, ch}, to: {line, ch}, ?options: object) → TextMarker
      Can be used to mark a range of text with a specific CSS class name. from and to should be {line, ch} objects. The options parameter is optional. When given, it should be an object that may contain the following configuration options:
      -
      className: string
      +
      className: string
      Assigns a CSS class to the marked stretch of text.
      -
      inclusiveLeft: boolean
      +
      inclusiveLeft: boolean
      Determines whether text inserted on the left of the marker will end up inside or outside of it.
      -
      inclusiveRight: boolean
      +
      inclusiveRight: boolean
      Like inclusiveLeft, but for the right side.
      -
      atomic: boolean
      +
      atomic: boolean
      Atomic ranges act as a single unit when cursor movement is concerned—i.e. it is impossible to place the cursor inside of them. In atomic ranges, inclusiveLeft and inclusiveRight have a different meaning—they will prevent the cursor from being placed respectively directly before and directly after the range.
      -
      collapsed: boolean
      +
      collapsed: boolean
      Collapsed ranges do not show up in the display. Setting a range to be collapsed will automatically make it atomic.
      -
      clearOnEnter: boolean
      +
      clearOnEnter: boolean
      When enabled, will cause the mark to clear itself whenever the cursor enters its range. This is mostly useful for text-replacement widgets that need to 'snap open' when the @@ -1043,11 +1042,11 @@

      Text-marking methods

      the "clear" event fired on the range handle can be used to be notified when this happens.
      -
      replacedWith: Element
      +
      replacedWith: Element
      Use a given node to display this range. Implies both collapsed and atomic. The given DOM node must be an inline element (as opposed to a block element).
      -
      readOnly: boolean|string
      +
      readOnly: boolean|string
      A read-only span can, as long as it is not cleared, not be modified except by calling setValue to reset @@ -1056,12 +1055,12 @@

      Text-marking methods

      existing undo events being partially nullified by read-only spans would corrupt the history (in the current implementation).
      -
      startStyle: string
      Can be used to specify +
      startStyle: string
      Can be used to specify an extra CSS class to be applied to the leftmost span that is part of the marker.
      -
      endStyle: string
      Equivalent +
      endStyle: string
      Equivalent to startStyle, but for the rightmost span.
      -
      shared: boolean
      When the +
      shared: boolean
      When the target document is linked to other documents, you can set shared to true to make the marker appear in all documents. By default, a marker appears @@ -1082,7 +1081,7 @@

      Text-marking methods

      the replacedWith option, if any.
      -
      doc.setBookmark(pos: {line, ch}, ?options: object) → CodeMirror.TextMarker
      +
      doc.setBookmark(pos: {line, ch}, ?options: object) → TextMarker
      Inserts a bookmark, a handle that follows the text around it as it is being edited, at the given position. A bookmark has two methods find() and clear(). The first @@ -1091,27 +1090,27 @@

      Text-marking methods

      The options argument is optional. If given, the following properties are recognized:
      -
      widget: Element
      Can be used to display a DOM +
      widget: Element
      Can be used to display a DOM node at the current location of the bookmark (analogous to the replacedWith option to markText).
      -
      insertLeft: boolean
      By default, text typed +
      insertLeft: boolean
      By default, text typed when the cursor is on top of the bookmark will end up to the right of the bookmark. Set this option to true to make it go to the left instead.
      -
      doc.findMarksAt(pos: {line, ch}) → array<CodeMirror.TextMarker>
      +
      doc.findMarksAt(pos: {line, ch}) → array<TextMarker>
      Returns an array of all the bookmarks and marked ranges present at the given position.
      -
      doc.getAllMarks() → array<CodeMirror.TextMarker>
      +
      doc.getAllMarks() → array<TextMarker>
      Returns an array containing all marked ranges in the document.

      Widget, gutter, and decoration methods

      -
      cm.setGutterMarker(line: integer|LineHandle, gutterID: string, value: Element) → LineHandle
      +
      cm.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) @@ -1120,11 +1119,11 @@

      Widget, gutter, and decoration methods

      will be shown in the specified gutter next to the specified line.
      -
      cm.clearGutter(gutterID: string)
      +
      cm.clearGutter(gutterID: string)
      Remove all gutter markers in the gutter with the given ID.
      -
      cm.addLineClass(line: integer|LineHandle, where: string, class: string) → LineHandle
      +
      cm.addLineClass(line: integer|LineHandle, where: string, class: string) → LineHandle
      Set a CSS class name for the given line. line can be a number or a line handle. where determines to which element this class should be applied, can can be one @@ -1135,7 +1134,7 @@

      Widget, gutter, and decoration methods

      gutter elements). class should be the name of the class to apply.
      -
      cm.removeLineClass(line: integer|LineHandle, where: string, class: string) → LineHandle
      +
      cm.removeLineClass(line: integer|LineHandle, where: string, class: string) → LineHandle
      Remove a CSS class from a line. line can be a line handle or number. where should be one of "text", "background", @@ -1144,7 +1143,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) → {line: integer, handle: LineHandle, text: string, gutterMarkers: object<Element>, textClass: string, bgClass: string, wrapClass: string, widgets: array<CodeMirror.LineWidget>}
      +
      cm.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, @@ -1155,7 +1154,7 @@

      Widget, gutter, and decoration methods

      line, and the various class properties refer to classes added with addLineClass.
      -
      cm.addWidget(pos: {line, ch}, node: Element, scrollIntoView: boolean)
      +
      cm.addWidget(pos: {line, ch}, node: Element, scrollIntoView: boolean)
      Puts node, which should be an absolutely positioned DOM node, into the editor, positioned right below the given {line, ch} position. @@ -1164,7 +1163,7 @@

      Widget, gutter, and decoration methods

      widget again, simply use DOM methods (move it somewhere else, or call removeChild on its parent).
      -
      cm.addLineWidget(line: integer|LineHandle, node: Element, ?options: object) → CodeMirror.LineWidget
      +
      cm.addLineWidget(line: integer|LineHandle, node: Element, ?options: object) → LineWidget
      Adds a line widget, an element shown below a line, spanning the whole of the editor's width, and moving the lines below it downwards. line should be either an integer or a @@ -1174,15 +1173,15 @@

      Widget, gutter, and decoration methods

      the widget. The following options are supported (all default to false) →
      -
      coverGutter: boolean
      +
      coverGutter: boolean
      Whether the widget should cover the gutter.
      -
      noHScroll: boolean
      +
      noHScroll: boolean
      Whether the widget should stay fixed in the face of horizontal scrolling.
      -
      above: boolean
      +
      above: boolean
      Causes the widget to be placed above instead of below the text of the line.
      -
      showIfHidden: boolean
      +
      showIfHidden: boolean
      When true, will cause the widget to be rendered even if the line it is associated with is hidden.
      @@ -1192,8 +1191,8 @@

      Widget, gutter, and decoration methods

      the widget placement. It'll have a line property pointing at the line handle that it is associated with, and the following methods:
      -
      clear()
      Removes the widget.
      -
      changed()
      Call +
      clear()
      Removes the widget.
      +
      changed()
      Call this if you made some change to the widget's DOM node that might affect its height. It'll force CodeMirror to update the height of the line that contains the widget.
      @@ -1204,7 +1203,7 @@

      Widget, gutter, and decoration methods

      Sizing, scrolling and positioning methods

      -
      cm.setSize(width: number|string, height: number|string)
      +
      cm.setSize(width: number|string, height: number|string)
      Programatically set the size of the editor (overriding the applicable CSS rules). width and height height @@ -1213,16 +1212,16 @@

      Sizing, scrolling and positioning methods

      pass null for either of them to indicate that that dimension should not be changed.
      -
      cm.scrollTo(x: number, y: number)
      +
      cm.scrollTo(x: number, y: number)
      Scroll the editor to a given (pixel) position. Both arguments may be left as null or undefined to have no effect.
      -
      cm.getScrollInfo() → {left, top, width, height, clientWidth, clientHeight}
      +
      cm.getScrollInfo() → {left, top, width, height, clientWidth, clientHeight}
      Get an {left, top, width, height, clientWidth, clientHeight} object that represents the current scroll position, the size of the scrollable area, and the size of the visible area (minus scrollbars).
      -
      cm.scrollIntoView(pos: {line, ch}|{left, top, right, bottom}, ?margin: number)
      +
      cm.scrollIntoView(pos: {line, ch}|{left, top, right, bottom}, ?margin: number)
      Scrolls the given element into view. pos may be either a {line, ch} position, referring to a given character, null, to refer to the cursor, or @@ -1231,7 +1230,7 @@

      Sizing, scrolling and positioning methods

      optional. When given, it indicates the amount of pixels around the given area that should be made visible as well.
      -
      cm.cursorCoords(where: boolean|{line, ch}, mode: string) → {left, top, bottom}
      +
      cm.cursorCoords(where: boolean|{line, ch}, mode: string) → {left, top, bottom}
      Returns an {left, top, bottom} object containing the coordinates of the cursor position. If mode is "local", they will be @@ -1242,29 +1241,29 @@

      Sizing, scrolling and positioning methods

      end (false) of the selection, or, if a {line, ch} object is given, it specifies the precise position at which you want to measure.
      -
      cm.charCoords(pos: {line, ch}, mode: string) → {left, right, top, bottom}
      +
      cm.charCoords(pos: {line, ch}, mode: string) → {left, right, top, bottom}
      Returns the position and dimensions of an arbitrary character. pos should be a {line, ch} object. This differs from cursorCoords in that it'll give the size of the whole character, rather than just the position that the cursor would have when it would sit at that position.
      -
      cm.coordsChar(object: {left, top}, ?mode: string) → {line, ch}
      +
      cm.coordsChar(object: {left, top}, ?mode: string) → {line, ch}
      Given an {left, top} object, returns the {line, ch} position that corresponds to it. The optional mode parameter determines relative to what the coordinates are interpreted. It may be "window", "page" (the default), or "local".
      -
      cm.defaultTextHeight() → number
      +
      cm.defaultTextHeight() → number
      Returns the line height of the default font for the editor.
      -
      cm.defaultCharWidth() → number
      +
      cm.defaultCharWidth() → number
      Returns the pixel width of an 'x' in the default font for the editor. (Note that for non-monospace fonts, this is mostly useless, and even for monospace fonts, non-ascii characters might have a different width).
      -
      cm.getViewport() → {from: number, to: number}
      +
      cm.getViewport() → {from: number, to: number}
      Returns a {from, to} object indicating the start (inclusive) and end (exclusive) of the currently rendered part of the document. In big documents, when most content is @@ -1273,7 +1272,7 @@

      Sizing, scrolling and positioning methods

      the viewportChange event.
      -
      cm.refresh()
      +
      cm.refresh()
      If your code does something to change the size of the editor element (window resizes are already listened for), or unhides it, you should probably follow up by calling this method to @@ -1288,27 +1287,27 @@

      Mode, state, and token-related methods

      more detailed description of how these work.

      -
      doc.getMode() → object
      +
      doc.getMode() → object
      Gets the mode object for the editor. Note that this is distinct from getOption("mode"), which gives you the mode specification, rather than the resolved, instantiated mode object.
      -
      cm.getTokenAt(pos: {line, ch}) → object
      +
      cm.getTokenAt(pos: {line, ch}) → object
      Retrieves information about the token the current mode found before the given position (a {line, ch} object). The returned object has the following properties:
      -
      start
      The character (on the given line) at which the token starts.
      -
      end
      The character at which the token ends.
      -
      string
      The token's string.
      -
      type
      The token type the mode assigned +
      start
      The character (on the given line) at which the token starts.
      +
      end
      The character at which the token ends.
      +
      string
      The token's string.
      +
      type
      The token type the mode assigned to the token, such as "keyword" or "comment" (may also be null).
      -
      state
      The mode's state at the end of this token.
      +
      state
      The mode's state at the end of this token.
      -
      cm.getStateAfter(?line: integer) → object
      +
      cm.getStateAfter(?line: integer) → object
      Returns the mode's parser state, if any, at the end of the given line number. If no line number is given, the state at the end of the document is returned. This can be useful for storing @@ -1319,10 +1318,10 @@

      Mode, state, and token-related methods

      Miscellaneous methods

      -
      CodeMirror(elt: Element|function(elt: Element), ?config: object)
      +
      CodeMirror(elt: Element|function(elt: Element), ?config: object)
      The constructor. See Basic Usage.
      -
      cm.operation(func: () → any) → any
      +
      cm.operation(func: () → any) → any
      CodeMirror internally buffers changes and only updates its DOM structure after it has finished performing some operation. If you need to perform a lot of operations on a CodeMirror @@ -1332,44 +1331,44 @@

      Miscellaneous methods

      lot faster. The return value from this method will be the return value of your function.
      -
      cm.indentLine(line: integer|LineHandle, ?dir: string)
      +
      cm.indentLine(line: integer|LineHandle, ?dir: string)
      Adjust the indentation of the given line. The second argument (which defaults to "smart") may be one of:
      -
      "prev"
      +
      "prev"
      Base indentation on the indentation of the previous line.
      -
      "smart"
      +
      "smart"
      Use the mode's smart indentation if available, behave like "prev" otherwise.
      -
      "add"
      +
      "add"
      Increase the indentation of the line by one indent unit.
      -
      "subtract"
      +
      "subtract"
      Reduce the indentation of the line.
      -
      doc.posFromIndex(index: integer) → {line, ch}
      +
      doc.posFromIndex(index: integer) → {line, ch}
      Calculates and returns a {line, ch} object for a zero-based index who's value is relative to the start of the editor's text. If the index is out of range of the text then the returned object is clipped to start or end of the text respectively.
      -
      doc.indexFromPos(object: {line, ch}) → integer
      +
      doc.indexFromPos(object: {line, ch}) → integer
      The reverse of posFromIndex.
      -
      cm.focus()
      +
      cm.focus()
      Give the editor focus.
      -
      cm.getInputField() → TextAreaElement
      +
      cm.getInputField() → TextAreaElement
      Returns the hidden textarea used to read input.
      -
      cm.getWrapperElement() → Element
      +
      cm.getWrapperElement() → Element
      Returns the DOM node that represents the editor, and controls its size. Remove this from your tree to delete an editor instance.
      -
      cm.getScrollerElement() → Element
      +
      cm.getScrollerElement() → Element
      Returns the DOM node that is responsible for the scrolling of the editor.
      -
      cm.getGutterElement() → Element
      +
      cm.getGutterElement() → Element
      Fetches the DOM node that contains the editor gutters.
      @@ -1378,7 +1377,7 @@

      Static properties

      several useful properties.

      -
      CodeMirror.version: string
      +
      CodeMirror.version: string
      It contains a string that indicates the version of the library. For releases, this simply contains "major.minor" (for @@ -1387,7 +1386,7 @@

      Static properties

      development snapshots, " +" (space, plus) is added.
      -
      CodeMirror.fromTextArea(textArea: TextAreaElement, ?config: object)
      +
      CodeMirror.fromTextArea(textArea: TextAreaElement, ?config: object)
      The method provides another way to initialize an editor. It takes a textarea DOM node as first argument and an optional configuration @@ -1397,26 +1396,26 @@

      Static properties

      is submitted. A CodeMirror instance created this way has three additional methods:
      -
      cm.save()
      +
      cm.save()
      Copy the content of the editor into the textarea.
      -
      cm.toTextArea()
      +
      cm.toTextArea()
      Remove the editor, and restore the original textarea (with the editor's current content).
      -
      cm.getTextArea() → TextAreaElement
      +
      cm.getTextArea() → TextAreaElement
      Returns the textarea that the instance was based on.
      -
      CodeMirror.defineExtension(name: string, value: any)
      +
      CodeMirror.defineExtension(name: string, value: any)
      If you want to define extra methods in terms of the CodeMirror API, it is possible to use defineExtension. This will cause the given value (usually a method) to be added to all CodeMirror instances created from then on.
      -
      CodeMirror.defineOption(name: string, +
      CodeMirror.defineOption(name: string, default: any, updateFunc: function)
      Similarly, defineOption can be used to define new options for CodeMirror. The updateFunc will be called with the @@ -1424,7 +1423,7 @@

      Static properties

      and whenever the option is modified through setOption.
      -
      CodeMirror.defineInitHook(func: function)
      +
      CodeMirror.defineInitHook(func: function)
      If your extention just needs to run some code whenever a CodeMirror instance is initialized, use CodeMirror.defineInitHook. Give it a function as @@ -1459,24 +1458,20 @@

      Add-ons

      relevant when matching a string. It will cause the search to be case-insensitive. A search cursor has the following methods:
      -
      - findNext() → boolean
      - findPrevious() → boolean -
      +
      findNext() → boolean
      +
      findPrevious() → boolean
      Search forward or backward from the current position. The return value indicates whether a match was found. If matching a regular expression, the return value will be the array returned by the match method, in case you want to extract matched groups.
      -
      - from() → {line, ch}
      - to() → {line, ch} -
      +
      from() → {line, ch}
      +
      to() → {line, ch}
      These are only valid when the last call to findNext or findPrevious did not return false. They will return {line, ch} objects pointing at the start and end of the match.
      -
      replace(text: string)
      +
      replace(text: string)
      Replaces the currently found match with the given text and adjusts the cursor position to reflect the replacement.
      @@ -1684,45 +1679,43 @@

      Writing CodeMirror Modes

      the following API:

      -
      eol() → boolean
      +
      eol() → boolean
      Returns true only if the stream is at the end of the line.
      -
      sol() → boolean
      +
      sol() → boolean
      Returns true only if the stream is at the start of the line.
      -
      peek() → string
      +
      peek() → string
      Returns the next character in the stream without advancing it. Will return an null at the end of the line.
      -
      next() → string
      +
      next() → string
      Returns the next character in the stream and advances it. Also returns null when no more characters are available.
      -
      eat(match: string|regexp|function(char: string) → boolean) → string
      +
      eat(match: string|regexp|function(char: string) → boolean) → string
      match can be a character, a regular expression, or a function that takes a character and returns a boolean. If the next character in the stream 'matches' the given argument, it is consumed and returned. Otherwise, undefined is returned.
      -
      eatWhile(match: string|regexp|function(char: string) → boolean) → boolean
      +
      eatWhile(match: string|regexp|function(char: string) → boolean) → boolean
      Repeatedly calls eat with the given argument, until it fails. Returns true if any characters were eaten.
      -
      eatSpace() → boolean
      +
      eatSpace() → boolean
      Shortcut for eatWhile when matching white-space.
      -
      skipToEnd()
      +
      skipToEnd()
      Moves the position to the end of the line.
      -
      skipTo(ch: string) → boolean
      +
      skipTo(ch: string) → boolean
      Skips to the next occurrence of the given character, if found on the current line (doesn't advance the stream if the character does not occur on the line). Returns true if the character was found.
      -
      - match(pattern: string, ?consume: boolean, ?caseFold: boolean) → boolean
      - match(pattern: regexp, ?consume: boolean) → array<string> -
      +
      match(pattern: string, ?consume: boolean, ?caseFold: boolean) → boolean
      +
      match(pattern: regexp, ?consume: boolean) → array<string>
      Act like a multi-character eat—if consume is true or not given—or a look-ahead that doesn't update the stream @@ -1734,18 +1727,18 @@

      Writing CodeMirror Modes

      returned by match, in case you need to extract matched groups.
      -
      backUp(n: integer)
      +
      backUp(n: integer)
      Backs up the stream n characters. Backing it up further than the start of the current token will cause things to break, so be careful.
      -
      column() → integer
      +
      column() → integer
      Returns the column (taking into account tabs) at which the current token starts.
      -
      indentation() → integer
      +
      indentation() → integer
      Tells you how far the current line has been indented, in spaces. Corrects for tab characters.
      -
      current() → string
      +
      current() → string
      Get the string between the start of the current token and the current stream position.
      From 20cbf22edfefcf06892907120b779a228e0030ab Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 4 Apr 2013 11:46:15 +0200 Subject: [PATCH 0463/5273] Revert changes to cursor adjustment during replaceRange Issue #1415 --- lib/codemirror.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index ac8b41a0ae..9a96cd6986 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2141,7 +2141,7 @@ window.CodeMirror = (function() { // hint is null, leave the selection alone as much as possible var adjustPos = function(pos) { - if (posEq(change.from, change.to) ? posLess(pos, change.from) : !posLess(change.from, pos)) return pos; + if (posLess(pos, change.from)) return pos; if (!posLess(change.to, pos)) return end; var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; @@ -2609,7 +2609,6 @@ window.CodeMirror = (function() { if (indentString != curSpaceString) replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); line.stateAfter = null; - return indentString.length; } function changeLine(cm, handle, op) { @@ -2757,7 +2756,7 @@ window.CodeMirror = (function() { if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; else dir = dir ? "add" : "subtract"; } - if (isLine(this.doc, n)) return indentLine(this, n, dir, aggressive); + if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); }), indentSelection: operation(null, function(how) { var sel = this.doc.sel; @@ -3297,8 +3296,7 @@ window.CodeMirror = (function() { newlineAndIndent: function(cm) { operation(cm, function() { cm.replaceSelection("\n", "end", "+input"); - var line = cm.getCursor().line, indented = cm.indentLine(line, null, true); - if (indented) cm.setCursor(line, indented); + cm.indentLine(cm.getCursor().line, null, true); })(); }, toggleOverwrite: function(cm) {cm.toggleOverwrite();} From c59f87245d0ce230713646c7857b0a9497c287fd Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Thu, 4 Apr 2013 20:28:40 +0200 Subject: [PATCH 0464/5273] Add Midnight theme --- demo/theme.html | 2 ++ theme/midnight.css | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 theme/midnight.css diff --git a/demo/theme.html b/demo/theme.html index 046d1fc3e1..0f979f73aa 100644 --- a/demo/theme.html +++ b/demo/theme.html @@ -21,6 +21,7 @@ + @@ -54,6 +55,7 @@

      CodeMirror: Theme demo

      + diff --git a/theme/midnight.css b/theme/midnight.css new file mode 100644 index 0000000000..e567625c6c --- /dev/null +++ b/theme/midnight.css @@ -0,0 +1,52 @@ +/* Based on the theme at http://bonsaiden.github.com/JavaScript-Garden */ + +/**/ +.breakpoints {width: .8em;} +.breakpoint { color: #822; } + +/**/ +span.CodeMirror-matchhighlight { background: #494949 } +.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67; !important } + +/**/ +.activeline {background: #253540 !important;} + +.cm-s-midnight.CodeMirror { + background: #0F192A; + color: #D1EDFF; +} + +.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} + +.cm-s-midnight div.CodeMirror-selected {background: #314D67 !important;} +.cm-s-midnight .CodeMirror-gutters {background: #0F192A; border-right: 1px solid;} +.cm-s-midnight .CodeMirror-linenumber {color: #D0D0D0;} +.cm-s-midnight .CodeMirror-cursor { + border-left: 1px solid #F8F8F0 !important; +} + +.cm-s-midnight span.cm-comment {color: #428BDD;} +.cm-s-midnight span.cm-atom {color: #AE81FF;} +.cm-s-midnight span.cm-number {color: #D1EDFF;} + +.cm-s-midnight span.cm-property, .cm-s-tropicaleve span.cm-attribute {color: #A6E22E;} +.cm-s-midnight span.cm-keyword {color: #E83737;} +.cm-s-midnight span.cm-string {color: #1DC116;} + +.cm-s-midnight span.cm-variable {color: #FFAA3E;} +.cm-s-midnight span.cm-variable-2 {color: #FFAA3E;} +.cm-s-midnight span.cm-def {color: #4DD;} +.cm-s-midnight span.cm-error {background: #F92672; color: #F8F8F0;} +.cm-s-midnight span.cm-bracket {color: #D1EDFF;} +.cm-s-midnight span.cm-tag {color: #008;} +.cm-s-midnight span.cm-link {color: #AE81FF;} + +.cm-s-midnight .CodeMirror-matchingbracket { + text-decoration: underline; + color: white !important; +} + +.typ { color: #FFAA3E; } +.atn { color: #606; } +.atv { color: #080; } +.dec { color: #606; } From d1942cc0ab010c34f683fd14c193418646fdedbc Mon Sep 17 00:00:00 2001 From: Liam Newman Date: Thu, 4 Apr 2013 12:58:39 -0700 Subject: [PATCH 0465/5273] Add npm module badge Simple badge for current npm module --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 976584e3b9..61f6b64525 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# CodeMirror [![Build Status](https://secure.travis-ci.org/marijnh/CodeMirror.png?branch=master)](http://travis-ci.org/marijnh/CodeMirror) +# CodeMirror +[![Build Status](https://secure.travis-ci.org/marijnh/CodeMirror.png?branch=master)](http://travis-ci.org/marijnh/CodeMirror) +[![NPM version](https://badge.fury.io/js/codemirror.png)](http://badge.fury.io/js/codemirror) CodeMirror is a JavaScript component that provides a code editor in the browser. When a mode is available for the language you are coding From 1520c653e9b68f5991c4d22a83d8534412f983e8 Mon Sep 17 00:00:00 2001 From: Ian Wehrman Date: Thu, 4 Apr 2013 16:58:02 -0700 Subject: [PATCH 0466/5273] Prevent the latter part of hyphenated terms from being identified as attributes. --- 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 ed09284f29..abfd214454 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -57,7 +57,7 @@ CodeMirror.defineMode('shell', function() { return 'number'; } } - stream.eatWhile(/\w/); + stream.eatWhile(/[\w-]/); var cur = stream.current(); if (stream.peek() === '=' && /\w+/.test(cur)) return 'def'; return words.hasOwnProperty(cur) ? words[cur] : null; From 7b8f79618da67ceae5e1f32f43da86ccce8eb398 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 7 Apr 2013 13:07:55 +0200 Subject: [PATCH 0467/5273] [show-hint addon] Support onSelect and onClose callbacks --- addon/hint/show-hint.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index b3be8ef5ea..d132aa75d3 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -29,6 +29,7 @@ CodeMirror.showHint = function(cm, getHints, options) { // When there is only one completion, use it directly. if (!continued && options.completeSingle !== false && completions.length == 1) { pickCompletion(cm, data, completions[0]); + if (data.onClose) data.onClose(); return true; } @@ -85,6 +86,7 @@ CodeMirror.showHint = function(cm, getHints, options) { hints.scrollTop = node.offsetTop - 3; else if (node.offsetTop + node.offsetHeight > hints.scrollTop + hints.clientHeight) hints.scrollTop = node.offsetTop + node.offsetHeight - hints.clientHeight + 3; + if (data.onSelect) data.onSelect(completions[selectedHint]); } function screenAmount() { @@ -138,7 +140,7 @@ CodeMirror.showHint = function(cm, getHints, options) { }); var done = false, once; - function close() { + function close(willContinue) { if (done) return; done = true; clearTimeout(once); @@ -148,6 +150,7 @@ CodeMirror.showHint = function(cm, getHints, options) { cm.off("blur", onBlur); cm.off("focus", onFocus); cm.off("scroll", onScroll); + if (!willContinue && data.onClose) data.onClose(); } function pick() { pickCompletion(cm, data, completions[selectedHint]); @@ -163,8 +166,9 @@ CodeMirror.showHint = function(cm, getHints, options) { (pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) close(); else - once = setTimeout(function(){close(); continued = true; startHinting();}, 70); + once = setTimeout(function(){close(true); continued = true; startHinting();}, 70); } + if (data.onSelect) data.onSelect(completions[0]); return true; } From cf52a93edfc15519d1cb4f488b473fec49a1f5ee Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Fri, 5 Apr 2013 19:29:58 +0200 Subject: [PATCH 0468/5273] [vim keymap] Add ; , commands for reapting f t F T motions --- keymap/vim.js | 31 ++++++++++++++++++++++++++- test/vim_test.js | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/keymap/vim.js b/keymap/vim.js index ba0e0942c1..26c3c7d4b9 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -173,6 +173,10 @@ { keys: ['T', 'character'], type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: false }}, + { keys: [';'], type: 'motion', motion: 'repeatLastCharacterSearch', + motionArgs: { forward: true }}, + { keys: [','], type: 'motion', motion: 'repeatLastCharacterSearch', + motionArgs: { forward: false }}, { keys: ['\'', 'character'], type: 'motion', motion: 'goToMark' }, { keys: ['`', 'character'], type: 'motion', motion: 'goToMark' }, { keys: [']', '`',], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } }, @@ -347,6 +351,8 @@ searchQuery: null, // Whether we are searching backwards. searchIsReversed: false, + // Recording latest f, t, F or T motion command. + lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''}, registerController: new RegisterController({}) }; } @@ -1175,13 +1181,15 @@ var repeat = motionArgs.repeat; var curEnd = moveToCharacter(cm, repeat, motionArgs.forward, motionArgs.selectedCharacter); - if(!curEnd)return cm.getCursor(); var increment = motionArgs.forward ? -1 : 1; + recordLastCharacterSearch(increment, motionArgs); + if(!curEnd)return cm.getCursor(); curEnd.ch += increment; return curEnd; }, moveToCharacter: function(cm, motionArgs) { var repeat = motionArgs.repeat; + recordLastCharacterSearch(0, motionArgs); return moveToCharacter(cm, repeat, motionArgs.forward, motionArgs.selectedCharacter) || cm.getCursor(); }, @@ -1245,6 +1253,20 @@ var start = tmp.start; var end = tmp.end; return [start, end]; + }, + repeatLastCharacterSearch: function(cm, motionArgs) { + var lastSearch = getVimGlobalState().lastChararacterSearch; + var repeat = motionArgs.repeat; + var forward = motionArgs.forward === lastSearch.forward; + var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1); + cm.moveH(-increment, 'char'); + var curEnd = moveToCharacter(cm, repeat, forward, lastSearch.selectedCharacter); + if (!curEnd) { + cm.moveH(increment, 'char') + return cm.getCursor(); + } + curEnd.ch += increment; + return curEnd; } }; @@ -1788,6 +1810,13 @@ end: { line: cur.line, ch: wordEnd }}; } + function recordLastCharacterSearch(increment, args) { + var vimGlobalState = getVimGlobalState(); + vimGlobalState.lastChararacterSearch.increment = increment; + vimGlobalState.lastChararacterSearch.forward = args.forward; + vimGlobalState.lastChararacterSearch.selectedCharacter = args.selectedCharacter; + } + /* * Returns the boundaries of the next word. If the cursor in the middle of * the word, then returns the boundaries of the current word, starting at diff --git a/test/vim_test.js b/test/vim_test.js index bc04b7fc70..ea3ea4d55b 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1184,6 +1184,62 @@ testVim('._repeat', function(cm, vim, helpers) { helpers.doKeys('3', '.'); eq('6', cm.getValue()); }, { value: '1 2 3 4 5 6'}); +testVim('f;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('f', 'x'); + helpers.doKeys(';'); + helpers.doKeys('2', ';'); + eq(9, cm.getCursor().ch); +}, { value: '01x3xx678x'}); +testVim('F;', function(cm, vim, helpers) { + cm.setCursor(0, 8); + helpers.doKeys('F', 'x'); + helpers.doKeys(';'); + helpers.doKeys('2', ';'); + eq(2, cm.getCursor().ch); +}, { value: '01x3xx6x8x'}); +testVim('t;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('t', 'x'); + helpers.doKeys(';'); + helpers.doKeys('2', ';'); + eq(8, cm.getCursor().ch); +}, { value: '01x3xx678x'}); +testVim('T;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('T', 'x'); + helpers.doKeys(';'); + helpers.doKeys('2', ';'); + eq(2, cm.getCursor().ch); +}, { value: '0xx3xx678x'}); +testVim('f,', function(cm, vim, helpers) { + cm.setCursor(0, 6); + helpers.doKeys('f', 'x'); + helpers.doKeys(','); + helpers.doKeys('2', ','); + eq(2, cm.getCursor().ch); +}, { value: '01x3xx678x'}); +testVim('F,', function(cm, vim, helpers) { + cm.setCursor(0, 3); + helpers.doKeys('F', 'x'); + helpers.doKeys(','); + helpers.doKeys('2', ','); + eq(9, cm.getCursor().ch); +}, { value: '01x3xx678x'}); +testVim('t,', function(cm, vim, helpers) { + cm.setCursor(0, 6); + helpers.doKeys('t', 'x'); + helpers.doKeys(','); + helpers.doKeys('2', ','); + eq(3, cm.getCursor().ch); +}, { value: '01x3xx678x'}); +testVim('T,', function(cm, vim, helpers) { + cm.setCursor(0, 4); + helpers.doKeys('T', 'x'); + helpers.doKeys(','); + helpers.doKeys('2', ','); + eq(8, cm.getCursor().ch); +}, { value: '01x3xx67xx'}); // Ex mode tests testVim('ex_go_to_line', function(cm, vim, helpers) { From 3bc89192dd221818f0c9e819876023d324b4758e Mon Sep 17 00:00:00 2001 From: Golevka Date: Sat, 6 Apr 2013 21:31:59 +0800 Subject: [PATCH 0469/5273] [closetag addon] close tags with attributes containing slashes (such as path or text/javascript) --- addon/edit/closetag.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index 54fa195463..454dfea5e6 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -55,7 +55,8 @@ if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); var lowerTagName = tagName.toLowerCase(); // Don't process the '>' at the end of an end-tag or self-closing tag - if (tok.type == "tag" && state.type == "closeTag" || tok.string.indexOf("/") > -1 || + if (tok.type == "tag" && state.type == "closeTag" || + tok.string.indexOf("/") == (tok.string.length - 1) || // match something like dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1) return CodeMirror.Pass; From 02ea26c0d0e4cf29ec05490a80d6ee3f79f5c3ef Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 7 Apr 2013 13:18:42 +0200 Subject: [PATCH 0470/5273] [javascript mode] Tokenize leading whitespace in block comments as comment Closes #1431 --- 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 89f1220369..cf3a5f003c 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -402,7 +402,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { state.lexical.align = false; state.indented = stream.indentation(); } - if (stream.eatSpace()) return null; + if (state.tokenize != jsTokenComment && stream.eatSpace()) return null; var style = state.tokenize(stream, state); if (type == "comment") return style; state.lastType = type; From fcf6f33052dcaf98def7318a8a6d20365ed88912 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 8 Apr 2013 11:08:17 +0200 Subject: [PATCH 0471/5273] [javascript mode] Properly handle commas Closes #1433 --- mode/javascript/javascript.js | 37 +++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index cf3a5f003c..229fb2dc0a 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -269,13 +269,19 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return pass(pushlex("stat"), expression, expect(";"), poplex); } function expression(type) { - if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator); + return expressionInner(type, maybeoperatorComma); + } + function expressionNoComma(type) { + return expressionInner(type, maybeoperatorNoComma); + } + function expressionInner(type, maybeop) { + if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); if (type == "function") return cont(functiondef); if (type == "keyword c") return cont(maybeexpression); - if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator); + if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop); if (type == "operator") return cont(expression); - if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator); - if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator); + if (type == "[") return cont(pushlex("]"), commasep(expressionNoComma, "]"), poplex, maybeop); + if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeop); return cont(); } function maybeexpression(type) { @@ -283,20 +289,25 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return pass(expression); } - function maybeoperator(type, value) { + function maybeoperatorComma(type, value) { + if (type == ",") return cont(expression); + return maybeoperatorNoComma(type, value, maybeoperatorComma); + } + function maybeoperatorNoComma(type, value, me) { + if (!me) me = maybeoperatorNoComma; if (type == "operator") { - if (/\+\+|--/.test(value)) return cont(maybeoperator); + if (/\+\+|--/.test(value)) return cont(me); if (value == "?") return cont(expression, expect(":"), expression); return cont(expression); } if (type == ";") return; - if (type == "(") return cont(pushlex(")", "call"), commasep(expression, ")"), poplex, maybeoperator); - if (type == ".") return cont(property, maybeoperator); - if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator); + if (type == "(") return cont(pushlex(")", "call"), commasep(expressionNoComma, ")"), poplex, me); + if (type == ".") return cont(property, me); + if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, me); } function maybelabel(type) { if (type == ":") return cont(poplex, statement); - return pass(maybeoperator, expect(";"), poplex); + return pass(maybeoperatorComma, expect(";"), poplex); } function property(type) { if (type == "variable") {cx.marked = "property"; return cont();} @@ -308,7 +319,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } else if (type == "number" || type == "string") { cx.marked = type + " property"; } - if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression); + if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expressionNoComma); } function getterSetter(type) { if (type == ":") return cont(expression); @@ -351,7 +362,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return pass(); } function vardef2(type, value) { - if (value == "=") return cont(expression, vardef2); + if (value == "=") return cont(expressionNoComma, vardef2); if (type == ",") return cont(vardef1); } function forspec1(type) { @@ -362,7 +373,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function formaybein(_type, value) { if (value == "in") return cont(expression); - return cont(maybeoperator, forspec2); + return cont(maybeoperatorComma, forspec2); } function forspec2(type, value) { if (type == ";") return cont(forspec3); From 6e44713cdb6966cde5b76e783697b3ec53a6bc32 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 8 Apr 2013 11:54:48 +0200 Subject: [PATCH 0472/5273] Fix distance-tracking in coordsChar on bidi text --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 9a96cd6986..3ef882832d 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1222,8 +1222,8 @@ window.CodeMirror = (function() { 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;} + if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;} + else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;} } } From b6d456db96f7e671980bc68916ddd904b384dc2b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 8 Apr 2013 12:05:08 +0200 Subject: [PATCH 0473/5273] Add historyEventDelay option --- doc/manual.html | 5 +++++ lib/codemirror.js | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index 45ea1a9225..295ae003cb 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -245,6 +245,11 @@

      Configuration

      The maximum number of undo levels that the editor stores. Defaults to 40.
      +
      historyEventDelay: integer
      +
      The period of inactivity (in milliseconds) that will cause a + new history event to be started when typing or deleting. + Defaults to 500.
      +
      tabindex: integer
      The tab index to assign to the editor. If not given, no tab index diff --git a/lib/codemirror.js b/lib/codemirror.js index 3ef882832d..6d15dbdc4a 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3111,6 +3111,7 @@ window.CodeMirror = (function() { option("flattenSpans", true); option("pollInterval", 100); option("undoDepth", 40, function(cm, val){cm.doc.history.undoDepth = val;}); + option("historyEventDelay", 500); option("viewportMargin", 10, function(cm){cm.refresh();}, true); option("maxHighlightLength", 10000, function(cm){loadMode(cm); cm.refresh();}, true); option("moveInputWithCursor", true, function(cm, val) { @@ -4861,7 +4862,8 @@ window.CodeMirror = (function() { if (cur && (hist.lastOp == opId || hist.lastOrigin == change.origin && change.origin && - ((change.origin.charAt(0) == "+" && hist.lastTime > time - 600) || change.origin.charAt(0) == "*"))) { + ((change.origin.charAt(0) == "+" && doc.cm && hist.lastTime > time - doc.cm.options.historyEventDelay) || + change.origin.charAt(0) == "*"))) { // Merge this change into the last event var last = lst(cur.changes); if (posEq(change.from, change.to) && posEq(change.from, last.to)) { From 4c53964e532e271cbd3b0461f56d2eec4a406578 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 8 Apr 2013 12:13:25 +0200 Subject: [PATCH 0474/5273] [javascript mode] Correct indentation for nested, brace-less if/else statements Closes #1436 --- mode/javascript/javascript.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 229fb2dc0a..f501174ee0 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -13,7 +13,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var operator = kw("operator"), atom = {type: "atom", style: "atom"}; var jsKeywords = { - "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, + "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B, "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "var": kw("var"), "const": kw("var"), "let": kw("var"), "function": kw("function"), "catch": kw("catch"), @@ -256,6 +256,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "keyword b") return cont(pushlex("form"), statement, poplex); if (type == "{") return cont(pushlex("}"), block, poplex); if (type == ";") return cont(); + if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse(cx.state.indented)); if (type == "function") return cont(functiondef); if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"), poplex, statement, poplex); @@ -365,6 +366,15 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (value == "=") return cont(expressionNoComma, vardef2); if (type == ",") return cont(vardef1); } + function maybeelse(indent) { + return function(type, value) { + if (type == "keyword b" && value == "else") { + cx.state.lexical = new JSLexical(indent, 0, "form", null, cx.state.lexical); + return cont(expression, statement, poplex); + } + return pass(); + }; + } function forspec1(type) { if (type == "var") return cont(vardef1, expect(";"), forspec2); if (type == ";") return cont(forspec2); From f35feec32c45f79ec9be111124e068190144823a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Apr 2013 08:15:30 +0200 Subject: [PATCH 0475/5273] [show-hint addon] Clean up code that handles custom keymap Issue #1440 --- addon/hint/show-hint.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index d132aa75d3..0c29e793ab 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -93,7 +93,7 @@ CodeMirror.showHint = function(cm, getHints, options) { return Math.floor(hints.clientHeight / hints.firstChild.offsetHeight) || 1; } - var ourMap = { + var ourMap, baseMap = { Up: function() {changeActive(selectedHint - 1);}, Down: function() {changeActive(selectedHint + 1);}, PageUp: function() {changeActive(selectedHint - screenAmount());}, @@ -104,11 +104,14 @@ CodeMirror.showHint = function(cm, getHints, options) { Tab: pick, Esc: close }; - if (options.customKeys) for (var key in options.customKeys) if (options.customKeys.hasOwnProperty(key)) { - var val = options.customKeys[key]; - if (/^(Up|Down|Enter|Esc)$/.test(key)) val = ourMap[val]; - ourMap[key] = val; - } + if (options.customKeys) { + ourMap = {}; + for (var key in options.customKeys) if (options.customKeys.hasOwnProperty(key)) { + var val = options.customKeys[key]; + if (baseMap.hasOwnProperty(val)) val = baseMap[val]; + ourMap[key] = val; + } + } else ourMap = baseMap; cm.addKeyMap(ourMap); cm.on("cursorActivity", cursorActivity); From 8dae6abc0d5a188e2954679b85a969cd8fa1edb4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Apr 2013 08:20:58 +0200 Subject: [PATCH 0476/5273] [show-hint addon] Make sure onClose is actually called Issue #1425 --- 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 0c29e793ab..55c58b3b2b 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -153,7 +153,7 @@ CodeMirror.showHint = function(cm, getHints, options) { cm.off("blur", onBlur); cm.off("focus", onFocus); cm.off("scroll", onScroll); - if (!willContinue && data.onClose) data.onClose(); + if (willContinue !== true && data.onClose) data.onClose(); } function pick() { pickCompletion(cm, data, completions[selectedHint]); From 71cd784305159dddbd4184792b6238d0f8a2bd1e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Apr 2013 08:25:11 +0200 Subject: [PATCH 0477/5273] [show-hint addon] Pass option node as second argument to onSelect --- addon/hint/show-hint.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 55c58b3b2b..cbaa043571 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -86,7 +86,7 @@ CodeMirror.showHint = function(cm, getHints, options) { hints.scrollTop = node.offsetTop - 3; else if (node.offsetTop + node.offsetHeight > hints.scrollTop + hints.clientHeight) hints.scrollTop = node.offsetTop + node.offsetHeight - hints.clientHeight + 3; - if (data.onSelect) data.onSelect(completions[selectedHint]); + if (data.onSelect) data.onSelect(completions[selectedHint], node); } function screenAmount() { @@ -171,7 +171,7 @@ CodeMirror.showHint = function(cm, getHints, options) { else once = setTimeout(function(){close(true); continued = true; startHinting();}, 70); } - if (data.onSelect) data.onSelect(completions[0]); + if (data.onSelect) data.onSelect(completions[0], hints.firstChild); return true; } From ca2551bd077e5e921871fd936d6bde18a3b7e95b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Apr 2013 09:01:48 +0200 Subject: [PATCH 0478/5273] [javascript mode] Don't expect an expression after else Issue #1441 --- 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 f501174ee0..c138b6fc63 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -370,7 +370,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return function(type, value) { if (type == "keyword b" && value == "else") { cx.state.lexical = new JSLexical(indent, 0, "form", null, cx.state.lexical); - return cont(expression, statement, poplex); + return cont(statement, poplex); } return pass(); }; From 3d046a4bae8382858ba046e9e4a899bca815a6f6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Apr 2013 09:06:50 +0200 Subject: [PATCH 0479/5273] Handle dblclick events specifically on IE Apparently, canceling the initial mousedown will stop the second mousedown from firing, but still fire the dblclick event. --- lib/codemirror.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 6d15dbdc4a..c4fd1af1d1 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1458,7 +1458,16 @@ window.CodeMirror = (function() { function registerEventHandlers(cm) { var d = cm.display; on(d.scroller, "mousedown", operation(cm, onMouseDown)); - on(d.scroller, "dblclick", operation(cm, e_preventDefault)); + if (ie) + on(d.scroller, "dblclick", operation(cm, function(e) { + var pos = posFromMouse(cm, e); + if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; + e_preventDefault(e); + var word = findWordAt(getLine(cm.doc, pos.line).text, pos); + extendSelection(cm.doc, word.from, word.to); + })); + else + on(d.scroller, "dblclick", e_preventDefault); on(d.lineSpace, "selectstart", function(e) { if (!eventInWidget(d, e)) e_preventDefault(e); }); From e3f7c466557955e54298a56d61897c8baac7d2ac Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Apr 2013 15:56:37 +0200 Subject: [PATCH 0480/5273] Add Firepad to real-world uses --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 6bebfebc18..cf90ea2555 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -48,6 +48,7 @@

      { } CodeMi
    • Fastfig (online computation/math tool)
    • Farabi (modern Perl IDE)
    • FathomJS integration (slides with editors, again)
    • +
    • Firepad (collaborative text editor)
    • Go language tour
    • GitHub's Android app
    • Google Apps Script
    • From 90983502df989731608647c457dd170add29b78d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Apr 2013 17:41:04 +0200 Subject: [PATCH 0481/5273] Add defineDocExtension function --- doc/manual.html | 15 ++++++++++----- lib/codemirror.js | 4 +++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 295ae003cb..49dd5883d5 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1414,11 +1414,16 @@

      Static properties

      CodeMirror.defineExtension(name: string, value: any)
      -
      If you want to define extra methods in terms - of the CodeMirror API, it is possible to - use defineExtension. This - will cause the given value (usually a method) to be added to all - CodeMirror instances created from then on.
      +
      If you want to define extra methods in terms of the + CodeMirror API, it is possible to + use defineExtension. This will cause the given + value (usually a method) to be added to all CodeMirror instances + created from then on.
      + +
      CodeMirror.defineDocExtension(name: string, value: any)
      +
      Like defineExtension, + but the method will be added to the interface + for Doc objects instead.
      CodeMirror.defineOption(name: string, default: any, updateFunc: function)
      diff --git a/lib/codemirror.js b/lib/codemirror.js index c4fd1af1d1..bf5c9e69c6 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3192,7 +3192,9 @@ window.CodeMirror = (function() { CodeMirror.defineExtension = function(name, func) { CodeMirror.prototype[name] = func; }; - + CodeMirror.defineDocExtension = function(name, func) { + Doc.prototype[name] = func; + } CodeMirror.defineOption = option; var initHooks = []; From 8d14e586f448d9e50e981472886bfa61001f06ff Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Apr 2013 19:00:14 +0200 Subject: [PATCH 0482/5273] [searchcursor addon] Make search cursors work on docs --- addon/search/searchcursor.js | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/addon/search/searchcursor.js b/addon/search/searchcursor.js index fd134636e3..a590e84443 100644 --- a/addon/search/searchcursor.js +++ b/addon/search/searchcursor.js @@ -1,11 +1,11 @@ (function(){ var Pos = CodeMirror.Pos; - function SearchCursor(cm, query, pos, caseFold) { - this.atOccurrence = false; this.cm = cm; + function SearchCursor(doc, query, pos, caseFold) { + this.atOccurrence = false; this.doc = doc; if (caseFold == null && typeof query == "string") caseFold = false; - pos = pos ? cm.clipPos(pos) : Pos(0, 0); + pos = pos ? doc.clipPos(pos) : Pos(0, 0); this.pos = {from: pos, to: pos}; // The matches method is filled in based on the type of query. @@ -17,7 +17,7 @@ this.matches = function(reverse, pos) { if (reverse) { query.lastIndex = 0; - var line = cm.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start; + var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start; for (;;) { query.lastIndex = cutOff; var newMatch = query.exec(line); @@ -28,7 +28,7 @@ } } else { query.lastIndex = pos.ch; - var line = cm.getLine(pos.line), match = query.exec(line), + var line = doc.getLine(pos.line), match = query.exec(line), start = match && match.index; } if (match && match[0]) @@ -48,7 +48,7 @@ this.matches = function() {}; } else { this.matches = function(reverse, pos) { - var line = fold(cm.getLine(pos.line)), len = query.length, match; + var line = fold(doc.getLine(pos.line)), len = query.length, match; if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1) : (match = line.indexOf(query, pos.ch)) != -1) return {from: Pos(pos.line, match), @@ -57,14 +57,14 @@ } } else { this.matches = function(reverse, pos) { - var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(cm.getLine(ln)); + var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(doc.getLine(ln)); var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match)); if (reverse ? offsetA >= pos.ch || offsetA != match.length : offsetA <= pos.ch || offsetA != line.length - match.length) return; for (;;) { - if (reverse ? !ln : ln == cm.lineCount() - 1) return; - line = fold(cm.getLine(ln += reverse ? -1 : 1)); + if (reverse ? !ln : ln == doc.lineCount() - 1) return; + line = fold(doc.getLine(ln += reverse ? -1 : 1)); match = target[reverse ? --idx : ++idx]; if (idx > 0 && idx < target.length - 1) { if (line != match) return; @@ -86,7 +86,7 @@ findPrevious: function() {return this.find(true);}, find: function(reverse) { - var self = this, pos = this.cm.clipPos(reverse ? this.pos.from : this.pos.to); + var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to); function savePosAndFail(line) { var pos = Pos(line, 0); self.pos = {from: pos, to: pos}; @@ -102,10 +102,10 @@ } if (reverse) { if (!pos.line) return savePosAndFail(0); - pos = Pos(pos.line-1, this.cm.getLine(pos.line-1).length); + pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length); } else { - var maxLine = this.cm.lineCount(); + var maxLine = this.doc.lineCount(); if (pos.line == maxLine - 1) return savePosAndFail(maxLine); pos = Pos(pos.line + 1, 0); } @@ -118,13 +118,16 @@ replace: function(newText) { if (!this.atOccurrence) return; var lines = CodeMirror.splitLines(newText); - this.cm.replaceRange(lines, this.pos.from, this.pos.to); + this.doc.replaceRange(lines, this.pos.from, this.pos.to); this.pos.to = Pos(this.pos.from.line + lines.length - 1, lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0)); } }; CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) { + return new SearchCursor(this.doc, query, pos, caseFold); + }); + CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) { return new SearchCursor(this, query, pos, caseFold); }); })(); From db8f1842bb0176053c9ba03a0f943577b3c76241 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Apr 2013 21:24:26 +0200 Subject: [PATCH 0483/5273] Add missing semicolon Shush, linter. --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index bf5c9e69c6..abae2882a2 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3194,7 +3194,7 @@ window.CodeMirror = (function() { }; CodeMirror.defineDocExtension = function(name, func) { Doc.prototype[name] = func; - } + }; CodeMirror.defineOption = option; var initHooks = []; From cc90184e2da39b8d5a3fe2b3dc36c0f14f4f8d22 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 10 Apr 2013 09:39:06 +0200 Subject: [PATCH 0484/5273] Prevent selection-drawing code from calling charCoords with ch: -1 --- lib/codemirror.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index abae2882a2..5f253de552 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -793,9 +793,16 @@ window.CodeMirror = (function() { } iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { - var leftPos = coords(dir == "rtl" ? to - 1 : from); - var rightPos = coords(dir == "rtl" ? from : to - 1); - var left = leftPos.left, right = rightPos.right; + var leftPos = coords(from), rightPos, left, right; + if (from == to) { + rightPos = leftPos; + left = right = leftPos.left; + } else { + rightPos = coords(to - 1); + if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } + left = leftPos.left; + right = rightPos.right; + } if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part add(left, leftPos.top, null, leftPos.bottom); left = pl; From 8698e629d49c203f451250ae1fc30f6b8e0d1af8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 10 Apr 2013 09:42:29 +0200 Subject: [PATCH 0485/5273] Add Blogger's template editor to real-world uses --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index cf90ea2555..576a003de0 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -25,6 +25,7 @@

      { } CodeMi
    • Adobe Brackets (code editor)
    • Amber (JavaScript-based Smalltalk system)
    • APEye (tool for testing & documenting APIs)
    • +
    • Blogger's template editor
    • BlueGriffon (HTML editor)
    • Cargo Collective (creative publishing platform)
    • Code per Node (Drupal module)
    • From ac8b53b737da172697b68fae0398981a7fe5ad15 Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Wed, 10 Apr 2013 20:53:15 +0200 Subject: [PATCH 0486/5273] [vim keymap] Fix ;, behavior for d c y operators --- keymap/vim.js | 1 + test/vim_test.js | 132 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/keymap/vim.js b/keymap/vim.js index 26c3c7d4b9..83885bb6c1 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1260,6 +1260,7 @@ var forward = motionArgs.forward === lastSearch.forward; var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1); cm.moveH(-increment, 'char'); + motionArgs.inclusive = forward ? true : false; var curEnd = moveToCharacter(cm, repeat, forward, lastSearch.selectedCharacter); if (!curEnd) { cm.moveH(increment, 'char') diff --git a/test/vim_test.js b/test/vim_test.js index ea3ea4d55b..09f6e4b541 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1240,6 +1240,138 @@ testVim('T,', function(cm, vim, helpers) { helpers.doKeys('2', ','); eq(8, cm.getCursor().ch); }, { value: '01x3xx67xx'}); +testVim('fd,;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('f', '4'); + cm.setCursor(0, 0); + helpers.doKeys('d', ';'); + eq('56789', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 9); + helpers.doKeys('d', ','); + eq('01239', cm.getValue()); +}, { value: '0123456789'}); +testVim('Fd,;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('F', '4'); + cm.setCursor(0, 9); + helpers.doKeys('d', ';'); + eq('01239', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 0); + helpers.doKeys('d', ','); + eq('56789', cm.getValue()); +}, { value: '0123456789'}); +testVim('td,;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('t', '4'); + cm.setCursor(0, 0); + helpers.doKeys('d', ';'); + eq('456789', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 9); + helpers.doKeys('d', ','); + eq('012349', cm.getValue()); +}, { value: '0123456789'}); +testVim('Td,;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('T', '4'); + cm.setCursor(0, 9); + helpers.doKeys('d', ';'); + eq('012349', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 0); + helpers.doKeys('d', ','); + eq('456789', cm.getValue()); +}, { value: '0123456789'}); +testVim('fc,;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('f', '4'); + cm.setCursor(0, 0); + helpers.doKeys('c', ';', 'Esc'); + eq('56789', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 9); + helpers.doKeys('c', ','); + eq('01239', cm.getValue()); +}, { value: '0123456789'}); +testVim('Fc,;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('F', '4'); + cm.setCursor(0, 9); + helpers.doKeys('c', ';', 'Esc'); + eq('01239', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 0); + helpers.doKeys('c', ','); + eq('56789', cm.getValue()); +}, { value: '0123456789'}); +testVim('tc,;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('t', '4'); + cm.setCursor(0, 0); + helpers.doKeys('c', ';', 'Esc'); + eq('456789', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 9); + helpers.doKeys('c', ','); + eq('012349', cm.getValue()); +}, { value: '0123456789'}); +testVim('Tc,;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('T', '4'); + cm.setCursor(0, 9); + helpers.doKeys('c', ';', 'Esc'); + eq('012349', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 0); + helpers.doKeys('c', ','); + eq('456789', cm.getValue()); +}, { value: '0123456789'}); +testVim('fy,;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('f', '4'); + cm.setCursor(0, 0); + helpers.doKeys('y', ';', 'P'); + eq('012340123456789', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 9); + helpers.doKeys('y', ',', 'P'); + eq('012345678456789', cm.getValue()); +}, { value: '0123456789'}); +testVim('Fy,;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('F', '4'); + cm.setCursor(0, 9); + helpers.doKeys('y', ';', 'p'); + eq('012345678945678', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 0); + helpers.doKeys('y', ',', 'P'); + eq('012340123456789', cm.getValue()); +}, { value: '0123456789'}); +testVim('ty,;', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('t', '4'); + cm.setCursor(0, 0); + helpers.doKeys('y', ';', 'P'); + eq('01230123456789', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 9); + helpers.doKeys('y', ',', 'p'); + eq('01234567895678', cm.getValue()); +}, { value: '0123456789'}); +testVim('Ty,;', function(cm, vim, helpers) { + cm.setCursor(0, 9); + helpers.doKeys('T', '4'); + cm.setCursor(0, 9); + helpers.doKeys('y', ';', 'p'); + eq('01234567895678', cm.getValue()); + helpers.doKeys('u'); + cm.setCursor(0, 0); + helpers.doKeys('y', ',', 'P'); + eq('01230123456789', cm.getValue()); +}, { value: '0123456789'}); // Ex mode tests testVim('ex_go_to_line', function(cm, vim, helpers) { From 0ef9137286cd6c806a030605925d29b0ef645138 Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Tue, 9 Apr 2013 09:58:43 +0200 Subject: [PATCH 0487/5273] [vim keymap] Add Ctrl-a Ctrl-x to increment/decrement numerical tokens --- keymap/vim.js | 32 ++++++++++++++++++++++++++++++++ test/vim_test.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/keymap/vim.js b/keymap/vim.js index 83885bb6c1..66679c0e4d 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -260,6 +260,10 @@ actionArgs: { position: 'bottom' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, { keys: ['.'], type: 'action', action: 'repeatLastEdit' }, + { keys: ['Ctrl-a'], type: 'action', action: 'incrementNumberToken', + actionArgs: {increase: true, backtrack: false}}, + { keys: ['Ctrl-x'], type: 'action', action: 'incrementNumberToken', + actionArgs: {increase: false, backtrack: false}}, // Text object motions { keys: ['a', 'character'], type: 'motion', motion: 'textObjectManipulation' }, @@ -1568,6 +1572,34 @@ } } }, + incrementNumberToken: function(cm, actionArgs, vim) { + var cur = cm.getCursor(); + var lineStr = cm.getLine(cur.line); + var re = /-?\d+/g; + 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; + if(cur.ch < end)break; + } + if(!actionArgs.backtrack && (end <= cur.ch))return; + if (token) { + var increment = actionArgs.increase ? 1 : -1; + var number = parseInt(token) + (increment * actionArgs.repeat); + var from = {ch:start, line:cur.line}; + var to = {ch:end, line:cur.line}; + numberStr = number.toString(); + cm.replaceRange(numberStr, from, to); + } else { + return; + } + cm.setCursor({line: cur.line, ch: start + numberStr.length - 1}); + }, repeatLastEdit: function(cm, actionArgs, vim) { // TODO: Make this repeat insert mode changes. var lastEdit = vim.lastEdit; diff --git a/test/vim_test.js b/test/vim_test.js index 09f6e4b541..7c080c46ca 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -722,6 +722,35 @@ testVim('Y', function(cm, vim, helpers) { }, { value: ' word1\nword2\n word3' }); // Action tests +testVim('ctrl-a', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('Ctrl-a'); + eq('-9', cm.getValue()); + helpers.assertCursorAt(0, 1); + helpers.doKeys('2','Ctrl-a'); + eq('-7', cm.getValue()); +}, {value: '-10'}); +testVim('ctrl-x', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('Ctrl-x'); + eq('-1', cm.getValue()); + helpers.assertCursorAt(0, 1); + helpers.doKeys('2','Ctrl-x'); + eq('-3', cm.getValue()); +}, {value: '0'}); +testVim('Ctrl-x/Ctrl-a search forward', function(cm, vim, helpers) { + ['Ctrl-x', 'Ctrl-a'].forEach(function(key) { + cm.setCursor(0, 0); + helpers.doKeys(key); + helpers.assertCursorAt(0, 5); + helpers.doKeys('l'); + helpers.doKeys(key); + helpers.assertCursorAt(0, 10); + cm.setCursor(0, 11); + helpers.doKeys(key); + helpers.assertCursorAt(0, 11); + }); +}, {value: '__jmp1 jmp2 jmp'}); testVim('a', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('a'); From 890e32805b592e7a39633675d9f52808f0362893 Mon Sep 17 00:00:00 2001 From: Jason Grout Date: Thu, 11 Apr 2013 08:22:24 -0500 Subject: [PATCH 0488/5273] Fix typos in markText docs --- doc/manual.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 49dd5883d5..adfba1bf15 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1043,8 +1043,8 @@

      Text-marking methods

      When enabled, will cause the mark to clear itself whenever the cursor enters its range. This is mostly useful for text-replacement widgets that need to 'snap open' when the - user tries to edit them. A - the "clear" event + user tries to edit them. The + "clear" event fired on the range handle can be used to be notified when this happens.
      replacedWith: Element
      @@ -1081,7 +1081,7 @@

      Text-marking methods

      marker is no longer in the document, and finally getOptions(copyWidget), which returns an object representing the options for the marker. - If copyWidget is given an true, it will clone the + If copyWidget is given true, it will clone the value of the replacedWith option, if any.

      From 25fa0241d90436e469d7bd49b2b3e2d81222d970 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 12 Apr 2013 09:36:56 +0200 Subject: [PATCH 0489/5273] [show-hint addon] Support displayText property for completions --- 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 cbaa043571..58acf728c6 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -42,7 +42,7 @@ CodeMirror.showHint = function(cm, getHints, options) { if (completion.className != null) className = completion.className + " " + className; elt.className = className; if (completion.render) completion.render(elt, data, completion); - else elt.appendChild(document.createTextNode(getText(completion))); + else elt.appendChild(document.createTextNode(completion.displayText || getText(completion))); elt.hintId = i; } var pos = cm.cursorCoords(options.alignWithWord !== false ? data.from : null); From 20647247ed7116d09bde12d88ee624c31c5d579d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 12 Apr 2013 21:19:18 +0200 Subject: [PATCH 0490/5273] Add Flattr link to front page --- index.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 9b250b63d0..8b76987f2d 100644 --- a/index.html +++ b/index.html @@ -262,8 +262,9 @@

      Support CodeMirror

      (Paypal, bank, or - Gittip) + class="quasilink">bank, + Gittip, or + Flattr)
    • Purchase commercial support
    From c519feae3458881d7dc4258df7079c5464c971fe Mon Sep 17 00:00:00 2001 From: santec Date: Mon, 15 Apr 2013 09:59:28 +0200 Subject: [PATCH 0491/5273] [sql mode] Add some keywords to mariadb and mysql modes --- mode/sql/sql.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/sql/sql.js b/mode/sql/sql.js index 15f65920ca..4ff847f32c 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -226,7 +226,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { CodeMirror.defineMIME("text/x-mysql", { 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 + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), + keywords: set(sqlKeywords + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), atoms: set("false true null unknown"), operatorChars: /^[*+\-%<>!=&|^]/, @@ -242,7 +242,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { CodeMirror.defineMIME("text/x-mariadb", { 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 + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), + keywords: set(sqlKeywords + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated global grant grants group groupby_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), atoms: set("false true null unknown"), operatorChars: /^[*+\-%<>!=&|^]/, From 58216885e00cec655b389eec00827ab66525a42a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 15 Apr 2013 11:16:00 +0200 Subject: [PATCH 0492/5273] Try to guard against IE9/10 sneakily resetting textarea selection on drag (And possibly in other situations.) Issue #1240 --- lib/codemirror.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 5f253de552..98d7355024 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1409,18 +1409,16 @@ window.CodeMirror = (function() { if (!cm.state.focused || hasSelection(input) || isReadOnly(cm)) return false; var text = input.value; if (text == prevInput && posEq(sel.from, sel.to)) return false; - // IE enjoys randomly deselecting our input's text when - // re-focusing. If the selection is gone but the cursor is at the - // start of the input, that's probably what happened. - if (ie && text && input.selectionStart === 0) { + if (ie && !ie_lt9 && cm.display.inputHasSelection === text) { resetInput(cm, true); return false; } + var withOp = !cm.curOp; if (withOp) startOperation(cm); sel.shift = false; var same = 0, l = Math.min(prevInput.length, text.length); - while (same < l && prevInput[same] == text[same]) ++same; + while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; var from = sel.from, to = sel.to; if (same < prevInput.length) from = Pos(from.line, from.ch - (prevInput.length - same)); @@ -1444,10 +1442,14 @@ window.CodeMirror = (function() { cm.display.prevInput = ""; minimal = hasCopyEvent && (doc.sel.to.line - doc.sel.from.line > 100 || (selected = cm.getSelection()).length > 1000); - if (minimal) cm.display.input.value = "-"; - else cm.display.input.value = selected || cm.getSelection(); + var content = minimal ? "-" : selected || cm.getSelection(); + cm.display.input.value = content; if (cm.state.focused) selectInput(cm.display.input); - } else if (user) cm.display.prevInput = cm.display.input.value = ""; + if (ie && !ie_lt9) cm.display.inputHasSelection = content; + } else if (user) { + cm.display.prevInput = cm.display.input.value = ""; + if (ie && !ie_lt9) cm.display.inputHasSelection = null; + } cm.display.inaccurateSelection = minimal; } @@ -2040,6 +2042,7 @@ window.CodeMirror = (function() { this.doc.mode.electricChars.indexOf(ch) > -1) setTimeout(operation(cm, function() {indentLine(cm, cm.doc.sel.to.line, "smart");}), 75); if (handleCharBinding(cm, e, ch)) return; + if (ie && !ie_lt9) cm.display.inputHasSelection = null; fastPoll(cm); } From 0ee523d47a6cb9b8f4be16425383435c0fb9745b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 15 Apr 2013 11:23:42 +0200 Subject: [PATCH 0493/5273] Stop 'phantom' after-the-fact drag starts in IE10 Closes #1445 --- lib/codemirror.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 98d7355024..161ac997e0 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -164,8 +164,6 @@ window.CodeMirror = (function() { d.pollingFast = false; // Self-resetting timeout for the poller d.poll = new Delayed(); - // True when a drag from the editor is active - d.draggingText = false; d.cachedCharWidth = d.cachedTextHeight = null; d.measureLineCache = []; @@ -1804,6 +1802,7 @@ window.CodeMirror = (function() { } function onDragStart(cm, e) { + if (ie && !cm.state.draggingText) { e_stop(e); return; } if (eventInWidget(cm.display, e)) return; var txt = cm.getSelection(); From c9c213ed1abadf00a1620f303c0a125a22050454 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 15 Apr 2013 11:32:48 +0200 Subject: [PATCH 0494/5273] Prevent duplicate selection updates from mouse clicks Closes #1450 --- lib/codemirror.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 161ac997e0..57e16806ab 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1665,9 +1665,12 @@ window.CodeMirror = (function() { e_preventDefault(e); if (type == "single") extendSelection(cm.doc, clipPos(doc, start)); - var startstart = sel.from, startend = sel.to; + var startstart = sel.from, startend = sel.to, lastPos = start; function doSelect(cur) { + if (posEq(lastPos, cur)) return; + lastPos = cur; + if (type == "single") { extendSelection(cm.doc, clipPos(doc, start), cur); return; From 046f2a336303137973c45a6bbe88fe85cb7cfd07 Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Thu, 11 Apr 2013 17:49:58 +0200 Subject: [PATCH 0495/5273] [vim keymap] Add HML cursor motions --- keymap/vim.js | 31 +++++++++++++++++++++++++++++++ test/vim_test.js | 18 ++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/keymap/vim.js b/keymap/vim.js index 66679c0e4d..01550449c5 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -79,6 +79,15 @@ { keys: ['PageUp'], type: 'keyToKey', toKeys: ['Ctrl-b'] }, { keys: ['PageDown'], type: 'keyToKey', toKeys: ['Ctrl-f'] }, // Motions + { keys: ['H'], type: 'motion', + motion: 'moveToTopLine', + motionArgs: { linewise: true }}, + { keys: ['M'], type: 'motion', + motion: 'moveToMiddleLine', + motionArgs: { linewise: true }}, + { keys: ['L'], type: 'motion', + motion: 'moveToBottomLine', + motionArgs: { linewise: true }}, { keys: ['h'], type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: false }}, @@ -1004,6 +1013,19 @@ */ // All of the functions below return Cursor objects. var motions = { + moveToTopLine: function(cm, motionArgs) { + var line = getUserVisibleLines(cm).top + motionArgs.repeat -1; + return { line: line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(line)) }; + }, + moveToMiddleLine: function(cm) { + var range = getUserVisibleLines(cm); + var line = Math.floor((range.top + range.bottom) * 0.5); + return { line: line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(line)) }; + }, + moveToBottomLine: function(cm, motionArgs) { + var line = getUserVisibleLines(cm).bottom - motionArgs.repeat +1; + return { line: line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(line)) }; + }, expandToLine: function(cm, motionArgs) { // Expands forward to end of line, and then to next line if repeat is // >1. Does not handle backward motion! @@ -2410,6 +2432,15 @@ } } } + function getUserVisibleLines(cm) { + var scrollInfo = cm.getScrollInfo(); + var occludeTorleranceTop = 6; + var occludeTorleranceBottom = 10; + var from = cm.coordsChar({left:0, top: occludeTorleranceTop}, 'local'); + var bottomY = scrollInfo.clientHeight - occludeTorleranceBottom; + var to = cm.coordsChar({left:0, top: bottomY}, 'local'); + return {top: from.line, bottom: to.line}; + } // Ex command handling // Care must be taken when adding to the default Ex command map. For any diff --git a/test/vim_test.js b/test/vim_test.js index 7c080c46ca..103259a9ef 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1401,6 +1401,24 @@ testVim('Ty,;', function(cm, vim, helpers) { helpers.doKeys('y', ',', 'P'); eq('01230123456789', cm.getValue()); }, { value: '0123456789'}); +testVim('HML', function(cm, vim, helpers) { + cm.setSize(600, 400); + cm.setCursor(120, 0); + helpers.doKeys('H'); + helpers.assertCursorAt(90, 2); + helpers.doKeys('L'); + helpers.assertCursorAt(119, 4); + helpers.doKeys('M'); + helpers.assertCursorAt(104,4); +}, { value: (function(){ + var upperLines = new Array(100); + var lowerLines = new Array(100); + var upper = ' xx\n'; + var lower = ' xx\n'; + upper = upperLines.join(upper); + lower = upperLines.join(lower); + return upper + lower; +})()}); // Ex mode tests testVim('ex_go_to_line', function(cm, vim, helpers) { From 09eba2305ffa044c091d0fff931a18d1e84531d9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 15 Apr 2013 11:48:10 +0200 Subject: [PATCH 0496/5273] [javascript mode] Make 'foo++ / 10' parse correctly (not a regexp) Issue #1451 --- 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 c138b6fc63..08c1cb1f4f 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -426,7 +426,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (state.tokenize != jsTokenComment && stream.eatSpace()) return null; var style = state.tokenize(stream, state); if (type == "comment") return style; - state.lastType = type; + state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type; return parseJS(state, style, type, content, stream); }, From b7db11ae8e6c4c62cd6589780f116183328a737d Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Sun, 14 Apr 2013 21:07:58 +0200 Subject: [PATCH 0497/5273] [vim keymap] Add [] motions --- keymap/vim.js | 138 +++++++++++++++++++++++++++++++++++++++++++++-- test/vim_test.js | 116 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 250 insertions(+), 4 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 01550449c5..499601b5b0 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -192,6 +192,12 @@ { keys: ['[', '`',], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } }, { keys: [']', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } }, { keys: ['[', '\''], type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } }, + { keys: [']', 'character'], type: 'motion', + motion: 'moveToSymbol', + motionArgs: { forward: true}}, + { keys: ['[', 'character'], type: 'motion', + motion: 'moveToSymbol', + motionArgs: { forward: false}}, { keys: ['|'], type: 'motion', motion: 'moveToColumn', motionArgs: { }}, @@ -1219,6 +1225,11 @@ return moveToCharacter(cm, repeat, motionArgs.forward, motionArgs.selectedCharacter) || cm.getCursor(); }, + moveToSymbol: function(cm, motionArgs) { + var repeat = motionArgs.repeat; + return findSymbol(cm, repeat, motionArgs.forward, + motionArgs.selectedCharacter) || cm.getCursor(); + }, moveToColumn: function(cm, motionArgs, vim) { var repeat = motionArgs.repeat; // repeat is equivalent to which column we want to move to! @@ -1872,6 +1883,127 @@ vimGlobalState.lastChararacterSearch.selectedCharacter = args.selectedCharacter; } + var symbolToMode = { + '(': 'bracket', ')': 'bracket', '{': 'bracket', '}': 'bracket', + '[': 'section', ']': 'section', + '*': 'comment', '/': 'comment', + 'm': 'method', 'M': 'method', + '#': 'preprocess' + }; + var findSymbolModes = { + bracket: { + isComplete: function(state) { + if (state.nextCh === state.symb) { + state.depth++; + if(state.depth >= 1)return true; + } else if (state.nextCh === state.reverseSymb) { + state.depth--; + } + return false; + } + }, + section: { + init: function(state) { + state.curMoveThrough = true; + state.symb = (state.forward ? ']' : '[') === state.symb ? '{' : '}'; + }, + isComplete: function(state) { + return state.index === 0 && state.nextCh === state.symb; + } + }, + comment: { + isComplete: function(state) { + var found = state.lastCh === '*' && state.nextCh === '/'; + state.lastCh = state.nextCh; + return found; + } + }, + // TODO: The original Vim implementation only operates on level 1 and 2. + // The current implementation doesn't check for code block level and + // therefore it operates on any levels. + method: { + init: function(state) { + state.symb = (state.symb === 'm' ? '{' : '}'); + state.reverseSymb = state.symb === '{' ? '}' : '{'; + }, + isComplete: function(state) { + if(state.nextCh === state.symb)return true; + return false; + } + }, + preprocess: { + init: function(state) { + state.index = 0; + }, + isComplete: function(state) { + if (state.nextCh === '#') { + var token = state.lineText.match(/#(\w+)/)[1]; + if (token === 'endif') { + if (state.forward && state.depth === 0) { + return true; + } + state.depth++; + } else if (token === 'if') { + if (!state.forward && state.depth === 0) { + return true; + } + state.depth--; + } + if(token === 'else' && state.depth === 0)return true; + } + return false; + } + } + }; + function findSymbol(cm, repeat, forward, symb) { + var cur = cm.getCursor(); + var increment = forward ? 1 : -1; + var endLine = forward ? cm.lineCount() : -1; + var curCh = cur.ch; + var line = cur.line; + var lineText = cm.getLine(line); + var state = { + lineText: lineText, + nextCh: lineText.charAt(curCh), + lastCh: null, + index: curCh, + symb: symb, + reverseSymb: (forward ? { ')': '(', '}': '{' } : { '(': ')', '{': '}' })[symb], + forward: forward, + depth: 0, + curMoveThrough: false + }; + var mode = symbolToMode[symb]; + if(!mode)return cur; + var init = findSymbolModes[mode].init; + var isComplete = findSymbolModes[mode].isComplete; + if(init)init(state); + while (line !== endLine && repeat) { + state.index += increment; + state.nextCh = state.lineText.charAt(state.index); + if (!state.nextCh) { + line += increment; + state.lineText = cm.getLine(line) || ''; + if (increment > 0) { + state.index = 0; + } else { + var lineLen = state.lineText.length; + state.index = (lineLen > 0) ? (lineLen-1) : 0; + } + state.nextCh = state.lineText.charAt(state.index); + } + if (isComplete(state)) { + cur.line = line; + cur.ch = state.index; + repeat--; + } + } + if (state.nextCh || state.curMoveThrough) { + return { line: line, ch: state.index }; + } + return cur; + } + /* * Returns the boundaries of the next word. If the cursor in the middle of * the word, then returns the boundaries of the current word, starting at @@ -2060,9 +2192,6 @@ var line = cur.line; symb = symb ? symb : cm.getLine(line).charAt(cur.ch); - // Are we at the opening or closing char - var forwards = inArray(symb, ['(', '[', '{']); - var reverseSymb = ({ '(': ')', ')': '(', '[': ']', ']': '[', @@ -2076,12 +2205,13 @@ // set our increment to move forward (+1) or backwards (-1) // depending on which bracket we're matching var increment = ({'(': 1, '{': 1, '[': 1})[symb] || -1; + var endLine = increment === 1 ? cm.lineCount() : -1; var depth = 1, nextCh = symb, index = cur.ch, lineText = cm.getLine(line); // Simple search for closing paren--just count openings and closings till // we find our match // TODO: use info from CodeMirror to ignore closing brackets in comments // and quotes, etc. - while (nextCh && depth > 0) { + while (line !== endLine && depth > 0) { index += increment; nextCh = lineText.charAt(index); if (!nextCh) { diff --git a/test/vim_test.js b/test/vim_test.js index 103259a9ef..7d4dde8585 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1419,6 +1419,122 @@ testVim('HML', function(cm, vim, helpers) { lower = upperLines.join(lower); return upper + lower; })()}); +var squareBracketMotionSandbox = ''+ + '({\n'+//0 + ' ({\n'+//11 + ' /*comment {\n'+//2 + ' */(\n'+//3 + '#else \n'+//4 + ' /* )\n'+//5 + '#if }\n'+//6 + ' )}*/\n'+//7 + ')}\n'+//8 + '{}\n'+//9 + '#else {{\n'+//10 + '{}\n'+//11 + '}\n'+//12 + '{\n'+//13 + '#endif\n'+//14 + '}\n'+//15 + '}\n'+//16 + '#else';//17 +testVim('[[, ]]', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys(']', ']'); + helpers.assertCursorAt(9,0); + helpers.doKeys('2', ']', ']'); + helpers.assertCursorAt(13,0); + helpers.doKeys(']', ']'); + helpers.assertCursorAt(17,0); + helpers.doKeys('[', '['); + helpers.assertCursorAt(13,0); + helpers.doKeys('2', '[', '['); + helpers.assertCursorAt(9,0); + helpers.doKeys('[', '['); + helpers.assertCursorAt(0,0); +}, { value: squareBracketMotionSandbox}); +testVim('[], ][', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys(']', '['); + helpers.assertCursorAt(12,0); + helpers.doKeys('2', ']', '['); + helpers.assertCursorAt(16,0); + helpers.doKeys(']', '['); + helpers.assertCursorAt(17,0); + helpers.doKeys('[', ']'); + helpers.assertCursorAt(16,0); + helpers.doKeys('2', '[', ']'); + helpers.assertCursorAt(12,0); + helpers.doKeys('[', ']'); + helpers.assertCursorAt(0,0); +}, { value: squareBracketMotionSandbox}); +testVim('[{, ]}', function(cm, vim, helpers) { + cm.setCursor(4, 10); + helpers.doKeys('[', '{'); + helpers.assertCursorAt(2,12); + helpers.doKeys('2', '[', '{'); + helpers.assertCursorAt(0,1); + cm.setCursor(4, 10); + helpers.doKeys(']', '}'); + helpers.assertCursorAt(6,11); + helpers.doKeys('2', ']', '}'); + helpers.assertCursorAt(8,1); + cm.setCursor(0,1); + helpers.doKeys(']', '}'); + helpers.assertCursorAt(8,1); + helpers.doKeys('[', '{'); + helpers.assertCursorAt(0,1); +}, { value: squareBracketMotionSandbox}); +testVim('[(, ])', function(cm, vim, helpers) { + cm.setCursor(4, 10); + helpers.doKeys('[', '('); + helpers.assertCursorAt(3,14); + helpers.doKeys('2', '[', '('); + helpers.assertCursorAt(0,0); + cm.setCursor(4, 10); + helpers.doKeys(']', ')'); + helpers.assertCursorAt(5,11); + helpers.doKeys('2', ']', ')'); + helpers.assertCursorAt(8,0); + helpers.doKeys('[', '('); + helpers.assertCursorAt(0,0); + helpers.doKeys(']', ')'); + helpers.assertCursorAt(8,0); +}, { value: squareBracketMotionSandbox}); +testVim('[*, ]*, [/, ]/', function(cm, vim, helpers) { + ['*', '/'].forEach(function(key){ + cm.setCursor(7, 0); + helpers.doKeys('2', '[', key); + helpers.assertCursorAt(2,2); + helpers.doKeys('2', ']', key); + helpers.assertCursorAt(7,5); + }); +}, { value: squareBracketMotionSandbox}); +testVim('[#, ]#', function(cm, vim, helpers) { + cm.setCursor(10, 3); + helpers.doKeys('2', '[', '#'); + helpers.assertCursorAt(4,0); + helpers.doKeys('5', ']', '#'); + helpers.assertCursorAt(17,0); + cm.setCursor(10, 3); + helpers.doKeys(']', '#'); + helpers.assertCursorAt(14,0); +}, { value: squareBracketMotionSandbox}); +testVim('[m, ]m, [M, ]M', function(cm, vim, helpers) { + cm.setCursor(11, 0); + helpers.doKeys('[', 'm'); + helpers.assertCursorAt(10,7); + helpers.doKeys('4', '[', 'm'); + helpers.assertCursorAt(1,3); + helpers.doKeys('5', ']', 'm'); + helpers.assertCursorAt(11,0); + helpers.doKeys('[', 'M'); + helpers.assertCursorAt(9,1); + helpers.doKeys('3', ']', 'M'); + helpers.assertCursorAt(15,0); + helpers.doKeys('5', '[', 'M'); + helpers.assertCursorAt(7,3); +}, { value: squareBracketMotionSandbox}); // Ex mode tests testVim('ex_go_to_line', function(cm, vim, helpers) { From 50c4d2c321cf5692a2a882e76e92d0d0f3a422d3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 16 Apr 2013 09:16:18 +0200 Subject: [PATCH 0498/5273] [brace-fold addon] Fix infinite loop when finding opening brace --- addon/fold/brace-fold.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/fold/brace-fold.js b/addon/fold/brace-fold.js index aad6e0141e..dc78883f35 100644 --- a/addon/fold/brace-fold.js +++ b/addon/fold/brace-fold.js @@ -1,7 +1,7 @@ CodeMirror.braceRangeFinder = function(cm, start) { var line = start.line, lineText = cm.getLine(line); var at = lineText.length, startChar, tokenType; - for (;;) { + for (; at > 0;) { var found = lineText.lastIndexOf("{", at); if (found < start.ch) break; tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type; From 6f45a030ccfba22f93097b06b06a7b3c599f8662 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 19 Apr 2013 15:06:18 +0200 Subject: [PATCH 0499/5273] Fix inaccurate type info in docs Closes #1459 --- doc/manual.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index adfba1bf15..b5dda00c59 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1336,7 +1336,7 @@

    Miscellaneous methods

    lot faster. The return value from this method will be the return value of your function. -
    cm.indentLine(line: integer|LineHandle, ?dir: string)
    +
    cm.indentLine(line: integer, ?dir: string)
    Adjust the indentation of the given line. The second argument (which defaults to "smart") may be one of:
    From e370099b99ee18f23e0669f86ff071fd97343258 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 19 Apr 2013 15:19:14 +0200 Subject: [PATCH 0500/5273] [clojure mode] Fix allowed symbol characters Closes #1460 --- mode/clojure/clojure.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mode/clojure/clojure.js b/mode/clojure/clojure.js index 7751212632..fae675477d 100644 --- a/mode/clojure/clojure.js +++ b/mode/clojure/clojure.js @@ -44,8 +44,7 @@ CodeMirror.defineMode("clojure", function () { sign: /[+-]/, exponent: /e/i, keyword_char: /[^\s\(\[\;\)\]]/, - basic: /[\w\$_\-]/, - lang_keyword: /[\w*+!\-_?:\/]/ + symbol: /[\w*+!\-\._?:\/]/ }; function stateStack(indent, type, prev) { // represents a state stack object @@ -195,10 +194,10 @@ CodeMirror.defineMode("clojure", function () { popStack(state); } } else if ( ch == ":" ) { - stream.eatWhile(tests.lang_keyword); + stream.eatWhile(tests.symbol); return ATOM; } else { - stream.eatWhile(tests.basic); + stream.eatWhile(tests.symbol); if (keywords && keywords.propertyIsEnumerable(stream.current())) { returnType = KEYWORD; From c7b802ae3c0b9240ef9c732e1e22ec0ce554407b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 19 Apr 2013 15:31:02 +0200 Subject: [PATCH 0501/5273] [lint addon] Don't try to display tooltip above top of document --- 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 d8961ac3f6..6c5519ab56 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -10,7 +10,7 @@ CodeMirror.validate = (function() { function position(e) { if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); - tt.style.top = (e.clientY - tt.offsetHeight - 5) + "px"; + tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; tt.style.left = (e.clientX + 5) + "px"; } CodeMirror.on(document, "mousemove", position); From 5a0e4eeafc8f03164e19c291be7964f4f1e39321 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 19 Apr 2013 15:54:17 +0200 Subject: [PATCH 0502/5273] [lint addon] Make sure tooltips are always hidden when their ref node is removed --- addon/lint/lint.js | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 6c5519ab56..231eb2f567 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -15,7 +15,7 @@ CodeMirror.validate = (function() { } CodeMirror.on(document, "mousemove", position); position(e); - tt.style.opacity = 1; + if (tt.style.opacity != null) tt.style.opacity = 1; return tt; } function rm(elt) { @@ -28,6 +28,22 @@ CodeMirror.validate = (function() { setTimeout(function() { rm(tt); }, 600); } + function showTooltipFor(e, content, node) { + var tooltip = showTooltip(e, content); + function hide() { + CodeMirror.off(node, "mouseout", hide); + if (tooltip) { hideTooltip(tooltip); tooltip = null; } + } + var poll = setInterval(function() { + if (tooltip) for (var n = node;; n = n.parentNode) { + if (n == document.body) return; + if (!n) { hide(); break; } + } + if (!tooltip) return clearInterval(poll); + }, 400); + CodeMirror.on(node, "mouseout", hide); + } + function LintState(cm, options, hasGutter) { this.marked = []; this.options = options; @@ -58,11 +74,9 @@ CodeMirror.validate = (function() { inner.className = "CodeMirror-lint-marker-multiple"; } - if (tooltips != false) { - var tooltip; - CodeMirror.on(inner, "mouseover", function(e) { tooltip = showTooltip(e, labels); }); - CodeMirror.on(inner, "mouseout", function() { if (tooltip) hideTooltip(tooltip); }); - } + if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) { + showTooltipFor(e, labels, inner); + }); return marker; } @@ -140,13 +154,8 @@ CodeMirror.validate = (function() { } function popupSpanTooltip(ann, e) { - var tooltip = showTooltip(e, annotationTooltip(ann)); var target = e.target || e.srcElement; - CodeMirror.on(target, "mouseout", hide); - function hide() { - CodeMirror.off(target, "mouseout", hide); - hideTooltip(tooltip); - } + showTooltipFor(e, annotationTooltip(ann), target); } // When the mouseover fires, the cursor might not actually be over From 9c349a57f221c166c4b50d8fe1f169de06ecb5e4 Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Mon, 15 Apr 2013 13:42:29 +0400 Subject: [PATCH 0503/5273] show-hint addon to emit "hintShowed" and "hintClosed" events --- addon/hint/show-hint.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 58acf728c6..0a5b1eb33f 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -50,6 +50,7 @@ CodeMirror.showHint = function(cm, getHints, options) { hints.style.left = left + "px"; hints.style.top = top + "px"; document.body.appendChild(hints); + CodeMirror.signal(cm, "hintShowed"); // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); @@ -154,6 +155,7 @@ CodeMirror.showHint = function(cm, getHints, options) { cm.off("focus", onFocus); cm.off("scroll", onScroll); if (willContinue !== true && data.onClose) data.onClose(); + CodeMirror.signal(cm, "hintClosed"); } function pick() { pickCompletion(cm, data, completions[selectedHint]); From 14465a501b4cd398c9cff0ae2cb96c0e739035a8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 19 Apr 2013 16:04:26 +0200 Subject: [PATCH 0504/5273] [show-hint addon] Use events to notify hint source on open/close/select Issue #1454 --- addon/hint/show-hint.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 0a5b1eb33f..2c54dcd77e 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -29,7 +29,7 @@ CodeMirror.showHint = function(cm, getHints, options) { // When there is only one completion, use it directly. if (!continued && options.completeSingle !== false && completions.length == 1) { pickCompletion(cm, data, completions[0]); - if (data.onClose) data.onClose(); + CodeMirror.signal(data, "close"); return true; } @@ -50,7 +50,7 @@ CodeMirror.showHint = function(cm, getHints, options) { hints.style.left = left + "px"; hints.style.top = top + "px"; document.body.appendChild(hints); - CodeMirror.signal(cm, "hintShowed"); + CodeMirror.signal(data, "shown"); // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); @@ -87,7 +87,7 @@ CodeMirror.showHint = function(cm, getHints, options) { hints.scrollTop = node.offsetTop - 3; else if (node.offsetTop + node.offsetHeight > hints.scrollTop + hints.clientHeight) hints.scrollTop = node.offsetTop + node.offsetHeight - hints.clientHeight + 3; - if (data.onSelect) data.onSelect(completions[selectedHint], node); + CodeMirror.signal(data, "select", completions[selectedHint], node); } function screenAmount() { @@ -154,8 +154,7 @@ CodeMirror.showHint = function(cm, getHints, options) { cm.off("blur", onBlur); cm.off("focus", onFocus); cm.off("scroll", onScroll); - if (willContinue !== true && data.onClose) data.onClose(); - CodeMirror.signal(cm, "hintClosed"); + if (willContinue !== true) CodeMirror.signal(data, "close"); } function pick() { pickCompletion(cm, data, completions[selectedHint]); @@ -173,7 +172,7 @@ CodeMirror.showHint = function(cm, getHints, options) { else once = setTimeout(function(){close(true); continued = true; startHinting();}, 70); } - if (data.onSelect) data.onSelect(completions[0], hints.firstChild); + CodeMirror.signal(data, "select", completions[0], hints.firstChild); return true; } From e6bc191c01c23b5a0313069a09030c502f73faf9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 19 Apr 2013 16:50:14 +0200 Subject: [PATCH 0505/5273] Document addToHistory option to markText --- doc/manual.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index b5dda00c59..a69a5cb92b 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1051,7 +1051,7 @@

    Text-marking methods

    Use a given node to display this range. Implies both collapsed and atomic. The given DOM node must be an inline element (as opposed to a block element).
    -
    readOnly: boolean|string
    +
    readOnly: boolean
    A read-only span can, as long as it is not cleared, not be modified except by calling setValue to reset @@ -1060,6 +1060,10 @@

    Text-marking methods

    existing undo events being partially nullified by read-only spans would corrupt the history (in the current implementation).
    +
    addToHistory: boolean
    +
    When set to true (default is false), adding this marker + will create an event in the undo history that can be + individually undone (clearing the marker).
    startStyle: string
    Can be used to specify an extra CSS class to be applied to the leftmost span that is part of the marker.
    From 36e4c894aeee094c2f8d2ef884162fb50c570306 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 19 Apr 2013 16:58:51 +0200 Subject: [PATCH 0506/5273] Mark release 3.12 --- doc/compress.html | 1 + index.html | 14 ++++++++++++++ lib/codemirror.js | 2 +- package.json | 2 +- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index cd4d41bac8..f1fa218def 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -30,6 +30,7 @@

    { } CodeMi

    Version: + + + + + + + + + + + + + + + + + + + + Select Font Size + + + + +

    + + + + From 1ecf154e62ff931f77894e966995bd19b3db0105 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 22 Apr 2013 12:58:00 +0200 Subject: [PATCH 0511/5273] [cobol mode] Integrate Issue #1465 --- doc/compress.html | 1 + doc/modes.html | 1 + mode/cobol/cobol.js | 459 +++++++++++++++++++++--------------------- mode/cobol/index.html | 118 +++++------ mode/meta.js | 1 + 5 files changed, 291 insertions(+), 289 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index f1fa218def..c51b2833e0 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -73,6 +73,7 @@

    { } CodeMi + diff --git a/doc/modes.html b/doc/modes.html index d016aca8ee..ac476bef78 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -27,6 +27,7 @@

    { } CodeMi
  • Asterisk dialplan
  • C, C++, C#
  • Clojure
  • +
  • COBOL
  • CoffeeScript
  • Common Lisp
  • CSS
  • diff --git a/mode/cobol/cobol.js b/mode/cobol/cobol.js index 8f45e3bbd8..d92491dde8 100644 --- a/mode/cobol/cobol.js +++ b/mode/cobol/cobol.js @@ -1,241 +1,240 @@ /** * Author: Gautam Mehta - * Branched from CodeMirror's Scheme mode + * Branched from CodeMirror's Scheme mode */ CodeMirror.defineMode("cobol", function () { - var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", CHARACTER = "string-2", - ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD = "keyword", MODTAG = "header", - COBOLLINENUM = "def", PERIOD = "link"; - function makeKeywords(str) { - var obj = {}, words = str.split(" "); - for (var i = 0; i < words.length; ++i) obj[words[i]] = true; - return obj; + var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", + ATOM = "atom", NUMBER = "number", KEYWORD = "keyword", MODTAG = "header", + COBOLLINENUM = "def", PERIOD = "link"; + function makeKeywords(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + var atoms = makeKeywords("TRUE FALSE ZEROES ZEROS ZERO SPACES SPACE LOW-VALUE LOW-VALUES "); + var keywords = makeKeywords( + "ACCEPT ACCESS ACQUIRE ADD ADDRESS " + + "ADVANCING AFTER ALIAS ALL ALPHABET " + + "ALPHABETIC ALPHABETIC-LOWER ALPHABETIC-UPPER ALPHANUMERIC ALPHANUMERIC-EDITED " + + "ALSO ALTER ALTERNATE AND ANY " + + "ARE AREA AREAS ARITHMETIC ASCENDING " + + "ASSIGN AT ATTRIBUTE AUTHOR AUTO " + + "AUTO-SKIP AUTOMATIC B-AND B-EXOR B-LESS " + + "B-NOT B-OR BACKGROUND-COLOR BACKGROUND-COLOUR BEEP " + + "BEFORE BELL BINARY BIT BITS " + + "BLANK BLINK BLOCK BOOLEAN BOTTOM " + + "BY CALL CANCEL CD CF " + + "CH CHARACTER CHARACTERS CLASS CLOCK-UNITS " + + "CLOSE COBOL CODE CODE-SET COL " + + "COLLATING COLUMN COMMA COMMIT COMMITMENT " + + "COMMON COMMUNICATION COMP COMP-0 COMP-1 " + + "COMP-2 COMP-3 COMP-4 COMP-5 COMP-6 " + + "COMP-7 COMP-8 COMP-9 COMPUTATIONAL COMPUTATIONAL-0 " + + "COMPUTATIONAL-1 COMPUTATIONAL-2 COMPUTATIONAL-3 COMPUTATIONAL-4 COMPUTATIONAL-5 " + + "COMPUTATIONAL-6 COMPUTATIONAL-7 COMPUTATIONAL-8 COMPUTATIONAL-9 COMPUTE " + + "CONFIGURATION CONNECT CONSOLE CONTAINED CONTAINS " + + "CONTENT CONTINUE CONTROL CONTROL-AREA CONTROLS " + + "CONVERTING COPY CORR CORRESPONDING COUNT " + + "CRT CRT-UNDER CURRENCY CURRENT CURSOR " + + "DATA DATE DATE-COMPILED DATE-WRITTEN DAY " + + "DAY-OF-WEEK DB DB-ACCESS-CONTROL-KEY DB-DATA-NAME DB-EXCEPTION " + + "DB-FORMAT-NAME DB-RECORD-NAME DB-SET-NAME DB-STATUS DBCS " + + "DBCS-EDITED DE DEBUG-CONTENTS DEBUG-ITEM DEBUG-LINE " + + "DEBUG-NAME DEBUG-SUB-1 DEBUG-SUB-2 DEBUG-SUB-3 DEBUGGING " + + "DECIMAL-POINT DECLARATIVES DEFAULT DELETE DELIMITED " + + "DELIMITER DEPENDING DESCENDING DESCRIBED DESTINATION " + + "DETAIL DISABLE DISCONNECT DISPLAY DISPLAY-1 " + + "DISPLAY-2 DISPLAY-3 DISPLAY-4 DISPLAY-5 DISPLAY-6 " + + "DISPLAY-7 DISPLAY-8 DISPLAY-9 DIVIDE DIVISION " + + "DOWN DROP DUPLICATE DUPLICATES DYNAMIC " + + "EBCDIC EGI EJECT ELSE EMI " + + "EMPTY EMPTY-CHECK ENABLE END END. END-ACCEPT END-ACCEPT. " + + "END-ADD END-CALL END-COMPUTE END-DELETE END-DISPLAY " + + "END-DIVIDE END-EVALUATE END-IF END-INVOKE END-MULTIPLY " + + "END-OF-PAGE END-PERFORM END-READ END-RECEIVE END-RETURN " + + "END-REWRITE END-SEARCH END-START END-STRING END-SUBTRACT " + + "END-UNSTRING END-WRITE END-XML ENTER ENTRY " + + "ENVIRONMENT EOP EQUAL EQUALS ERASE " + + "ERROR ESI EVALUATE EVERY EXCEEDS " + + "EXCEPTION EXCLUSIVE EXIT EXTEND EXTERNAL " + + "EXTERNALLY-DESCRIBED-KEY FD FETCH FILE FILE-CONTROL " + + "FILE-STREAM FILES FILLER FINAL FIND " + + "FINISH FIRST FOOTING FOR FOREGROUND-COLOR " + + "FOREGROUND-COLOUR FORMAT FREE FROM FULL " + + "FUNCTION GENERATE GET GIVING GLOBAL " + + "GO GOBACK GREATER GROUP HEADING " + + "HIGH-VALUE HIGH-VALUES HIGHLIGHT I-O I-O-CONTROL " + + "ID IDENTIFICATION IF IN INDEX " + + "INDEX-1 INDEX-2 INDEX-3 INDEX-4 INDEX-5 " + + "INDEX-6 INDEX-7 INDEX-8 INDEX-9 INDEXED " + + "INDIC INDICATE INDICATOR INDICATORS INITIAL " + + "INITIALIZE INITIATE INPUT INPUT-OUTPUT INSPECT " + + "INSTALLATION INTO INVALID INVOKE IS " + + "JUST JUSTIFIED KANJI KEEP KEY " + + "LABEL LAST LD LEADING LEFT " + + "LEFT-JUSTIFY LENGTH LENGTH-CHECK LESS LIBRARY " + + "LIKE LIMIT LIMITS LINAGE LINAGE-COUNTER " + + "LINE LINE-COUNTER LINES LINKAGE LOCAL-STORAGE " + + "LOCALE LOCALLY LOCK " + + "MEMBER MEMORY MERGE MESSAGE METACLASS " + + "MODE MODIFIED MODIFY MODULES MOVE " + + "MULTIPLE MULTIPLY NATIONAL NATIVE NEGATIVE " + + "NEXT NO NO-ECHO NONE NOT " + + "NULL NULL-KEY-MAP NULL-MAP NULLS NUMBER " + + "NUMERIC NUMERIC-EDITED OBJECT OBJECT-COMPUTER OCCURS " + + "OF OFF OMITTED ON ONLY " + + "OPEN OPTIONAL OR ORDER ORGANIZATION " + + "OTHER OUTPUT OVERFLOW OWNER PACKED-DECIMAL " + + "PADDING PAGE PAGE-COUNTER PARSE PERFORM " + + "PF PH PIC PICTURE PLUS " + + "POINTER POSITION POSITIVE PREFIX PRESENT " + + "PRINTING PRIOR PROCEDURE PROCEDURE-POINTER PROCEDURES " + + "PROCEED PROCESS PROCESSING PROGRAM PROGRAM-ID " + + "PROMPT PROTECTED PURGE QUEUE QUOTE " + + "QUOTES RANDOM RD READ READY " + + "REALM RECEIVE RECONNECT RECORD RECORD-NAME " + + "RECORDS RECURSIVE REDEFINES REEL REFERENCE " + + "REFERENCE-MONITOR REFERENCES RELATION RELATIVE RELEASE " + + "REMAINDER REMOVAL RENAMES REPEATED REPLACE " + + "REPLACING REPORT REPORTING REPORTS REPOSITORY " + + "REQUIRED RERUN RESERVE RESET RETAINING " + + "RETRIEVAL RETURN RETURN-CODE RETURNING REVERSE-VIDEO " + + "REVERSED REWIND REWRITE RF RH " + + "RIGHT RIGHT-JUSTIFY ROLLBACK ROLLING ROUNDED " + + "RUN SAME SCREEN SD SEARCH " + + "SECTION SECURE SECURITY SEGMENT SEGMENT-LIMIT " + + "SELECT SEND SENTENCE SEPARATE SEQUENCE " + + "SEQUENTIAL SET SHARED SIGN SIZE " + + "SKIP1 SKIP2 SKIP3 SORT SORT-MERGE " + + "SORT-RETURN SOURCE SOURCE-COMPUTER SPACE-FILL " + + "SPECIAL-NAMES STANDARD STANDARD-1 STANDARD-2 " + + "START STARTING STATUS STOP STORE " + + "STRING SUB-QUEUE-1 SUB-QUEUE-2 SUB-QUEUE-3 SUB-SCHEMA " + + "SUBFILE SUBSTITUTE SUBTRACT SUM SUPPRESS " + + "SYMBOLIC SYNC SYNCHRONIZED SYSIN SYSOUT " + + "TABLE TALLYING TAPE TENANT TERMINAL " + + "TERMINATE TEST TEXT THAN THEN " + + "THROUGH THRU TIME TIMES TITLE " + + "TO TOP TRAILING TRAILING-SIGN TRANSACTION " + + "TYPE TYPEDEF UNDERLINE UNEQUAL UNIT " + + "UNSTRING UNTIL UP UPDATE UPON " + + "USAGE USAGE-MODE USE USING VALID " + + "VALIDATE VALUE VALUES VARYING VLR " + + "WAIT WHEN WHEN-COMPILED WITH WITHIN " + + "WORDS WORKING-STORAGE WRITE XML XML-CODE " + + "XML-EVENT XML-NTEXT XML-TEXT ZERO ZERO-FILL " ); + + var builtins = makeKeywords("- * ** / + < <= = > >= "); + var tests = { + digit: /\d/, + digit_or_colon: /[\d:]/, + hex: /[0-9a-f]/i, + sign: /[+-]/, + exponent: /e/i, + keyword_char: /[^\s\(\[\;\)\]]/, + symbol: /[\w*+\-]/ + }; + function isNumber(ch, stream){ + // hex + if ( ch === '0' && stream.eat(/x/i) ) { + stream.eatWhile(tests.hex); + return true; } - var atoms = makeKeywords("TRUE FALSE ZEROES ZEROS ZERO SPACES SPACE LOW-VALUE LOW-VALUES "); - var keywords = makeKeywords( - "ACCEPT ACCESS ACQUIRE ADD ADDRESS " + - "ADVANCING AFTER ALIAS ALL ALPHABET " + - "ALPHABETIC ALPHABETIC-LOWER ALPHABETIC-UPPER ALPHANUMERIC ALPHANUMERIC-EDITED " + - "ALSO ALTER ALTERNATE AND ANY " + - "ARE AREA AREAS ARITHMETIC ASCENDING " + - "ASSIGN AT ATTRIBUTE AUTHOR AUTO " + - "AUTO-SKIP AUTOMATIC B-AND B-EXOR B-LESS " + - "B-NOT B-OR BACKGROUND-COLOR BACKGROUND-COLOUR BEEP " + - "BEFORE BELL BINARY BIT BITS " + - "BLANK BLINK BLOCK BOOLEAN BOTTOM " + - "BY CALL CANCEL CD CF " + - "CH CHARACTER CHARACTERS CLASS CLOCK-UNITS " + - "CLOSE COBOL CODE CODE-SET COL " + - "COLLATING COLUMN COMMA COMMIT COMMITMENT " + - "COMMON COMMUNICATION COMP COMP-0 COMP-1 " + - "COMP-2 COMP-3 COMP-4 COMP-5 COMP-6 " + - "COMP-7 COMP-8 COMP-9 COMPUTATIONAL COMPUTATIONAL-0 " + - "COMPUTATIONAL-1 COMPUTATIONAL-2 COMPUTATIONAL-3 COMPUTATIONAL-4 COMPUTATIONAL-5 " + - "COMPUTATIONAL-6 COMPUTATIONAL-7 COMPUTATIONAL-8 COMPUTATIONAL-9 COMPUTE " + - "CONFIGURATION CONNECT CONSOLE CONTAINED CONTAINS " + - "CONTENT CONTINUE CONTROL CONTROL-AREA CONTROLS " + - "CONVERTING COPY CORR CORRESPONDING COUNT " + - "CRT CRT-UNDER CURRENCY CURRENT CURSOR " + - "DATA DATE DATE-COMPILED DATE-WRITTEN DAY " + - "DAY-OF-WEEK DB DB-ACCESS-CONTROL-KEY DB-DATA-NAME DB-EXCEPTION " + - "DB-FORMAT-NAME DB-RECORD-NAME DB-SET-NAME DB-STATUS DBCS " + - "DBCS-EDITED DE DEBUG-CONTENTS DEBUG-ITEM DEBUG-LINE " + - "DEBUG-NAME DEBUG-SUB-1 DEBUG-SUB-2 DEBUG-SUB-3 DEBUGGING " + - "DECIMAL-POINT DECLARATIVES DEFAULT DELETE DELIMITED " + - "DELIMITER DEPENDING DESCENDING DESCRIBED DESTINATION " + - "DETAIL DISABLE DISCONNECT DISPLAY DISPLAY-1 " + - "DISPLAY-2 DISPLAY-3 DISPLAY-4 DISPLAY-5 DISPLAY-6 " + - "DISPLAY-7 DISPLAY-8 DISPLAY-9 DIVIDE DIVISION " + - "DOWN DROP DUPLICATE DUPLICATES DYNAMIC " + - "EBCDIC EGI EJECT ELSE EMI " + - "EMPTY EMPTY-CHECK ENABLE END END. END-ACCEPT END-ACCEPT. " + - "END-ADD END-CALL END-COMPUTE END-DELETE END-DISPLAY " + - "END-DIVIDE END-EVALUATE END-IF END-INVOKE END-MULTIPLY " + - "END-OF-PAGE END-PERFORM END-READ END-RECEIVE END-RETURN " + - "END-REWRITE END-SEARCH END-START END-STRING END-SUBTRACT " + - "END-UNSTRING END-WRITE END-XML ENTER ENTRY " + - "ENVIRONMENT EOP EQUAL EQUALS ERASE " + - "ERROR ESI EVALUATE EVERY EXCEEDS " + - "EXCEPTION EXCLUSIVE EXIT EXTEND EXTERNAL " + - "EXTERNALLY-DESCRIBED-KEY FD FETCH FILE FILE-CONTROL " + - "FILE-STREAM FILES FILLER FINAL FIND " + - "FINISH FIRST FOOTING FOR FOREGROUND-COLOR " + - "FOREGROUND-COLOUR FORMAT FREE FROM FULL " + - "FUNCTION GENERATE GET GIVING GLOBAL " + - "GO GOBACK GREATER GROUP HEADING " + - "HIGH-VALUE HIGH-VALUES HIGHLIGHT I-O I-O-CONTROL " + - "ID IDENTIFICATION IF IN INDEX " + - "INDEX-1 INDEX-2 INDEX-3 INDEX-4 INDEX-5 " + - "INDEX-6 INDEX-7 INDEX-8 INDEX-9 INDEXED " + - "INDIC INDICATE INDICATOR INDICATORS INITIAL " + - "INITIALIZE INITIATE INPUT INPUT-OUTPUT INSPECT " + - "INSTALLATION INTO INVALID INVOKE IS " + - "JUST JUSTIFIED KANJI KEEP KEY " + - "LABEL LAST LD LEADING LEFT " + - "LEFT-JUSTIFY LENGTH LENGTH-CHECK LESS LIBRARY " + - "LIKE LIMIT LIMITS LINAGE LINAGE-COUNTER " + - "LINE LINE-COUNTER LINES LINKAGE LOCAL-STORAGE " + - "LOCALE LOCALLY LOCK " + - "MEMBER MEMORY MERGE MESSAGE METACLASS " + - "MODE MODIFIED MODIFY MODULES MOVE " + - "MULTIPLE MULTIPLY NATIONAL NATIVE NEGATIVE " + - "NEXT NO NO-ECHO NONE NOT " + - "NULL NULL-KEY-MAP NULL-MAP NULLS NUMBER " + - "NUMERIC NUMERIC-EDITED OBJECT OBJECT-COMPUTER OCCURS " + - "OF OFF OMITTED ON ONLY " + - "OPEN OPTIONAL OR ORDER ORGANIZATION " + - "OTHER OUTPUT OVERFLOW OWNER PACKED-DECIMAL " + - "PADDING PAGE PAGE-COUNTER PARSE PERFORM " + - "PF PH PIC PICTURE PLUS " + - "POINTER POSITION POSITIVE PREFIX PRESENT " + - "PRINTING PRIOR PROCEDURE PROCEDURE-POINTER PROCEDURES " + - "PROCEED PROCESS PROCESSING PROGRAM PROGRAM-ID " + - "PROMPT PROTECTED PURGE QUEUE QUOTE " + - "QUOTES RANDOM RD READ READY " + - "REALM RECEIVE RECONNECT RECORD RECORD-NAME " + - "RECORDS RECURSIVE REDEFINES REEL REFERENCE " + - "REFERENCE-MONITOR REFERENCES RELATION RELATIVE RELEASE " + - "REMAINDER REMOVAL RENAMES REPEATED REPLACE " + - "REPLACING REPORT REPORTING REPORTS REPOSITORY " + - "REQUIRED RERUN RESERVE RESET RETAINING " + - "RETRIEVAL RETURN RETURN-CODE RETURNING REVERSE-VIDEO " + - "REVERSED REWIND REWRITE RF RH " + - "RIGHT RIGHT-JUSTIFY ROLLBACK ROLLING ROUNDED " + - "RUN SAME SCREEN SD SEARCH " + - "SECTION SECURE SECURITY SEGMENT SEGMENT-LIMIT " + - "SELECT SEND SENTENCE SEPARATE SEQUENCE " + - "SEQUENTIAL SET SHARED SIGN SIZE " + - "SKIP1 SKIP2 SKIP3 SORT SORT-MERGE " + - "SORT-RETURN SOURCE SOURCE-COMPUTER SPACE-FILL " + - "SPECIAL-NAMES STANDARD STANDARD-1 STANDARD-2 " + - "START STARTING STATUS STOP STORE " + - "STRING SUB-QUEUE-1 SUB-QUEUE-2 SUB-QUEUE-3 SUB-SCHEMA " + - "SUBFILE SUBSTITUTE SUBTRACT SUM SUPPRESS " + - "SYMBOLIC SYNC SYNCHRONIZED SYSIN SYSOUT " + - "TABLE TALLYING TAPE TENANT TERMINAL " + - "TERMINATE TEST TEXT THAN THEN " + - "THROUGH THRU TIME TIMES TITLE " + - "TO TOP TRAILING TRAILING-SIGN TRANSACTION " + - "TYPE TYPEDEF UNDERLINE UNEQUAL UNIT " + - "UNSTRING UNTIL UP UPDATE UPON " + - "USAGE USAGE-MODE USE USING VALID " + - "VALIDATE VALUE VALUES VARYING VLR " + - "WAIT WHEN WHEN-COMPILED WITH WITHIN " + - "WORDS WORKING-STORAGE WRITE XML XML-CODE " + - "XML-EVENT XML-NTEXT XML-TEXT ZERO ZERO-FILL " ); - - var builtins = makeKeywords("- * ** / + < <= = > >= "); - var indentKeys = makeKeywords(""); - var tests = { - digit: /\d/, - digit_or_colon: /[\d:]/, - hex: /[0-9a-f]/i, - sign: /[+-]/, - exponent: /e/i, - keyword_char: /[^\s\(\[\;\)\]]/, - symbol: /[\w*+\-]/ - }; - function isNumber(ch, stream){ - // hex - if ( ch === '0' && stream.eat(/x/i) ) { - stream.eatWhile(tests.hex); - return true; - } - // leading sign - if ( ( ch == '+' || ch == '-' ) && ( tests.digit.test(stream.peek()) ) ) { - stream.eat(tests.sign); - ch = stream.next(); + // leading sign + if ( ( ch == '+' || ch == '-' ) && ( tests.digit.test(stream.peek()) ) ) { + stream.eat(tests.sign); + ch = stream.next(); + } + if ( tests.digit.test(ch) ) { + stream.eat(ch); + stream.eatWhile(tests.digit); + if ( '.' == stream.peek()) { + stream.eat('.'); + stream.eatWhile(tests.digit); + } + if ( stream.eat(tests.exponent) ) { + stream.eat(tests.sign); + stream.eatWhile(tests.digit); + } + return true; + } + return false; + } + return { + startState: function () { + return { + indentStack: null, + indentation: 0, + mode: false + }; + }, + token: function (stream, state) { + if (state.indentStack == null && stream.sol()) { + // update indentation, but only if indentStack is empty + state.indentation = 6 ; //stream.indentation(); + } + // skip spaces + if (stream.eatSpace()) { + return null; + } + var returnType = null; + switch(state.mode){ + case "string": // multi-line string parsing mode + var next = false; + while ((next = stream.next()) != null) { + if (next == "\"" || next == "\'") { + state.mode = false; + break; + } } - if ( tests.digit.test(ch) ) { - stream.eat(ch); - stream.eatWhile(tests.digit); - if ( '.' == stream.peek()) { - stream.eat('.'); - stream.eatWhile(tests.digit); + returnType = STRING; // continue on in string mode + break; + default: // default parsing mode + var ch = stream.next(); + var col = stream.column(); + if (col >= 0 && col <= 5) { + returnType = COBOLLINENUM; + } else if (col >= 72 && col <= 79) { + stream.skipToEnd(); + returnType = MODTAG; + } else if (ch == "*" && col == 6) { // comment + stream.skipToEnd(); // rest of the line is a comment + returnType = COMMENT; + } else if (ch == "\"" || ch == "\'") { + state.mode = "string"; + returnType = STRING; + } else if (ch == "'" && !( tests.digit_or_colon.test(stream.peek()) )) { + returnType = ATOM; + } else if (ch == ".") { + returnType = PERIOD; + } else if (isNumber(ch,stream)){ + returnType = NUMBER; + } else { + if (stream.current().match(tests.symbol)) { + while (col < 71) { + if (stream.eat(tests.symbol) === undefined) { + break; + } else { + col++; + } } - if ( stream.eat(tests.exponent) ) { - stream.eat(tests.sign); - stream.eatWhile(tests.digit); - } - return true; + } + if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) { + returnType = KEYWORD; + } else if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase())) { + returnType = BUILTIN; + } else if (atoms && atoms.propertyIsEnumerable(stream.current().toUpperCase())) { + returnType = ATOM; + } else returnType = null; } - return false; + } + return returnType; + }, + indent: function (state) { + if (state.indentStack == null) return state.indentation; + return state.indentStack.indent; } - return { - startState: function () { - return { - indentStack: null, - indentation: 0, - mode: false - }; - }, - token: function (stream, state) { - if (state.indentStack == null && stream.sol()) { - // update indentation, but only if indentStack is empty - state.indentation = 6 ; //stream.indentation(); - } - // skip spaces - if (stream.eatSpace()) { - return null; - } - var returnType = null; - switch(state.mode){ - case "string": // multi-line string parsing mode - var next = false; - while ((next = stream.next()) != null) { - if (next == "\"" || next == "\'") { - state.mode = false; - break; - } - } - returnType = STRING; // continue on in string mode - break; - default: // default parsing mode - var ch = stream.next(); - var col = stream.column(); - if (col >= 0 && col <= 5) { - returnType = COBOLLINENUM; - } else if (col >= 72 && col <= 79) { - stream.skipToEnd(); - returnType = MODTAG; - } else if (ch == "*" && col == 6) { // comment - stream.skipToEnd(); // rest of the line is a comment - returnType = COMMENT; - } else if (ch == "\"" || ch == "\'") { - state.mode = "string"; - returnType = STRING; - } else if (ch == "'" && !( tests.digit_or_colon.test(stream.peek()) )) { - returnType = ATOM; - } else if (ch == ".") { - returnType = PERIOD; - } else if (isNumber(ch,stream)){ - returnType = NUMBER; - } else { - if (stream.current().match(tests.symbol)) { - while (col < 71) { - if (stream.eat(tests.symbol) === undefined) { - break; - } else { - col++; - } - } - } - if (keywords && keywords.propertyIsEnumerable(stream.current().toUpperCase())) { - returnType = KEYWORD; - } else if (builtins && builtins.propertyIsEnumerable(stream.current().toUpperCase())) { - returnType = BUILTIN; - } else if (atoms && atoms.propertyIsEnumerable(stream.current().toUpperCase())) { - returnType = ATOM; - } else returnType = null; - } - } - return returnType; - }, - indent: function (state) { - if (state.indentStack == null) return state.indentation; - return state.indentStack.indent; - } - }; + }; }); -CodeMirror.defineMIME("text/cbl", "cobol"); +CodeMirror.defineMIME("text/x-cobol", "cobol"); diff --git a/mode/cobol/index.html b/mode/cobol/index.html index c66a0e8619..71cc2fa151 100644 --- a/mode/cobol/index.html +++ b/mode/cobol/index.html @@ -7,7 +7,7 @@ - + @@ -24,42 +24,42 @@ - - - - - + + + + + + .CodeMirror { + border: 1px solid #eee; + font-size : 20px; + height : auto !important; + } + .CodeMirror-activeline-background {background: #555555 !important;} + -

    Select Theme Select Font Size + + + + + + + + + + + + + + + + + + + + Select Font Size + + +

    MIME types defined: text/x-haml.

    + +

    Parsing/Highlighting Tests: normal, verbose.

    + + + diff --git a/mode/haml/test.js b/mode/haml/test.js new file mode 100644 index 0000000000..b7178d40fb --- /dev/null +++ b/mode/haml/test.js @@ -0,0 +1,94 @@ +(function() { + var mode = CodeMirror.getMode({tabSize: 4}, "haml"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + // Requires at least one media query + MT("elementName", + "[tag %h1] Hey There"); + + MT("oneElementPerLine", + "[tag %h1] Hey There %h2"); + + MT("idSelector", + "[tag %h1][attribute #test] Hey There"); + + MT("classSelector", + "[tag %h1][attribute .hello] Hey There"); + + MT("docType", + "[tag !!! XML]"); + + MT("comment", + "[comment / Hello WORLD]"); + + MT("notComment", + "[tag %h1] This is not a / comment "); + + MT("attributes", + "[tag %a]([variable title][operator =][string \"test\"]){[atom :title] [operator =>] [string \"test\"]}"); + + MT("htmlCode", + "[tag

    ]Title[tag

    ]"); + + MT("rubyBlock", + "[operator =][variable-2 @item]"); + + MT("selectorRubyBlock", + "[tag %a.selector=] [variable-2 @item]"); + + MT("nestedRubyBlock", + "[tag %a]", + " [operator =][variable puts] [string \"test\"]"); + + MT("multilinePlaintext", + "[tag %p]", + " Hello,", + " World"); + + MT("multilineRuby", + "[tag %p]", + " [comment -# this is a comment]", + " [comment and this is a comment too]", + " Date/Time", + " [operator -] [variable now] [operator =] [tag DateTime][operator .][variable now]", + " [tag %strong=] [variable now]", + " [operator -] [keyword if] [variable now] [operator >] [tag DateTime][operator .][variable parse]([string \"December 31, 2006\"])", + " [operator =][string \"Happy\"]", + " [operator =][string \"Belated\"]", + " [operator =][string \"Birthday\"]"); + + MT("multilineComment", + "[comment /]", + " [comment Multiline]", + " [comment Comment]"); + + MT("hamlComment", + "[comment -# this is a comment]"); + + MT("multilineHamlComment", + "[comment -# this is a comment]", + " [comment and this is a comment too]"); + + MT("multilineHTMLComment", + "[comment ]"); + + MT("hamlAfterRubyTag", + "[attribute .block]", + " [tag %strong=] [variable now]", + " [attribute .test]", + " [operator =][variable now]", + " [attribute .right]"); + + MT("stretchedRuby", + "[operator =] [variable puts] [string \"Hello\"],", + " [string \"World\"]"); + + MT("interpolationInHashAttribute", + //"[tag %div]{[atom :id] [operator =>] [string \"#{][variable test][string }_#{][variable ting][string }\"]} test"); + "[tag %div]{[atom :id] [operator =>] [string \"#{][variable test][string }_#{][variable ting][string }\"]} test"); + + MT("interpolationInHTMLAttribute", + "[tag %div]([variable title][operator =][string \"#{][variable test][string }_#{][variable ting]()[string }\"]) Test"); +})(); diff --git a/test/index.html b/test/index.html index 0a0da5bd87..d397e8f7a2 100644 --- a/test/index.html +++ b/test/index.html @@ -57,6 +57,11 @@

    CodeMirror: Test Suite

    + + + + + @@ -84,7 +89,7 @@

    CodeMirror: Test Suite

    running = false, // Flag that states tests are running quit = false, // Flag to quit tests ASAP verbose = false; // Adds message for *every* test to output - + function runHarness(){ if (running) { quit = true; @@ -115,7 +120,7 @@

    CodeMirror: Test Suite

    ""; runTests(displayTest); } - + function setStatus(message, className, force){ if (quit && !force) return; if (!message) throw("must provide message"); From ea302c4a0a8fd8a784cfb21464ee5c0b3e0b45c1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 29 Apr 2013 10:18:09 +0200 Subject: [PATCH 0521/5273] [haml mode] Integrate --- doc/compress.html | 1 + doc/modes.html | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/compress.html b/doc/compress.html index c51b2833e0..9ed4773e8e 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -85,6 +85,7 @@

    { } CodeMi + diff --git a/doc/modes.html b/doc/modes.html index ac476bef78..af798aa774 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -38,6 +38,7 @@

    { } CodeMi
  • Gas (AT&T-style assembly)
  • Go
  • Groovy
  • +
  • HAML
  • Haskell
  • Haxe
  • HTML embedded scripts
  • From de9092bc99669da084fa99a16ad6ee010594dd92 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 29 Apr 2013 10:22:42 +0200 Subject: [PATCH 0522/5273] Remove TextMarker.getOptions It's hardly useful, error-prone, and too clunky. --- doc/manual.html | 12 +++--------- lib/codemirror.js | 16 ---------------- 2 files changed, 3 insertions(+), 25 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index d098421442..a92a6bc92a 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1104,18 +1104,12 @@

    Text-marking methods

    The method will return an object that represents the marker (with constuctor CodeMirror.TextMarker), which - exposes three methods: - clear(), to remove the mark, + exposes two methods: + clear(), to remove the mark, and find(), which returns a {from, to} object (both holding document positions), indicating the current position of the marked range, or undefined if the - marker is no longer in the document, and - finally getOptions(copyWidget), which returns an - object representing the options for the marker. - If copyWidget is given true, it will clone the - value of - the replacedWith - option, if any.
    + marker is no longer in the document.
    doc.setBookmark(pos: {line, ch}, ?options: object) → TextMarker
    Inserts a bookmark, a handle that follows the text around it diff --git a/lib/codemirror.js b/lib/codemirror.js index b2acbe0736..11817d7c6e 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3597,17 +3597,6 @@ window.CodeMirror = (function() { return from && {from: from, to: to}; }; - TextMarker.prototype.getOptions = function(copyWidget) { - var repl = this.replacedWith; - return {className: this.className, - inclusiveLeft: this.inclusiveLeft, inclusiveRight: this.inclusiveRight, - atomic: this.atomic, - collapsed: this.collapsed, - replacedWith: copyWidget ? repl && repl.cloneNode(true) : repl, - readOnly: this.readOnly, - startStyle: this.startStyle, endStyle: this.endStyle}; - }; - TextMarker.prototype.attachLine = function(line) { if (!this.lines.length && this.doc.cm) { var op = this.doc.cm.curOp; @@ -3705,11 +3694,6 @@ window.CodeMirror = (function() { SharedTextMarker.prototype.find = function() { return this.primary.find(); }; - SharedTextMarker.prototype.getOptions = function(copyWidget) { - var inner = this.primary.getOptions(copyWidget); - inner.shared = true; - return inner; - }; function markTextShared(doc, from, to, options, type) { options = copyObj(options); From ca3707b67ed60d866452c31cd1310cace4bb822c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 29 Apr 2013 10:47:05 +0200 Subject: [PATCH 0523/5273] Add TextMarker.changed method --- doc/manual.html | 17 +++++++++++------ lib/codemirror.js | 45 ++++++++++++++++++++++++++++++++------------- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index a92a6bc92a..6f47472050 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1104,12 +1104,17 @@

    Text-marking methods

    The method will return an object that represents the marker (with constuctor CodeMirror.TextMarker), which - exposes two methods: - clear(), to remove the mark, and - find(), which returns a {from, to} - object (both holding document positions), indicating the current - position of the marked range, or undefined if the - marker is no longer in the document.
    + exposes three methods: + clear(), to remove the mark, + find(), which returns + a {from, to} object (both holding document + positions), indicating the current position of the marked range, + or undefined if the marker is no longer in the + document, and finally changed(), + which you can call if you've done something that might change + the size of the marker (for example changing the content of + a replacedWith + node), and want to cheaply update the display.
    doc.setBookmark(pos: {line, ch}, ?options: object) → TextMarker
    Inserts a bookmark, a handle that follows the text around it diff --git a/lib/codemirror.js b/lib/codemirror.js index 11817d7c6e..7563e8804e 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -976,23 +976,28 @@ window.CodeMirror = (function() { if (memo.text == line.text && memo.markedSpans == line.markedSpans && cm.display.scroller.clientWidth == memo.width && memo.classes == line.textClass + "|" + line.bgClass + "|" + line.wrapClass) - return memo.measure; + return memo; } } + function clearCachedMeasurement(cm, line) { + var exists = findCachedMeasurement(cm, line); + if (exists) exists.text = exists.measure = exists.markedSpans = null; + } + function measureLine(cm, line) { // First look in the cache - var measure = findCachedMeasurement(cm, line); - if (!measure) { - // Failing that, recompute and store result in cache - measure = measureLineInner(cm, line); - var cache = cm.display.measureLineCache; - var memo = {text: line.text, width: cm.display.scroller.clientWidth, - markedSpans: line.markedSpans, measure: measure, - classes: line.textClass + "|" + line.bgClass + "|" + line.wrapClass}; - if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo; - else cache.push(memo); - } + var cached = findCachedMeasurement(cm, line); + if (cached) return cached.measure; + + // Failing that, recompute and store result in cache + var measure = measureLineInner(cm, line); + var cache = cm.display.measureLineCache; + var memo = {text: line.text, width: cm.display.scroller.clientWidth, + markedSpans: line.markedSpans, measure: measure, + classes: line.textClass + "|" + line.bgClass + "|" + line.wrapClass}; + if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo; + else cache.push(memo); return measure; } @@ -1068,7 +1073,7 @@ window.CodeMirror = (function() { if (sp.collapsed && (sp.to == null || sp.to == line.text.length)) hasBadSpan = true; } var cached = !hasBadSpan && findCachedMeasurement(cm, line); - if (cached) return measureChar(cm, line, line.text.length, cached).right; + if (cached) return measureChar(cm, line, line.text.length, cached.measure).right; var pre = lineContent(cm, line); var end = pre.appendChild(zeroWidthElement(cm.display.measure)); @@ -3597,6 +3602,20 @@ window.CodeMirror = (function() { return from && {from: from, to: to}; }; + TextMarker.prototype.changed = function() { + var pos = this.find(), cm = this.doc.cm; + if (!pos || !cm) return; + var line = getLine(this.doc, pos.from.line); + clearCachedMeasurement(cm, line); + if (pos.from.line >= cm.display.showingFrom && pos.from.line < cm.display.showingTo) { + for (var node = cm.display.lineDiv.firstChild; node; node = node.nextSibling) if (node.lineObj == line) { + if (node.offsetHeight != line.height) updateLineHeight(line, node.offsetHeight); + break; + } + runInOp(cm, function() { cm.curOp.selectionChanged = true; }); + } + }; + TextMarker.prototype.attachLine = function(line) { if (!this.lines.length && this.doc.cm) { var op = this.doc.cm.curOp; From c690083563f86739dc3d271516916d88b04370ed Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 29 Apr 2013 14:21:38 +0200 Subject: [PATCH 0524/5273] [sass mode] Remove hard-coded lists of html tags and pseudo-elements Issue #1466 --- mode/sass/sass.js | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/mode/sass/sass.js b/mode/sass/sass.js index e5c82e4e1b..1c13e9b415 100644 --- a/mode/sass/sass.js +++ b/mode/sass/sass.js @@ -3,24 +3,13 @@ CodeMirror.defineMode("sass", function(config) { return new RegExp("^" + words.join("|")); }; - var tags = ["&", "a","abbr","acronym","address","applet","area","article","aside","audio","b","base","basefont","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","command","datalist","dd","del","details","dfn","dir","div","dl","dt","em","embed","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","keygen","kbd","label","legend","li","link","map","mark","menu","meta","meter","nav","noframes","noscript","object","ol","optgroup","option","output","p","param","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strike","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","tt","u","ul","var","video","wbr"]; var keywords = ["true", "false", "null", "auto"]; var keywordsRegexp = new RegExp("^" + keywords.join("|")); var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-", "\\!=", "/", "\\*", "%", "and", "or", "not"]; var opRegexp = tokenRegexp(operators); - function htmlTag(val){ - for(var i=0; i Date: Mon, 29 Apr 2013 14:23:28 +0200 Subject: [PATCH 0525/5273] [sass mode] Remove unused variable --- mode/sass/sass.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/mode/sass/sass.js b/mode/sass/sass.js index 1c13e9b415..8758b25189 100644 --- a/mode/sass/sass.js +++ b/mode/sass/sass.js @@ -251,8 +251,6 @@ CodeMirror.defineMode("sass", function(config) { // atoms if (stream.eatWhile(/[\w-&]/)){ - - var current = stream.current(); // matches a property definition if (stream.peek() === ":" && !stream.match(pseudoElementsRegexp, false)) return "property"; From a9654a5f9add00d5ba74dd5a04b0e9d989daf8b3 Mon Sep 17 00:00:00 2001 From: Ivan Kurnosov Date: Tue, 30 Apr 2013 15:23:28 +1200 Subject: [PATCH 0526/5273] Updated sql's hookIdentifier to properly match escaped ` --- mode/sql/sql.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mode/sql/sql.js b/mode/sql/sql.js index 4ff847f32c..0ce2176da6 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -166,10 +166,9 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { // `identifier` function hookIdentifier(stream) { - var escaped = false, ch; + var ch; while ((ch = stream.next()) != null) { - if (ch == "`" && !escaped) return "variable-2"; - escaped = !escaped && ch == "`"; + if (ch == "`" && !stream.eat("`")) return "variable-2"; } return null; } From 9069b222ce48e8d5155ef10700f41e2c40cc5668 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 1 May 2013 12:05:32 +0200 Subject: [PATCH 0527/5273] Preserve Doc.prototype.constructor property --- lib/codemirror.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 7563e8804e..af89a0e755 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4520,6 +4520,7 @@ window.CodeMirror = (function() { }; Doc.prototype = createObj(BranchChunk.prototype, { + constructor: Doc, 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); From f57ab844957d50ebff3652b9dd7f629f1d56e97e Mon Sep 17 00:00:00 2001 From: Irakli Gozalishvili Date: Tue, 30 Apr 2013 13:36:03 +0400 Subject: [PATCH 0528/5273] Preserve constructor property on the editor instance. In some cases it's more convenient to access `CodeMirror` from the instance itself, but the way prototype was defined made it impossible. --- lib/codemirror.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index af89a0e755..4f0823b73a 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2733,6 +2733,7 @@ window.CodeMirror = (function() { // 'wrap f in an operation, performed on its `this` parameter' CodeMirror.prototype = { + constructor: CodeMirror, focus: function(){window.focus(); focusInput(this); onFocus(this); fastPoll(this);}, setOption: function(option, value) { From 0d8a43a05e331c1cb1881e8f11b970141fde23dd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 3 May 2013 08:58:25 +0200 Subject: [PATCH 0529/5273] [markdown mode] Directly use xml mode, rather than relying on text/html binding Since the mode uses the internals of the xml mode state object, it will break if another mode defines text/html (i.e. htmlmixed). Closes #1468 --- mode/markdown/markdown.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index c0be49460b..d93d55590e 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -1,7 +1,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { - var htmlFound = CodeMirror.mimeModes.hasOwnProperty("text/html"); - var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? "text/html" : "text/plain"); + var htmlFound = CodeMirror.modes.hasOwnProperty("xml"); + var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? {name: "xml", htmlMode: true} : "text/plain"); var aliases = { html: "htmlmixed", js: "javascript", From de983c613392d5f886e0142fc0a6c8ab9a81832e Mon Sep 17 00:00:00 2001 From: Randy Edmunds Date: Tue, 30 Apr 2013 19:43:42 -0700 Subject: [PATCH 0530/5273] [css mode] Add @import context --- mode/css/css.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mode/css/css.js b/mode/css/css.js index 1ef72b517d..8b1aca280e 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -230,6 +230,8 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { } else { style += " error"; } + } else if (context == "@import") { + style = "tag"; } else { style = "error"; } @@ -266,6 +268,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { } else if (type == "interpolation") state.stack.push("interpolation"); else if (type == "@media") state.stack.push("@media"); + else if (type == "@import") state.stack.push("@import"); else if (context == "@media" && /\b(keyword|attribute)\b/.test(style)) state.stack.push("@mediaType"); else if (context == "@mediaType" && stream.current() == ",") state.stack.pop(); @@ -273,6 +276,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { else if (context == "@mediaType(" && type == ")") state.stack.pop(); else if ((context == "rule" || context == "block") && type == ":") state.stack.push("propertyValue"); else if (context == "propertyValue" && type == ";") state.stack.pop(); + else if (context == "@import" && type == ";") state.stack.pop(); return style; }, From 85fb7c309f6b8329d2b317b6123084d2dd801a1a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 3 May 2013 09:10:30 +0200 Subject: [PATCH 0531/5273] [sql mode] Don't consider '.e' a number Closes #1489 --- mode/sql/index.html | 1 - mode/sql/sql.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mode/sql/index.html b/mode/sql/index.html index 7ec938a121..8a2495ca24 100644 --- a/mode/sql/index.html +++ b/mode/sql/index.html @@ -6,7 +6,6 @@ - @@ -68,7 +69,8 @@

    CodeMirror: JavaScript mode

    var editor = CodeMirror.fromTextArea(document.getElementById("code"), { lineNumbers: true, matchBrackets: true, - continueComments: "Enter" + continueComments: "Enter", + extraKeys: {"Ctrl-Q": "toggleComment"} }); diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 87856a89f3..fabe1c42b9 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -453,6 +453,9 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { }, electricChars: ":{}", + blockCommentStart: jsonMode ? null : "/*", + blockCommentEnd: jsonMode ? null : "*/", + lineComment: jsonMode ? null : "//", jsonMode: jsonMode }; diff --git a/mode/lua/lua.js b/mode/lua/lua.js index 90761e2941..b8deaa2575 100644 --- a/mode/lua/lua.js +++ b/mode/lua/lua.js @@ -133,7 +133,11 @@ CodeMirror.defineMode("lua", function(config, parserConfig) { indent: function(state, textAfter) { var closing = dedentPartial.test(textAfter); return state.basecol + indentUnit * (state.indentDepth - (closing ? 1 : 0)); - } + }, + + lineComment: "--", + blockCommentStart: "--[[", + blockCommentEnd: "]]" }; }); diff --git a/mode/ocaml/ocaml.js b/mode/ocaml/ocaml.js index 7dc3d283b2..32cbc0b7ba 100644 --- a/mode/ocaml/ocaml.js +++ b/mode/ocaml/ocaml.js @@ -106,7 +106,10 @@ CodeMirror.defineMode('ocaml', function() { token: function(stream, state) { if (stream.eatSpace()) return null; return state.tokenize(stream, state); - } + }, + + blockCommentStart: "(*", + blockCommentEnd: "*)" }; }); diff --git a/mode/php/php.js b/mode/php/php.js index 56497ed436..fa0db5b1fe 100644 --- a/mode/php/php.js +++ b/mode/php/php.js @@ -118,6 +118,9 @@ }, electricChars: "/{}:", + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//", innerMode: function(state) { return {state: state.curState, mode: state.curMode}; } }; diff --git a/mode/python/python.js b/mode/python/python.js index d69ef8389b..b623972b88 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -331,8 +331,9 @@ CodeMirror.defineMode("python", function(conf, parserConf) { } return state.scopes[0].offset; - } + }, + lineComment: "#" }; return external; }); diff --git a/mode/ruby/ruby.js b/mode/ruby/ruby.js index d106a542db..883244b1c7 100644 --- a/mode/ruby/ruby.js +++ b/mode/ruby/ruby.js @@ -186,8 +186,9 @@ CodeMirror.defineMode("ruby", function(config) { return ct.indented + (closing ? 0 : config.indentUnit) + (state.continuedLine ? config.indentUnit : 0); }, - electricChars: "}de" // enD and rescuE + electricChars: "}de", // enD and rescuE + lineComment: "#" }; }); diff --git a/mode/rust/rust.js b/mode/rust/rust.js index ea3005c360..7bee489b47 100644 --- a/mode/rust/rust.js +++ b/mode/rust/rust.js @@ -425,7 +425,10 @@ CodeMirror.defineMode("rust", function() { return lexical.indented + (closing ? 0 : (lexical.info == "alt" ? altIndentUnit : indentUnit)); }, - electricChars: "{}" + electricChars: "{}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" }; }); diff --git a/mode/scheme/scheme.js b/mode/scheme/scheme.js index 2ed0a24cd8..c5990ae92c 100644 --- a/mode/scheme/scheme.js +++ b/mode/scheme/scheme.js @@ -223,7 +223,9 @@ CodeMirror.defineMode("scheme", function () { indent: function (state) { if (state.indentStack == null) return state.indentation; return state.indentStack.indent; - } + }, + + lineComment: ";;" }; }); diff --git a/mode/xml/xml.js b/mode/xml/xml.js index 440343bbe7..b04248c6c6 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -317,6 +317,8 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { }, electricChars: "/", + blockCommentStart: "", configuration: parserConfig.htmlMode ? "html" : "xml" }; diff --git a/test/comment_test.js b/test/comment_test.js new file mode 100644 index 0000000000..311bdb5f49 --- /dev/null +++ b/test/comment_test.js @@ -0,0 +1,46 @@ +namespace = "comment_"; + +(function() { + function test(name, mode, run, before, after) { + return testCM(name, function(cm) { + run(cm); + eq(cm.getValue(), after); + }, {value: before, mode: mode}); + } + + var simpleProg = "function foo() {\n return bar;\n}"; + + test("block", "javascript", function(cm) { + cm.blockComment(Pos(0, 3), Pos(3, 0), {blockCommentLead: " *"}); + }, simpleProg + "\n", "/* function foo() {\n * return bar;\n * }\n */"); + + test("blockToggle", "javascript", function(cm) { + cm.blockComment(Pos(0, 3), Pos(2, 0), {blockCommentLead: " *"}); + cm.uncomment(Pos(0, 3), Pos(2, 0), {blockCommentLead: " *"}); + }, simpleProg, simpleProg); + + test("line", "javascript", function(cm) { + cm.lineComment(Pos(1, 1), Pos(1, 1)); + }, simpleProg, "function foo() {\n// return bar;\n}"); + + test("lineToggle", "javascript", function(cm) { + cm.lineComment(Pos(0, 0), Pos(2, 1)); + cm.uncomment(Pos(0, 0), Pos(2, 1)); + }, simpleProg, simpleProg); + + test("fallbackToBlock", "css", function(cm) { + cm.lineComment(Pos(0, 0), Pos(2, 1)); + }, "html {\n border: none;\n}", "/* html {\n border: none;\n} */"); + + test("fallbackToLine", "ruby", function(cm) { + cm.blockComment(Pos(0, 0), Pos(1)); + }, "def blah()\n return hah\n", "# def blah()\n# return hah\n"); + + test("commentRange", "javascript", function(cm) { + cm.blockComment(Pos(1, 2), Pos(1, 13), {fullLines: false}); + }, simpleProg, "function foo() {\n /*return bar;*/\n}"); + + test("indented", "javascript", function(cm) { + cm.lineComment(Pos(1, 0), Pos(2), {indent: true}); + }, simpleProg, "function foo() {\n // return bar;\n // }"); +})(); diff --git a/test/driver.js b/test/driver.js index aba427702e..ae79c328fe 100644 --- a/test/driver.js +++ b/test/driver.js @@ -23,8 +23,9 @@ function test(name, run, expectedFail) { tests.push({name: name, func: run, expectedFail: expectedFail}); return name; } +var namespace = ""; function testCM(name, run, opts, expectedFail) { - return test("core_" + name, function() { + return test(namespace + name, function() { var place = document.getElementById("testground"), cm = CodeMirror(place, opts); var successful = false; try { diff --git a/test/index.html b/test/index.html index d397e8f7a2..816cef5948 100644 --- a/test/index.html +++ b/test/index.html @@ -9,6 +9,7 @@ + @@ -53,6 +54,7 @@

    CodeMirror: Test Suite

    + diff --git a/test/test.js b/test/test.js index 93d899a66e..637f6e79ca 100644 --- a/test/test.js +++ b/test/test.js @@ -32,6 +32,8 @@ var opera_version = opera && navigator.userAgent.match(/Version\/(\d+\.\d+)/); if (opera_version) opera_version = Number(opera_version); var opera_lt10 = opera && (!opera_version || opera_version < 10); +namespace = "core_"; + test("core_fromTextArea", function() { var te = document.getElementById("code"); te.value = "CONTENT"; From 3095862234bed78cb2dda2581ffe17cad5878a63 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 13 May 2013 13:53:18 +0200 Subject: [PATCH 0571/5273] [comment addon] Fix lint errors --- addon/comment/comment.js | 5 ++--- addon/lint/lint.js | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/addon/comment/comment.js b/addon/comment/comment.js index 2963268a72..ae42b6bcd5 100644 --- a/addon/comment/comment.js +++ b/addon/comment/comment.js @@ -1,6 +1,6 @@ (function() { "use strict"; - + var noOptions = {}; var nonWS = /[^\s\u00a0]/; var Pos = CodeMirror.Pos; @@ -34,7 +34,6 @@ self.operation(function() { if (options.indent) { - var baseCol = CodeMirror.countColumn(firstLine, null, tabSize); var baseString = firstLine.slice(0, firstNonWS(firstLine)); for (var i = from.line; i < end; ++i) { var line = self.getLine(i), cut = baseString.length; @@ -112,7 +111,7 @@ }); return true; } - + // Try block comments var startString = options.blockCommentStart || mode.blockCommentStart; var endString = options.blockCommentEnd || mode.blockCommentEnd; diff --git a/addon/lint/lint.js b/addon/lint/lint.js index ca05da76ef..29fd8d9c3c 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -105,11 +105,11 @@ CodeMirror.validate = (function() { } function startLinting(cm) { - var state = cm._lintState, options = state.options; - if (options.async) - options.getAnnotations(cm, updateLinting, options); - else - updateLinting(cm, options.getAnnotations(cm.getValue())); + var state = cm._lintState, options = state.options; + if (options.async) + options.getAnnotations(cm, updateLinting, options); + else + updateLinting(cm, options.getAnnotations(cm.getValue())); } function updateLinting(cm, annotationsNotSorted) { From 669c8dd45baff0193e3ac78c325c5d903af74c15 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 13 May 2013 14:05:30 +0200 Subject: [PATCH 0572/5273] [comment addon] Another lint fix --- addon/comment/comment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/comment/comment.js b/addon/comment/comment.js index ae42b6bcd5..4f590f2870 100644 --- a/addon/comment/comment.js +++ b/addon/comment/comment.js @@ -26,7 +26,7 @@ } return; } - var tabSize = self.getOption("tabSize"), firstLine = self.getLine(from.line); + var firstLine = self.getLine(from.line); if (firstLine == null) return; var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1); var pad = options.padding == null ? " " : options.padding; From 373cb16763574e3d1d31847f2fb911472d06114d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 13 May 2013 14:11:59 +0200 Subject: [PATCH 0573/5273] Fix context menu select-all in IE9+ Closes #1522 --- lib/codemirror.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 699f55a4c5..fec1d582d9 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2097,6 +2097,13 @@ window.CodeMirror = (function() { // Adds "Select all" to context menu in FF if (posEq(sel.from, sel.to)) display.input.value = display.prevInput = " "; + function prepareSelectAllHack() { + if (display.input.selectionStart != null) { + var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" : display.input.value); + display.prevInput = " "; + display.input.selectionStart = 1; display.input.selectionEnd = extval.length; + } + } function rehide() { display.inputDiv.style.position = "relative"; display.input.style.cssText = oldCSS; @@ -2104,12 +2111,10 @@ window.CodeMirror = (function() { slowPoll(cm); // Try to detect the user choosing select-all - if (display.input.selectionStart != null && (!ie || ie_lt9)) { + if (display.input.selectionStart != null) { + if (!ie || ie_lt9) prepareSelectAllHack(); clearTimeout(detectingSelectAll); - var extval = display.input.value = " " + (posEq(sel.from, sel.to) ? "" : display.input.value), i = 0; - display.prevInput = " "; - display.input.selectionStart = 1; display.input.selectionEnd = extval.length; - var poll = function(){ + var i = 0, poll = function(){ if (display.prevInput == " " && display.input.selectionStart == 0) operation(cm, commands.selectAll)(cm); else if (i++ < 10) detectingSelectAll = setTimeout(poll, 500); @@ -2119,6 +2124,7 @@ window.CodeMirror = (function() { } } + if (ie && !ie_lt9) prepareSelectAllHack(); if (captureMiddleClick) { e_stop(e); var mouseup = function() { From fb6df35b2e9c79d6fe4b834d92b8f7ed0407f385 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 13 May 2013 16:27:06 +0200 Subject: [PATCH 0574/5273] [less mode] Remove fixed list of tags It makes no sense. Issue #1466 --- mode/less/less.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/mode/less/less.js b/mode/less/less.js index 6df4790995..09f510e032 100644 --- a/mode/less/less.js +++ b/mode/less/less.js @@ -7,12 +7,6 @@ CodeMirror.defineMode("less", function(config) { var indentUnit = config.indentUnit, type; function ret(style, tp) {type = tp; return style;} - //html tags - var tags = "a abbr acronym address applet area article aside audio b base basefont bdi bdo big blockquote body br button canvas caption cite code col colgroup command datalist dd del details dfn dir div dl dt em embed fieldset figcaption figure font footer form frame frameset h1 h2 h3 h4 h5 h6 head header hgroup hr html i iframe img input ins keygen kbd label legend li link map mark menu meta meter nav noframes noscript object ol optgroup option output p param pre progress q rp rt ruby s samp script section select small source span strike strong style sub summary sup table tbody td textarea tfoot th thead time title tr track tt u ul var video wbr".split(' '); - - function inTagsArray(val){ - for(var i=0; i Date: Mon, 13 May 2013 22:43:29 +0200 Subject: [PATCH 0575/5273] [vim keymap] Add actionArgs for command 'i' 'I' --- keymap/vim.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 48276836ca..4d7833f14e 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -245,9 +245,10 @@ actionArgs: { insertAt: 'charAfter' }}, { keys: ['A'], type: 'action', action: 'enterInsertMode', actionArgs: { insertAt: 'eol' }}, - { keys: ['i'], type: 'action', action: 'enterInsertMode' }, + { keys: ['i'], type: 'action', action: 'enterInsertMode', + actionArgs: { insertAt: 'inplace' }}, { keys: ['I'], type: 'action', action: 'enterInsertMode', - motion: 'moveToFirstNonWhiteSpaceCharacter' }, + actionArgs: { insertAt: 'firstNonBlank' }}, { keys: ['o'], type: 'action', action: 'newLineAndEnterInsertMode', actionArgs: { after: true }}, { keys: ['O'], type: 'action', action: 'newLineAndEnterInsertMode', @@ -368,7 +369,7 @@ return false; } - var circularJumpList = function() { + var createCircularJumpList = function() { var size = 100; var pointer = -1; var head = 0; @@ -442,7 +443,7 @@ searchQuery: null, // Whether we are searching backwards. searchIsReversed: false, - jumpList: circularJumpList(), + jumpList: createCircularJumpList(), // Recording latest f, t, F or T motion command. lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''}, registerController: new RegisterController({}) @@ -1528,6 +1529,8 @@ cm.setCursor(cursor); } else if (insertAt == 'charAfter') { cm.setCursor(offsetCursor(cm.getCursor(), 0, 1)); + } else if (insertAt == 'firstNonBlank') { ++ cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm)); } cm.setOption('keyMap', 'vim-insert'); }, From 1f3e26ab6869f0a3de97f5cf01e37c93e54f4a7f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 14 May 2013 10:51:09 +0200 Subject: [PATCH 0576/5273] [vim keymap] Remove stray plus character Issue #1525 --- keymap/vim.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keymap/vim.js b/keymap/vim.js index 4d7833f14e..3640e65be8 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1530,7 +1530,7 @@ } else if (insertAt == 'charAfter') { cm.setCursor(offsetCursor(cm.getCursor(), 0, 1)); } else if (insertAt == 'firstNonBlank') { -+ cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm)); + cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm)); } cm.setOption('keyMap', 'vim-insert'); }, From b5e0401e4424084e39cd3762feb284c01cc9caf6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 14 May 2013 11:13:46 +0200 Subject: [PATCH 0577/5273] Allow mode spec objects to have mime types as name Other properties will be added/overridden in the config object for the mime type. --- lib/codemirror.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index fec1d582d9..15a092f9c4 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3180,10 +3180,15 @@ window.CodeMirror = (function() { }; CodeMirror.resolveMode = function(spec) { - if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) + if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { spec = mimeModes[spec]; - else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) + } else if (typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + var found = mimeModes[spec.name]; + spec = createObj(found, spec); + spec.name = found.name; + } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { return CodeMirror.resolveMode("application/xml"); + } if (typeof spec == "string") return {name: spec}; else return spec || {name: "null"}; }; From c3cb802df2e001bc0b2d1b78766a603a48ec2d1b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 14 May 2013 11:18:16 +0200 Subject: [PATCH 0578/5273] [clike mode] Fix interaction of dontAlignCalls and statementIndentUnit Closes #1518 --- mode/clike/clike.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 83bf8019f2..09621bc08d 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -150,8 +150,8 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; var closing = firstChar == ctx.type; if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); - else if (dontAlignCalls && ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit; - else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else if (ctx.align && (!dontAlignCalls || ctx.type != ")")) return ctx.column + (closing ? 0 : 1); + else if (ctx.type == ")" && !closing) return ctx.indented + statementIndentUnit; else return ctx.indented + (closing ? 0 : indentUnit); }, From 00504d8a36c1cd4cb5699601bc49ca1012c2fe78 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 14 May 2013 11:25:48 +0200 Subject: [PATCH 0579/5273] Don't crash when getMode is passed null --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 15a092f9c4..7f5f672adb 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3182,7 +3182,7 @@ window.CodeMirror = (function() { CodeMirror.resolveMode = function(spec) { if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { spec = mimeModes[spec]; - } else if (typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { + } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { var found = mimeModes[spec.name]; spec = createObj(found, spec); spec.name = found.name; From ea523decb8bd3562bfaae4891903c46e9c190f87 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 15 May 2013 13:03:59 +0200 Subject: [PATCH 0580/5273] Shuffle real-world uses on front page, add Bitbucket and JSFiddle --- doc/realworld.html | 2 ++ index.html | 39 ++++++++++++++++++++------------------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/doc/realworld.html b/doc/realworld.html index c3f2c814fc..941d926dbe 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -25,6 +25,7 @@

    { } CodeMi
  • Adobe Brackets (code editor)
  • Amber (JavaScript-based Smalltalk system)
  • APEye (tool for testing & documenting APIs)
  • +
  • Bitbucket (code hosting)
  • Blogger's template editor
  • BlueGriffon (HTML editor)
  • Cargo Collective (creative publishing platform)
  • @@ -66,6 +67,7 @@

    { } CodeMi
  • Joomla plugin
  • jQuery fundamentals (interactive tutorial)
  • jsbin.com (JS playground)
  • +
  • jsfiddle.com (another JS playground)
  • JSHint (JS linter)
  • Jumpseller (online store builder)
  • kl1p (paste service)
  • diff --git a/index.html b/index.html index 1dba41984b..a0d3d5b48f 100644 --- a/index.html +++ b/index.html @@ -120,28 +120,29 @@

    Usage demos:

    Real-world uses:

    From 36fe7d5b4a3ffdd804933a323a45f23ae0885e20 Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Tue, 14 May 2013 23:16:39 +0200 Subject: [PATCH 0581/5273] [vim keymap] Change defaultKeymap notation format --- keymap/vim.js | 108 ++++++++++++++++++----------------------------- test/vim_test.js | 62 +++++++++++++-------------- 2 files changed, 73 insertions(+), 97 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 3640e65be8..9c0197faaa 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -58,26 +58,26 @@ var defaultKeymap = [ // Key to key mapping. This goes first to make it possible to override // existing mappings. - { keys: ['Left'], type: 'keyToKey', toKeys: ['h'] }, - { keys: ['Right'], type: 'keyToKey', toKeys: ['l'] }, - { keys: ['Up'], type: 'keyToKey', toKeys: ['k'] }, - { keys: ['Down'], type: 'keyToKey', toKeys: ['j'] }, - { keys: ['Space'], type: 'keyToKey', toKeys: ['l'] }, - { keys: ['Backspace'], type: 'keyToKey', toKeys: ['h'] }, - { keys: ['Ctrl-Space'], type: 'keyToKey', toKeys: ['W'] }, - { keys: ['Ctrl-Backspace'], type: 'keyToKey', toKeys: ['B'] }, - { keys: ['Shift-Space'], type: 'keyToKey', toKeys: ['w'] }, - { keys: ['Shift-Backspace'], type: 'keyToKey', toKeys: ['b'] }, - { keys: ['Ctrl-n'], type: 'keyToKey', toKeys: ['j'] }, - { keys: ['Ctrl-p'], type: 'keyToKey', toKeys: ['k'] }, - { keys: ['Ctrl-['], type: 'keyToKey', toKeys: ['Esc'] }, - { keys: ['Ctrl-c'], type: 'keyToKey', toKeys: ['Esc'] }, + { keys: [''], type: 'keyToKey', toKeys: ['h'] }, + { keys: [''], type: 'keyToKey', toKeys: ['l'] }, + { keys: [''], type: 'keyToKey', toKeys: ['k'] }, + { keys: [''], type: 'keyToKey', toKeys: ['j'] }, + { keys: [''], type: 'keyToKey', toKeys: ['l'] }, + { keys: [''], type: 'keyToKey', toKeys: ['h'] }, + { keys: [''], type: 'keyToKey', toKeys: ['W'] }, + { keys: [''], type: 'keyToKey', toKeys: ['B'] }, + { keys: [''], type: 'keyToKey', toKeys: ['w'] }, + { keys: [''], type: 'keyToKey', toKeys: ['b'] }, + { keys: [''], type: 'keyToKey', toKeys: ['j'] }, + { keys: [''], type: 'keyToKey', toKeys: ['k'] }, + { keys: ['C-['], type: 'keyToKey', toKeys: [''] }, + { keys: [''], type: 'keyToKey', toKeys: [''] }, { keys: ['s'], type: 'keyToKey', toKeys: ['c', 'l'] }, { keys: ['S'], type: 'keyToKey', toKeys: ['c', 'c'] }, - { keys: ['Home'], type: 'keyToKey', toKeys: ['0'] }, - { keys: ['End'], type: 'keyToKey', toKeys: ['$'] }, - { keys: ['PageUp'], type: 'keyToKey', toKeys: ['Ctrl-b'] }, - { keys: ['PageDown'], type: 'keyToKey', toKeys: ['Ctrl-f'] }, + { keys: [''], type: 'keyToKey', toKeys: ['0'] }, + { keys: [''], type: 'keyToKey', toKeys: ['$'] }, + { keys: [''], type: 'keyToKey', toKeys: [''] }, + { keys: [''], type: 'keyToKey', toKeys: [''] }, // Motions { keys: ['H'], type: 'motion', motion: 'moveToTopLine', @@ -136,14 +136,14 @@ motionArgs: { forward: false, toJumplist: true }}, { keys: ['}'], type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: true, toJumplist: true }}, - { keys: ['Ctrl-f'], type: 'motion', + { keys: [''], type: 'motion', motion: 'moveByPage', motionArgs: { forward: true }}, - { keys: ['Ctrl-b'], type: 'motion', + { keys: [''], type: 'motion', motion: 'moveByPage', motionArgs: { forward: false }}, - { keys: ['Ctrl-d'], type: 'motion', + { keys: [''], type: 'motion', motion: 'moveByScroll', motionArgs: { forward: true, explicitRepeat: true }}, - { keys: ['Ctrl-u'], type: 'motion', + { keys: [''], type: 'motion', motion: 'moveByScroll', motionArgs: { forward: false, explicitRepeat: true }}, { keys: ['g', 'g'], type: 'motion', @@ -237,9 +237,9 @@ { keys: ['~'], type: 'operatorMotion', operator: 'swapcase', motion: 'moveByCharacters', motionArgs: { forward: true }}, // Actions - { keys: ['Ctrl-i'], type: 'action', action: 'jumpListWalk', + { keys: [''], type: 'action', action: 'jumpListWalk', actionArgs: { forward: true }}, - { keys: ['Ctrl-o'], type: 'action', action: 'jumpListWalk', + { keys: [''], type: 'action', action: 'jumpListWalk', actionArgs: { forward: false }}, { keys: ['a'], type: 'action', action: 'enterInsertMode', actionArgs: { insertAt: 'charAfter' }}, @@ -264,7 +264,7 @@ { keys: ['r', 'character'], type: 'action', action: 'replace' }, { keys: ['R'], type: 'action', action: 'enterReplaceMode' }, { keys: ['u'], type: 'action', action: 'undo' }, - { keys: ['Ctrl-r'], type: 'action', action: 'redo' }, + { keys: [''], type: 'action', action: 'redo' }, { keys: ['m', 'character'], type: 'action', action: 'setMark' }, { keys: ['\"', 'character'], type: 'action', action: 'setRegister' }, { keys: ['z', 'z'], type: 'action', action: 'scrollToCursor', @@ -274,7 +274,7 @@ motion: 'moveToFirstNonWhiteSpaceCharacter' }, { keys: ['z', 't'], type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }}, - { keys: ['z', 'Enter'], type: 'action', action: 'scrollToCursor', + { keys: ['z', ''], type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, { keys: ['z', '-'], type: 'action', action: 'scrollToCursor', @@ -283,9 +283,9 @@ actionArgs: { position: 'bottom' }, motion: 'moveToFirstNonWhiteSpaceCharacter' }, { keys: ['.'], type: 'action', action: 'repeatLastEdit' }, - { keys: ['Ctrl-a'], type: 'action', action: 'incrementNumberToken', + { keys: [''], type: 'action', action: 'incrementNumberToken', actionArgs: {increase: true, backtrack: false}}, - { keys: ['Ctrl-x'], type: 'action', action: 'incrementNumberToken', + { keys: [''], type: 'action', action: 'incrementNumberToken', actionArgs: {increase: false, backtrack: false}}, // Text object motions { keys: ['a', 'character'], type: 'motion', @@ -509,7 +509,7 @@ handleKey: function(cm, key) { var command; var vim = getVimState(cm); - if (key == 'Esc') { + if (key == '') { // Clear input state and get back to normal mode. vim.inputState = new InputState(); if (vim.visualMode) { @@ -717,10 +717,10 @@ inputState.selectedCharacter = keys[keys.length - 1]; if(inputState.selectedCharacter.length>1){ switch(inputState.selectedCharacter){ - case "Enter": + case "": inputState.selectedCharacter='\n'; break; - case "Space": + case "": inputState.selectedCharacter=' '; break; default: @@ -2930,41 +2930,14 @@ // Converts a key string sequence of the form abd into Vim's // keymap representation. function parseKeyString(str) { - var idx = 0; + var key, match; var keys = []; - while (idx < str.length) { - if (str.charAt(idx) != '<') { - keys.push(str.charAt(idx)); - idx++; - continue; - } - // Vim key notation here means desktop Vim key-notation. - // See :help key-notation in desktop Vim. - var vimKeyNotationStart = ++idx; - while (str.charAt(idx++) != '>') {} - var vimKeyNotation = str.substring(vimKeyNotationStart, idx - 1); - var mod=''; - var match = (/^C-(.+)$/).exec(vimKeyNotation); - if (match) { - mod='Ctrl-'; - vimKeyNotation=match[1]; - } - var key; - switch (vimKeyNotation) { - case 'BS': - key = 'Backspace'; - break; - case 'CR': - key = 'Enter'; - break; - case 'Del': - key = 'Delete'; - break; - default: - key = vimKeyNotation; - break; - } - keys.push(mod + key); + while (str) { + match = (/<\w+-.+?>|<\w+>|./).exec(str); + if(match === null)break; + key = match[0]; + str = str.substring(match.index + key.length); + keys.push(key); } return keys; } @@ -3148,8 +3121,11 @@ } if (modifier) { // Vim will parse modifier+key combination as a single key. - key = modifier + '-' + key; + key = modifier.charAt(0) + '-' + key; } + var specialKey = ({Enter:'CR',Backspace:'BS',Delete:'Del'})[key]; + key = specialKey ? specialKey : key; + key = key.length > 1 ? '<'+ key + '>' : key; vim.handleKey(cm, key); } diff --git a/test/vim_test.js b/test/vim_test.js index f2304b99cf..83bbec9ac6 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -190,32 +190,32 @@ function testJumplist(name, keys, endPos, startPos, dialog) { helpers.assertCursorAt(endPos); }, {value: jumplistScene}); }; -testJumplist('jumplist_H', ['H', 'Ctrl-o'], [5,2], [5,2]); -testJumplist('jumplist_M', ['M', 'Ctrl-o'], [2,2], [2,2]); -testJumplist('jumplist_L', ['L', 'Ctrl-o'], [2,2], [2,2]); -testJumplist('jumplist_[[', ['[', '[', 'Ctrl-o'], [5,2], [5,2]); -testJumplist('jumplist_]]', [']', ']', 'Ctrl-o'], [2,2], [2,2]); -testJumplist('jumplist_G', ['G', 'Ctrl-o'], [5,2], [5,2]); -testJumplist('jumplist_gg', ['g', 'g', 'Ctrl-o'], [5,2], [5,2]); -testJumplist('jumplist_%', ['%', 'Ctrl-o'], [1,5], [1,5]); -testJumplist('jumplist_{', ['{', 'Ctrl-o'], [1,5], [1,5]); -testJumplist('jumplist_}', ['}', 'Ctrl-o'], [1,5], [1,5]); -testJumplist('jumplist_\'', ['m', 'a', 'h', '\'', 'a', 'h', 'Ctrl-i'], [1,5], [1,5]); -testJumplist('jumplist_`', ['m', 'a', 'h', '`', 'a', 'h', 'Ctrl-i'], [1,5], [1,5]); -testJumplist('jumplist_*_cachedCursor', ['*', 'Ctrl-o'], [1,3], [1,3]); -testJumplist('jumplist_#_cachedCursor', ['#', 'Ctrl-o'], [1,3], [1,3]); -testJumplist('jumplist_n', ['#', 'n', 'Ctrl-o'], [1,1], [2,3]); -testJumplist('jumplist_N', ['#', 'N', 'Ctrl-o'], [1,1], [2,3]); -testJumplist('jumplist_repeat_', ['*', '*', '*', '3', 'Ctrl-o'], [2,3], [2,3]); -testJumplist('jumplist_repeat_', ['*', '*', '*', '3', 'Ctrl-o', '2', 'Ctrl-i'], [5,0], [2,3]); -testJumplist('jumplist_repeated_motion', ['3', '*', 'Ctrl-o'], [2,3], [2,3]); -testJumplist('jumplist_/', ['/', 'Ctrl-o'], [2,3], [2,3], 'dialog'); -testJumplist('jumplist_?', ['?', 'Ctrl-o'], [2,3], [2,3], 'dialog'); +testJumplist('jumplist_H', ['H', ''], [5,2], [5,2]); +testJumplist('jumplist_M', ['M', ''], [2,2], [2,2]); +testJumplist('jumplist_L', ['L', ''], [2,2], [2,2]); +testJumplist('jumplist_[[', ['[', '[', ''], [5,2], [5,2]); +testJumplist('jumplist_]]', [']', ']', ''], [2,2], [2,2]); +testJumplist('jumplist_G', ['G', ''], [5,2], [5,2]); +testJumplist('jumplist_gg', ['g', 'g', ''], [5,2], [5,2]); +testJumplist('jumplist_%', ['%', ''], [1,5], [1,5]); +testJumplist('jumplist_{', ['{', ''], [1,5], [1,5]); +testJumplist('jumplist_}', ['}', ''], [1,5], [1,5]); +testJumplist('jumplist_\'', ['m', 'a', 'h', '\'', 'a', 'h', ''], [1,5], [1,5]); +testJumplist('jumplist_`', ['m', 'a', 'h', '`', 'a', 'h', ''], [1,5], [1,5]); +testJumplist('jumplist_*_cachedCursor', ['*', ''], [1,3], [1,3]); +testJumplist('jumplist_#_cachedCursor', ['#', ''], [1,3], [1,3]); +testJumplist('jumplist_n', ['#', 'n', ''], [1,1], [2,3]); +testJumplist('jumplist_N', ['#', 'N', ''], [1,1], [2,3]); +testJumplist('jumplist_repeat_', ['*', '*', '*', '3', ''], [2,3], [2,3]); +testJumplist('jumplist_repeat_', ['*', '*', '*', '3', '', '2', ''], [5,0], [2,3]); +testJumplist('jumplist_repeated_motion', ['3', '*', ''], [2,3], [2,3]); +testJumplist('jumplist_/', ['/', ''], [2,3], [2,3], 'dialog'); +testJumplist('jumplist_?', ['?', ''], [2,3], [2,3], 'dialog'); testJumplist('jumplist_skip_delted_mark', - ['*', 'n', 'n', 'k', 'd', 'k', 'Ctrl-o', 'Ctrl-o', 'Ctrl-o'], + ['*', 'n', 'n', 'k', 'd', 'k', '', '', ''], [0,2], [0,2]); testJumplist('jumplist_skip_delted_mark', - ['*', 'n', 'n', 'k', 'd', 'k', 'Ctrl-o', 'Ctrl-i', 'Ctrl-i'], + ['*', 'n', 'n', 'k', 'd', 'k', '', '', ''], [1,0], [0,2]); /** * @param name Name of the test @@ -970,22 +970,22 @@ testVim('Y', function(cm, vim, helpers) { // Action tests testVim('ctrl-a', function(cm, vim, helpers) { cm.setCursor(0, 0); - helpers.doKeys('Ctrl-a'); + helpers.doKeys(''); eq('-9', cm.getValue()); helpers.assertCursorAt(0, 1); - helpers.doKeys('2','Ctrl-a'); + helpers.doKeys('2',''); eq('-7', cm.getValue()); }, {value: '-10'}); testVim('ctrl-x', function(cm, vim, helpers) { cm.setCursor(0, 0); - helpers.doKeys('Ctrl-x'); + helpers.doKeys(''); eq('-1', cm.getValue()); helpers.assertCursorAt(0, 1); - helpers.doKeys('2','Ctrl-x'); + helpers.doKeys('2',''); eq('-3', cm.getValue()); }, {value: '0'}); -testVim('Ctrl-x/Ctrl-a search forward', function(cm, vim, helpers) { - ['Ctrl-x', 'Ctrl-a'].forEach(function(key) { +testVim('/ search forward', function(cm, vim, helpers) { + ['', ''].forEach(function(key) { cm.setCursor(0, 0); helpers.doKeys(key); helpers.assertCursorAt(0, 5); @@ -1103,7 +1103,7 @@ testVim('r', function(cm, vim, helpers) { eq('wuuuet\nanother', cm.getValue(),'3r failed'); helpers.assertCursorAt(0, 3); cm.setCursor(0, 4); - helpers.doKeys('v', 'j', 'h', 'r', 'Space'); + helpers.doKeys('v', 'j', 'h', 'r', ''); eq('wuuu \n her', cm.getValue(),'Replacing selection by space-characters failed'); }, { value: 'wordet\nanother' }); testVim('R', function(cm, vim, helpers) { @@ -2001,7 +2001,7 @@ testVim('ex_api_test', function(cm, vim, helpers) { helpers.doEx(':ext to'); eq(val,'to','Defining ex-command failed'); CodeMirror.Vim.map('',':ext'); - helpers.doKeys('Ctrl-Enter','Space'); + helpers.doKeys('',''); is(res,'Mapping to key failed'); }); // For now, this test needs to be last because it messes up : for future tests. From 9a8282fd1d310b3bf61d101b230b4766a933688c Mon Sep 17 00:00:00 2001 From: Alex Piggott Date: Wed, 15 May 2013 13:14:57 +0200 Subject: [PATCH 0582/5273] [brace-fold addon] Also handle square brackets --- addon/fold/brace-fold.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/addon/fold/brace-fold.js b/addon/fold/brace-fold.js index dc78883f35..efdffb877c 100644 --- a/addon/fold/brace-fold.js +++ b/addon/fold/brace-fold.js @@ -3,17 +3,23 @@ CodeMirror.braceRangeFinder = function(cm, start) { var at = lineText.length, startChar, tokenType; for (; at > 0;) { var found = lineText.lastIndexOf("{", at); - if (found < start.ch) break; + var startToken = '{', endToken = '}'; + if (found < start.ch) { + found = lineText.lastIndexOf("[", at); + if (found < start.ch) break; + startToken = '['; endToken = ']'; + } + tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type; if (!/^(comment|string)/.test(tokenType)) { startChar = found; break; } at = found - 1; } - if (startChar == null || lineText.lastIndexOf("}") > startChar) return; + if (startChar == null || lineText.lastIndexOf(startToken) > startChar) return; var count = 1, lastLine = cm.lineCount(), end, endCh; outer: for (var i = line + 1; i < lastLine; ++i) { var text = cm.getLine(i), pos = 0; for (;;) { - var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos); + var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); if (nextOpen < 0) nextOpen = text.length; if (nextClose < 0) nextClose = text.length; pos = Math.min(nextOpen, nextClose); From 6b7e2953febaba158e6128b7a3d07b7b02c88636 Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Mon, 13 May 2013 19:12:09 +0400 Subject: [PATCH 0583/5273] mark-selection addon improvement Addresses issue #1484 and speeds up mark-selection add-on by maintaining text selection coverage with small chunks of text marks. --- addon/selection/mark-selection.js | 135 +++++++++++++++++++++++++++--- 1 file changed, 125 insertions(+), 10 deletions(-) diff --git a/addon/selection/mark-selection.js b/addon/selection/mark-selection.js index d7ff30c9a9..80eb9def0f 100644 --- a/addon/selection/mark-selection.js +++ b/addon/selection/mark-selection.js @@ -13,22 +13,137 @@ cm.on("cursorActivity", updateSelectedText); } else if (!val && prev) { cm.off("cursorActivity", updateSelectedText); - clearSelectedText(cm); - delete cm._selectionMark; + removeTextMarks(cm); } }); - function clearSelectedText(cm) { - if (cm._selectionMark) cm._selectionMark.clear(); + function cmp(pos1, pos2) { + return pos1.line !== pos2.line ? pos1.line - pos2.line : pos1.ch - pos2.ch; + } + + function removeTextMarks(cm) { + if (cm._selectionMarks) { + for(var i = 0; i < cm._selectionMarks.length; ++i) { + cm._selectionMarks[i].clear(); + } + } + cm._selectionMarks = null; + } + + function markText(cm, start, end) { + if (cmp(start, end) === 0) + return; + var opt = {className: "CodeMirror-selectedtext"}; + cm._selectionMarks.push(cmp(start, end) <= 0 ? cm.markText(start, end, opt) : cm.markText(end, start, opt)); + } + + var CHUNK_SIZE = 8; + var Pos = CodeMirror.Pos; + + function coverRange(cm, anchor, head) { + if (Math.abs(anchor.line - head.line) < CHUNK_SIZE) { + markText(cm, anchor, head); + return; + } + if (head.line > anchor.line) { + markText(cm, anchor, Pos(anchor.line + CHUNK_SIZE, 0)); + for(var line = anchor.line + CHUNK_SIZE; line + CHUNK_SIZE < head.line; line += CHUNK_SIZE) + markText(cm, Pos(line, 0), Pos(line + CHUNK_SIZE, 0)); + markText(cm, Pos(line, 0), head); + } else { + markText(cm, anchor, Pos(anchor.line - CHUNK_SIZE + 1, 0)); + for(var line = anchor.line - CHUNK_SIZE + 1; line - CHUNK_SIZE > head.line; line -= CHUNK_SIZE) + markText(cm, Pos(line, 0), Pos(line - CHUNK_SIZE, 0)); + markText(cm, Pos(line, 0), head); + } + } + + function createInitialCoverage(cm) { + var anchor = cm.getCursor("anchor"); + var head = cm.getCursor("head"); + cm._selectionMarks = []; + coverRange(cm, anchor, head); + } + + function getCoveredRange(cm) { + var first = cm._selectionMarks[0].find(); + var last = cm._selectionMarks[cm._selectionMarks.length - 1].find(); + if (!first || !last) + return null; + var reversed = cmp(first.from, last.to) >= 0; + return reversed ? {anchor: first.to, head: last.from, reversed: reversed} : {anchor: first.from, head: last.to, reversed: reversed}; + } + + function incrementalCoverageUpdate(cm) { + var anchor = cm.getCursor("anchor"); + var head = cm.getCursor("head"); + var reversed = cmp(head, anchor) < 0; + var lastSelection = getCoveredRange(cm); + // if the anchor of selection moved or selection changed direction - remove everything and construct from scratch. + if (!lastSelection || cmp(anchor, lastSelection.anchor) !== 0 || (reversed ^ lastSelection.reversed)) { + removeTextMarks(cm); + createInitialCoverage(cm); + return; + } + // fast return if nothing changed + if (cmp(head, lastSelection.head) === 0) + return; + + // if only column changed then update last text mark + if (head.line === lastSelection.head.line) { + var lastMark = cm._selectionMarks.pop(); + var position = lastMark.find(); + lastMark.clear(); + markText(cm, reversed ? position.to : position.from, head); + return; + } + + if (!reversed) { + // if selection shrinks + if (head.line < lastSelection.head.line) { + var textMark, + position; + do { + textMark = cm._selectionMarks.pop(); + position = textMark.find(); + textMark.clear(); + } while (cm._selectionMarks.length && position.from.line >= head.line); + markText(cm, position.from, head); + } else { + var textMark = cm._selectionMarks.pop(); + var position = textMark.find(); + textMark.clear(); + coverRange(cm, position.from, head); + } + } else { + // selection getting smaller + if (head.line > lastSelection.head.line) { + var textMark, + position; + do { + textMark = cm._selectionMarks.pop(); + position = textMark.find(); + textMark.clear(); + } while (cm._selectionMarks.length && position.to.line <= head.line); + markText(cm, position.to, head); + } else { + var textMark = cm._selectionMarks.pop(); + var position = textMark.find(); + coverRange(cm, position.to, head); + textMark.clear(); + } + } } function updateSelectedText(cm) { - clearSelectedText(cm); + cm.operation(function() { + if (!cm.somethingSelected()) + return removeTextMarks(cm); + + if (!cm._selectionMarks || !cm._selectionMarks.length) + return createInitialCoverage(cm); - if (cm.somethingSelected()) - cm._selectionMark = cm.markText(cm.getCursor("start"), cm.getCursor("end"), - {className: "CodeMirror-selectedtext"}); - else - cm._selectionMark = null; + incrementalCoverageUpdate(cm); + }); } })(); From 5a5f9f4e25b1a88de413fbca295881beacd5b82a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 16 May 2013 11:32:46 +0200 Subject: [PATCH 0584/5273] [mark-selection addon] Simplify Issue #1523 --- addon/selection/mark-selection.js | 183 ++++++++++++------------------ 1 file changed, 71 insertions(+), 112 deletions(-) diff --git a/addon/selection/mark-selection.js b/addon/selection/mark-selection.js index 80eb9def0f..c97776e492 100644 --- a/addon/selection/mark-selection.js +++ b/addon/selection/mark-selection.js @@ -1,7 +1,8 @@ // Because sometimes you need to mark the selected *text*. // // Adds an option 'styleSelectedText' which, when enabled, gives -// selected text the CSS class "CodeMirror-selectedtext". +// selected text the CSS class given as option value, or +// "CodeMirror-selectedtext" when the value is not a string. (function() { "use strict"; @@ -9,141 +10,99 @@ CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) { var prev = old && old != CodeMirror.Init; if (val && !prev) { - updateSelectedText(cm); - cm.on("cursorActivity", updateSelectedText); + cm.state.markedSelection = []; + cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext"; + reset(cm); + cm.on("cursorActivity", onCursorActivity); + cm.on("change", onChange); } else if (!val && prev) { - cm.off("cursorActivity", updateSelectedText); - removeTextMarks(cm); + cm.off("cursorActivity", onCursorActivity); + cm.off("change", onChange); + clear(cm); + cm.state.markedSelection = cm.state.markedSelectionStyle = null; } }); - function cmp(pos1, pos2) { - return pos1.line !== pos2.line ? pos1.line - pos2.line : pos1.ch - pos2.ch; - } - - function removeTextMarks(cm) { - if (cm._selectionMarks) { - for(var i = 0; i < cm._selectionMarks.length; ++i) { - cm._selectionMarks[i].clear(); - } - } - cm._selectionMarks = null; + function onCursorActivity(cm) { + cm.operation(function() { update(cm); }); } - function markText(cm, start, end) { - if (cmp(start, end) === 0) - return; - var opt = {className: "CodeMirror-selectedtext"}; - cm._selectionMarks.push(cmp(start, end) <= 0 ? cm.markText(start, end, opt) : cm.markText(end, start, opt)); + function onChange(cm) { + if (cm.state.markedSelection.length) + cm.operation(function() { clear(cm); }); } var CHUNK_SIZE = 8; var Pos = CodeMirror.Pos; - function coverRange(cm, anchor, head) { - if (Math.abs(anchor.line - head.line) < CHUNK_SIZE) { - markText(cm, anchor, head); - return; - } - if (head.line > anchor.line) { - markText(cm, anchor, Pos(anchor.line + CHUNK_SIZE, 0)); - for(var line = anchor.line + CHUNK_SIZE; line + CHUNK_SIZE < head.line; line += CHUNK_SIZE) - markText(cm, Pos(line, 0), Pos(line + CHUNK_SIZE, 0)); - markText(cm, Pos(line, 0), head); - } else { - markText(cm, anchor, Pos(anchor.line - CHUNK_SIZE + 1, 0)); - for(var line = anchor.line - CHUNK_SIZE + 1; line - CHUNK_SIZE > head.line; line -= CHUNK_SIZE) - markText(cm, Pos(line, 0), Pos(line - CHUNK_SIZE, 0)); - markText(cm, Pos(line, 0), head); + function cmp(pos1, pos2) { + return pos1.line - pos2.line || pos1.ch - pos2.ch; + } + + function coverRange(cm, from, to, addAt) { + if (cmp(from, to) == 0) return; + var array = cm.state.markedSelection; + var cls = cm.state.markedSelectionStyle; + for (var line = from.line;;) { + var start = line == from.line ? from : Pos(line, 0); + var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line; + var end = atEnd ? to : Pos(endLine, 0); + var mark = cm.markText(start, end, {className: cls}); + if (addAt == null) array.push(mark); + else array.splice(addAt++, 0, mark); + if (atEnd) break; + line = endLine; } } - function createInitialCoverage(cm) { - var anchor = cm.getCursor("anchor"); - var head = cm.getCursor("head"); - cm._selectionMarks = []; - coverRange(cm, anchor, head); + function clear(cm) { + var array = cm.state.markedSelection; + for (var i = 0; i < array.length; ++i) array[i].clear(); + array.length = 0; } - function getCoveredRange(cm) { - var first = cm._selectionMarks[0].find(); - var last = cm._selectionMarks[cm._selectionMarks.length - 1].find(); - if (!first || !last) - return null; - var reversed = cmp(first.from, last.to) >= 0; - return reversed ? {anchor: first.to, head: last.from, reversed: reversed} : {anchor: first.from, head: last.to, reversed: reversed}; + function reset(cm) { + clear(cm); + var from = cm.getCursor("start"), to = cm.getCursor("end"); + coverRange(cm, from, to); } - function incrementalCoverageUpdate(cm) { - var anchor = cm.getCursor("anchor"); - var head = cm.getCursor("head"); - var reversed = cmp(head, anchor) < 0; - var lastSelection = getCoveredRange(cm); - // if the anchor of selection moved or selection changed direction - remove everything and construct from scratch. - if (!lastSelection || cmp(anchor, lastSelection.anchor) !== 0 || (reversed ^ lastSelection.reversed)) { - removeTextMarks(cm); - createInitialCoverage(cm); - return; - } - // fast return if nothing changed - if (cmp(head, lastSelection.head) === 0) - return; + function update(cm) { + var from = cm.getCursor("start"), to = cm.getCursor("end"); + if (cmp(from, to) == 0) return clear(cm); - // if only column changed then update last text mark - if (head.line === lastSelection.head.line) { - var lastMark = cm._selectionMarks.pop(); - var position = lastMark.find(); - lastMark.clear(); - markText(cm, reversed ? position.to : position.from, head); - return; - } + var array = cm.state.markedSelection; + if (!array.length) return coverRange(cm, from, to); + + var coverStart = array[0].find(), coverEnd = array[array.length - 1].find(); + if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE || + cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0) + return reset(cm); - if (!reversed) { - // if selection shrinks - if (head.line < lastSelection.head.line) { - var textMark, - position; - do { - textMark = cm._selectionMarks.pop(); - position = textMark.find(); - textMark.clear(); - } while (cm._selectionMarks.length && position.from.line >= head.line); - markText(cm, position.from, head); + while (cmp(from, coverStart.from) > 0) { + array.shift().clear(); + coverStart = array[0].find(); + } + if (cmp(from, coverStart.from) < 0) { + if (coverStart.to.line - from.line < CHUNK_SIZE) { + array.shift().clear(); + coverRange(cm, from, coverStart.to, 0); } else { - var textMark = cm._selectionMarks.pop(); - var position = textMark.find(); - textMark.clear(); - coverRange(cm, position.from, head); + coverRange(cm, from, coverStart.from, 0); } - } else { - // selection getting smaller - if (head.line > lastSelection.head.line) { - var textMark, - position; - do { - textMark = cm._selectionMarks.pop(); - position = textMark.find(); - textMark.clear(); - } while (cm._selectionMarks.length && position.to.line <= head.line); - markText(cm, position.to, head); + } + + while (cmp(to, coverEnd.to) < 0) { + array.pop().clear(); + coverEnd = array[array.length - 1].find(); + } + if (cmp(to, coverEnd.to) > 0) { + if (to.line - coverEnd.from.line < CHUNK_SIZE) { + array.pop().clear(); + coverRange(cm, coverEnd.from, to); } else { - var textMark = cm._selectionMarks.pop(); - var position = textMark.find(); - coverRange(cm, position.to, head); - textMark.clear(); + coverRange(cm, coverEnd.to, to); } } } - - function updateSelectedText(cm) { - cm.operation(function() { - if (!cm.somethingSelected()) - return removeTextMarks(cm); - - if (!cm._selectionMarks || !cm._selectionMarks.length) - return createInitialCoverage(cm); - - incrementalCoverageUpdate(cm); - }); - } })(); From eccea9beaad51a34006430b446892d9a5333e543 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 16 May 2013 11:39:14 +0200 Subject: [PATCH 0585/5273] Move addon state objects into cm.state Rather than polluting the top-level of the editor object --- addon/display/placeholder.js | 8 ++++---- addon/lint/lint.js | 14 +++++++------- addon/search/match-highlighter.js | 8 ++++---- addon/search/search.js | 2 +- addon/selection/active-line.js | 12 ++++++------ 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/addon/display/placeholder.js b/addon/display/placeholder.js index f85f2df127..18f9dff3ab 100644 --- a/addon/display/placeholder.js +++ b/addon/display/placeholder.js @@ -19,14 +19,14 @@ }); function clearPlaceholder(cm) { - if (cm._placeholder) { - cm._placeholder.parentNode.removeChild(cm._placeholder); - cm._placeholder = null; + if (cm.state.placeholder) { + cm.state.placeholder.parentNode.removeChild(cm.state.placeholder); + cm.state.placeholder = null; } } function setPlaceholder(cm) { clearPlaceholder(cm); - var elt = cm._placeholder = document.createElement("pre"); + var elt = cm.state.placeholder = document.createElement("pre"); elt.style.cssText = "height: 0; overflow: visible"; elt.className = "CodeMirror-placeholder"; elt.appendChild(document.createTextNode(cm.getOption("placeholder"))); diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 29fd8d9c3c..2e7cea1925 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -59,7 +59,7 @@ CodeMirror.validate = (function() { } function clearMarks(cm) { - var state = cm._lintState; + var state = cm.state.lint; if (state.hasGutter) cm.clearGutter(GUTTER_ID); for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear(); @@ -105,7 +105,7 @@ CodeMirror.validate = (function() { } function startLinting(cm) { - var state = cm._lintState, options = state.options; + var state = cm.state.lint, options = state.options; if (options.async) options.getAnnotations(cm, updateLinting, options); else @@ -114,7 +114,7 @@ CodeMirror.validate = (function() { function updateLinting(cm, annotationsNotSorted) { clearMarks(cm); - var state = cm._lintState, options = state.options; + var state = cm.state.lint, options = state.options; var annotations = groupByLine(annotationsNotSorted); @@ -148,7 +148,7 @@ CodeMirror.validate = (function() { } function onChange(cm) { - var state = cm._lintState; + var state = cm.state.lint; clearTimeout(state.timeout); state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay || 500); } @@ -179,14 +179,14 @@ CodeMirror.validate = (function() { if (old && old != CodeMirror.Init) { clearMarks(cm); cm.off("change", onChange); - CodeMirror.off(cm.getWrapperElement(), "mouseover", cm._lintState.onMouseOver); - delete cm._lintState; + CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); + delete cm.state.lint; } if (val) { var gutters = cm.getOption("gutters"), hasLintGutter = false; for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; - var state = cm._lintState = new LintState(cm, parseOptions(val), hasLintGutter); + var state = cm.state.lint = new LintState(cm, parseOptions(val), hasLintGutter); cm.on("change", onChange); if (state.options.tooltips != false) CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); diff --git a/addon/search/match-highlighter.js b/addon/search/match-highlighter.js index 14c1dab5b6..0800f4c638 100644 --- a/addon/search/match-highlighter.js +++ b/addon/search/match-highlighter.js @@ -24,19 +24,19 @@ CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) { var prev = old && old != CodeMirror.Init; if (val && !prev) { - cm._matchHighlightState = new State(val); + cm.state.matchHighlighter = new State(val); cm.on("cursorActivity", highlightMatches); } else if (!val && prev) { - var over = cm._matchHighlightState.overlay; + var over = cm.state.matchHighlighter.overlay; if (over) cm.removeOverlay(over); - cm._matchHighlightState = null; + cm.state.matchHighlighter = null; cm.off("cursorActivity", highlightMatches); } }); function highlightMatches(cm) { cm.operation(function() { - var state = cm._matchHighlightState; + var state = cm.state.matchHighlighter; if (state.overlay) { cm.removeOverlay(state.overlay); state.overlay = null; diff --git a/addon/search/search.js b/addon/search/search.js index 6331b86555..eb9ab8bede 100644 --- a/addon/search/search.js +++ b/addon/search/search.js @@ -27,7 +27,7 @@ this.overlay = null; } function getSearchState(cm) { - return cm._searchState || (cm._searchState = new SearchState()); + return cm.state.search || (cm.state.search = new SearchState()); } function getSearchCursor(cm, query, pos) { // Heuristic: if the query string is all lowercase, do a case insensitive search. diff --git a/addon/selection/active-line.js b/addon/selection/active-line.js index 211de0fefd..65fab6f162 100644 --- a/addon/selection/active-line.js +++ b/addon/selection/active-line.js @@ -17,23 +17,23 @@ } else if (!val && prev) { cm.off("cursorActivity", updateActiveLine); clearActiveLine(cm); - delete cm._activeLine; + delete cm.state.activeLine; } }); function clearActiveLine(cm) { - if ("_activeLine" in cm) { - cm.removeLineClass(cm._activeLine, "wrap", WRAP_CLASS); - cm.removeLineClass(cm._activeLine, "background", BACK_CLASS); + if ("activeLine" in cm.state) { + cm.removeLineClass(cm.state.activeLine, "wrap", WRAP_CLASS); + cm.removeLineClass(cm.state.activeLine, "background", BACK_CLASS); } } function updateActiveLine(cm) { var line = cm.getLineHandle(cm.getCursor().line); - if (cm._activeLine == line) return; + if (cm.state.activeLine == line) return; clearActiveLine(cm); cm.addLineClass(line, "wrap", WRAP_CLASS); cm.addLineClass(line, "background", BACK_CLASS); - cm._activeLine = line; + cm.state.activeLine = line; } })(); From 6286d9db04d604a12f660c9b3fc0ce66929abb6b Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Tue, 14 May 2013 00:41:49 +0200 Subject: [PATCH 0586/5273] [vim keymap] Add macro support for normal mode [vim keymap] Remove duplicated @ logic [vim keymap] Remove q swapping [vim keymap] Recover mis-deleted line from 3-way merge conflict [vim keymap] "q" repeatable by count [vim keymap] Remove deprecated lookup tables [vim keymap] Robustify if condition [vim keymap] Revise logKey logic [vim keymap] IE8 compatible forEach [vim keymap] Transparentize hidden states [vim keymap] Minor fixup [vim keymap] Eliminate globals/Remove unused function/Add tests --- keymap/vim.js | 101 ++++++++++++++++++++++++++++++++++++++++++++++- test/index.html | 1 + test/vim_test.js | 16 ++++++++ 3 files changed, 117 insertions(+), 1 deletion(-) diff --git a/keymap/vim.js b/keymap/vim.js index 9c0197faaa..fd8167e098 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -262,6 +262,8 @@ { keys: ['P'], type: 'action', action: 'paste', actionArgs: { after: false }}, { keys: ['r', 'character'], type: 'action', action: 'replace' }, + { keys: ['@', 'character'], type: 'action', action: 'replayMacro' }, + { keys: ['q', 'character'], type: 'action', action: 'enterMacroRecordMode' }, { keys: ['R'], type: 'action', action: 'enterReplaceMode' }, { keys: ['u'], type: 'action', action: 'undo' }, { keys: [''], type: 'action', action: 'redo' }, @@ -411,7 +413,7 @@ } var mark = buffer[(size + pointer) % size]; // skip marks that are temporarily removed from text buffer - if (!mark.find()) { + if (mark && !mark.find()) { var inc = offset > 0 ? 1 : -1; var newCur; var oldCur = cm.getCursor(); @@ -434,6 +436,26 @@ move: move }; }; + + var createMacroState = function() { + return { + macroKeyBuffer: [], + latestRegister: undefined, + enteredMacroMode: undefined, + isMacroPlaying: false, + toggle: function(cm, registerName) { + if (this.enteredMacroMode) { //onExit + this.enteredMacroMode(); // close dialog + this.enteredMacroMode = undefined; + } else { //onEnter + this.latestRegister = registerName; + this.enteredMacroMode = cm.openDialog( + '(recording)['+registerName+']', null, {bottom:true}); + } + } + } + } + // Global Vim state. Call getVimGlobalState to get and initialize. var vimGlobalState; function getVimGlobalState() { @@ -444,6 +466,7 @@ // Whether we are searching backwards. searchIsReversed: false, jumpList: createCircularJumpList(), + macroModeState: createMacroState(), // Recording latest f, t, F or T motion command. lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''}, registerController: new RegisterController({}) @@ -509,6 +532,14 @@ handleKey: function(cm, key) { var command; var vim = getVimState(cm); + var macroModeState = getVimGlobalState().macroModeState; + if (macroModeState.enteredMacroMode) { + if (key == 'q') { + actions.exitMacroRecordMode(); + return; + } + logKey(macroModeState, key); + } if (key == '') { // Clear input state and get back to normal mode. vim.inputState = new InputState(); @@ -671,6 +702,9 @@ this.unamedRegister.set(text, linewise); } }, + setRegisterText: function(name, text, linewise) { + this.getRegister(name).set(text, linewise); + }, // Gets the register named @name. If one of @name doesn't already exist, // create it. If @name is invalid, return the unamedRegister. getRegister: function(name) { @@ -1521,6 +1555,30 @@ // view into the right place. cm.scrollIntoView(); }, + replayMacro: function(cm, actionArgs) { + var registerName = actionArgs.selectedCharacter; + var repeat = actionArgs.repeat; + var macroModeState = getVimGlobalState().macroModeState; + if (registerName == '@') { + registerName = macroModeState.latestRegister; + } + var keyBuffer = parseRegisterToKeyBuffer(macroModeState, registerName); + while(repeat--){ + executeMacroKeyBuffer(cm, macroModeState, keyBuffer); + } + }, + exitMacroRecordMode: function(cm, actionArgs) { + var macroModeState = getVimGlobalState().macroModeState; + macroModeState.toggle(); + parseKeyBufferToRegister(macroModeState.latestRegister, + macroModeState.macroKeyBuffer); + }, + enterMacroRecordMode: function(cm, actionArgs) { + var macroModeState = getVimGlobalState().macroModeState; + var registerName = actionArgs.selectedCharacter; + macroModeState.toggle(cm, registerName); + emptyMacroKeyBuffer(macroModeState); + }, enterInsertMode: function(cm, actionArgs) { var insertAt = (actionArgs) ? actionArgs.insertAt : null; if (insertAt == 'eol') { @@ -3190,6 +3248,47 @@ fallthrough: ['default'] }; + function parseRegisterToKeyBuffer(macroModeState, registerName) { + var match, key; + var register = getVimGlobalState().registerController.getRegister(registerName); + var text = register.toString(); + var macroKeyBuffer = macroModeState.macroKeyBuffer; + emptyMacroKeyBuffer(macroModeState); + do { + match = text.match(/<\w+-.+>|<\w+>|.|\n/); + if(match === null)break; + key = match[0]; + text = text.substring(match.index + key.length); + macroKeyBuffer.push(key); + } while (text); + return macroKeyBuffer; + } + + function parseKeyBufferToRegister(registerName, keyBuffer) { + var text = keyBuffer.join(''); + getVimGlobalState().registerController.setRegisterText(registerName, text); + } + + function emptyMacroKeyBuffer(macroModeState) { + if(macroModeState.isMacroPlaying)return; + var macroKeyBuffer = macroModeState.macroKeyBuffer; + macroKeyBuffer.length = 0; + } + + function executeMacroKeyBuffer(cm, macroModeState, keyBuffer) { + macroModeState.isMacroPlaying = true; + for (var i = 0, len = keyBuffer.length; i < len; i++) { + CodeMirror.Vim.handleKey(cm, keyBuffer[i]); + }; + macroModeState.isMacroPlaying = false; + } + + function logKey(macroModeState, key) { + if(macroModeState.isMacroPlaying)return; + var macroKeyBuffer = macroModeState.macroKeyBuffer; + macroKeyBuffer.push(key); + } + function exitReplaceMode(cm) { cm.toggleOverwrite(); cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true); diff --git a/test/index.html b/test/index.html index 816cef5948..3eb691576a 100644 --- a/test/index.html +++ b/test/index.html @@ -9,6 +9,7 @@ + diff --git a/test/vim_test.js b/test/vim_test.js index 83bbec9ac6..ff376c6dc2 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -169,6 +169,22 @@ function testVim(name, run, opts, expectedFail) { } }, expectedFail); }; +testVim('qq@q', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'q', 'l', 'l', 'q'); + helpers.assertCursorAt(0,2); + helpers.doKeys('@', 'q'); + helpers.assertCursorAt(0,4); +}, { value: ' '}); +testVim('@@', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('q', 'q', 'l', 'l', 'q'); + helpers.assertCursorAt(0,2); + helpers.doKeys('@', 'q'); + helpers.assertCursorAt(0,4); + helpers.doKeys('@', '@'); + helpers.assertCursorAt(0,6); +}, { value: ' '}); var jumplistScene = ''+ 'word\n'+ '(word)\n'+ From 4206fd03bb0c6c7a4f0eea002d777e3839ca420e Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Thu, 16 May 2013 11:00:25 +0200 Subject: [PATCH 0587/5273] [vim keymap] Fix zz/zt/zb --- keymap/vim.js | 23 ++++++++++------------- test/vim_test.js | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index fd8167e098..ac6d29c465 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1538,22 +1538,19 @@ }, scrollToCursor: function(cm, actionArgs) { var lineNum = cm.getCursor().line; - var heightProp = window.getComputedStyle(cm.getScrollerElement()). - getPropertyValue('height'); - var height = parseInt(heightProp); - var y = cm.charCoords({line: lineNum, ch: 0}, "local").top; - var halfHeight = parseInt(height) / 2; + var charCoords = cm.charCoords({line: lineNum, ch: 0}, "local"); + var height = cm.getScrollInfo().clientHeight; + var y = charCoords.top; + var lineHeight = charCoords.bottom - y; switch (actionArgs.position) { - case 'center': y = y - (height / 2) + 10; - break; - case 'bottom': y = y - height; - break; - case 'top': break; + case 'center': y = y - (height / 2) + lineHeight; + break; + case 'bottom': y = y - height + lineHeight*1.4; + break; + case 'top': y = y + lineHeight*0.4; + break; } cm.scrollTo(null, y); - // The calculations are slightly off, use scrollIntoView to nudge the - // view into the right place. - cm.scrollIntoView(); }, replayMacro: function(cm, actionArgs) { var registerName = actionArgs.selectedCharacter; diff --git a/test/vim_test.js b/test/vim_test.js index ff376c6dc2..69714079de 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1752,14 +1752,45 @@ testVim('HML', function(cm, vim, helpers) { helpers.doKeys('M'); helpers.assertCursorAt(103,4); }, { value: (function(){ - var upperLines = new Array(100); - var lowerLines = new Array(100); + var lines = new Array(100); var upper = ' xx\n'; var lower = ' xx\n'; - upper = upperLines.join(upper); - lower = upperLines.join(lower); + upper = lines.join(upper); + lower = lines.join(lower); return upper + lower; })()}); + +var zVals = ['zb','zz','zt','z-','z.','z'].map(function(e, idx){ + var lineNum = 250; + var lines = 35; + testVim(e, function(cm, vim, helpers) { + var k1 = e[0]; + var k2 = e.substring(1); + var textHeight = cm.defaultTextHeight(); + cm.setSize(600, lines*textHeight); + cm.setCursor(lineNum, 0); + helpers.doKeys(k1, k2); + zVals[idx] = cm.getScrollInfo().top; + }, { value: (function(){ + return new Array(500).join('\n'); + })()}); +}); +testVim('zb', function(cm, vim, helpers){ + eq(zVals[2], zVals[5]); +}); + var squareBracketMotionSandbox = ''+ '({\n'+//0 ' ({\n'+//11 From 3788103b7b94f5960c3d3380097f7bb332daabad Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 16 May 2013 14:29:53 +0200 Subject: [PATCH 0588/5273] [real-world uses] Add Upsource --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 941d926dbe..0c51cc79cd 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -98,6 +98,7 @@

    { } CodeMi
  • Tumblr code highlighting shim
  • TurboPY (web publishing framework)
  • UmpleOnline (model-oriented programming tool)
  • +
  • Upsource (code viewer)
  • WebGL playground
  • WeScheme (learning tool)
  • WordPress plugin
  • From 7b8ed766a8a545a6bedc594a34f466ebe260baf7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 16 May 2013 15:40:25 +0200 Subject: [PATCH 0589/5273] [css mode] Recognize SVG properties Closes #1529 --- mode/css/css.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mode/css/css.js b/mode/css/css.js index f4ee021ed4..b9953c1767 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -392,7 +392,17 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "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" + "word-spacing", "word-wrap", "z-index", + // SVG-specific + "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-profile", + "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", "kerning", "text-anchor", "writing-mode" ]); var colorKeywords = keySet([ From 18c08f6efcc3dd646e2f1d7e32575cbe2940d39a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 16 May 2013 15:50:22 +0200 Subject: [PATCH 0590/5273] [real-world uses] Better link for Upsource --- doc/realworld.html | 2 +- index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/realworld.html b/doc/realworld.html index 0c51cc79cd..75507842dd 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -98,7 +98,7 @@

    { } CodeMi
  • Tumblr code highlighting shim
  • TurboPY (web publishing framework)
  • UmpleOnline (model-oriented programming tool)
  • -
  • Upsource (code viewer)
  • +
  • Upsource (code viewer)
  • WebGL playground
  • WeScheme (learning tool)
  • WordPress plugin
  • diff --git a/index.html b/index.html index a0d3d5b48f..f5244742ea 100644 --- a/index.html +++ b/index.html @@ -129,6 +129,7 @@

    Real-world uses:

  • Eloquent JavaScript
  • Emmet
  • Prose.io
  • +
  • Upsource
  • Paper.js
  • Codev
  • Tributary
  • @@ -138,7 +139,6 @@

    Real-world uses:

  • The File Tree
  • JSHint
  • SQLFiddle
  • -
  • Try Haxe
  • CSSDeck
  • sketchPatch Livecodelab
  • NoTex
  • From fc38d5f9aaa946b2bce6458d07fb48a279021bd0 Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Thu, 16 May 2013 14:55:05 +0200 Subject: [PATCH 0591/5273] [vim keymap] Improve code structure for later usage --- keymap/vim.js | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index ac6d29c465..42e6ecaac0 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -3163,36 +3163,37 @@ * modifers. */ // TODO: Figure out a way to catch capslock. - function handleKeyEvent_(cm, key, modifier) { - if (isUpperCase(key)) { + function cmKeyToVimKey(key, modifier) { + var vimKey = key; + if (isUpperCase(vimKey)) { // Convert to lower case if shift is not the modifier since the key // we get from CodeMirror is always upper case. if (modifier == 'Shift') { modifier = null; } else { - key = key.toLowerCase(); + vimKey = vimKey.toLowerCase(); } } if (modifier) { // Vim will parse modifier+key combination as a single key. - key = modifier.charAt(0) + '-' + key; + vimKey = modifier.charAt(0) + '-' + vimKey; } - var specialKey = ({Enter:'CR',Backspace:'BS',Delete:'Del'})[key]; - key = specialKey ? specialKey : key; - key = key.length > 1 ? '<'+ key + '>' : key; - vim.handleKey(cm, key); + var specialKey = ({Enter:'CR',Backspace:'BS',Delete:'Del'})[vimKey]; + vimKey = specialKey ? specialKey : vimKey; + vimKey = vimKey.length > 1 ? '<'+ vimKey + '>' : vimKey; + return vimKey; } // Closure to bind CodeMirror, key, modifier. - function keyMapper(key, modifier) { + function keyMapper(vimKey) { return function(cm) { - handleKeyEvent_(cm, key, modifier); + vim.handleKey(cm, vimKey); }; } var modifiers = ['Shift', 'Ctrl']; - var keyMap = { + var cmToVimKeymap = { 'nofallthrough': true, 'style': 'fat-cursor' }; @@ -3204,11 +3205,9 @@ // them. key = "'" + key + "'"; } - if (modifier) { - keyMap[modifier + '-' + key] = keyMapper(keys[i], modifier); - } else { - keyMap[key] = keyMapper(keys[i]); - } + var vimKey = cmKeyToVimKey(keys[i], modifier); + var cmKey = modifier ? modifier + '-' + key : key; + cmToVimKeymap[cmKey] = keyMapper(vimKey); } } bindKeys(upperCaseAlphabet); @@ -3220,7 +3219,7 @@ bindKeys(numbers, 'Ctrl'); bindKeys(specialKeys); bindKeys(specialKeys, 'Ctrl'); - return keyMap; + return cmToVimKeymap; } CodeMirror.keyMap.vim = buildVimKeyMap(); From 20f7dc8c6f62fdcce602ec00c63d48d319c6a79a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 20 May 2013 00:02:15 +0200 Subject: [PATCH 0592/5273] [real-world uses] Add snippets.pro --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 75507842dd..f90b0f5a13 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -90,6 +90,7 @@

    { } CodeMi
  • RealTime.io (Internet-of-Things infrastructure)
  • sketchPatch Livecodelab
  • Skulpt (in-browser Python environment)
  • +
  • Snippets.pro (code snippet sharing)
  • SolidShops (hosted e-commerce platform)
  • SQLFiddle (SQL playground)
  • The File Tree (collab editor)
  • From 14f3188c42f5c368a5a760cbd46510e00d8e337f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 20 May 2013 14:48:45 +0200 Subject: [PATCH 0593/5273] More involved span-affects-wrapping test on Webkit A dash is only handled specially when preceded by a word character. Issue #1531 --- demo/spanaffectswrapping_shim.html | 11 ++++++----- lib/codemirror.js | 24 +++++++++++++++++------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/demo/spanaffectswrapping_shim.html b/demo/spanaffectswrapping_shim.html index 733db067ff..14b6c8d82a 100644 --- a/demo/spanaffectswrapping_shim.html +++ b/demo/spanaffectswrapping_shim.html @@ -14,23 +14,24 @@

    CodeMirror: odd wrapping shim

    in lib/codemirror.js for some more details.

    -
    +
    foooo,-10br
    
     
         
         
    +    
         
         
         
    @@ -73,6 +74,7 @@ 

    CodeMirror: Test Suite

    + -

    A plain text/Smarty mode which allows for custom delimiter tags (defaults to { and }).

    +
    + +

    Smarty 3

    + + + + + + +

    A plain text/Smarty version 2 or 3 mode, which allows for custom delimiter tags.

    MIME types defined: text/x-smarty

    diff --git a/mode/smarty/smarty.js b/mode/smarty/smarty.js index 7d7e62f86e..00c1df5aa8 100644 --- a/mode/smarty/smarty.js +++ b/mode/smarty/smarty.js @@ -1,140 +1,186 @@ +/** + * Smarty 2 and 3 mode. + */ CodeMirror.defineMode("smarty", function(config) { - var keyFuncs = ["debug", "extends", "function", "include", "literal"]; + "use strict"; + + // our default settings; check to see if they're overridden + var settings = { + rightDelimiter: '}', + leftDelimiter: '{', + smartyVersion: 2 // for backward compatibility + }; + if (config.hasOwnProperty("leftDelimiter")) { + settings.leftDelimiter = config.leftDelimiter; + } + if (config.hasOwnProperty("rightDelimiter")) { + settings.rightDelimiter = config.rightDelimiter; + } + if (config.hasOwnProperty("smartyVersion") && config.smartyVersion === 3) { + settings.smartyVersion = 3; + } + + var keyFunctions = ["debug", "extends", "function", "include", "literal"]; var last; var regs = { operatorChars: /[+\-*&%=<>!?]/, - validIdentifier: /[a-zA-Z0-9\_]/, - stringChar: /[\'\"]/ + validIdentifier: /[a-zA-Z0-9_]/, + stringChar: /['"]/ }; - var leftDelim = (typeof config.mode.leftDelimiter != 'undefined') ? config.mode.leftDelimiter : "{"; - var rightDelim = (typeof config.mode.rightDelimiter != 'undefined') ? config.mode.rightDelimiter : "}"; - function ret(style, lst) { last = lst; return style; } - - function tokenizer(stream, state) { - function chain(parser) { + var helpers = { + continue: function(style, lastType) { + last = lastType; + return style; + }, + chain: function(stream, state, parser) { state.tokenize = parser; return parser(stream, state); } + }; - if (stream.match(leftDelim, true)) { - if (stream.eat("*")) { - return chain(inBlock("comment", "*" + rightDelim)); - } - else { - state.tokenize = inSmarty; - return "tag"; - } - } - else { - // I'd like to do an eatWhile() here, but I can't get it to eat only up to the rightDelim string/char - stream.next(); - return null; - } - } - function inSmarty(stream, state) { - if (stream.match(rightDelim, true)) { - state.tokenize = tokenizer; - return ret("tag", null); - } + // our various parsers + var parsers = { - var ch = stream.next(); - if (ch == "$") { - stream.eatWhile(regs.validIdentifier); - return ret("variable-2", "variable"); - } - else if (ch == ".") { - return ret("operator", "property"); - } - else if (regs.stringChar.test(ch)) { - state.tokenize = inAttribute(ch); - return ret("string", "string"); - } - else if (regs.operatorChars.test(ch)) { - stream.eatWhile(regs.operatorChars); - return ret("operator", "operator"); - } - else if (ch == "[" || ch == "]") { - return ret("bracket", "bracket"); - } - else if (/\d/.test(ch)) { - stream.eatWhile(/\d/); - return ret("number", "number"); - } - else { - if (state.last == "variable") { - if (ch == "@") { - stream.eatWhile(regs.validIdentifier); - return ret("property", "property"); + // the main tokenizer + tokenizer: function(stream, state) { + if (stream.match(settings.leftDelimiter, true)) { + if (stream.eat("*")) { + return helpers.chain(stream, state, parsers.inBlock("comment", "*" + settings.rightDelimiter)); + } else { + // Smarty 3 allows { and } surrounded by whitespace to NOT slip into Smarty mode + state.depth++; + var isEol = stream.eol(); + var isFollowedByWhitespace = /\s/.test(stream.peek()); + if (settings.smartyVersion === 3 && settings.leftDelimiter === "{" && (isEol || isFollowedByWhitespace)) { + state.depth--; + return null; + } else { + state.tokenize = parsers.smarty; + last = "startTag"; + return "tag"; + } } - else if (ch == "|") { - stream.eatWhile(regs.validIdentifier); - return ret("qualifier", "modifier"); - } - } - else if (state.last == "whitespace") { - stream.eatWhile(regs.validIdentifier); - return ret("attribute", "modifier"); - } - else if (state.last == "property") { - stream.eatWhile(regs.validIdentifier); - return ret("property", null); - } - else if (/\s/.test(ch)) { - last = "whitespace"; + } else { + stream.next(); return null; } + }, - var str = ""; - if (ch != "/") { - str += ch; - } - var c = ""; - while ((c = stream.eat(regs.validIdentifier))) { - str += c; - } - var i, j; - for (i=0, j=keyFuncs.length; i Date: Thu, 23 May 2013 12:06:16 +0200 Subject: [PATCH 0607/5273] [trailingspace addon] Add --- addon/edit/trailingspace.js | 15 ++++++++++++++ demo/trailingspace.html | 39 +++++++++++++++++++++++++++++++++++++ doc/manual.html | 15 ++++++++++---- lib/codemirror.js | 3 ++- 4 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 addon/edit/trailingspace.js create mode 100644 demo/trailingspace.html diff --git a/addon/edit/trailingspace.js b/addon/edit/trailingspace.js new file mode 100644 index 0000000000..f6bb02645d --- /dev/null +++ b/addon/edit/trailingspace.js @@ -0,0 +1,15 @@ +CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) { + if (prev == CodeMirror.Init) prev = false; + if (prev && !val) + cm.removeOverlay("trailingspace"); + else if (!prev && val) + cm.addOverlay({ + token: function(stream) { + for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {} + if (i > stream.pos) { stream.pos = i; return null; } + stream.pos = l; + return "trailingspace"; + }, + name: "trailingspace" + }); +}); diff --git a/demo/trailingspace.html b/demo/trailingspace.html new file mode 100644 index 0000000000..ca74152eca --- /dev/null +++ b/demo/trailingspace.html @@ -0,0 +1,39 @@ + + + + + CodeMirror: Trailing Whitespace Demo + + + + + + + + +

    CodeMirror: Trailing Whitespace Demo

    + +
    + + + +

    Uses +the trailingspace +addon to highlight trailing whitespace.

    + + + diff --git a/doc/manual.html b/doc/manual.html index 5d029aebc1..33625b577c 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -939,10 +939,10 @@

    Configuration methods

    override the styling of the base mode entirely, instead of the two being applied together.

    cm.removeOverlay(mode: string|object)
    -
    Pass this the exact argument passed for - the mode parameter - to addOverlay to remove - an overlay again.
    +
    Pass this the exact value passed for the mode + parameter to addOverlay, + or a string that corresponds to the name propery of + that value, to remove an overlay again.
    cm.on(type: string, func: (...args))
    Register an event handler for the given event type (a @@ -1558,6 +1558,13 @@

    Add-ons

    to customize it. Demo here.
    +
    edit/trailingspace.js
    +
    Adds an option showTrailingSpace which, when + enabled, adds the CSS class cm-trailingspace to + stretches of whitespace at the end of lines. + The demo has a nice + squiggly underline style for this class.
    +
    comment/comment.js
    Addon for commenting and uncommenting code. Adds three methods to CodeMirror instances: diff --git a/lib/codemirror.js b/lib/codemirror.js index 1b124a432e..a2324e7679 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2780,7 +2780,8 @@ window.CodeMirror = (function() { removeOverlay: operation(null, function(spec) { var overlays = this.state.overlays; for (var i = 0; i < overlays.length; ++i) { - if (overlays[i].modeSpec == spec) { + var cur = overlays[i].modeSpec; + if (cur == spec || typeof spec == "string" && cur.name == spec) { overlays.splice(i, 1); this.state.modeGen++; regChange(this); From 2daf724ed578726f2e37ef22dc8eebebd44b2a64 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 23 May 2013 13:11:07 +0200 Subject: [PATCH 0608/5273] [smarty mode] Fix lint errors --- mode/smarty/smarty.js | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/mode/smarty/smarty.js b/mode/smarty/smarty.js index 00c1df5aa8..856f7bb3be 100644 --- a/mode/smarty/smarty.js +++ b/mode/smarty/smarty.js @@ -29,7 +29,7 @@ CodeMirror.defineMode("smarty", function(config) { }; var helpers = { - continue: function(style, lastType) { + cont: function(style, lastType) { last = lastType; return style; }, @@ -79,47 +79,47 @@ CodeMirror.defineMode("smarty", function(config) { } else { state.tokenize = parsers.tokenizer; } - return helpers.continue("tag", null); + return helpers.cont("tag", null); } if (stream.match(settings.leftDelimiter, true)) { state.depth++; - return helpers.continue("tag", "startTag"); + return helpers.cont("tag", "startTag"); } var ch = stream.next(); if (ch == "$") { stream.eatWhile(regs.validIdentifier); - return helpers.continue("variable-2", "variable"); + return helpers.cont("variable-2", "variable"); } else if (ch == ".") { - return helpers.continue("operator", "property"); + return helpers.cont("operator", "property"); } else if (regs.stringChar.test(ch)) { state.tokenize = parsers.inAttribute(ch); - return helpers.continue("string", "string"); + return helpers.cont("string", "string"); } else if (regs.operatorChars.test(ch)) { stream.eatWhile(regs.operatorChars); - return helpers.continue("operator", "operator"); + return helpers.cont("operator", "operator"); } else if (ch == "[" || ch == "]") { - return helpers.continue("bracket", "bracket"); + return helpers.cont("bracket", "bracket"); } else if (/\d/.test(ch)) { stream.eatWhile(/\d/); - return helpers.continue("number", "number"); + return helpers.cont("number", "number"); } else { if (state.last == "variable") { if (ch == "@") { stream.eatWhile(regs.validIdentifier); - return helpers.continue("property", "property"); + return helpers.cont("property", "property"); } else if (ch == "|") { stream.eatWhile(regs.validIdentifier); - return helpers.continue("qualifier", "modifier"); + return helpers.cont("qualifier", "modifier"); } } else if (state.last == "whitespace") { stream.eatWhile(regs.validIdentifier); - return helpers.continue("attribute", "modifier"); + return helpers.cont("attribute", "modifier"); } if (state.last == "property") { stream.eatWhile(regs.validIdentifier); - return helpers.continue("property", null); + return helpers.cont("property", null); } else if (/\s/.test(ch)) { last = "whitespace"; return null; @@ -129,19 +129,19 @@ CodeMirror.defineMode("smarty", function(config) { if (ch != "/") { str += ch; } - var c = null; + var c = null; while (c = stream.eat(regs.validIdentifier)) { str += c; } for (var i=0, j=keyFunctions.length; i Date: Fri, 24 May 2013 08:31:56 +0200 Subject: [PATCH 0609/5273] Remove unneeded cursor set at end of drag (The mousemove events should already have taken care of that.) Issue #1488 --- lib/codemirror.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index a2324e7679..f21f76a34e 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1728,8 +1728,6 @@ window.CodeMirror = (function() { function done(e) { counter = Infinity; - var cur = posFromMouse(cm, e); - if (cur) doSelect(cur); e_preventDefault(e); focusInput(cm); off(document, "mousemove", move); From 6edd771495c6a333166b7d22a5ebe0e0df47483e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 24 May 2013 09:22:39 +0200 Subject: [PATCH 0610/5273] Also fire beforeChange for undo/redo changes But disable its update method in that case. Issue #1539 --- doc/manual.html | 27 ++++++++++++++++----------- lib/codemirror.js | 23 +++++++++++++++-------- test/test.js | 13 +++++++++++++ 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 33625b577c..6fa58c6e30 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -406,17 +406,22 @@

    Events

    properties, as with the "change" event, but never a next property, since this is fired for each - individual change, and not batched per operation. It also - has update(from, to, text) - and cancel() methods, which may be used to modify - or cancel the change. All three arguments to update - are optional, and can be left off to leave the existing value - for that field intact. Note: you may not do - anything from a "beforeChange" handler that would - cause changes to the document or its visualization. Doing so - will, since this handler is called directly from the bowels of - the CodeMirror implementation, probably cause the editor to - become corrupted.
    + individual change, and not batched per operation. It also has + a cancel() method, which can be called to cancel + the change, and, if the change isn't coming + from an undo or redo event, an update(from, to, + text) method, which may be used to modify the change. + Undo or redo changes can't be modified, because they hold some + metainformation for restoring old marked ranges that is only + valid for that specific change. All three arguments + to update are optional, and can be left off to + leave the existing value for that field + intact. Note: you may not do anything from + a "beforeChange" handler that would cause changes + to the document or its visualization. Doing so will, since this + handler is called directly from the bowels of the CodeMirror + implementation, probably cause the editor to become + corrupted.
    "cursorActivity" (instance: CodeMirror)
    Will be fired when the cursor or selection moves, or any diff --git a/lib/codemirror.js b/lib/codemirror.js index f21f76a34e..b92b3a9bbc 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2186,21 +2186,21 @@ window.CodeMirror = (function() { return {anchor: adjustPos(doc.sel.anchor), head: adjustPos(doc.sel.head)}; } - function filterChange(doc, change) { + function filterChange(doc, change, update) { var obj = { canceled: false, from: change.from, to: change.to, text: change.text, origin: change.origin, - 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; - }, 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); @@ -2217,7 +2217,7 @@ window.CodeMirror = (function() { } if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { - change = filterChange(doc, change); + change = filterChange(doc, change, true); if (!change) return; } @@ -2262,9 +2262,16 @@ window.CodeMirror = (function() { anchorAfter: event.anchorBefore, headAfter: event.headBefore}; (type == "undo" ? hist.undone : hist.done).push(anti); + 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; + if (filter && !filterChange(doc, change, false)) { + (type == "undo" ? hist.done : hist.undone).length = 0; + return; + } + anti.changes.push(historyChangeFromChange(doc, change)); var after = i ? computeSelAfterChange(doc, change, null) diff --git a/test/test.js b/test/test.js index 637f6e79ca..d42a76bd41 100644 --- a/test/test.js +++ b/test/test.js @@ -1358,6 +1358,19 @@ testCM("beforeChange", function(cm) { eq(cm.getValue(), "hello,_i_am_a\nhey_hey_hey"); }, {value: "abcdefghijk"}); +testCM("beforeChangeUndo", function(cm) { + cm.setLine(0, "hi"); + cm.setLine(0, "bye"); + eq(cm.historySize().undo, 2); + cm.on("beforeChange", function(cm, change) { + is(!change.update); + change.cancel(); + }); + cm.undo(); + eq(cm.historySize().undo, 0); + eq(cm.getValue(), "bye\ntwo"); +}, {value: "one\ntwo"}); + testCM("beforeSelectionChange", function(cm) { function notAtEnd(cm, pos) { var len = cm.getLine(pos.line).length; From 83fdc1e77cc078029504de549b2eef8e1bb83f12 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 25 May 2013 06:59:11 +0200 Subject: [PATCH 0611/5273] Fix patch d07c5471ca649b78366b4c10c3ef698504a454a6 The argument order to Delayed.set was wrong, and we actually want to ensure that the resize fires at least every 100ms during a resize, so that the display doesn't lag too much. --- lib/codemirror.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index b92b3a9bbc..aa0de5de43 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1513,14 +1513,15 @@ window.CodeMirror = (function() { // Prevent wrapper from ever scrolling on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); - var resizeTimer = new Delayed(); + var resizeTimer; function onResize() { - resizeTimer.set(function() { + if (resizeTimer == null) resizeTimer = setTimeout(function() { + resizeTimer = null; // Might be a text scaling operation, clear size caches. d.cachedCharWidth = d.cachedTextHeight = null; clearCaches(cm); runInOp(cm, bind(regChange, cm)); - }, 200); + }, 100); } on(window, "resize", onResize); // Above handler holds on to the editor and its data structures. From 8e6b9f5e15d16f388fa15f88a930013a87f6c304 Mon Sep 17 00:00:00 2001 From: Ben Keen Date: Fri, 24 May 2013 22:11:59 -0700 Subject: [PATCH 0612/5273] [smarty mode] bugfixes - escaped quotes in strings now displayed properly - whitespace no longer affects qualifiers - parentheses properly highlighted --- mode/smarty/smarty.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mode/smarty/smarty.js b/mode/smarty/smarty.js index 856f7bb3be..826c2b966c 100644 --- a/mode/smarty/smarty.js +++ b/mode/smarty/smarty.js @@ -91,6 +91,8 @@ CodeMirror.defineMode("smarty", function(config) { if (ch == "$") { stream.eatWhile(regs.validIdentifier); return helpers.cont("variable-2", "variable"); + } else if (ch == "|") { + return helpers.cont("operator", "pipe"); } else if (ch == ".") { return helpers.cont("operator", "property"); } else if (regs.stringChar.test(ch)) { @@ -101,6 +103,8 @@ CodeMirror.defineMode("smarty", function(config) { return helpers.cont("operator", "operator"); } else if (ch == "[" || ch == "]") { return helpers.cont("bracket", "bracket"); + } else if (ch == "(" || ch == ")") { + return helpers.cont("bracket", "operator"); } else if (/\d/.test(ch)) { stream.eatWhile(/\d/); return helpers.cont("number", "number"); @@ -114,6 +118,9 @@ CodeMirror.defineMode("smarty", function(config) { stream.eatWhile(regs.validIdentifier); return helpers.cont("qualifier", "modifier"); } + } else if (state.last == "pipe") { + stream.eatWhile(regs.validIdentifier); + return helpers.cont("qualifier", "modifier"); } else if (state.last == "whitespace") { stream.eatWhile(regs.validIdentifier); return helpers.cont("attribute", "modifier"); @@ -147,11 +154,15 @@ CodeMirror.defineMode("smarty", function(config) { inAttribute: function(quote) { return function(stream, state) { + var prevChar = null; + var currChar = null; while (!stream.eol()) { - if (stream.next() == quote) { + currChar = stream.peek(); + if (stream.next() == quote && prevChar !== '\\') { state.tokenize = parsers.smarty; break; } + prevChar = currChar; } return "string"; }; From 3f203d7b83d58a701ee9c980408fe1aab018795d Mon Sep 17 00:00:00 2001 From: John Connor Date: Sat, 25 May 2013 13:41:25 -0400 Subject: [PATCH 0613/5273] [vim keymap] 'dd' now handles last line corretly. Current behavior: ``` word1 word2 ``` If the cursor is on the last line and 'dd' is executed, the buffer does not change. Expected behavior: ``` word1 word2 ``` --- keymap/vim.js | 10 ++++++++++ test/vim_test.js | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/keymap/vim.js b/keymap/vim.js index 532e640a1f..51b93aec30 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -663,6 +663,9 @@ } RegisterController.prototype = { pushText: function(registerName, operator, text, linewise) { + if (linewise && text.charAt(0) == '\n') { + text = text.slice(1) + '\n'; + } // Lowercase and uppercase registers refer to the same register. // Uppercase just means append. var register = this.isValidRegister(registerName) ? @@ -1476,6 +1479,13 @@ }, // delete is a javascript keyword. 'delete': function(cm, operatorArgs, vim, curStart, curEnd) { + // If the ending line is past the last line, inclusive, instead of + // including the trailing \n, include the \n before the starting line + if (operatorArgs.linewise && + curEnd.line > cm.lastLine() && curStart.line > cm.firstLine()) { + curStart.line--; + curStart.ch = lineLength(cm, curStart.line); + } getVimGlobalState().registerController.pushText( operatorArgs.registerName, 'delete', cm.getRange(curStart, curEnd), operatorArgs.linewise); diff --git a/test/vim_test.js b/test/vim_test.js index 69714079de..f3b53508f6 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -782,6 +782,13 @@ testVim('dd_multiply_repeat', function(cm, vim, helpers) { is(register.linewise); helpers.assertCursorAt(0, lines[6].textStart); }); +testVim('dd_lastline', function(cm, vim, helpers) { + cm.setCursor(cm.lineCount(), 0); + var expectedLineCount = cm.lineCount() - 1; + helpers.doKeys('d', 'd'); + eq(expectedLineCount, cm.lineCount()); + helpers.assertCursorAt(cm.lineCount() - 1, 0); +}); // Yank commands should behave the exact same as d commands, expect that nothing // gets deleted. testVim('yw_repeat', function(cm, vim, helpers) { From 4c2fa0767a4168250bde05015ced6ec31f697686 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 27 May 2013 12:01:19 +0200 Subject: [PATCH 0614/5273] Update Webkit spanAffectsWrapping hack to recognize some common Unicode punctuation Issue #1219 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index aa0de5de43..a68417598c 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -5287,7 +5287,7 @@ window.CodeMirror = (function() { spanAffectsWrapping = function(str, i) { if (i > 1 && str.charCodeAt(i - 1) == 45 && /\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) return true; - return /[~!#%&*)=+}\]|\"\.>,:;][({[<]|\?[\w~`@#$%\^&*(_=+{[|><]/.test(str.slice(i - 1, i + 1)); + return /[~!#%&*)=+}\]|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`@#$%\^&*(_=+{[|><]|…[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1)); }; var knownScrollbarWidth; From 9a50176800dfd9f4a5cdc19564a26381e71ed96f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 28 May 2013 08:17:47 +0200 Subject: [PATCH 0615/5273] [comment addon] Fix bug in uncommenting line-commented blocks (http://stackoverflow.com/questions/16702574/codemirror-comment-js-addon-wont-uncomment-in-ruby-mode) --- addon/comment/comment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/comment/comment.js b/addon/comment/comment.js index 4f590f2870..b25bd96f22 100644 --- a/addon/comment/comment.js +++ b/addon/comment/comment.js @@ -97,7 +97,7 @@ var line = self.getLine(i); var found = line.indexOf(lineString); if (found == -1 && (i != end || i == start) && nonWS.test(line)) break lineComment; - if (i != start && nonWS.test(line.slice(0, found))) break lineComment; + if (i != start && found > -1 && nonWS.test(line.slice(0, found))) break lineComment; lines.push(line); } self.operation(function() { From 8aaac4445a317fff82ab314e9dd6f6d8404c8ff7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 28 May 2013 10:06:37 +0200 Subject: [PATCH 0616/5273] [xml mode] Make else indentation style correspond to rest of project --- mode/xml/xml.js | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/mode/xml/xml.js b/mode/xml/xml.js index b04248c6c6..ae71c64130 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -58,20 +58,19 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { if (stream.eat("[")) { if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>")); else return null; - } - else if (stream.match("--")) return chain(inBlock("comment", "-->")); - else if (stream.match("DOCTYPE", true, true)) { + } else if (stream.match("--")) { + return chain(inBlock("comment", "-->")); + } else if (stream.match("DOCTYPE", true, true)) { stream.eatWhile(/[\w\._\-]/); return chain(doctype(1)); + } else { + return null; } - else return null; - } - else if (stream.eat("?")) { + } else if (stream.eat("?")) { stream.eatWhile(/[\w\._\-]/); state.tokenize = inBlock("meta", "?>"); return "meta"; - } - else { + } else { var isClose = stream.eat("/"); tagName = ""; var c; @@ -81,8 +80,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { state.tokenize = inTag; return "tag"; } - } - else if (ch == "&") { + } else if (ch == "&") { var ok; if (stream.eat("#")) { if (stream.eat("x")) { @@ -94,8 +92,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); } return ok ? "atom" : "error"; - } - else { + } else { stream.eatWhile(/[^&<]/); return null; } @@ -107,16 +104,15 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { state.tokenize = inText; type = ch == ">" ? "endTag" : "selfcloseTag"; return "tag"; - } - else if (ch == "=") { + } else if (ch == "=") { type = "equals"; return null; - } - else if (/[\'\"]/.test(ch)) { + } else if (ch == "<") { + return "error"; + } else if (/[\'\"]/.test(ch)) { state.tokenize = inAttribute(ch); return state.tokenize(stream, state); - } - else { + } else { stream.eatWhile(/[^\s\u00a0=<>\"\']/); return "word"; } From a85d89c082cb5764ad137b6d1a3d79cffbb7f275 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 28 May 2013 13:49:18 +0200 Subject: [PATCH 0617/5273] [xml-hint addon] Rewrite from scratch Using some of the ideas from the html5 hinter. Can now use a much richer source of hinting information, and also completes properties and property values. --- addon/hint/show-hint.js | 13 +++- addon/hint/xml-hint.js | 168 +++++++++++++--------------------------- demo/xmlcomplete.html | 119 ++++++++++++++++------------ doc/manual.html | 33 +++++++- 4 files changed, 164 insertions(+), 169 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 2c54dcd77e..504fda786b 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -1,7 +1,7 @@ CodeMirror.showHint = function(cm, getHints, options) { if (!options) options = {}; var startCh = cm.getCursor().ch, continued = false; - var closeOn = options.closeCharacters || /[\s()\[\]{};:]/; + var closeOn = options.closeCharacters || /[\s()\[\]{};:>]/; function startHinting() { // We want a single cursor position. @@ -114,6 +114,7 @@ CodeMirror.showHint = function(cm, getHints, options) { } } else ourMap = baseMap; + cm.state.completionActive = true; cm.addKeyMap(ourMap); cm.on("cursorActivity", cursorActivity); var closingOnBlur; @@ -154,7 +155,10 @@ CodeMirror.showHint = function(cm, getHints, options) { cm.off("blur", onBlur); cm.off("focus", onFocus); cm.off("scroll", onScroll); - if (willContinue !== true) CodeMirror.signal(data, "close"); + if (willContinue !== true) { + CodeMirror.signal(data, "close"); + cm.state.completionActive = false; + } } function pick() { pickCompletion(cm, data, completions[selectedHint]); @@ -169,8 +173,9 @@ CodeMirror.showHint = function(cm, getHints, options) { pos.ch < startCh || cm.somethingSelected() || (pos.ch && closeOn.test(line.charAt(pos.ch - 1)))) close(); - else - once = setTimeout(function(){close(true); continued = true; startHinting();}, 70); + else { + once = setTimeout(function(){close(true); continued = true; startHinting();}, 170); + } } CodeMirror.signal(data, "select", completions[0], hints.firstChild); return true; diff --git a/addon/hint/xml-hint.js b/addon/hint/xml-hint.js index 42eab6f3b7..bc26a09c6d 100644 --- a/addon/hint/xml-hint.js +++ b/addon/hint/xml-hint.js @@ -1,118 +1,60 @@ (function() { - - CodeMirror.xmlHints = []; - - CodeMirror.xmlHint = function(cm) { - - var cursor = cm.getCursor(); - - if (cursor.ch > 0) { - - var text = cm.getRange(CodeMirror.Pos(0, 0), cursor); - var typed = ''; - var simbol = ''; - for(var i = text.length - 1; i >= 0; i--) { - if(text[i] == ' ' || text[i] == '<') { - simbol = text[i]; - break; - } - else { - typed = text[i] + typed; - } - } - - text = text.slice(0, text.length - typed.length); - - var path = getActiveElement(text) + simbol; - var hints = CodeMirror.xmlHints[path]; - - if(typeof hints === 'undefined') - hints = ['']; - else { - hints = hints.slice(0); - for (var i = hints.length - 1; i >= 0; i--) { - if(hints[i].indexOf(typed) != 0) - hints.splice(i, 1); - } - } - - return { - list: hints, - from: CodeMirror.Pos(cursor.line, cursor.ch - typed.length), - to: cursor - }; + "use strict"; + + var Pos = CodeMirror.Pos; + + CodeMirror.xmlHint = function(cm, options) { + var tags = options && options.schemaInfo; + if (!tags) return; + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var inner = CodeMirror.innerMode(cm.getMode(), token.state); + if (inner.mode.name != "xml") return; + var result = [], replaceToken = false, prefix; + var isTag = token.string.charAt(0) == "<"; + if (!inner.state.tagName || isTag) { // Tag completion + if (isTag) { + prefix = token.string.slice(1); + replaceToken = true; + } + var cx = inner.state.context, curTag = cx && tags[cx.tagName]; + var childList = cx ? curTag && curTag.children : tags["!top"]; + if (childList) { + for (var i = 0; i < childList.length; ++i) if (!prefix || childList[i].indexOf(prefix) == 0) + result.push("<" + childList[i]); + } else { + for (var name in tags) if (tags.hasOwnProperty(name) && name != "!top" && (!prefix || name.indexOf(prefix) == 0)) + result.push("<" + name); + } + if (cx && (!prefix || ("/" + cx.tagName).indexOf(prefix) == 0)) + result.push(""); + } else { + // Attribute completion + var curTag = tags[inner.state.tagName], attrs = curTag && curTag.attrs; + if (!attrs) return; + if (token.type == "string" || token.string == "=") { // A value + var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)), + Pos(cur.line, token.type == "string" ? token.start : token.end)); + var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues; + if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return; + if (token.type == "string") { + prefix = token.string.charAt(0) == '"' ? token.string.slice(1) : token.string; + replaceToken = true; } - }; - - var getActiveElement = function(text) { - - var element = ''; - - if(text.length >= 0) { - - var regex = new RegExp('<([^!?][^\\s/>]*)[\\s\\S]*?>', 'g'); - - var matches = []; - var match; - while ((match = regex.exec(text)) != null) { - matches.push({ - tag: match[1], - selfclose: (match[0].slice(match[0].length - 2) === '/>') - }); - } - - for (var i = matches.length - 1, skip = 0; i >= 0; i--) { - - var item = matches[i]; - - if (item.tag[0] == '/') - { - skip++; - } - else if (item.selfclose == false) - { - if (skip > 0) - { - skip--; - } - else - { - element = '<' + item.tag + '>' + element; - } - } - } - - element += getOpenTag(text); + for (var i = 0; i < atValues.length; ++i) if (!prefix || atValues[i].indexOf(prefix) == 0) + result.push('"' + atValues[i] + '"'); + } else { // An attribute name + if (token.type == "attribute") { + prefix = token.string; + replaceToken = true; } - - return element; + for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || attr.indexOf(prefix) == 0)) + result.push(attr); + } + } + return { + list: result, + from: replaceToken ? Pos(cur.line, token.start) : cur, + to: replaceToken ? Pos(cur.line, token.end) : cur }; - - var getOpenTag = function(text) { - - var open = text.lastIndexOf('<'); - var close = text.lastIndexOf('>'); - - if (close < open) - { - text = text.slice(open); - - if(text != '<') { - - var space = text.indexOf(' '); - if(space < 0) - space = text.indexOf('\t'); - if(space < 0) - space = text.indexOf('\n'); - - if (space < 0) - space = text.length; - - return text.slice(0, space); - } - } - - return ''; - }; - + }; })(); diff --git a/demo/xmlcomplete.html b/demo/xmlcomplete.html index 28a50638f7..a03b4c5fcc 100644 --- a/demo/xmlcomplete.html +++ b/demo/xmlcomplete.html @@ -7,75 +7,96 @@ -

    CodeMirror: XML Autocomplete demo

    -
    +
    -

    Type '<' or space inside tag or - press ctrl-space to activate autocompletion. See - the code (here - and here) to figure out how - it works.

    +

    Press ctrl-space, or type a '<' character to + activate autocompletion. This demo defines a simple schema that + guides completion. The schema can be customized—see + the manual.

    diff --git a/doc/manual.html b/doc/manual.html index 6fa58c6e30..07e72c7b63 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1682,12 +1682,39 @@

    Add-ons

    is an array of strings (the completions), and from and to give the start and end of the token that is being completed. Depends - on addon/hint/show-hint.css. See the other files in - the addon/hint for - hint sources for various languages. Check + on addon/hint/show-hint.css. Check out the demo for an example.
    +
    hint/javascript-hint.js
    +
    Defines a simple hinting function for JavaScript + (CodeMirror.javascriptHint) and CoffeeScript + (CodeMirror.coffeescriptHint) code. This will + simply use the JavaScript environment that the editor runs in as + a source of information about objects and their properties.
    + +
    hint/xml-hint.js
    +
    Defines CodeMirror.xmlHint, which produces + hints for XML tagnames, attribute names, and attribute values, + guided by a schemaInfo option (a property of the + second argument passed to the hinting function, or the third + argument passed to CodeMirror.showHint).
    The + schema info should be an object mapping tag names to information + about these tags, with optionally a "!top" property + containing a list of the names of valid top-level tags. The + values of the properties should be objects with optional + properties children (an array of valid child + element names, omit to simply allow all tags to appear) + and attrs (an object mapping attribute names + to null for free-form attributes, and an array of + valid values for restricted + attributes). Demo + here.
    + +
    hint/python-hint.js
    +
    A very simple hinting function for Python code. + Defines CodeMirror.pythonHint.
    +
    match-highlighter.js
    Adds a highlightSelectionMatches option that can be enabled to highlight all instances of a currently From d23d0589aae8d98f236ef0eb0e29b435fcad3b9f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 28 May 2013 15:06:36 +0200 Subject: [PATCH 0618/5273] [html-hint addon] Rewrite to reuse xml-hint instead of own hinting function --- addon/hint/html-hint.js | 895 +++++++++++++++------------------------- demo/html5complete.html | 76 +--- doc/manual.html | 11 + 3 files changed, 349 insertions(+), 633 deletions(-) diff --git a/addon/hint/html-hint.js b/addon/hint/html-hint.js index 8b5dc6f002..23238df054 100755 --- a/addon/hint/html-hint.js +++ b/addon/hint/html-hint.js @@ -1,582 +1,335 @@ (function () { - function htmlHint(editor, htmlStructure, getToken) { - var cur = editor.getCursor(); - var token = getToken(editor, cur); - var keywords = []; - var i = 0; - var j = 0; - var k = 0; - var from = {line: cur.line, ch: cur.ch}; - var to = {line: cur.line, ch: cur.ch}; - var flagClean = true; + var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" "); + var targets = ["_blank", "_self", "_top", "_parent"]; + var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"]; + var methods = ["get", "post", "put", "delete"]; + var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]; + var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech", + "3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait", + "orientation:landscape", "device-height: [X]", "device-width: [X]"]; + var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags - var text = editor.getRange({line: 0, ch: 0}, cur); - - var open = text.lastIndexOf('<'); - var close = text.lastIndexOf('>'); - var tokenString = token.string.replace("<",""); - - if(open > close) { - var last = editor.getRange({line: cur.line, ch: cur.ch - 1}, cur); - if(last == "<") { - for(i = 0; i < htmlStructure.length; i++) { - keywords.push(htmlStructure[i].tag); - } - from.ch = token.start + 1; - } else { - var counter = 0; - var found = function(token, type, position) { - counter++; - if(counter > 50) return; - if(token.type == type) { - return token; - } else { - position.ch = token.start; - var newToken = editor.getTokenAt(position); - return found(newToken, type, position); - } - }; - - var nodeToken = found(token, "tag", {line: cur.line, ch: cur.ch}); - var node = nodeToken.string.substring(1); - - if(token.type === null && token.string.trim() === "") { - for(i = 0; i < htmlStructure.length; i++) { - if(htmlStructure[i].tag == node) { - for(j = 0; j < htmlStructure[i].attr.length; j++) { - keywords.push(htmlStructure[i].attr[j].key + "=\"\" "); - } - - for(k = 0; k < globalAttributes.length; k++) { - keywords.push(globalAttributes[k].key + "=\"\" "); - } - } - } - } else if(token.type == "string") { - tokenString = tokenString.substring(1, tokenString.length - 1); - var attributeToken = found(token, "attribute", {line: cur.line, ch: cur.ch}); - var attribute = attributeToken.string; - - for(i = 0; i < htmlStructure.length; i++) { - if(htmlStructure[i].tag == node) { - for(j = 0; j < htmlStructure[i].attr.length; j++) { - if(htmlStructure[i].attr[j].key == attribute) { - for(k = 0; k < htmlStructure[i].attr[j].values.length; k++) { - keywords.push(htmlStructure[i].attr[j].values[k]); - } - } - } - - for(j = 0; j < globalAttributes.length; j++) { - if(globalAttributes[j].key == attribute) { - for(k = 0; k < globalAttributes[j].values.length; k++) { - keywords.push(globalAttributes[j].values[k]); - } - } - } - } - } - from.ch = token.start + 1; - } else if(token.type == "attribute") { - for(i = 0; i < htmlStructure.length; i++) { - if(htmlStructure[i].tag == node) { - for(j = 0; j < htmlStructure[i].attr.length; j++) { - keywords.push(htmlStructure[i].attr[j].key + "=\"\" "); - } - - for(k = 0; k < globalAttributes.length; k++) { - keywords.push(globalAttributes[k].key + "=\"\" "); - } - } - } - from.ch = token.start; - } else if(token.type == "tag") { - for(i = 0; i < htmlStructure.length; i++) { - keywords.push(htmlStructure[i].tag); - } - - from.ch = token.start + 1; - } + var data = { + a: { + attrs: { + href: null, ping: null, type: null, + media: media, + target: targets, + hreflang: langs } - } else { - for(i = 0; i < htmlStructure.length; i++) { - keywords.push("<" + htmlStructure[i].tag); + }, + abbr: s, + acronym: s, + address: s, + applet: s, + area: { + attrs: { + alt: null, coords: null, href: null, target: null, ping: null, + media: media, hreflang: langs, type: null, + shape: ["default", "rect", "circle", "poly"] } - - tokenString = ("<" + tokenString).trim(); - from.ch = token.start; - } - - if(flagClean === true && tokenString.trim() === "") { - flagClean = false; - } - - if(flagClean) { - keywords = cleanResults(tokenString, keywords); - } - - return {list: keywords, from: from, to: to}; - } - - - var cleanResults = function(text, keywords) { - var results = []; - var i = 0; - - for(i = 0; i < keywords.length; i++) { - if(keywords[i].substring(0, text.length) == text) { - results.push(keywords[i]); + }, + article: s, + aside: s, + audio: { + attrs: { + src: null, mediagroup: null, + crossorigin: ["anonymous", "use-credentials"], + preload: ["none", "metadata", "auto"], + autoplay: ["", "autoplay"], + loop: ["", "loop"], + controls: ["", "controls"] } - } - - return results; + }, + b: s, + base: { attrs: { href: null, target: targets } }, + basefont: s, + bdi: s, + bdo: s, + big: s, + blockquote: { attrs: { cite: null } }, + body: s, + br: s, + button: { + attrs: { + form: null, formaction: null, name: null, value: null, + autofocus: ["", "autofocus"], + disabled: ["", "autofocus"], + formenctype: encs, + formmethod: methods, + formnovalidate: ["", "novalidate"], + formtarget: targets, + type: ["submit", "reset", "button"] + } + }, + canvas: { attrs: { width: null, height: null } }, + caption: s, + center: s, + cite: s, + code: s, + col: { attrs: { span: null } }, + colgroup: { attrs: { span: null } }, + command: { + attrs: { + type: ["command", "checkbox", "radio"], + label: null, icon: null, radiogroup: null, command: null, title: null, + disabled: ["", "disabled"], + checked: ["", "checked"] + } + }, + data: { attrs: { value: null } }, + datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } }, + datalist: { attrs: { data: null } }, + dd: s, + del: { attrs: { cite: null, datetime: null } }, + details: { attrs: { open: ["", "open"] } }, + dfn: s, + dir: s, + div: s, + dl: s, + dt: s, + em: s, + embed: { attrs: { src: null, type: null, width: null, height: null } }, + eventsource: { attrs: { src: null } }, + fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } }, + figcaption: s, + figure: s, + font: s, + footer: s, + form: { + attrs: { + action: null, name: null, + "accept-charset": charsets, + autocomplete: ["on", "off"], + enctype: encs, + method: methods, + novalidate: ["", "novalidate"], + target: targets + } + }, + frame: s, + frameset: s, + h1: s, h2: s, h3: s, h4: s, h5: s, h6: s, + head: { + attrs: {}, + children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"] + }, + header: s, + hgroup: s, + hr: s, + html: { + attrs: { manifest: null }, + children: ["head", "body"] + }, + i: s, + iframe: { + attrs: { + src: null, srcdoc: null, name: null, width: null, height: null, + sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"], + seamless: ["", "seamless"] + } + }, + img: { + attrs: { + alt: null, src: null, ismap: null, usemap: null, width: null, height: null, + crossorigin: ["anonymous", "use-credentials"] + } + }, + input: { + attrs: { + alt: null, dirname: null, form: null, formaction: null, + height: null, list: null, max: null, maxlength: null, min: null, + name: null, pattern: null, placeholder: null, size: null, src: null, + step: null, value: null, width: null, + accept: ["audio/*", "video/*", "image/*"], + autocomplete: ["on", "off"], + autofocus: ["", "autofocus"], + checked: ["", "checked"], + disabled: ["", "disabled"], + formenctype: encs, + formmethod: methods, + formnovalidate: ["", "novalidate"], + formtarget: targets, + multiple: ["", "multiple"], + readonly: ["", "readonly"], + required: ["", "required"], + type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month", + "week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio", + "file", "submit", "image", "reset", "button"] + } + }, + ins: { attrs: { cite: null, datetime: null } }, + kbd: s, + keygen: { + attrs: { + challenge: null, form: null, name: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + keytype: ["RSA"] + } + }, + label: { attrs: { "for": null, form: null } }, + legend: s, + li: { attrs: { value: null } }, + link: { + attrs: { + href: null, type: null, + hreflang: langs, + media: media, + sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"] + } + }, + map: { attrs: { name: null } }, + mark: s, + menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } }, + meta: { + attrs: { + content: null, + charset: charsets, + name: ["viewport", "application-name", "author", "description", "generator", "keywords"], + "http-equiv": ["content-language", "content-type", "default-style", "refresh"] + } + }, + meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } }, + nav: s, + noframes: s, + noscript: s, + object: { + attrs: { + data: null, type: null, name: null, usemap: null, form: null, width: null, height: null, + typemustmatch: ["", "typemustmatch"] + } + }, + ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } }, + optgroup: { attrs: { disabled: ["", "disabled"], label: null } }, + option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } }, + output: { attrs: { "for": null, form: null, name: null } }, + p: s, + param: { attrs: { name: null, value: null } }, + pre: s, + progress: { attrs: { value: null, max: null } }, + q: { attrs: { cite: null } }, + rp: s, + rt: s, + ruby: s, + s: s, + samp: s, + script: { + attrs: { + type: ["text/javascript"], + src: null, + async: ["", "async"], + defer: ["", "defer"], + charset: charsets + } + }, + section: s, + select: { + attrs: { + form: null, name: null, size: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + multiple: ["", "multiple"] + } + }, + small: s, + source: { attrs: { src: null, type: null, media: null } }, + span: s, + strike: s, + strong: s, + style: { + attrs: { + type: ["text/css"], + media: media, + scoped: null + } + }, + sub: s, + summary: s, + sup: s, + table: s, + tbody: s, + td: { attrs: { colspan: null, rowspan: null, headers: null } }, + textarea: { + attrs: { + dirname: null, form: null, maxlength: null, name: null, placeholder: null, + rows: null, cols: null, + autofocus: ["", "autofocus"], + disabled: ["", "disabled"], + readonly: ["", "readonly"], + required: ["", "required"], + wrap: ["soft", "hard"] + } + }, + tfoot: s, + th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } }, + thead: s, + time: { attrs: { datetime: null } }, + title: s, + tr: s, + track: { + attrs: { + src: null, label: null, "default": null, + kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"], + srclang: langs + } + }, + tt: s, + u: s, + ul: s, + "var": s, + video: { + attrs: { + src: null, poster: null, width: null, height: null, + crossorigin: ["anonymous", "use-credentials"], + preload: ["auto", "metadata", "none"], + autoplay: ["", "autoplay"], + mediagroup: ["movie"], + muted: ["", "muted"], + controls: ["", "controls"] + } + }, + wbr: s }; - var htmlStructure = [ - {tag: '!DOCTYPE', attr: []}, - {tag: 'a', attr: [ - {key: 'href', values: ["#"]}, - {key: 'target', values: ["_blank","_self","_top","_parent"]}, - {key: 'ping', values: [""]}, - {key: 'media', values: ["#"]}, - {key: 'hreflang', values: ["en","es"]}, - {key: 'type', values: []} - ]}, - {tag: 'abbr', attr: []}, - {tag: 'acronym', attr: []}, - {tag: 'address', attr: []}, - {tag: 'applet', attr: []}, - {tag: 'area', attr: [ - {key: 'alt', values: [""]}, - {key: 'coords', values: ["rect: left, top, right, bottom","circle: center-x, center-y, radius","poly: x1, y1, x2, y2, ..."]}, - {key: 'shape', values: ["default","rect","circle","poly"]}, - {key: 'href', values: ["#"]}, - {key: 'target', values: ["#"]}, - {key: 'ping', values: []}, - {key: 'media', values: []}, - {key: 'hreflang', values: []}, - {key: 'type', values: []} - - ]}, - {tag: 'article', attr: []}, - {tag: 'aside', attr: []}, - {tag: 'audio', attr: [ - {key: 'src', values: []}, - {key: 'crossorigin', values: ["anonymous","use-credentials"]}, - {key: 'preload', values: ["none","metadata","auto"]}, - {key: 'autoplay', values: ["","autoplay"]}, - {key: 'mediagroup', values: []}, - {key: 'loop', values: ["","loop"]}, - {key: 'controls', values: ["","controls"]} - ]}, - {tag: 'b', attr: []}, - {tag: 'base', attr: [ - {key: 'href', values: ["#"]}, - {key: 'target', values: ["_blank","_self","_top","_parent"]} - ]}, - {tag: 'basefont', attr: []}, - {tag: 'bdi', attr: []}, - {tag: 'bdo', attr: []}, - {tag: 'big', attr: []}, - {tag: 'blockquote', attr: [ - {key: 'cite', values: ["http://"]} - ]}, - {tag: 'body', attr: []}, - {tag: 'br', attr: []}, - {tag: 'button', attr: [ - {key: 'autofocus', values: ["","autofocus"]}, - {key: 'disabled', values: ["","disabled"]}, - {key: 'form', values: []}, - {key: 'formaction', values: []}, - {key: 'formenctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]}, - {key: 'formmethod', values: ["get","post","put","delete"]}, - {key: 'formnovalidate', values: ["","novalidate"]}, - {key: 'formtarget', values: ["_blank","_self","_top","_parent"]}, - {key: 'name', values: []}, - {key: 'type', values: ["submit","reset","button"]}, - {key: 'value', values: []} - ]}, - {tag: 'canvas', attr: [ - {key: 'width', values: []}, - {key: 'height', values: []} - ]}, - {tag: 'caption', attr: []}, - {tag: 'center', attr: []}, - {tag: 'cite', attr: []}, - {tag: 'code', attr: []}, - {tag: 'col', attr: [ - {key: 'span', values: []} - ]}, - {tag: 'colgroup', attr: [ - {key: 'span', values: []} - ]}, - {tag: 'command', attr: [ - {key: 'type', values: ["command","checkbox","radio"]}, - {key: 'label', values: []}, - {key: 'icon', values: []}, - {key: 'disabled', values: ["","disabled"]}, - {key: 'checked', values: ["","checked"]}, - {key: 'radiogroup', values: []}, - {key: 'command', values: []}, - {key: 'title', values: []} - ]}, - {tag: 'data', attr: [ - {key: 'value', values: []} - ]}, - {tag: 'datagrid', attr: [ - {key: 'disabled', values: ["","disabled"]}, - {key: 'multiple', values: ["","multiple"]} - ]}, - {tag: 'datalist', attr: [ - {key: 'data', values: []} - ]}, - {tag: 'dd', attr: []}, - {tag: 'del', attr: [ - {key: 'cite', values: []}, - {key: 'datetime', values: []} - ]}, - {tag: 'details', attr: [ - {key: 'open', values: ["","open"]} - ]}, - {tag: 'dfn', attr: []}, - {tag: 'dir', attr: []}, - {tag: 'div', attr: [ - {key: 'id', values: []}, - {key: 'class', values: []}, - {key: 'style', values: []} - ]}, - {tag: 'dl', attr: []}, - {tag: 'dt', attr: []}, - {tag: 'em', attr: []}, - {tag: 'embed', attr: [ - {key: 'src', values: []}, - {key: 'type', values: []}, - {key: 'width', values: []}, - {key: 'height', values: []} - ]}, - {tag: 'eventsource', attr: [ - {key: 'src', values: []} - ]}, - {tag: 'fieldset', attr: [ - {key: 'disabled', values: ["","disabled"]}, - {key: 'form', values: []}, - {key: 'name', values: []} - ]}, - {tag: 'figcaption', attr: []}, - {tag: 'figure', attr: []}, - {tag: 'font', attr: []}, - {tag: 'footer', attr: []}, - {tag: 'form', attr: [ - {key: 'accept-charset', values: ["UNKNOWN","utf-8"]}, - {key: 'action', values: []}, - {key: 'autocomplete', values: ["on","off"]}, - {key: 'enctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]}, - {key: 'method', values: ["get","post","put","delete","dialog"]}, - {key: 'name', values: []}, - {key: 'novalidate', values: ["","novalidate"]}, - {key: 'target', values: ["_blank","_self","_top","_parent"]} - ]}, - {tag: 'frame', attr: []}, - {tag: 'frameset', attr: []}, - {tag: 'h1', attr: []}, - {tag: 'h2', attr: []}, - {tag: 'h3', attr: []}, - {tag: 'h4', attr: []}, - {tag: 'h5', attr: []}, - {tag: 'h6', attr: []}, - {tag: 'head', attr: []}, - {tag: 'header', attr: []}, - {tag: 'hgroup', attr: []}, - {tag: 'hr', attr: []}, - {tag: 'html', attr: [ - {key: 'manifest', values: []} - ]}, - {tag: 'i', attr: []}, - {tag: 'iframe', attr: [ - {key: 'src', values: []}, - {key: 'srcdoc', values: []}, - {key: 'name', values: []}, - {key: 'sandbox', values: ["allow-top-navigation","allow-same-origin","allow-forms","allow-scripts"]}, - {key: 'seamless', values: ["","seamless"]}, - {key: 'width', values: []}, - {key: 'height', values: []} - ]}, - {tag: 'img', attr: [ - {key: 'alt', values: []}, - {key: 'src', values: []}, - {key: 'crossorigin', values: ["anonymous","use-credentials"]}, - {key: 'ismap', values: []}, - {key: 'usemap', values: []}, - {key: 'width', values: []}, - {key: 'height', values: []} - ]}, - {tag: 'input', attr: [ - {key: 'accept', values: ["audio/*","video/*","image/*"]}, - {key: 'alt', values: []}, - {key: 'autocomplete', values: ["on","off"]}, - {key: 'autofocus', values: ["","autofocus"]}, - {key: 'checked', values: ["","checked"]}, - {key: 'disabled', values: ["","disabled"]}, - {key: 'dirname', values: []}, - {key: 'form', values: []}, - {key: 'formaction', values: []}, - {key: 'formenctype', values: ["application/x-www-form-urlencoded","multipart/form-data","text/plain"]}, - {key: 'formmethod', values: ["get","post","put","delete"]}, - {key: 'formnovalidate', values: ["","novalidate"]}, - {key: 'formtarget', values: ["_blank","_self","_top","_parent"]}, - {key: 'height', values: []}, - {key: 'list', values: []}, - {key: 'max', values: []}, - {key: 'maxlength', values: []}, - {key: 'min', values: []}, - {key: 'multiple', values: ["","multiple"]}, - {key: 'name', values: []}, - {key: 'pattern', values: []}, - {key: 'placeholder', values: []}, - {key: 'readonly', values: ["","readonly"]}, - {key: 'required', values: ["","required"]}, - {key: 'size', values: []}, - {key: 'src', values: []}, - {key: 'step', values: []}, - {key: 'type', values: [ - "hidden","text","search","tel","url","email","password","datetime","date","month","week","time","datetime-local", - "number","range","color","checkbox","radio","file","submit","image","reset","button" - ]}, - {key: 'value', values: []}, - {key: 'width', values: []} - ]}, - {tag: 'ins', attr: [ - {key: 'cite', values: []}, - {key: 'datetime', values: []} - ]}, - {tag: 'kbd', attr: []}, - {tag: 'keygen', attr: [ - {key: 'autofocus', values: ["","autofocus"]}, - {key: 'challenge', values: []}, - {key: 'disabled', values: ["","disabled"]}, - {key: 'form', values: []}, - {key: 'keytype', values: ["RSA"]}, - {key: 'name', values: []} - ]}, - {tag: 'label', attr: [ - {key: 'for', values: []}, - {key: 'form', values: []} - ]}, - {tag: 'legend', attr: []}, - {tag: 'li', attr: [ - {key: 'value', values: []} - ]}, - {tag: 'link', attr: [ - {key: 'href', values: []}, - {key: 'hreflang', values: ["en","es"]}, - {key: 'media', values: [ - "all","screen","print","embossed","braille","handheld","print","projection","screen","tty","tv","speech","3d-glasses", - "resolution [>][<][=] [X]dpi","resolution [>][<][=] [X]dpcm","device-aspect-ratio: 16/9","device-aspect-ratio: 4/3", - "device-aspect-ratio: 32/18","device-aspect-ratio: 1280/720","device-aspect-ratio: 2560/1440","orientation:portrait", - "orientation:landscape","device-height: [X]px","device-width: [X]px","-webkit-min-device-pixel-ratio: 2" - ]}, - {key: 'type', values: []}, - {key: 'sizes', values: ["all","16x16","16x16 32x32","16x16 32x32 64x64"]} - ]}, - {tag: 'map', attr: [ - {key: 'name', values: []} - ]}, - {tag: 'mark', attr: []}, - {tag: 'menu', attr: [ - {key: 'type', values: ["list","context","toolbar"]}, - {key: 'label', values: []} - ]}, - {tag: 'meta', attr: [ - {key: 'charset', attr: ["utf-8"]}, - {key: 'name', attr: ["viewport","application-name","author","description","generator","keywords"]}, - {key: 'content', attr: ["","width=device-width","initial-scale=1, maximum-scale=1, minimun-scale=1, user-scale=no"]}, - {key: 'http-equiv', attr: ["content-language","content-type","default-style","refresh"]} - ]}, - {tag: 'meter', attr: [ - {key: 'value', values: []}, - {key: 'min', values: []}, - {key: 'low', values: []}, - {key: 'high', values: []}, - {key: 'max', values: []}, - {key: 'optimum', values: []} - ]}, - {tag: 'nav', attr: []}, - {tag: 'noframes', attr: []}, - {tag: 'noscript', attr: []}, - {tag: 'object', attr: [ - {key: 'data', values: []}, - {key: 'type', values: []}, - {key: 'typemustmatch', values: ["","typemustmatch"]}, - {key: 'name', values: []}, - {key: 'usemap', values: []}, - {key: 'form', values: []}, - {key: 'width', values: []}, - {key: 'height', values: []} - ]}, - {tag: 'ol', attr: [ - {key: 'reversed', values: ["", "reversed"]}, - {key: 'start', values: []}, - {key: 'type', values: ["1","a","A","i","I"]} - ]}, - {tag: 'optgroup', attr: [ - {key: 'disabled', values: ["","disabled"]}, - {key: 'label', values: []} - ]}, - {tag: 'option', attr: [ - {key: 'disabled', values: ["", "disabled"]}, - {key: 'label', values: []}, - {key: 'selected', values: ["", "selected"]}, - {key: 'value', values: []} - ]}, - {tag: 'output', attr: [ - {key: 'for', values: []}, - {key: 'form', values: []}, - {key: 'name', values: []} - ]}, - {tag: 'p', attr: []}, - {tag: 'param', attr: [ - {key: 'name', values: []}, - {key: 'value', values: []} - ]}, - {tag: 'pre', attr: []}, - {tag: 'progress', attr: [ - {key: 'value', values: []}, - {key: 'max', values: []} - ]}, - {tag: 'q', attr: [ - {key: 'cite', values: []} - ]}, - {tag: 'rp', attr: []}, - {tag: 'rt', attr: []}, - {tag: 'ruby', attr: []}, - {tag: 's', attr: []}, - {tag: 'samp', attr: []}, - {tag: 'script', attr: [ - {key: 'type', values: ["text/javascript"]}, - {key: 'src', values: []}, - {key: 'async', values: ["","async"]}, - {key: 'defer', values: ["","defer"]}, - {key: 'charset', values: ["utf-8"]} - ]}, - {tag: 'section', attr: []}, - {tag: 'select', attr: [ - {key: 'autofocus', values: ["", "autofocus"]}, - {key: 'disabled', values: ["", "disabled"]}, - {key: 'form', values: []}, - {key: 'multiple', values: ["", "multiple"]}, - {key: 'name', values: []}, - {key: 'size', values: []} - ]}, - {tag: 'small', attr: []}, - {tag: 'source', attr: [ - {key: 'src', values: []}, - {key: 'type', values: []}, - {key: 'media', values: []} - ]}, - {tag: 'span', attr: []}, - {tag: 'strike', attr: []}, - {tag: 'strong', attr: []}, - {tag: 'style', attr: [ - {key: 'type', values: ["text/css"]}, - {key: 'media', values: ["all","braille","print","projection","screen","speech"]}, - {key: 'scoped', values: []} - ]}, - {tag: 'sub', attr: []}, - {tag: 'summary', attr: []}, - {tag: 'sup', attr: []}, - {tag: 'table', attr: [ - {key: 'border', values: []} - ]}, - {tag: 'tbody', attr: []}, - {tag: 'td', attr: [ - {key: 'colspan', values: []}, - {key: 'rowspan', values: []}, - {key: 'headers', values: []} - ]}, - {tag: 'textarea', attr: [ - {key: 'autofocus', values: ["","autofocus"]}, - {key: 'disabled', values: ["","disabled"]}, - {key: 'dirname', values: []}, - {key: 'form', values: []}, - {key: 'maxlength', values: []}, - {key: 'name', values: []}, - {key: 'placeholder', values: []}, - {key: 'readonly', values: ["","readonly"]}, - {key: 'required', values: ["","required"]}, - {key: 'rows', values: []}, - {key: 'cols', values: []}, - {key: 'wrap', values: ["soft","hard"]} - ]}, - {tag: 'tfoot', attr: []}, - {tag: 'th', attr: [ - {key: 'colspan', values: []}, - {key: 'rowspan', values: []}, - {key: 'headers', values: []}, - {key: 'scope', values: ["row","col","rowgroup","colgroup"]} - ]}, - {tag: 'thead', attr: []}, - {tag: 'time', attr: [ - {key: 'datetime', values: []} - ]}, - {tag: 'title', attr: []}, - {tag: 'tr', attr: []}, - {tag: 'track', attr: [ - {key: 'kind', values: ["subtitles","captions","descriptions","chapters","metadata"]}, - {key: 'src', values: []}, - {key: 'srclang', values: ["en","es"]}, - {key: 'label', values: []}, - {key: 'default', values: []} - ]}, - {tag: 'tt', attr: []}, - {tag: 'u', attr: []}, - {tag: 'ul', attr: []}, - {tag: 'var', attr: []}, - {tag: 'video', attr: [ - {key: "src", values: []}, - {key: "crossorigin", values: ["anonymous","use-credentials"]}, - {key: "poster", values: []}, - {key: "preload", values: ["auto","metadata","none"]}, - {key: "autoplay", values: ["","autoplay"]}, - {key: "mediagroup", values: ["movie"]}, - {key: "loop", values: ["","loop"]}, - {key: "muted", values: ["","muted"]}, - {key: "controls", values: ["","controls"]}, - {key: "width", values: []}, - {key: "height", values: []} - ]}, - {tag: 'wbr', attr: []} - ]; + var globalAttrs = { + accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], + "class": null, + contenteditable: ["true", "false"], + contextmenu: null, + dir: ["ltr", "rtl", "auto"], + draggable: ["true", "false", "auto"], + dropzone: ["copy", "move", "link", "string:", "file:"], + hidden: ["hidden"], + id: null, + inert: ["inert"], + itemid: null, + itemprop: null, + itemref: null, + itemscope: ["itemscope"], + itemtype: null, + lang: ["en", "es"], + spellcheck: ["true", "false"], + style: null, + tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"], + title: null, + translate: ["yes", "no"], + onclick: null, + rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"] + }; + function populate(obj) { + for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr)) + obj.attrs[attr] = globalAttrs[attr]; + } - var globalAttributes = [ - {key: "accesskey", values: ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"]}, - {key: "class", values: []}, - {key: "contenteditable", values: ["true", "false"]}, - {key: "contextmenu", values: []}, - {key: "dir", values: ["ltr","rtl","auto"]}, - {key: "draggable", values: ["true","false","auto"]}, - {key: "dropzone", values: ["copy","move","link","string:","file:"]}, - {key: "hidden", values: ["hidden"]}, - {key: "id", values: []}, - {key: "inert", values: ["inert"]}, - {key: "itemid", values: []}, - {key: "itemprop", values: []}, - {key: "itemref", values: []}, - {key: "itemscope", values: ["itemscope"]}, - {key: "itemtype", values: []}, - {key: "lang", values: ["en","es"]}, - {key: "spellcheck", values: ["true","false"]}, - {key: "style", values: []}, - {key: "tabindex", values: ["1","2","3","4","5","6","7","8","9"]}, - {key: "title", values: []}, - {key: "translate", values: ["yes","no"]}, - {key: "onclick", values: []}, - {key: 'rel', values: ["stylesheet","alternate","author","bookmark","help","license","next","nofollow","noreferrer","prefetch","prev","search","tag"]} - ]; + populate(s); + for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s) + populate(data[tag]); - CodeMirror.htmlHint = function(editor) { - if(String.prototype.trim == undefined) { - String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g, '');}; - } - return htmlHint(editor, htmlStructure, function (e, cur) { return e.getTokenAt(cur); }); + CodeMirror.htmlSchema = data; + CodeMirror.htmlHint = function(cm, options) { + var local = {schemaInfo: data}; + if (options) for (var opt in options) local[opt] = options[opt]; + return CodeMirror.xmlHint(cm, local); }; })(); diff --git a/demo/html5complete.html b/demo/html5complete.html index 5091354ae9..5b2dd0de1d 100644 --- a/demo/html5complete.html +++ b/demo/html5complete.html @@ -2,12 +2,12 @@ - CodeMirror: Close-Tag Demo + CodeMirror: HTML completion demo - + @@ -21,72 +21,24 @@ -

    HTML5 code completation demo

    -
      -
    • Type an html tag. If you press Ctrl+Space a hint panel show the code suggest. You can type to autocomplete tags, attributes if your cursor are inner a tag or attribute values if your cursor are inner a attribute value.
    • -
    +

    HTML completion demo

    +

    Shows the XML completer + parameterized with information about the tags in HTML. + Press ctrl-space to activate completion.

    -
    diff --git a/doc/manual.html b/doc/manual.html index 07e72c7b63..3bfc3d0e91 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1711,6 +1711,17 @@

    Add-ons

    attributes). Demo here.
    +
    hint/html-hint.js
    +
    Provides schema info to + the xml-hint addon for HTML + documents. Defines a schema + object CodeMirror.htmlSchema that you can pass to + as a schemaInfo option, and + a CodeMirror.htmlHint hinting function that + automatically calls CodeMirror.xmlHint with this + schema data. See + the demo.
    +
    hint/python-hint.js
    A very simple hinting function for Python code. Defines CodeMirror.pythonHint.
    From a22787fa013b6027d8c2ec94b75124a9c19dbb7b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 28 May 2013 19:35:29 +0200 Subject: [PATCH 0619/5273] Work around IE bug where drag events get fired twice Closes #1551 --- lib/codemirror.js | 57 ++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index a68417598c..37f7a1100d 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1744,11 +1744,41 @@ window.CodeMirror = (function() { on(document, "mouseup", up); } + function clickInGutter(cm, e) { + var display = cm.display; + try { var mX = e.clientX, mY = e.clientY; } + catch(e) { return false; } + + if (mX >= Math.floor(getRect(display.gutters).right)) return false; + e_preventDefault(e); + if (!hasHandler(cm, "gutterClick")) return true; + + var lineBox = getRect(display.lineDiv); + if (mY > lineBox.bottom) return true; + mY -= lineBox.top - display.viewOffset; + + for (var i = 0; i < cm.options.gutters.length; ++i) { + var g = display.gutters.childNodes[i]; + if (g && getRect(g).right >= mX) { + var line = lineAtHeight(cm.doc, mY); + var gutter = cm.options.gutters[i]; + signalLater(cm, "gutterClick", cm, line, gutter, e); + break; + } + } + return true; + } + + // 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; + function onDrop(e) { var cm = this; if (eventInWidget(cm.display, e) || (cm.options.onDragEvent && cm.options.onDragEvent(cm, addStop(e)))) return; e_preventDefault(e); + if (ie) lastDrop = +new Date; var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; if (!pos || isReadOnly(cm)) return; if (files && files.length && window.FileReader && window.File) { @@ -1788,33 +1818,8 @@ window.CodeMirror = (function() { } } - function clickInGutter(cm, e) { - var display = cm.display; - try { var mX = e.clientX, mY = e.clientY; } - catch(e) { return false; } - - if (mX >= Math.floor(getRect(display.gutters).right)) return false; - e_preventDefault(e); - if (!hasHandler(cm, "gutterClick")) return true; - - var lineBox = getRect(display.lineDiv); - if (mY > lineBox.bottom) return true; - mY -= lineBox.top - display.viewOffset; - - for (var i = 0; i < cm.options.gutters.length; ++i) { - var g = display.gutters.childNodes[i]; - if (g && getRect(g).right >= mX) { - var line = lineAtHeight(cm.doc, mY); - var gutter = cm.options.gutters[i]; - signalLater(cm, "gutterClick", cm, line, gutter, e); - break; - } - } - return true; - } - function onDragStart(cm, e) { - if (ie && !cm.state.draggingText) { e_stop(e); return; } + if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } if (eventInWidget(cm.display, e)) return; var txt = cm.getSelection(); From c71f96fbf30af73c19c8453ea32cfc9d2d053975 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 28 May 2013 19:59:48 +0200 Subject: [PATCH 0620/5273] [javascript mode] More comma-handling tweaks Issue #1443 --- mode/javascript/javascript.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index fabe1c42b9..ab76a57e81 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -270,17 +270,18 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return pass(pushlex("stat"), expression, expect(";"), poplex); } function expression(type) { - return expressionInner(type, maybeoperatorComma); + return expressionInner(type, false); } function expressionNoComma(type) { - return expressionInner(type, maybeoperatorNoComma); + return expressionInner(type, true); } - function expressionInner(type, maybeop) { + function expressionInner(type, noComma) { + var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma; if (atomicTypes.hasOwnProperty(type)) return cont(maybeop); if (type == "function") return cont(functiondef); - if (type == "keyword c") return cont(maybeexpression); + if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression); if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop); - if (type == "operator") return cont(expression); + if (type == "operator") return cont(noComma ? expressionNoComma : expression); if (type == "[") return cont(pushlex("]"), commasep(expressionNoComma, "]"), poplex, maybeop); if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeop); return cont(); @@ -289,9 +290,13 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type.match(/[;\}\)\],]/)) return pass(); return pass(expression); } + function maybeexpressionNoComma(type) { + if (type.match(/[;\}\)\],]/)) return pass(); + return pass(expressionNoComma); + } function maybeoperatorComma(type, value) { - if (type == ",") return pass(); + if (type == ",") return cont(expression); return maybeoperatorNoComma(type, value, maybeoperatorComma); } function maybeoperatorNoComma(type, value, me) { From a828fa125508eb7c6e59894af20ff5918811da37 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 28 May 2013 21:57:40 +0200 Subject: [PATCH 0621/5273] [xml-hint demo] Fix minor bug, add sponsor link --- demo/xmlcomplete.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/demo/xmlcomplete.html b/demo/xmlcomplete.html index a03b4c5fcc..5363b39611 100644 --- a/demo/xmlcomplete.html +++ b/demo/xmlcomplete.html @@ -25,6 +25,10 @@

    CodeMirror: XML Autocomplete demo

    guides completion. The schema can be customized—see the manual.

    +

    Development of the xml-hint addon was kindly + sponsored + by www.xperiment.mobi.

    + From ba5554ddeaae8e6525d7ea196ec8da3ba1dac6a3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 29 May 2013 10:05:15 +0200 Subject: [PATCH 0625/5273] Fix partial-updating of lines with line widgets above them Issue #1554 --- lib/codemirror.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 0cbfbb1917..0865b55889 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -656,25 +656,25 @@ window.CodeMirror = (function() { if (reuse) { reuse.alignable = null; - var isOk = true, widgetsSeen = 0; + var isOk = true, widgetsSeen = 0, insertBefore = null; for (var n = reuse.firstChild, next; n; n = next) { next = n.nextSibling; if (!/\bCodeMirror-linewidget\b/.test(n.className)) { reuse.removeChild(n); } else { for (var i = 0, first = true; i < line.widgets.length; ++i) { - var widget = line.widgets[i], isFirst = false; - if (!widget.above) { isFirst = first; first = false; } + var widget = line.widgets[i]; + if (!widget.above) { insertBefore = n; first = false; } if (widget.node == n.firstChild) { positionLineWidget(widget, n, reuse, dims); ++widgetsSeen; - if (isFirst) reuse.insertBefore(lineElement, n); break; } } if (i == line.widgets.length) { isOk = false; break; } } } + reuse.insertBefore(lineElement, insertBefore); if (isOk && widgetsSeen == line.widgets.length) { wrap = reuse; reuse.className = line.wrapClass || ""; From 3328ed0ebc31182f3853d6564d45bcabcc8c1806 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 30 May 2013 12:14:24 +0200 Subject: [PATCH 0626/5273] Reset scrollbarwidth cache when window is resized Zooming can produce different measurements. --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 0865b55889..96a84d3d89 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1518,7 +1518,7 @@ window.CodeMirror = (function() { if (resizeTimer == null) resizeTimer = setTimeout(function() { resizeTimer = null; // Might be a text scaling operation, clear size caches. - d.cachedCharWidth = d.cachedTextHeight = null; + d.cachedCharWidth = d.cachedTextHeight = knownScrollbarWidth = null; clearCaches(cm); runInOp(cm, bind(regChange, cm)); }, 100); From 0bfab07985e5734a2d8eb364d9d12d4ddcfe1719 Mon Sep 17 00:00:00 2001 From: MinRK Date: Thu, 23 May 2013 12:41:39 -0700 Subject: [PATCH 0627/5273] forgive one pixel in scrollbars Sometimes I find that CodeMirror adds scrollbars inappropriately (most often due to browser zoom). Digging around suggested that it is some non-integers resulting in rounding up the measured size, and I haven't been able to find a case where the two values differ by more than one pixel, so simply setting the threshold one pixel higher seems to address the issue. This PR forgives one pixel in the size comparison before drawing the scrollbars. --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 96a84d3d89..717ac6f4d5 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -323,8 +323,8 @@ window.CodeMirror = (function() { d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px"; d.gutters.style.height = Math.max(totalHeight, d.scroller.clientHeight - scrollerCutOff) + "px"; var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight); - var needsH = d.scroller.scrollWidth > d.scroller.clientWidth; - var needsV = scrollHeight > d.scroller.clientHeight; + var needsH = d.scroller.scrollWidth > (d.scroller.clientWidth + 1); + var needsV = scrollHeight > (d.scroller.clientHeight + 1); if (needsV) { d.scrollbarV.style.display = "block"; d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0"; From cd6540cb3b6d6e5de55eab2c4b692cbe768d8e97 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 30 May 2013 12:36:11 +0200 Subject: [PATCH 0628/5273] Add handleMouseEvents option to markText and addLineWidget --- doc/manual.html | 11 +++++++++++ lib/codemirror.js | 17 ++++++++++------- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 3bfc3d0e91..2b3874aaa5 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1090,6 +1090,12 @@

    Text-marking methods

    Use a given node to display this range. Implies both collapsed and atomic. The given DOM node must be an inline element (as opposed to a block element).
    +
    handleMouseEvents: boolean
    +
    When replacedWith is given, this determines + whether the editor will capture mouse and drag events + occurring in this widget. Default is false—the events will be + left alone for the default browser handler, or specific + handlers on the widget, to capture.
    readOnly: boolean
    A read-only span can, as long as it is not cleared, not be modified except by @@ -1231,6 +1237,11 @@

    Widget, gutter, and decoration methods

    showIfHidden: boolean
    When true, will cause the widget to be rendered even if the line it is associated with is hidden.
    +
    handleMouseEvents: boolean
    +
    Determines whether the editor will capture mouse and + drag events occurring in this widget. Default is false—the + events will be left alone for the default browser handler, + or specific handlers on the widget, to capture.
    Note that the widget node will become a descendant of nodes with CodeMirror-specific CSS classes, and those classes might in some diff --git a/lib/codemirror.js b/lib/codemirror.js index 717ac6f4d5..9b6b2e1ecd 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -602,8 +602,9 @@ window.CodeMirror = (function() { if (nextIntact && nextIntact.to == lineN) nextIntact = intact.shift(); if (lineIsHidden(cm.doc, line)) { if (line.height != 0) updateLineHeight(line, 0); - if (line.widgets && cur.previousSibling) for (var i = 0; i < line.widgets.length; ++i) - if (line.widgets[i].showIfHidden) { + if (line.widgets && cur.previousSibling) for (var i = 0; i < line.widgets.length; ++i) { + var w = line.widgets[i]; + if (w.showIfHidden) { var prev = cur.previousSibling; if (/pre/i.test(prev.nodeName)) { var wrap = elt("div", null, null, "position: relative"); @@ -611,9 +612,11 @@ window.CodeMirror = (function() { wrap.appendChild(prev); prev = wrap; } - var wnode = prev.appendChild(elt("div", [line.widgets[i].node], "CodeMirror-linewidget")); - positionLineWidget(line.widgets[i], wnode, prev, dims); + var wnode = prev.appendChild(elt("div", [w.node], "CodeMirror-linewidget")); + if (!w.handleMouseEvents) wnode.ignoreEvents = true; + positionLineWidget(w, wnode, prev, dims); } + } } else if (nextIntact && nextIntact.from <= lineN && nextIntact.to > lineN) { // This line is intact. Skip to the actual node. Update its // line number if needed. @@ -709,6 +712,7 @@ window.CodeMirror = (function() { if (ie_lt8) wrap.style.zIndex = 2; if (line.widgets && wrap != reuse) 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.ignoreEvents = true; positionLineWidget(widget, node, wrap, dims); if (widget.above) wrap.insertBefore(node, cm.options.lineNumbers && line.height != 0 ? gutterWrap : lineElement); @@ -1584,9 +1588,7 @@ window.CodeMirror = (function() { function eventInWidget(display, e) { for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { - if (!n) return true; - if (/\bCodeMirror-(?:line)?widget\b/.test(n.className) || - n.parentNode == display.sizer && n != display.mover) return true; + if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.mover) return true; } } @@ -3664,6 +3666,7 @@ window.CodeMirror = (function() { if (marker.replacedWith) { marker.collapsed = true; marker.replacedWith = elt("span", [marker.replacedWith], "CodeMirror-widget"); + if (!options.handleMouseEvents) marker.replacedWith.ignoreEvents = true; } if (marker.collapsed) sawCollapsedSpans = true; From 41aeb8a512bf2fe7cf52e75465e1701b9124e753 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 30 May 2013 13:32:05 +0200 Subject: [PATCH 0629/5273] Take top padding into account in "local" coordinate space, fix bug in fromCoordSystem Issue #1557 --- lib/codemirror.js | 18 +++++++++--------- test/test.js | 17 ++++++++++------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 9b6b2e1ecd..6b452d699d 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1109,7 +1109,8 @@ window.CodeMirror = (function() { if (context == "line") return rect; if (!context) context = "local"; var yOff = heightAtLine(cm, lineObj); - if (context != "local") yOff -= cm.display.viewOffset; + if (context == "local") yOff += paddingTop(cm.display); + else yOff -= cm.display.viewOffset; if (context == "page") { var lOff = getRect(cm.display.lineSpace); yOff += lOff.top + (window.pageYOffset || (document.documentElement || document.body).scrollTop); @@ -1125,19 +1126,18 @@ window.CodeMirror = (function() { function fromCoordSystem(cm, coords, context) { if (context == "div") return coords; var left = coords.left, top = coords.top; + // First move into "page" coordinate system if (context == "page") { left -= window.pageXOffset || (document.documentElement || document.body).scrollLeft; top -= window.pageYOffset || (document.documentElement || document.body).scrollTop; + } else if (context == "local" || !context) { + var localBox = getRect(cm.display.sizer); + left += localBox.left; + top += localBox.top; } + var lineSpaceBox = getRect(cm.display.lineSpace); - left -= lineSpaceBox.left; - top -= lineSpaceBox.top; - if (context == "local" || !context) { - var editorBox = getRect(cm.display.wrapper); - left += editorBox.left; - top += editorBox.top; - } - return {left: left, top: top}; + return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}; } function charCoords(cm, pos, context, lineObj) { diff --git a/test/test.js b/test/test.js index d42a76bd41..ec309107bf 100644 --- a/test/test.js +++ b/test/test.js @@ -211,15 +211,18 @@ testCM("coords", function(cm) { testCM("coordsChar", function(cm) { addDoc(cm, 35, 70); - for (var ch = 0; ch <= 35; ch += 5) { - for (var line = 0; line < 70; line += 5) { - cm.setCursor(line, ch); - var coords = cm.charCoords(Pos(line, ch)); - var pos = cm.coordsChar({left: coords.left, top: coords.top + 5}); - eqPos(pos, Pos(line, ch)); + for (var i = 0; i < 2; ++i) { + var sys = i ? "local" : "page"; + for (var ch = 0; ch <= 35; ch += 5) { + for (var line = 0; line < 70; line += 5) { + cm.setCursor(line, ch); + var coords = cm.charCoords(Pos(line, ch), sys); + var pos = cm.coordsChar({left: coords.left + 1, top: coords.top + 1}, sys); + eqPos(pos, Pos(line, ch)); + } } } -}); +}, {lineNumbers: true}); testCM("posFromIndex", function(cm) { cm.setValue( From b800af364642d1e053cfb3e6f2c196bdd1bc1cd0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 30 May 2013 13:39:07 +0200 Subject: [PATCH 0630/5273] Add a lineAtHeight method Issue #1556 --- doc/manual.html | 7 ++++++- lib/codemirror.js | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index 2b3874aaa5..2d78dbe454 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1299,7 +1299,7 @@

    Sizing, scrolling and positioning methods

    end (false) of the selection, or, if a {line, ch} object is given, it specifies the precise position at which you want to measure. -
    cm.charCoords(pos: {line, ch}, mode: string) → {left, right, top, bottom}
    +
    cm.charCoords(pos: {line, ch}, ?mode: string) → {left, right, top, bottom}
    Returns the position and dimensions of an arbitrary character. pos should be a {line, ch} object. This differs from cursorCoords in that @@ -1313,6 +1313,11 @@

    Sizing, scrolling and positioning methods

    the coordinates are interpreted. It may be "window", "page" (the default), or "local".
    +
    cm.lineAtHeight(height: number, ?mode: string) → number
    +
    Computes the line at the given pixel + height. mode can be one of the same strings + that coordsChar + accepts.
    cm.defaultTextHeight() → number
    Returns the line height of the default font for the editor.
    cm.defaultCharWidth() → number
    diff --git a/lib/codemirror.js b/lib/codemirror.js index 6b452d699d..191804ccc0 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2851,6 +2851,11 @@ window.CodeMirror = (function() { 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); + }, + defaultTextHeight: function() { return textHeight(this.display); }, defaultCharWidth: function() { return charWidth(this.display); }, From fb6df7fb3bb796eb26185e9dda894b0b868f92aa Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 30 May 2013 13:47:45 +0200 Subject: [PATCH 0631/5273] [vim keymap] Fix reliance on bug in coordsChar --- keymap/vim.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 51b93aec30..d29f39cac4 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2811,10 +2811,10 @@ } function getUserVisibleLines(cm) { var scrollInfo = cm.getScrollInfo(); - var occludeTorleranceTop = 6; - var occludeTorleranceBottom = 10; - var from = cm.coordsChar({left:0, top: occludeTorleranceTop}, 'local'); - var bottomY = scrollInfo.clientHeight - occludeTorleranceBottom; + var occludeToleranceTop = 6; + var occludeToleranceBottom = 10; + var from = cm.coordsChar({left:0, top: occludeToleranceTop + scrollInfo.top}, 'local'); + var bottomY = scrollInfo.clientHeight - occludeToleranceBottom + scrollInfo.top; var to = cm.coordsChar({left:0, top: bottomY}, 'local'); return {top: from.line, bottom: to.line}; } From a8088496ad582499fe7fb9a22b1f6ae66f6b88bd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 30 May 2013 14:09:01 +0200 Subject: [PATCH 0632/5273] [closebrackets addon] Add 'explode' feature Issue #1552 --- addon/edit/closebrackets.js | 40 ++++++++++++++++++++++++++++++------- doc/manual.html | 12 +++++++---- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 2abc8c5fe6..32819516fb 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -1,23 +1,36 @@ (function() { var DEFAULT_BRACKETS = "()[]{}''\"\""; + var DEFAULT_EXPLODE_ON_ENTER = "[]{}"; var SPACE_CHAR_REGEX = /\s/; CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { - var wasOn = old && old != CodeMirror.Init; - if (val && !wasOn) - cm.addKeyMap(buildKeymap(typeof val == "string" ? val : DEFAULT_BRACKETS)); - else if (!val && wasOn) + if (old != CodeMirror.Init && old) cm.removeKeyMap("autoCloseBrackets"); + if (!val) return; + var pairs = DEFAULT_BRACKETS, explode = DEFAULT_EXPLODE_ON_ENTER; + if (typeof val == "string") pairs = val; + else if (typeof val == "object") { + if (val.pairs != null) pairs = val.pairs; + if (val.explode != null) explode = val.explode; + } + var map = buildKeymap(pairs); + if (explode) map.Enter = buildExplodeHandler(explode); + cm.addKeyMap(map); }); + function charsAround(cm, pos) { + var str = cm.getRange(CodeMirror.Pos(pos.line, pos.ch - 1), + CodeMirror.Pos(pos.line, pos.ch + 1)); + return str.length == 2 ? str : null; + } + function buildKeymap(pairs) { var map = { name : "autoCloseBrackets", Backspace: function(cm) { if (cm.somethingSelected()) return CodeMirror.Pass; - var cur = cm.getCursor(), line = cm.getLine(cur.line); - if (cur.ch && cur.ch < line.length && - pairs.indexOf(line.slice(cur.ch - 1, cur.ch + 1)) % 2 == 0) + var cur = cm.getCursor(), around = charsAround(cm, cur); + if (around && pairs.indexOf(line.slice(cur.ch - 1, cur.ch + 1)) % 2 == 0) cm.replaceRange("", CodeMirror.Pos(cur.line, cur.ch - 1), CodeMirror.Pos(cur.line, cur.ch + 1)); else return CodeMirror.Pass; @@ -51,4 +64,17 @@ })(pairs.charAt(i), pairs.charAt(i + 1)); return map; } + + function buildExplodeHandler(pairs) { + return function(cm) { + var cur = cm.getCursor(), around = charsAround(cm, cur); + if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; + cm.operation(function() { + var newPos = CodeMirror.Pos(cur.line + 1, 0); + cm.replaceSelection("\n\n", {anchor: newPos, head: newPos}, "+input"); + cm.indentLine(cur.line + 1, null, true); + cm.indentLine(cur.line + 2, null, true); + }); + }; + } })(); diff --git a/doc/manual.html b/doc/manual.html index 2d78dbe454..cc9a1d8b86 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1574,10 +1574,14 @@

    Add-ons

    edit/closebrackets.js
    Defines an option autoCloseBrackets that will auto-close brackets and quotes when typed. By default, it'll - auto-close ()[]{}''"", but you can pass it a - string similar to that (containing pairs of matching characters) - to customize it. Demo - here.
    + auto-close ()[]{}''"", but you can pass it a string + similar to that (containing pairs of matching characters), or an + object with pairs and + optionally explode properties to customize + 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.
    edit/trailingspace.js
    Adds an option showTrailingSpace which, when From a092d987583dbc677deae277707037ef23c1476f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 30 May 2013 14:35:21 +0200 Subject: [PATCH 0633/5273] [show-hint addon] More complete documentation --- doc/manual.html | 69 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index cc9a1d8b86..ffa7c6f09c 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1695,14 +1695,69 @@

    Add-ons

    hint/show-hint.js
    Provides a framework for showing autocompletion hints. Defines CodeMirror.showHint, which takes a - CodeMirror instance and a hinting function, and pops up a widget - that allows the user to select a completion. Hinting functions - are function that take an editor instance, and return + CodeMirror instance, a hinting function, and optionally an + options object, and pops up a widget that allows the user to + select a completion. Hinting functions are function that take an + editor instance and an optional options object, and return a {list, from, to} object, where list - is an array of strings (the completions), and from - and to give the start and end of the token that is - being completed. Depends - on addon/hint/show-hint.css. Check + is an array of strings or objects (the completions), + and from and to give the start and end + of the token that is being completed. When completions aren't + simple strings, they should be objects with the folowing + properties: +
    +
    text: string
    +
    The completion text. This is the only required + property.
    +
    displayText: string
    +
    The text that should be displayed in the menu.
    +
    className: string
    +
    A CSS class name to apply to the completion's line in the + menu.
    +
    render: fn(Element, self, data)
    +
    A method used to create the DOM structure for showing the + completion by appending it to its first argument.
    +
    hint: fn(CodeMirror, self, data)
    +
    A method used to actually apply the completion, instead of + the default behavior.
    +
    + The plugin understands the following options (the options object + will also be passed along to the hinting function, which may + understand additional options): +
    +
    async: boolean
    +
    When set to true, the hinting function's signature should + be (cm, callback, ?options), and the completion + interface will only be popped up when the hinting function + calls the callback, passing it the object holding the + completions.
    +
    completeSingle: boolean
    +
    Determines whether, when only a single completion is + available, it is completed without showing the dialog. + Defaults to true.
    +
    alignWithWord: boolean
    +
    Whether the pop-up should be horizontally aligned with the + start of the word (true, default), or with the cursor (false).
    +
    customKeys: keymap
    +
    Allows you to provide a custom keymap of keys to be active + when the pop-up is active. To bind a key to a behavior that is + already present in the default keymap, bind it to the name of + the key in the default keymap (for example "Up").
    +
    + The following events will be fired on the completions object + during completion: +
    +
    "shown" ()
    +
    Fired when the pop-up is shown.
    +
    "select" (completion, Element)
    +
    Fired when a completion is selected. Passed the completion + value (string or object) and the DOM node that represents it + in the menu.
    +
    "close" ()
    +
    Fired when the completion is finished.
    +
    + This addon depends styles + from addon/hint/show-hint.css. Check out the demo for an example.
    From 2e62847db235b3e63a7d75026fb2d6e25e5f798b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 30 May 2013 14:47:55 +0200 Subject: [PATCH 0634/5273] [show-hint addon] Make sure to clear state.completionActive when no match is found --- addon/hint/show-hint.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 504fda786b..a0661e4622 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -24,12 +24,17 @@ CodeMirror.showHint = function(cm, getHints, options) { } function showHints(data) { - if (!data || !data.list.length) return; + if (!data || !data.list.length) { + if (continued) { + cm.state.completionActive = false; + CodeMirror.signal(data, "close"); + } + return; + } + var completions = data.list; - // When there is only one completion, use it directly. - if (!continued && options.completeSingle !== false && completions.length == 1) { + if (!continued && options.completeSingle != false && completions.length == 1) { pickCompletion(cm, data, completions[0]); - CodeMirror.signal(data, "close"); return true; } From 8955ce4817a754674594144b64aa1bac59c227d8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 30 May 2013 15:16:50 +0200 Subject: [PATCH 0635/5273] Add support for "window" coordinate system to charCoords/cursorCoords --- lib/codemirror.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 191804ccc0..a5fc2f2ed3 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1100,6 +1100,9 @@ window.CodeMirror = (function() { cm.display.lineNumChars = null; } + function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } + function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } + // Context is one of "line", "div" (display.lineDiv), "local"/null (editor), or "page" function intoCoordSystem(cm, lineObj, rect, context) { if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { @@ -1111,10 +1114,10 @@ window.CodeMirror = (function() { var yOff = heightAtLine(cm, lineObj); if (context == "local") yOff += paddingTop(cm.display); else yOff -= cm.display.viewOffset; - if (context == "page") { + if (context == "page" || context == "window") { var lOff = getRect(cm.display.lineSpace); - yOff += lOff.top + (window.pageYOffset || (document.documentElement || document.body).scrollTop); - var xOff = lOff.left + (window.pageXOffset || (document.documentElement || document.body).scrollLeft); + 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; @@ -1128,8 +1131,8 @@ window.CodeMirror = (function() { var left = coords.left, top = coords.top; // First move into "page" coordinate system if (context == "page") { - left -= window.pageXOffset || (document.documentElement || document.body).scrollLeft; - top -= window.pageYOffset || (document.documentElement || document.body).scrollTop; + left -= pageScrollX(); + top -= pageScrollY(); } else if (context == "local" || !context) { var localBox = getRect(cm.display.sizer); left += localBox.left; From 14fc698b95f4229bf4609e84caf2194c9c2c214b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 30 May 2013 15:25:58 +0200 Subject: [PATCH 0636/5273] Remove explicit compensation for paddingTop in scrolling code Local coords now include paddingTop. Issue #1557 --- lib/codemirror.js | 13 ++++++------- test/test.js | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index a5fc2f2ed3..f56c6880e4 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2537,9 +2537,9 @@ window.CodeMirror = (function() { function scrollCursorIntoView(cm) { var coords = scrollPosIntoView(cm, cm.doc.sel.head, cm.options.cursorScrollMargin); if (!cm.state.focused) return; - var display = cm.display, box = getRect(display.sizer), doScroll = null, pTop = paddingTop(cm.display); - if (coords.top + pTop + box.top < 0) doScroll = true; - else if (coords.bottom + pTop + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; + var display = cm.display, box = getRect(display.sizer), 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 hidden = display.cursor.style.display == "none"; if (hidden) { @@ -2577,12 +2577,11 @@ window.CodeMirror = (function() { } function calculateScrollPos(cm, x1, y1, x2, y2) { - var display = cm.display, pt = paddingTop(display); - y1 += pt; y2 += pt; + var display = cm.display, snapMargin = textHeight(cm.display); if (y1 < 0) y1 = 0; var screen = display.scroller.clientHeight - scrollerCutOff, screentop = display.scroller.scrollTop, result = {}; var docBottom = cm.doc.height + paddingVert(display); - var atTop = y1 < pt + 10, atBottom = y2 + pt > docBottom - 10; + var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; if (y1 < screentop) { result.scrollTop = atTop ? 0 : y1; } else if (y2 > screentop + screen) { @@ -2950,7 +2949,7 @@ window.CodeMirror = (function() { if (left + node.offsetWidth > hspace) left = hspace - node.offsetWidth; } - node.style.top = (top + paddingTop(display)) + "px"; + node.style.top = top + "px"; node.style.left = node.style.right = ""; if (horiz == "right") { left = display.sizer.clientWidth - node.offsetWidth; diff --git a/test/test.js b/test/test.js index ec309107bf..07e2d67130 100644 --- a/test/test.js +++ b/test/test.js @@ -516,6 +516,24 @@ testCM("scrollSnap", function(cm) { is(info.left == 0 && info.top + 2 > info.height - cm.getScrollerElement().clientHeight, "scrolled clean to bottom"); }); +testCM("scrollIntoView", function(cm) { + var outer = cm.getWrapperElement().getBoundingClientRect(); + function test(line, ch) { + var pos = Pos(line, ch); + cm.scrollIntoView(pos); + var box = cm.charCoords(pos, "window"); + is(box.left >= outer.left && box.right <= outer.right && + box.top >= outer.top && box.bottom <= outer.bottom); + } + addDoc(cm, 200, 200); + test(199, 199); + test(0, 0); + test(100, 100); + test(199, 0); + test(0, 199); + test(100, 100); +}); + testCM("selectionPos", function(cm) { if (phantom) return; cm.setSize(100, 100); From 97b3110549e3e68a5519cff294929d149bdbff2c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 30 May 2013 15:36:30 +0200 Subject: [PATCH 0637/5273] Another test that fails mysteriously on Travis' Phantom (but not on my local one, or in a real browser) --- test/test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test.js b/test/test.js index 07e2d67130..cefe14cc90 100644 --- a/test/test.js +++ b/test/test.js @@ -517,6 +517,7 @@ testCM("scrollSnap", function(cm) { }); testCM("scrollIntoView", function(cm) { + if (phantom) return; var outer = cm.getWrapperElement().getBoundingClientRect(); function test(line, ch) { var pos = Pos(line, ch); From c2f527ecea98b99eb5d21fbf666e672412a0a115 Mon Sep 17 00:00:00 2001 From: Mike Ivanov Date: Thu, 30 May 2013 20:43:09 -0300 Subject: [PATCH 0638/5273] Fix a non-word --- doc/manual.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index ffa7c6f09c..b36053a4fd 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -757,14 +757,14 @@

    Constructor

    Content manipulation methods

    -
    doc.getValue(?seperator: string) → string
    +
    doc.getValue(?separator: string) → string
    Get the current editor content. You can pass it an optional argument to specify the string to be used to separate lines (defaults to "\n").
    doc.setValue(content: string)
    Set the editor content.
    -
    doc.getRange(from: {line, ch}, to: {line, ch}, ?seperator: string) → string
    +
    doc.getRange(from: {line, ch}, to: {line, ch}, ?separator: string) → string
    Get the text between the given points in the editor, which should be {line, ch} objects. An optional third argument can be given to indicate the line separator string to From 83709e32d44941bfef4e3f7bce02b68bde9ef663 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 31 May 2013 10:07:38 +0200 Subject: [PATCH 0639/5273] Fix bug in measuring of lines with only collapsed elements Closes #1559 --- lib/codemirror.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index f56c6880e4..ab09ad7f2c 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4153,9 +4153,8 @@ window.CodeMirror = (function() { } function lineContent(cm, realLine, measure) { - var merged, line = realLine, lineBefore, sawBefore, simple = true; + var merged, line = realLine, lineBefore, sawBefore, empty = true; while (merged = collapsedSpanAtStart(line)) { - simple = false; line = getLine(cm.doc, merged.find().from.line); if (!lineBefore) lineBefore = line; } @@ -4165,6 +4164,7 @@ window.CodeMirror = (function() { if (line.textClass) builder.pre.className = line.textClass; do { + if (line.text) empty = false; builder.measure = line == realLine && measure; builder.pos = 0; builder.addToken = builder.measure ? buildTokenMeasure : buildToken; @@ -4176,14 +4176,11 @@ window.CodeMirror = (function() { } var next = insertLineContent(line, builder, getLineStyles(cm, line)); sawBefore = line == lineBefore; - if (next) { - line = getLine(cm.doc, next.to.line); - simple = false; - } + if (next) line = getLine(cm.doc, next.to.line); } while (next); if (measure && !builder.addedOne) - measure[0] = builder.pre.appendChild(simple ? elt("span", "\u00a0") : zeroWidthElement(cm.display.measure)); + measure[0] = builder.pre.appendChild(empty ? elt("span", "\u00a0") : zeroWidthElement(cm.display.measure)); if (!builder.pre.firstChild && !lineIsHidden(cm.doc, realLine)) builder.pre.appendChild(document.createTextNode("\u00a0")); From f338135f2f35dd18d3f6e948edcaeae393150035 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 31 May 2013 10:50:39 +0200 Subject: [PATCH 0640/5273] Support a disableInput property on keymaps Stop suppressing key events for nofallthrough keymaps. Issue #1558 --- keymap/emacs.js | 2 +- keymap/vim.js | 1 + lib/codemirror.js | 21 +++++++++++++-------- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/keymap/emacs.js b/keymap/emacs.js index fab3ab9fe6..39bea17dcf 100644 --- a/keymap/emacs.js +++ b/keymap/emacs.js @@ -25,6 +25,6 @@ CodeMirror.keyMap["emacs-Ctrl-X"] = { "Ctrl-S": "save", "Ctrl-W": "save", "S": "saveAll", "F": "open", "U": "undo", "K": "close", - auto: "emacs", nofallthrough: true + auto: "emacs", nofallthrough: true, disableInput: true }; })(); diff --git a/keymap/vim.js b/keymap/vim.js index d29f39cac4..bd1c16c292 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -3208,6 +3208,7 @@ var modifiers = ['Shift', 'Ctrl']; var cmToVimKeymap = { 'nofallthrough': true, + 'disableInput': true, 'style': 'fat-cursor' }; function bindKeys(keys, modifier) { diff --git a/lib/codemirror.js b/lib/codemirror.js index ab09ad7f2c..9a8bd37379 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -236,9 +236,11 @@ window.CodeMirror = (function() { } function keyMapChanged(cm) { - var style = keyMap[cm.options.keyMap].style; + var map = keyMap[cm.options.keyMap], style = map.style; cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") + (style ? " cm-keymap-" + style : ""); + if (map.disableInput) cm.doc.cantEdit |= cantEdit_keymap; + else cm.doc.cantEdit &= ~cantEdit_keymap; } function themeChanged(cm) { @@ -2003,7 +2005,6 @@ window.CodeMirror = (function() { } else { handled = lookupKey(name, keymaps, function(b) { return doHandleBinding(cm, b); }); } - if (handled == "stop") handled = false; if (handled) { e_preventDefault(e); @@ -2485,7 +2486,7 @@ window.CodeMirror = (function() { function skipAtomic(doc, pos, bias, mayClear) { var flipped = false, curPos = pos; var dir = bias || 1; - doc.cantEdit = false; + doc.cantEdit &= ~cantEdit_inatomic; search: for (;;) { var line = getLine(doc, curPos.line); if (line.markedSpans) { @@ -2517,7 +2518,7 @@ window.CodeMirror = (function() { // -- try again *with* clearing, if we didn't already if (!mayClear) return skipAtomic(doc, pos, bias, true); // Otherwise, turn off editing until further notice, and return the start of the doc - doc.cantEdit = true; + doc.cantEdit |= cantEdit_inatomic; return Pos(doc.first, 0); } flipped = true; newPos = pos; dir = -dir; @@ -3428,7 +3429,7 @@ window.CodeMirror = (function() { for (var i = 0; i < maps.length; ++i) { var done = lookup(maps[i]); - if (done) return done; + if (done) return done != "stop"; } } function isModifierKey(event) { @@ -3610,8 +3611,8 @@ window.CodeMirror = (function() { if (min != null && cm) regChange(cm, min, max + 1); this.lines.length = 0; this.explicitlyCleared = true; - if (this.collapsed && this.doc.cantEdit) { - this.doc.cantEdit = false; + if (this.atomic && (this.doc.cantEdit & cantEdit_inatomic)) { + this.doc.cantEdit &= ~cantEdit_inatomic; if (cm) reCheckSelection(cm); } if (withOp) endOperation(cm); @@ -4527,6 +4528,8 @@ window.CodeMirror = (function() { } }; + var cantEdit_inatomic = 1, cantEdit_keymap = 2; + var nextDocId = 0; var Doc = CodeMirror.Doc = function(text, mode, firstLine) { if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); @@ -4535,7 +4538,7 @@ window.CodeMirror = (function() { BranchChunk.call(this, [new LeafChunk([makeLine("", null)])]); this.first = firstLine; this.scrollTop = this.scrollLeft = 0; - this.cantEdit = false; + this.cantEdit = 0; this.history = makeHistory(); this.frontier = firstLine; var start = Pos(firstLine, 0); @@ -4783,6 +4786,8 @@ window.CodeMirror = (function() { loadMode(cm); if (!cm.options.lineWrapping) computeMaxLength(cm); cm.options.mode = doc.modeOption; + if (keyMap[cm.options.keyMap].disableInput) doc.cantEdit |= cantEdit_keymap; + else doc.cantEdit &= ~cantEdit_keymap; regChange(cm); } From 63a49817a4522ada322ea81fd8b341d4dd7ee598 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Sat, 1 Jun 2013 00:54:26 -0400 Subject: [PATCH 0641/5273] Change disableInput behavior to allow programmatic edits. --- lib/codemirror.js | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 9a8bd37379..5f361e4b3e 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -239,8 +239,7 @@ window.CodeMirror = (function() { var map = keyMap[cm.options.keyMap], style = map.style; cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") + (style ? " cm-keymap-" + style : ""); - if (map.disableInput) cm.doc.cantEdit |= cantEdit_keymap; - else cm.doc.cantEdit &= ~cantEdit_keymap; + cm.doc.disableInput = !!map.disableInput; } function themeChanged(cm) { @@ -1423,7 +1422,7 @@ window.CodeMirror = (function() { if (!cm.state.focused || hasSelection(input) || isReadOnly(cm)) return false; var text = input.value; if (text == prevInput && posEq(sel.from, sel.to)) return false; - if (ie && !ie_lt9 && cm.display.inputHasSelection === text) { + if (cm.doc.disableInput || ie && !ie_lt9 && cm.display.inputHasSelection === text) { resetInput(cm, true); return false; } @@ -2486,7 +2485,7 @@ window.CodeMirror = (function() { function skipAtomic(doc, pos, bias, mayClear) { var flipped = false, curPos = pos; var dir = bias || 1; - doc.cantEdit &= ~cantEdit_inatomic; + doc.cantEdit = false; search: for (;;) { var line = getLine(doc, curPos.line); if (line.markedSpans) { @@ -2518,7 +2517,7 @@ window.CodeMirror = (function() { // -- try again *with* clearing, if we didn't already if (!mayClear) return skipAtomic(doc, pos, bias, true); // Otherwise, turn off editing until further notice, and return the start of the doc - doc.cantEdit |= cantEdit_inatomic; + doc.cantEdit = true; return Pos(doc.first, 0); } flipped = true; newPos = pos; dir = -dir; @@ -3611,8 +3610,8 @@ window.CodeMirror = (function() { if (min != null && cm) regChange(cm, min, max + 1); this.lines.length = 0; this.explicitlyCleared = true; - if (this.atomic && (this.doc.cantEdit & cantEdit_inatomic)) { - this.doc.cantEdit &= ~cantEdit_inatomic; + if (this.atomic && this.doc.cantEdit) { + this.doc.cantEdit = false; if (cm) reCheckSelection(cm); } if (withOp) endOperation(cm); @@ -4528,8 +4527,6 @@ window.CodeMirror = (function() { } }; - var cantEdit_inatomic = 1, cantEdit_keymap = 2; - var nextDocId = 0; var Doc = CodeMirror.Doc = function(text, mode, firstLine) { if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); @@ -4538,7 +4535,7 @@ window.CodeMirror = (function() { BranchChunk.call(this, [new LeafChunk([makeLine("", null)])]); this.first = firstLine; this.scrollTop = this.scrollLeft = 0; - this.cantEdit = 0; + this.cantEdit = false; this.history = makeHistory(); this.frontier = firstLine; var start = Pos(firstLine, 0); @@ -4786,8 +4783,7 @@ window.CodeMirror = (function() { loadMode(cm); if (!cm.options.lineWrapping) computeMaxLength(cm); cm.options.mode = doc.modeOption; - if (keyMap[cm.options.keyMap].disableInput) doc.cantEdit |= cantEdit_keymap; - else doc.cantEdit &= ~cantEdit_keymap; + doc.disableInput = !!keyMap[cm.options.keyMap].disableInput; regChange(cm); } From c086444347fae9c4bca0d2b98c19b7499539fd57 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 2 Jun 2013 17:42:59 +0200 Subject: [PATCH 0642/5273] Fixup 63a49817a4522ada322ea81fd8b341d4dd7ee598 Issue #1565 --- lib/codemirror.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 5f361e4b3e..d378040336 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -239,7 +239,7 @@ window.CodeMirror = (function() { var map = keyMap[cm.options.keyMap], style = map.style; cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-keymap-\S+/g, "") + (style ? " cm-keymap-" + style : ""); - cm.doc.disableInput = !!map.disableInput; + cm.state.disableInput = map.disableInput; } function themeChanged(cm) { @@ -1419,10 +1419,10 @@ window.CodeMirror = (function() { // supported or compatible enough yet to rely on.) function readInput(cm) { var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc, sel = doc.sel; - if (!cm.state.focused || hasSelection(input) || isReadOnly(cm)) return false; + if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.state.disableInput) return false; var text = input.value; if (text == prevInput && posEq(sel.from, sel.to)) return false; - if (cm.doc.disableInput || ie && !ie_lt9 && cm.display.inputHasSelection === text) { + if (ie && !ie_lt9 && cm.display.inputHasSelection === text) { resetInput(cm, true); return false; } @@ -4783,7 +4783,6 @@ window.CodeMirror = (function() { loadMode(cm); if (!cm.options.lineWrapping) computeMaxLength(cm); cm.options.mode = doc.modeOption; - doc.disableInput = !!keyMap[cm.options.keyMap].disableInput; regChange(cm); } From 88efc61e32fefde35b845510c6445b9bb1be7bb8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 2 Jun 2013 18:02:37 +0200 Subject: [PATCH 0643/5273] [closebrackets addon] Fix reference to removed variable Issue #1552 --- 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 32819516fb..6fbf38ae67 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -30,7 +30,7 @@ Backspace: function(cm) { if (cm.somethingSelected()) return CodeMirror.Pass; var cur = cm.getCursor(), around = charsAround(cm, cur); - if (around && pairs.indexOf(line.slice(cur.ch - 1, cur.ch + 1)) % 2 == 0) + if (around && pairs.indexOf(around) % 2 == 0) cm.replaceRange("", CodeMirror.Pos(cur.line, cur.ch - 1), CodeMirror.Pos(cur.line, cur.ch + 1)); else return CodeMirror.Pass; From 5e9bcf71dfe0d449cb045aa6c51404620e5a49e5 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Sat, 1 Jun 2013 10:15:02 -0400 Subject: [PATCH 0644/5273] [vim keymap] Add support for :sort --- keymap/vim.js | 92 ++++++++++++++++++++++++++++++++++++++++++++---- test/vim_test.js | 55 ++++++++++++++++++++++++++++- 2 files changed, 139 insertions(+), 8 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index bd1c16c292..df40bfc02e 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -967,7 +967,9 @@ }, processEx: function(cm, vim, command) { function onPromptClose(input) { - exCommandDispatcher.processCommand(cm, input); + // Give the prompt some time to close so that if processCommand shows + // an error, the elements don't overlap. + window.setTimeout(10, exCommandDispatcher.processCommand(cm, input)); } function onPromptKeyDown(e, input, close) { var keyName = CodeMirror.keyName(e); @@ -1189,7 +1191,7 @@ return null; }, jumpToMark: function(cm, motionArgs, vim) { - var best = cm.getCursor(); + var best = cm.getCursor(); for (var i = 0; i < motionArgs.repeat; i++) { var cursor = best; for (var key in vim.marks) { @@ -2150,7 +2152,7 @@ } }, // TODO: The original Vim implementation only operates on level 1 and 2. - // The current implementation doesn't check for code block level and + // The current implementation doesn't check for code block level and // therefore it operates on any levels. method: { init: function(state) { @@ -2202,7 +2204,7 @@ reverseSymb: (forward ? { ')': '(', '}': '{' } : { '(': ')', '{': '}' })[symb], forward: forward, depth: 0, - curMoveThrough: false + curMoveThrough: false }; var mode = symbolToMode[symb]; if(!mode)return cur; @@ -2828,6 +2830,7 @@ { name: 'write', shortName: 'w', type: 'builtIn' }, { name: 'undo', shortName: 'u', type: 'builtIn' }, { name: 'redo', shortName: 'red', type: 'builtIn' }, + { name: 'sort', shortName: 'sor', type: 'builtIn'}, { name: 'substitute', shortName: 's', type: 'builtIn'}, { name: 'nohlsearch', shortName: 'noh', type: 'builtIn'}, { name: 'delmarks', shortName: 'delm', type: 'builtin'} @@ -2874,7 +2877,11 @@ showConfirm(cm, 'Not an editor command ":' + input + '"'); return; } - exCommands[commandName](cm, params); + try { + exCommands[commandName](cm, params); + } catch(e) { + showConfirm(cm, e); + } }, parseInput_: function(cm, inputStream, result) { inputStream.eatWhile(':'); @@ -2919,7 +2926,7 @@ break; default: inputStream.backUp(1); - return cm.getCursor().line; + return undefined; } }, parseCommandArgs_: function(inputStream, params, command) { @@ -3029,6 +3036,77 @@ linewise: true }, repeatOverride: params.line+1}); }, + sort: function(cm, params) { + var reverse, ignoreCase, unique, number; + function parseArgs() { + if (params.argString) { + var args = new CodeMirror.StringStream(params.argString); + if (args.eat('!')) { reverse = true; } + if (args.eol()) { return; } + if (!args.eatSpace()) { throw 'invalid arguments ' + args.match(/.*/)[0]; } + var opts = args.match(/[a-z]+/); + if (opts) { + opts = opts[0]; + ignoreCase = opts.indexOf('i') != -1; + unique = opts.indexOf('u') != -1; + var decimal = opts.indexOf('d') != -1 && 1; + var hex = opts.indexOf('x') != -1 && 1; + var octal = opts.indexOf('o') != -1 && 1; + if (decimal + hex + octal > 1) { throw 'invalid arguments'; } + number = decimal && 'decimal' || hex && 'hex' || octal && 'octal'; + } + if (args.eatSpace() && args.match(/\/.*\//)) { throw 'patterns not supported'; } + } + } + parseArgs(); + var lineStart = params.line || cm.firstLine(); + var lineEnd = params.lineEnd || params.line || cm.lastLine(); + if (lineStart == lineEnd) { return; } + var curStart = { line: lineStart, ch: 0 }; + var curEnd = { line: lineEnd, ch: lineLength(cm, lineEnd) }; + var text = cm.getRange(curStart, curEnd).split('\n'); + var numberRegex = (number == 'decimal') ? /(-?)([\d]+)/ : + (number == 'hex') ? /(-?)(?:0x)?([0-9a-f]+)/i : + (number == 'octal') ? /([0-7]+)/ : null; + var radix = (number == 'decimal') ? 10 : (number == 'hex') ? 16 : (number == 'octal') ? 8 : null; + var numPart = [], textPart = []; + if (number) { + for (var i = 0; i < text.length; i++) { + if (numberRegex.exec(text[i])) { + numPart.push(text[i]); + } else { + textPart.push(text[i]); + } + } + } else { + textPart = text; + } + function compareFn(a, b) { + if (reverse) { var tmp; tmp = a; a = b; b = tmp; } + if (ignoreCase) { a = a.toLowerCase(); b = b.toLowerCase(); } + var anum = number && numberRegex.exec(a); + var bnum = number && numberRegex.exec(b); + if (!anum) { return a < b ? -1 : 1; } + anum = parseInt((anum[1] + anum[2]).toLowerCase(), radix); + bnum = parseInt((bnum[1] + bnum[2]).toLowerCase(), radix); + return anum - bnum; + } + numPart.sort(compareFn); + textPart.sort(compareFn); + text = (!reverse) ? textPart.concat(numPart) : numPart.concat(textPart); + if (unique) { // Remove duplicate lines + var textOld = text; + var lastLine; + text = [] + for (var i = 0; i < textOld.length; i++) { + if (textOld[i] != lastLine) { + text.push(textOld[i]); + } + lastLine = textOld[i]; + } + } + cm.replaceRange(text.join('\n'), curStart, curEnd); + }, substitute: function(cm, params) { var argString = params.argString; var slashes = findUnescapedSlashes(argString); @@ -3067,7 +3145,7 @@ } var state = getSearchState(cm); var query = state.getQuery(); - var lineStart = params.line || cm.firstLine(); + var lineStart = (params.line !== undefined) ? params.line : cm.getCursor().line; var lineEnd = params.lineEnd || lineStart; if (count) { lineStart = lineEnd; diff --git a/test/vim_test.js b/test/vim_test.js index f3b53508f6..28c967b8f5 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -11,7 +11,7 @@ var code = '' + ' bufp = buf;\n' + ' }\n' + '\n' + -' return (--n >= 0) ? (unsigned char) *bufp++ : EOF;\n' + +' return (--n >= 0) ? (unsigned char) *bufp++ : EOF;\n' + ' \n' + '}\n'; @@ -1940,6 +1940,59 @@ testVim('ex_write', function(cm, vim, helpers) { } CodeMirror.commands.save = tmp; }); +testVim('ex_sort', function(cm, vim, helpers) { + helpers.doEx('sort'); + eq('Z\na\nb\nc\nd', cm.getValue()); +}, { value: 'b\nZ\nd\nc\na'}); +testVim('ex_sort_reverse', function(cm, vim, helpers) { + helpers.doEx('sort!'); + eq('d\nc\nb\na', cm.getValue()); +}, { value: 'b\nd\nc\na'}); +testVim('ex_sort_range', function(cm, vim, helpers) { + helpers.doEx('2,3sort'); + eq('b\nc\nd\na', cm.getValue()); +}, { value: 'b\nd\nc\na'}); +testVim('ex_sort_oneline', function(cm, vim, helpers) { + helpers.doEx('2sort'); + // Expect no change. + eq('b\nd\nc\na', cm.getValue()); +}, { value: 'b\nd\nc\na'}); +testVim('ex_sort_ignoreCase', function(cm, vim, helpers) { + helpers.doEx('sort i'); + eq('a\nb\nc\nd\nZ', cm.getValue()); +}, { value: 'b\nZ\nd\nc\na'}); +testVim('ex_sort_unique', function(cm, vim, helpers) { + helpers.doEx('sort u'); + eq('Z\na\nb\nc\nd', cm.getValue()); +}, { value: 'b\nZ\na\na\nd\na\nc\na'}); +testVim('ex_sort_decimal', function(cm, vim, helpers) { + helpers.doEx('sort d'); + eq('d3\n s5\n6\n.9', cm.getValue()); +}, { value: '6\nd3\n s5\n.9'}); +testVim('ex_sort_decimal_negative', function(cm, vim, helpers) { + helpers.doEx('sort d'); + eq('z-9\nd3\n s5\n6\n.9', cm.getValue()); +}, { value: '6\nd3\n s5\n.9\nz-9'}); +testVim('ex_sort_decimal_reverse', function(cm, vim, helpers) { + helpers.doEx('sort! d'); + eq('.9\n6\n s5\nd3', cm.getValue()); +}, { value: '6\nd3\n s5\n.9'}); +testVim('ex_sort_hex', function(cm, vim, helpers) { + helpers.doEx('sort x'); + eq(' s5\n6\n.9\n&0xB\nd3', cm.getValue()); +}, { value: '6\nd3\n s5\n&0xB\n.9'}); +testVim('ex_sort_octal', function(cm, vim, helpers) { + helpers.doEx('sort o'); + eq('.8\n.9\nd3\n s5\n6', cm.getValue()); +}, { value: '6\nd3\n s5\n.9\n.8'}); +testVim('ex_sort_decimal_mixed', function(cm, vim, helpers) { + helpers.doEx('sort d'); + eq('y\nz\nc1\nb2\na3', cm.getValue()); +}, { value: 'a3\nz\nc1\ny\nb2'}); +testVim('ex_sort_decimal_mixed_reverse', function(cm, vim, helpers) { + helpers.doEx('sort! d'); + eq('a3\nb2\nc1\nz\ny', cm.getValue()); +}, { value: 'a3\nz\nc1\ny\nb2'}); testVim('ex_substitute_same_line', function(cm, vim, helpers) { cm.setCursor(1, 0); helpers.doEx('s/one/two'); From 366c18b89eb02b9e6b1e3b7c45e64ae9cb6a71e6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 2 Jun 2013 18:26:44 +0200 Subject: [PATCH 0645/5273] [show-hint addon] (experiment) Add a container option --- 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 a0661e4622..ab23e97383 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -54,7 +54,7 @@ CodeMirror.showHint = function(cm, getHints, options) { var left = pos.left, top = pos.bottom, below = true; hints.style.left = left + "px"; hints.style.top = top + "px"; - document.body.appendChild(hints); + (options.container || document.body).appendChild(hints); CodeMirror.signal(data, "shown"); // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. From 7c72746248d722fdc8c51f064e18e118d0ae7ad6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 3 Jun 2013 11:36:17 +0200 Subject: [PATCH 0646/5273] Fix bug that caused zero-length spans to occasionally survive edits Issue #1561 --- lib/codemirror.js | 7 +++++++ test/test.js | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index d378040336..eab89da931 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3847,6 +3847,13 @@ window.CodeMirror = (function() { } } } + if (sameLine && first) { + // Make sure we didn't create any zero-length spans + for (var i = 0; i < first.length; ++i) + if (first[i].from != null && first[i].from == first[i].to && first[i].marker.type != "bookmark") + first.splice(i--, 1); + if (!first.length) first = null; + } var newMarkers = [first]; if (!sameLine) { diff --git a/test/test.js b/test/test.js index cefe14cc90..fe478bb58e 100644 --- a/test/test.js +++ b/test/test.js @@ -450,6 +450,13 @@ testCM("markClearBetween", function(cm) { eq(cm.findMarksAt(Pos(1, 1)).length, 0); }); +testCM("deleteSpanCollapsedInclusiveLeft", function(cm) { + var from = Pos(1, 0), to = Pos(1, 1); + var m = cm.markText(from, to, {collapsed: true, inclusiveLeft: true}); + // Delete collapsed span. + cm.replaceRange("", from, to); +}, {value: "abc\nX\ndef"}); + testCM("bookmark", function(cm) { function p(v) { return v && Pos(v[0], v[1]); } forEach([{a: [1, 0], b: [1, 1], c: "", d: [1, 4]}, From de92ca1bab49a2f18bd6f7e9d8200a9d75270304 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 3 Jun 2013 14:06:42 +0200 Subject: [PATCH 0647/5273] Allow inline widgets to wrap again, measurement of their start and end --- lib/codemirror.css | 1 - lib/codemirror.js | 55 ++++++++++++++++++++++++++++++++-------------- test/test.js | 16 ++++++++++++++ 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index f5379d967c..52881f7dfd 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -205,7 +205,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} } .CodeMirror-widget { - display: inline-block; } .CodeMirror-wrap .CodeMirror-scroll { diff --git a/lib/codemirror.js b/lib/codemirror.js index eab89da931..b32de75c37 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -799,17 +799,17 @@ window.CodeMirror = (function() { function drawForLine(line, fromArg, toArg, retTop) { var lineObj = getLine(doc, line); var lineLen = lineObj.text.length, rVal = retTop ? Infinity : -Infinity; - function coords(ch) { - return charCoords(cm, Pos(line, ch), "div", lineObj); + 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), rightPos, left, right; + var leftPos = coords(from, "left"), rightPos, left, right; if (from == to) { rightPos = leftPos; left = right = leftPos.left; } else { - rightPos = coords(to - 1); + rightPos = coords(to - 1, "right"); if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } left = leftPos.left; right = rightPos.right; @@ -968,7 +968,7 @@ window.CodeMirror = (function() { return e.offsetLeft; } - function measureChar(cm, line, ch, data) { + function measureChar(cm, line, ch, data, bias) { var dir = -1; data = data || measureLine(cm, line); @@ -979,7 +979,8 @@ window.CodeMirror = (function() { } return {left: pos < ch ? r.right : r.left, right: pos > ch ? r.left : r.right, - top: r.top, bottom: r.bottom}; + top: bias == "right" && r.topRight != null ? r.topRight : r.top, + bottom: bias == "right" && r.bottomRight != null ? r.bottomRight : r.bottom}; } function findCachedMeasurement(cm, line) { @@ -1052,9 +1053,9 @@ window.CodeMirror = (function() { if (ie_lt9 && display.measure.first != pre) removeChildrenAndAdd(display.measure, pre); - for (var i = 0, cur; i < measure.length; ++i) if (cur = measure[i]) { - var size = getRect(cur); - var top = Math.max(0, size.top - outer.top), bot = Math.min(size.bottom - outer.top, maxBot); + function categorizeVSpan(top, bot) { + if (bot > maxBot) bot = maxBot; + if (top < 0) top = 0; for (var j = 0; j < vranges.length; j += 2) { var rtop = vranges[j], rbot = vranges[j+1]; if (rtop > bot || rbot < top) continue; @@ -1063,17 +1064,37 @@ window.CodeMirror = (function() { Math.min(bot, rbot) - Math.max(top, rtop) >= (bot - top) >> 1) { vranges[j] = Math.min(top, rtop); vranges[j+1] = Math.max(bot, rbot); - break; + return j; } } - if (j == vranges.length) vranges.push(top, bot); + vranges.push(top, bot); + return j; + } + + for (var i = 0, cur; i < measure.length; ++i) if (cur = measure[i]) { + var size; + // A widget might wrap, needs special care + if (/\bCodeMirror-widget\b/.test(cur.className) && cur.getClientRects) { + var rects = cur.getClientRects(), rLeft = rects[0], rRight = rects[rects.length - 1]; + if (rects.length == 1) { + size = rLeft; + } else { + var vCatLeft = categorizeVSpan(rLeft.top - outer.top, rLeft.bottom - outer.top); + var vCatRight = categorizeVSpan(rRight.top - outer.top, rRight.bottom - outer.top); + data[i] = {left: rLeft.left - outer.left, right: rRight.right - outer.left, + top: vCatLeft, topRight: vCatRight}; + continue; + } + } else size = getRect(cur); + var vCat = categorizeVSpan(size.top - outer.top, size.bottom - outer.top); var right = size.right; if (cur.measureRight) right = getRect(cur.measureRight).left; - data[i] = {left: size.left - outer.left, right: right - outer.left, top: j}; + data[i] = {left: size.left - outer.left, right: right - outer.left, top: vCat}; } for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) { - var vr = cur.top; + var vr = cur.top, vrRight = cur.topRight; cur.top = vranges[vr]; cur.bottom = vranges[vr+1]; + if (vrRight != null) { cur.topRight = vranges[vrRight]; cur.bottomRight = vranges[vrRight]; } } return data; @@ -1086,7 +1107,7 @@ window.CodeMirror = (function() { if (sp.collapsed && (sp.to == null || sp.to == line.text.length)) hasBadSpan = true; } var cached = !hasBadSpan && findCachedMeasurement(cm, line); - if (cached) return measureChar(cm, line, line.text.length, cached.measure).right; + if (cached) return measureChar(cm, line, line.text.length, cached.measure, "right").right; var pre = lineContent(cm, line); var end = pre.appendChild(zeroWidthElement(cm.display.measure)); @@ -1144,16 +1165,16 @@ window.CodeMirror = (function() { return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}; } - function charCoords(cm, pos, context, lineObj) { + function charCoords(cm, pos, context, lineObj, bias) { if (!lineObj) lineObj = getLine(cm.doc, pos.line); - return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch), context); + return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, null, bias), context); } function cursorCoords(cm, pos, context, lineObj, measurement) { lineObj = lineObj || getLine(cm.doc, pos.line); if (!measurement) measurement = measureLine(cm, lineObj); function get(ch, right) { - var m = measureChar(cm, lineObj, ch, measurement); + var m = measureChar(cm, lineObj, ch, measurement, right ? "right" : "left"); if (right) m.left = m.right; else m.right = m.left; return intoCoordSystem(cm, lineObj, m, context); } diff --git a/test/test.js b/test/test.js index fe478bb58e..8936be8daf 100644 --- a/test/test.js +++ b/test/test.js @@ -786,6 +786,22 @@ testCM("badNestedFold", function(cm) { is(/overlap/i.test(caught.message), "wrong error"); }); +testCM("wrappingInlineWidget", function(cm) { + cm.setSize("10em"); + var w = document.createElement("span"); + w.style.background = "yellow"; + w.innerHTML = "one two three four"; + cm.markText(Pos(0, 6), Pos(0, 9), {replacedWith: w}); + var cur0 = cm.cursorCoords(Pos(0, 0)), cur1 = cm.cursorCoords(Pos(0, 10)); + is(cur0.top < cur1.top); + is(cur0.bottom < cur1.bottom); + var curL = cm.cursorCoords(Pos(0, 6)), curR = cm.cursorCoords(Pos(0, 9)); + eq(curL.top, cur0.top); + eq(curL.bottom, cur0.bottom); + eq(curR.top, cur1.top); + eq(curR.bottom, cur1.bottom); +}, {value: "1 2 3 xxx 4 5 6", lineWrapping: true}); + testCM("inlineWidget", function(cm) { var w = cm.setBookmark(Pos(0, 2), {widget: document.createTextNode("uu")}); cm.setCursor(0, 2); From 0bcc95abe15059403e0bd4d31e839c1267e8b36d Mon Sep 17 00:00:00 2001 From: tfjgeorge Date: Tue, 4 Jun 2013 11:45:39 +0300 Subject: [PATCH 0648/5273] Update index.html. Fixed typo jsfiddle.net instead of jsfiddle.com --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 0f855ecbb3..59599c46cb 100644 --- a/index.html +++ b/index.html @@ -123,7 +123,7 @@

    Real-world uses:

  • Light Table
  • Adobe Brackets
  • jsbin.com
  • -
  • jsfiddle.com
  • +
  • jsfiddle.net
  • Bitbucket
  • Google Apps Script
  • Eloquent JavaScript
  • From 9fcee65e590a96b3dff045bf10f7db17d2d38c0d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 4 Jun 2013 11:14:19 +0200 Subject: [PATCH 0649/5273] Fix bug where measuring the right of a wrapped inline widget broke at end of line --- lib/codemirror.js | 7 ++++--- test/test.js | 10 +++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index b32de75c37..bd5d5d25d3 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -977,10 +977,11 @@ window.CodeMirror = (function() { if (r) break; if (dir < 0 && pos == 0) dir = 1; } + var rightV = (pos < ch || bias == "right") && r.topRight != null; return {left: pos < ch ? r.right : r.left, right: pos > ch ? r.left : r.right, - top: bias == "right" && r.topRight != null ? r.topRight : r.top, - bottom: bias == "right" && r.bottomRight != null ? r.bottomRight : r.bottom}; + top: rightV ? r.topRight : r.top, + bottom: rightV ? r.bottomRight : r.bottom}; } function findCachedMeasurement(cm, line) { @@ -1094,7 +1095,7 @@ window.CodeMirror = (function() { for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) { var vr = cur.top, vrRight = cur.topRight; cur.top = vranges[vr]; cur.bottom = vranges[vr+1]; - if (vrRight != null) { cur.topRight = vranges[vrRight]; cur.bottomRight = vranges[vrRight]; } + if (vrRight != null) { cur.topRight = vranges[vrRight]; cur.bottomRight = vranges[vrRight+1]; } } return data; diff --git a/test/test.js b/test/test.js index 8936be8daf..fa8cccdc6f 100644 --- a/test/test.js +++ b/test/test.js @@ -787,9 +787,9 @@ testCM("badNestedFold", function(cm) { }); testCM("wrappingInlineWidget", function(cm) { - cm.setSize("10em"); + cm.setSize("11em"); var w = document.createElement("span"); - w.style.background = "yellow"; + w.style.color = "red"; w.innerHTML = "one two three four"; cm.markText(Pos(0, 6), Pos(0, 9), {replacedWith: w}); var cur0 = cm.cursorCoords(Pos(0, 0)), cur1 = cm.cursorCoords(Pos(0, 10)); @@ -800,7 +800,11 @@ testCM("wrappingInlineWidget", function(cm) { eq(curL.bottom, cur0.bottom); eq(curR.top, cur1.top); eq(curR.bottom, cur1.bottom); -}, {value: "1 2 3 xxx 4 5 6", lineWrapping: true}); + cm.replaceRange("", Pos(0, 9), Pos(0)); + curR = cm.cursorCoords(Pos(0, 9)); + eq(curR.top, cur1.top); + eq(curR.bottom, cur1.bottom); +}, {value: "1 2 3 xxx 4", lineWrapping: true}); testCM("inlineWidget", function(cm) { var w = cm.setBookmark(Pos(0, 2), {widget: document.createTextNode("uu")}); From eafb2cadf67c9e6da560ab948dfdb2cb84baa2e3 Mon Sep 17 00:00:00 2001 From: santec Date: Wed, 5 Jun 2013 08:57:20 +0200 Subject: [PATCH 0650/5273] [sql mode] Minor fixes * index.html included codemirror.js twice * optimize .tableName syntax check --- mode/sql/index.html | 3 +-- mode/sql/sql.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mode/sql/index.html b/mode/sql/index.html index 8a2495ca24..bc3b3a819c 100644 --- a/mode/sql/index.html +++ b/mode/sql/index.html @@ -5,7 +5,6 @@ SQL Mode for CodeMirror - + + +

    CodeMirror: merge view demo

    + +
    + +

    The merge +addon provides an interface for displaying and merging diffs, +either two-way +or three-way. The left +(or center) pane is editable, and the differences with the other +pane(s) are shown live as you edit it.

    + +

    This addon depends on +the google-diff-match-patch +library to compute the diffs.

    + + diff --git a/doc/manual.html b/doc/manual.html index 4bf94b1c81..2ecd71fbe3 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1957,6 +1957,20 @@

    Add-ons

    Also gives the editor a CodeMirror-empty CSS class whenever it doesn't contain any text. See the demo.
    + +
    merge/merge.js
    +
    Implements an interface for merging changes, using either a + 2-way or a 3-way view. The CodeMirror.MergeView + constructor takes arguments similar to + the CodeMirror + constructor, first a node to append the interface to, and then + an options object. Two extra optional options are + recognized, origLeft and origRight, + which may be strings that provide original versions of the + document, which will be shown to the left and right of the + editor in non-editable CodeMirror instances. The merge interface + will highlight changes between the editable document and the + original(s) (demo).

    Writing CodeMirror Modes

    diff --git a/test/lint/lint.js b/test/lint/lint.js index 5f808922f2..4fc577fa01 100644 --- a/test/lint/lint.js +++ b/test/lint/lint.js @@ -103,7 +103,7 @@ function checkDir(dir) { fs.readdirSync(dir).forEach(function(file) { var fname = dir + "/" + file; if (/\.js$/.test(file)) checkFile(fname); - else if (fs.lstatSync(fname).isDirectory()) checkDir(fname); + else if (file != "dep" && fs.lstatSync(fname).isDirectory()) checkDir(fname); }); } From 4dee296563f3d6e6c1f1d93919e3a4875f60c70a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 19 Jun 2013 19:31:08 +0200 Subject: [PATCH 0736/5273] [show-hint addon] Fix problem with close event firing too late --- addon/hint/show-hint.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 02c94f4408..35e5cbb721 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -19,7 +19,7 @@ this.cm = cm; this.getHints = getHints; this.options = options; - this.widget = null; + this.widget = this.onClose = null; } Completion.prototype = { @@ -27,6 +27,7 @@ if (!this.active()) return; if (this.widget) this.widget.close(); + if (this.onClose) this.onClose(); this.cm.state.completionActive = null; CodeMirror.signal(this.cm, "endCompletion", this.cm); }, @@ -96,6 +97,7 @@ debounce = setTimeout(update, 170); } this.cm.on("cursorActivity", activity); + this.onClose = done; } }; From 03449c69ffebdac0648a3f4d347cddd365522572 Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Wed, 19 Jun 2013 15:53:02 -0400 Subject: [PATCH 0737/5273] [markdown mode] Fix bug with two links or email addresses on same line. --- mode/markdown/markdown.js | 4 ++-- mode/markdown/test.js | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index d93d55590e..72b0d6ced2 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -308,11 +308,11 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { return type; } - if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, true)) { + if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) { return switchInline(stream, state, inlineElement(linkinline, '>')); } - if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, true)) { + if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) { return switchInline(stream, state, inlineElement(linkemail, '>')); } diff --git a/mode/markdown/test.js b/mode/markdown/test.js index c451412fee..99ae056132 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -533,9 +533,15 @@ MT("linkWeb", "[link ] foo"); + MT("linkWebDouble", + "[link ] foo [link ]"); + MT("linkEmail", "[link ] foo"); + MT("linkEmailDouble", + "[link ] foo [link ]"); + MT("emAsterisk", "[em *foo*] bar"); From 112fdb507e33d0e3140124cdc4a689e790b2fec0 Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Wed, 19 Jun 2013 16:00:29 -0400 Subject: [PATCH 0738/5273] [test harness] Escape < and & in test input/results. --- test/mode_test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/mode_test.js b/test/mode_test.js index 79a7752492..c759b257bf 100644 --- a/test/mode_test.js +++ b/test/mode_test.js @@ -84,7 +84,7 @@ var s = ''; if (pass) { s += '
    '; - s += '
    ' + text + '
    '; + s += '
    ' + text.replace('&', '&').replace('<', '<') + '
    '; s += '
    '; s += prettyPrintOutputTable(observedOutput); s += '
    '; @@ -92,7 +92,7 @@ return s; } else { s += '
    '; - s += '
    ' + text + '
    '; + s += '
    ' + text.replace('&', '&').replace('<', '<') + '
    '; s += '
    '; s += 'expected:'; s += prettyPrintOutputTable(expectedOutput); @@ -178,7 +178,7 @@ s += '' + '' + - val.replace(/ /g,'\xb7') + + val.replace(/ /g,'\xb7').replace('&', '&').replace('<', '<') + '' + ''; } From b609e8f0e9041a619ad647d714b6ecdcf908e909 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Jun 2013 10:41:33 +0200 Subject: [PATCH 0739/5273] Document inputRead and keyHandled events --- doc/manual.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/manual.html b/doc/manual.html index 2ecd71fbe3..ceaad6b44b 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -431,6 +431,17 @@

    Events

    Will be fired when the cursor or selection moves, or any change is made to the editor content.
    +
    "keyHandled" (instance: CodeMirror, name: string, event: Event)
    +
    Fired after a key is handled through a + keymap. name is the name of the handled key (for + example "Ctrl-X" or "'q'"), + and event is the DOM keydown + or keypress event.
    + +
    "inputRead" (instance: CodeMirror, changeObj: object)
    +
    Fired whenever new input is read from the hidden textarea + (typed or pasted by the user).
    +
    "beforeSelectionChange" (instance: CodeMirror, selection: {head, anchor})
    This event is fired before the selection is moved. Its handler may modify the resulting selection head and anchor. From 7e4a1382542273717942961b862dd13da966123b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Jun 2013 10:44:37 +0200 Subject: [PATCH 0740/5273] Mark release 3.14.0 --- doc/compress.html | 2 ++ doc/manual.html | 10 ++++------ doc/oldrelease.html | 14 ++++++++++++++ index.html | 41 +++++++++++++++++++++++++++-------------- lib/codemirror.js | 2 +- package.json | 2 +- 6 files changed, 49 insertions(+), 22 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 9c0fafec18..fede6f43fa 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -30,6 +30,7 @@

    { } CodeMi

    Version: ", f); + else + f(prompt(text, "")); + } + + // Tooltips + + function tempTooltip(cm, content) { + var where = cm.cursorCoords(); + var tip = makeTooltip(where.right + 1, where.bottom, content); + function clear() { + if (!tip.parentNode) return; + cm.off("cursorActivity", clear); + fadeOut(tip); + } + setTimeout(clear, 1700); + cm.on("cursorActivity", clear); + } + + function makeTooltip(x, y, content) { + var node = elt("div", cls + "tooltip", content); + node.style.left = x + "px"; + node.style.top = y + "px"; + document.body.appendChild(node); + return node; + } + + function remove(node) { + var p = node && node.parentNode; + if (p) p.removeChild(node); + } + + function fadeOut(tooltip) { + tooltip.style.opacity = "0"; + setTimeout(function() { remove(tooltip); }, 1100); + } + + function showError(ts, cm, msg) { + if (ts.options.showError) + ts.options.showError(cm, msg); + else + tempTooltip(cm, String(msg)); + } +})(); diff --git a/demo/tern.html b/demo/tern.html new file mode 100644 index 0000000000..22464f8a60 --- /dev/null +++ b/demo/tern.html @@ -0,0 +1,95 @@ + + + + + CodeMirror: Tern Demo + + + + + + + + + + + + + + + + + + + + + + + + + +

    CodeMirror: Tern Demo

    + +

    + + + + + From 2677aba253ef5c0a1ed6332e961cef5712f334d3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 20 Jun 2013 17:37:44 +0200 Subject: [PATCH 0744/5273] [xml-fold addon] Prevent infinite recursion from weird lastIndexOf behavior Issue #1625 --- 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 b764bc0190..29d730eb71 100644 --- a/addon/fold/xml-fold.js +++ b/addon/fold/xml-fold.js @@ -43,7 +43,7 @@ } function toTagStart(iter) { for (;;) { - var lt = iter.text.lastIndexOf("<", iter.ch - 1); + var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1; if (lt == -1) { if (prevLine(iter)) continue; else return; } if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; } xmlTagStart.lastIndex = lt; @@ -65,7 +65,7 @@ } function toPrevTag(iter) { for (;;) { - var gt = iter.text.lastIndexOf(">", iter.ch - 1); + var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1; if (gt == -1) { if (prevLine(iter)) continue; else return; } if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; } var lastSlash = iter.text.lastIndexOf("/", gt); From f674dd148c27c882d3a85885caa9c27bb5638ee5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 21 Jun 2013 09:53:32 +0200 Subject: [PATCH 0745/5273] Support insertAt option to addLineWidget Issue #1627 --- doc/manual.html | 10 ++++++++-- lib/codemirror.js | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 655e64db4c..68692e2956 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1253,7 +1253,7 @@

    Widget, gutter, and decoration methods

    widget again, simply use DOM methods (move it somewhere else, or call removeChild on its parent).

    -
    cm.addLineWidget(line: integer|LineHandle, node: Element, ?options: object) → LineWidget
    +
    cm.addLineWidget(line: integer|LineHandle, node: Element, ?options: object, ?pos: integer) → LineWidget
    Adds a line widget, an element shown below a line, spanning the whole of the editor's width, and moving the lines below it downwards. line should be either an integer or a @@ -1261,7 +1261,7 @@

    Widget, gutter, and decoration methods

    will be displayed below the given line. options, when given, should be an object that configures the behavior of the widget. The following options are supported (all default to - false) → + false):
    coverGutter: boolean
    Whether the widget should cover the gutter.
    @@ -1279,6 +1279,12 @@

    Widget, gutter, and decoration methods

    drag events occurring in this widget. Default is false—the events will be left alone for the default browser handler, or specific handlers on the widget, to capture.
    +
    insertAt: integer
    +
    By default, the widget is added below other widgets for + the line. This option can be used to place it at a different + position (zero for the top, N to put it after the Nth other + widget). Note that this only has effect once, when the + widget is created. Note that the widget node will become a descendant of nodes with CodeMirror-specific CSS classes, and those classes might in some diff --git a/lib/codemirror.js b/lib/codemirror.js index 5da1f17fea..ea3f8d9328 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4078,7 +4078,9 @@ window.CodeMirror = (function() { var widget = new LineWidget(cm, node, options); if (widget.noHScroll) cm.display.alignWidgets = true; changeLine(cm, handle, function(line) { - (line.widgets || (line.widgets = [])).push(widget); + var widgets = line.widgets || (line.widgets = []); + if (options.insertAt == null) widgets.push(widget); + else widgets.splice(Math.max(widgets.length - 1, options.insertAt), 0, widget); widget.line = line; if (!lineIsHidden(cm.doc, line) || widget.showIfHidden) { var aboveVisible = heightAtLine(cm, line) < cm.display.scroller.scrollTop; From 93a850a52b98ddf5a633b793df33edb0b3794ab1 Mon Sep 17 00:00:00 2001 From: James Campos Date: Tue, 18 Jun 2013 17:56:48 -0700 Subject: [PATCH 0746/5273] [vim keymap] Fix bugs in line handling Closes #1612 --- keymap/vim.js | 49 ++++++++++++++++++++++++------------------------ test/vim_test.js | 25 +++++++++++++++++------- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index e05be03176..8c942a3ff5 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -554,19 +554,16 @@ // Clear input state and get back to normal mode. vim.inputState = new InputState(); if (vim.visualMode) { - exitVisualMode(cm, vim); + exitVisualMode(cm); } return; } - if (vim.visualMode && - cursorEqual(cm.getCursor('head'), cm.getCursor('anchor'))) { - // The selection was cleared. Exit visual mode. - exitVisualMode(cm, vim); - } + // Enter visual mode when the mouse selects text. if (!vim.visualMode && !cursorEqual(cm.getCursor('head'), cm.getCursor('anchor'))) { vim.visualMode = true; vim.visualLine = false; + cm.on('mousedown', exitVisualMode); } if (key != '0' || (key == '0' && vim.inputState.getRepeat() === 0)) { // Have to special case 0 since it's both a motion and a number. @@ -1146,7 +1143,7 @@ operators[operator](cm, operatorArgs, vim, curStart, curEnd, curOriginal); if (vim.visualMode) { - exitVisualMode(cm, vim); + exitVisualMode(cm); } if (operatorArgs.enterInsertMode) { actions.enterInsertMode(cm, {}, vim); @@ -1272,8 +1269,13 @@ } var repeat = motionArgs.repeat+(motionArgs.repeatOffset||0); var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat; - if (line < cm.firstLine() || line > cm.lastLine() ) { - return null; + var first = cm.firstLine(); + var last = cm.lastLine(); + // Vim cancels linewise motions that start on an edge and move beyond + // that edge. It does not cancel motions that do not start on an edge. + if ((line < first && cur.line == first) || + (line > last && cur.line == last)) { + return; } if(motionArgs.toFirstChar){ endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line)); @@ -1478,18 +1480,12 @@ operatorArgs.registerName, 'change', cm.getRange(curStart, curEnd), operatorArgs.linewise); if (operatorArgs.linewise) { - // Delete starting at the first nonwhitespace character of the first - // line, instead of from the start of the first line. This way we get - // an indent when we get into insert mode. This behavior isn't quite - // correct because we should treat this as a completely new line, and - // indent should be whatever codemirror thinks is the right indent. - // But cm.indentLine doesn't seem work on empty lines. - // TODO: Fix the above. - curStart.ch = - findFirstNonWhiteSpaceCharacter(cm.getLine(curStart.line)); - // Insert an additional newline so that insert mode can start there. - // curEnd should be on the first character of the new line. - cm.replaceRange('\n', curStart, curEnd); + // Push the next line back down, if there is a next line. + var replacement = curEnd.line > cm.lastLine() ? '' : '\n'; + cm.replaceRange(replacement, curStart, curEnd); + cm.indentLine(curStart.line, 'smart'); + // null ch so setCursor moves to end of line. + curStart.ch = null; } else { // Exclude trailing whitespace if the range is not all whitespace. var text = cm.getRange(curStart, curEnd); @@ -1651,6 +1647,7 @@ // equal to the repeat times the size of the previous visual // operation. if (!vim.visualMode) { + cm.on('mousedown', exitVisualMode); vim.visualMode = true; vim.visualLine = !!actionArgs.linewise; if (vim.visualLine) { @@ -1692,7 +1689,7 @@ // mode instead of exiting visual mode. vim.visualLine = false; } else { - exitVisualMode(cm, vim); + exitVisualMode(cm); } } updateMark(cm, vim, '<', cursorIsBefore(curStart, curEnd) ? curStart @@ -1832,7 +1829,7 @@ cm.replaceRange(replaceWithStr, curStart, curEnd); if(vim.visualMode){ cm.setCursor(curStart); - exitVisualMode(cm,vim); + exitVisualMode(cm); }else{ cm.setCursor(offsetCursor(curEnd, 0, -1)); } @@ -1989,7 +1986,9 @@ return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, '\\$1'); } - function exitVisualMode(cm, vim) { + function exitVisualMode(cm) { + cm.off('mousedown', exitVisualMode); + var vim = cm.vimState; vim.visualMode = false; vim.visualLine = false; var selectionStart = cm.getCursor('anchor'); @@ -2842,7 +2841,7 @@ processCommand: function(cm, input) { var vim = getVimState(cm); if (vim.visualMode) { - exitVisualMode(cm, vim); + exitVisualMode(cm); } var inputStream = new CodeMirror.StringStream(input); var params = {}; diff --git a/test/vim_test.js b/test/vim_test.js index 47fc6cd14f..44639c72c8 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -296,8 +296,10 @@ testMotion('l', 'l', makeCursor(0, 1)); testMotion('l_repeat', ['2', 'l'], makeCursor(0, 2)); testMotion('j', 'j', offsetCursor(word1.end, 1, 0), word1.end); testMotion('j_repeat', ['2', 'j'], offsetCursor(word1.end, 2, 0), word1.end); +testMotion('j_repeat_clip', ['1000', 'j'], endOfDocument); testMotion('k', 'k', offsetCursor(word3.end, -1, 0), word3.end); testMotion('k_repeat', ['2', 'k'], makeCursor(0, 4), makeCursor(2, 4)); +testMotion('k_repeat_clip', ['1000', 'k'], makeCursor(0, 4), makeCursor(2, 4)); testMotion('w', 'w', word1.start); testMotion('w_multiple_newlines_no_space', 'w', makeCursor(12, 2), makeCursor(11, 2)); testMotion('w_multiple_newlines_with_space', 'w', makeCursor(14, 0), makeCursor(12, 51)); @@ -818,12 +820,6 @@ testVim('dd_lastline', function(cm, vim, helpers) { eq(expectedLineCount, cm.lineCount()); helpers.assertCursorAt(cm.lineCount() - 1, 0); }); -testVim('cw', function(cm, vim, helpers) { - cm.setCursor(0, 0); - helpers.doKeys('c', '2', 'w'); - eq(' word3', cm.getValue()); - helpers.assertCursorAt(0, 0); -}, { value: 'word1 word2 word3'}); // Yank commands should behave the exact same as d commands, expect that nothing // gets deleted. testVim('yw_repeat', function(cm, vim, helpers) { @@ -854,6 +850,12 @@ testVim('yy_multiply_repeat', function(cm, vim, helpers) { // Change commands behave like d commands except that it also enters insert // mode. In addition, when the change is linewise, an additional newline is // inserted so that insert mode starts on that line. +testVim('cw', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('c', '2', 'w'); + eq(' word3', cm.getValue()); + helpers.assertCursorAt(0, 0); +}, { value: 'word1 word2 word3'}); testVim('cw_repeat', function(cm, vim, helpers) { // Assert that cw does delete newline if it should go to the next line, and // that repeat works properly. @@ -877,9 +879,14 @@ testVim('cc_multiply_repeat', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq(expectedBuffer, register.text); is(register.linewise); - helpers.assertCursorAt(0, lines[0].textStart); eq('vim-insert', cm.getOption('keyMap')); }); +testVim('cc_append', function(cm, vim, helpers) { + var expectedLineCount = cm.lineCount(); + cm.setCursor(cm.lastLine(), 0); + helpers.doKeys('c', 'c'); + eq(expectedLineCount, cm.lineCount()); +}); // Swapcase commands edit in place and do not modify registers. testVim('g~w_repeat', function(cm, vim, helpers) { // Assert that dw does delete newline if it should go to the next line, and @@ -1471,6 +1478,10 @@ testVim('visual_join', function(cm, vim, helpers) { helpers.doKeys('l', 'V', 'l', 'j', 'j', 'J'); eq(' 1 2 3\n 4\n 5', cm.getValue()); }, { value: ' 1\n 2\n 3\n 4\n 5' }); +testVim('visual_blank', function(cm, vim, helpers) { + helpers.doKeys('v', 'k'); + eq(vim.visualMode, true); +}, { value: '\n' }); testVim('/ and n/N', function(cm, vim, helpers) { cm.openDialog = helpers.fakeOpenDialog('match'); helpers.doKeys('/'); From 44cc08d6610783f9be8c98310b221ed684f721a9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 21 Jun 2013 10:05:41 +0200 Subject: [PATCH 0747/5273] Fix bug in addLineWidget / insertAt implementation (f674dd148c27c882d3a85885caa9c27bb5638ee5) --- lib/codemirror.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index ea3f8d9328..986f1640c8 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4035,7 +4035,7 @@ window.CodeMirror = (function() { // LINE WIDGETS var LineWidget = CodeMirror.LineWidget = function(cm, node, options) { - for (var opt in options) if (options.hasOwnProperty(opt)) + if (options) for (var opt in options) if (options.hasOwnProperty(opt)) this[opt] = options[opt]; this.cm = cm; this.node = node; @@ -4079,8 +4079,8 @@ window.CodeMirror = (function() { if (widget.noHScroll) cm.display.alignWidgets = true; changeLine(cm, handle, function(line) { var widgets = line.widgets || (line.widgets = []); - if (options.insertAt == null) widgets.push(widget); - else widgets.splice(Math.max(widgets.length - 1, options.insertAt), 0, widget); + if (widget.insertAt == null) widgets.push(widget); + else widgets.splice(Math.max(widgets.length - 1, widget.insertAt), 0, widget); widget.line = line; if (!lineIsHidden(cm.doc, line) || widget.showIfHidden) { var aboveVisible = heightAtLine(cm, line) < cm.display.scroller.scrollTop; From 41deb2c055ba2efee8b5ee62b740df4582390827 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 24 Jun 2013 10:24:02 +0200 Subject: [PATCH 0748/5273] [matchtags addon] Add Issue #1625 --- addon/edit/matchtags.js | 31 +++++++++++++++++++++++++++++++ addon/fold/xml-fold.js | 15 ++++++++++----- demo/matchtags.html | 37 +++++++++++++++++++++++++++++++++++++ doc/manual.html | 11 +++++++++++ 4 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 addon/edit/matchtags.js create mode 100644 demo/matchtags.html diff --git a/addon/edit/matchtags.js b/addon/edit/matchtags.js new file mode 100644 index 0000000000..8cdc8b20c8 --- /dev/null +++ b/addon/edit/matchtags.js @@ -0,0 +1,31 @@ +(function() { + "use strict"; + + CodeMirror.defineOption("matchTags", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) + cm.off("cursorActivity", doMatchTags); + if (val) + cm.on("cursorActivity", doMatchTags); + }); + + function doMatchTags(cm) { + cm.operation(function() { + if (cm.state.matchedTags) { cm.state.matchedTags(); cm.state.matchedTags = null; } + + var cur = cm.getCursor(); + var match = CodeMirror.findMatchingTag(cm, cur) || CodeMirror.findEnclosingTag(cm, cur); + if (!match) return; + var one = cm.markText(match.open.from, match.open.to, {className: "CodeMirror-matchingbracket"}); + var two = cm.markText(match.close.from, match.close.to, {className: "CodeMirror-matchingbracket"}); + cm.state.matchedTags = function() { one.clear(); two.clear(); }; + }); + } + + CodeMirror.commands.toMatchingTag = function(cm) { + var found = CodeMirror.findMatchingTag(cm, cm.getCursor()); + if (found) { + var other = found.at == "close" ? found.open : found.close; + cm.setSelection(other.to, other.from); + } + }; +})(); diff --git a/addon/fold/xml-fold.js b/addon/fold/xml-fold.js index 29d730eb71..572feaa244 100644 --- a/addon/fold/xml-fold.js +++ b/addon/fold/xml-fold.js @@ -2,6 +2,7 @@ "use strict"; var Pos = CodeMirror.Pos; + function cmp(a, b) { return a.line - b.line || a.ch - b.ch; } var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; @@ -136,14 +137,18 @@ CodeMirror.findMatchingTag = function(cm, pos) { var iter = new Iter(cm, pos.line, pos.ch); - var end = toTagEnd(iter), start = toTagStart(iter); - if (!end || end == "selfClose" || !start) return; + var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); + var start = end && toTagStart(iter); + if (!end || end == "selfClose" || !start || cmp(iter, pos) > 0) return; + var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]}; if (start[1]) { // closing tag - return findMatchingOpen(iter, start[2]); + var open = findMatchingOpen(iter, start[2]); + return open && {open: open, close: here, at: "close"}; } else { // opening tag - toTagEnd(iter); - return findMatchingClose(iter, start[2]); + iter = new Iter(cm, to.line, to.ch); + var close = findMatchingClose(iter, start[2]); + return close && {open: here, close: close, at: "open"}; } }; diff --git a/demo/matchtags.html b/demo/matchtags.html new file mode 100644 index 0000000000..053c0ed667 --- /dev/null +++ b/demo/matchtags.html @@ -0,0 +1,37 @@ + + + + + CodeMirror: Tag Matcher Demo + + + + + + + + + + +

    CodeMirror: Tag Matcher Demo

    + +
    + + + +

    Put the cursor on or inside a pair of tags to highlight them. + Press Ctrl-J to jump to the tag that matches the one under the + cursor.

    + + diff --git a/doc/manual.html b/doc/manual.html index 68692e2956..4284535f3f 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1659,6 +1659,17 @@

    Add-ons

    them, should have the second character also moved to its own line.
    Demo here.
    +
    edit/matchtags.js
    +
    Defines an option matchTags that, when enabled, + will cause the tags around the cursor to be highlighted (using + the CodeMirror-matchingbrackets class). Also + defines + a command toMatchingTag, + which you can bind a key to in order to jump to the tag mathing + the one under the cursor. Depends on + the addon/fold/xml-fold.js + addon. Demo here.
    +
    edit/trailingspace.js
    Adds an option showTrailingSpace which, when enabled, adds the CSS class cm-trailingspace to From 493bd95ca309958ac3e1335a704893decc77a92d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 24 Jun 2013 10:37:24 +0200 Subject: [PATCH 0749/5273] [real-world uses] Add Echoplexus and Shadertoy --- doc/realworld.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/realworld.html b/doc/realworld.html index 98aaff989b..6e76980b4a 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -47,6 +47,7 @@

    { } CodeMi
  • CSSDeck (CSS showcase)
  • Deck.js integration (slides with editors)
  • DbNinja (MySQL access interface)
  • +
  • Echoplexus (chat and collaborative coding)
  • Elm language examples
  • Eloquent JavaScript (book)
  • Emmet (fast XML editing)
  • @@ -89,6 +90,7 @@

    { } CodeMi
  • Quivive File Manager
  • Rascal (tiny computer)
  • RealTime.io (Internet-of-Things infrastructure)
  • +
  • Shadertoy (shader sharing)
  • sketchPatch Livecodelab
  • Skulpt (in-browser Python environment)
  • Snippets.pro (code snippet sharing)
  • From a48327868c691c94841f635442330603a9ca4bf4 Mon Sep 17 00:00:00 2001 From: Drew Bratcher Date: Sun, 23 Jun 2013 22:49:37 -0700 Subject: [PATCH 0750/5273] [jade mode] Add --- mode/jade/index.html | 54 +++++++++++++++++++++++++++ mode/jade/jade.js | 88 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 mode/jade/index.html create mode 100644 mode/jade/jade.js diff --git a/mode/jade/index.html b/mode/jade/index.html new file mode 100644 index 0000000000..0e68ba8ac4 --- /dev/null +++ b/mode/jade/index.html @@ -0,0 +1,54 @@ + + + + + CodeMirror: Jade Templating Mode + + + + + + + +

    CodeMirror: Jade Templating Mode

    + + +

    The Jade Templating Mode

    +

    Created by Drew Bratcher. Managed as part of an Adobe Brackets extension at https://github.com/dbratcher/brackets-jade.

    +

    MIME type defined: text/x-jade.

    + + diff --git a/mode/jade/jade.js b/mode/jade/jade.js new file mode 100644 index 0000000000..2c62632f1e --- /dev/null +++ b/mode/jade/jade.js @@ -0,0 +1,88 @@ +CodeMirror.defineMode("jade", function () { + var symbol_regex1 = /^(?:~|!|%|\^|\*|\+|=|\\|:|;|,|\/|\?|&|<|>|\|)/; + var open_paren_regex = /^(\(|\[)/; + var close_paren_regex = /^(\)|\])/; + var keyword_regex1 = /^(if|else|return|var|function|include|doctype|each)/; + var keyword_regex2 = /^(#|{|}|\.)/; + var keyword_regex3 = /^(in)/; + var html_regex1 = /^(html|head|title|meta|link|script|body|br|div|input|span|a|img)/; + var html_regex2 = /^(h1|h2|h3|h4|h5|p|strong|em)/; + return { + startState: function () { + return { + inString: false, + stringType: "", + beforeTag: true, + justMatchedKeyword: false, + afterParen: false + }; + }, + token: function (stream, state) { + //check for state changes + if (!state.inString && ((stream.peek() == '"') || (stream.peek() == "'"))) { + state.stringType = stream.peek(); + stream.next(); // Skip quote + state.inString = true; // Update state + } + + //return state + if (state.inString) { + if (stream.skipTo(state.stringType)) { // Quote found on this line + stream.next(); // Skip quote + state.inString = false; // Clear flag + } else { + stream.skipToEnd(); // Rest of line is string + } + state.justMatchedKeyword = false; + return "string"; // Token style + } else if(stream.sol()) { + stream.eatSpace(); + if(stream.match(keyword_regex1)) { + state.justMatchedKeyword = true; + stream.eatSpace(); + return "keyword"; + } + if(stream.match(html_regex1) || stream.match(html_regex2)) { + state.justMatchedKeyword = true; + return "variable"; + } + return null; + } else if(stream.eatSpace()) { + state.justMatchedKeyword = false; + if(stream.match(keyword_regex3) && stream.eatSpace()) { + state.justMatchedKeyword = true; + return "keyword"; + } + return null; + } else if(stream.match(symbol_regex1)) { + state.justMatchedKeyword = false; + return "atom"; + } else if(stream.match(open_paren_regex)) { + state.afterParen = true; + state.justMatchedKeyword = true; + return "def"; + } else if(stream.match(close_paren_regex)) { + state.afterParen = false; + state.justMatchedKeyword = true; + return "def"; + } else if(stream.match(keyword_regex2)) { + state.justMatchedKeyword = true; + return "keyword"; + } else if(stream.eatSpace()) { + state.justMatchedKeyword = false; + return null; + } else { + stream.next(); + if(state.justMatchedKeyword){ + return "property"; + } else if(state.afterParen) { + return "property"; + } + return null; + } + } + }; +}); + +CodeMirror.defineMIME('text/x-jade', 'jade'); + From 8942221a52622b750f1d1c52c857aef05c85effc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 24 Jun 2013 10:41:22 +0200 Subject: [PATCH 0751/5273] [jade mode] Integrate --- doc/compress.html | 1 + doc/modes.html | 1 + mode/meta.js | 1 + 3 files changed, 3 insertions(+) diff --git a/doc/compress.html b/doc/compress.html index fede6f43fa..8b7a11d670 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -93,6 +93,7 @@

    { } CodeMi + diff --git a/doc/modes.html b/doc/modes.html index af798aa774..69c7d5e9ad 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -45,6 +45,7 @@

    { } CodeMi
  • HTML mixed-mode
  • HTTP
  • Java
  • +
  • Jade
  • JavaScript
  • Jinja2
  • LESS
  • diff --git a/mode/meta.js b/mode/meta.js index e8cfc8fb63..cb1051e68f 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -26,6 +26,7 @@ CodeMirror.modeInfo = [ {name: 'JavaServer Pages', mime: 'application/x-jsp', mode: 'htmlembedded'}, {name: 'HTML', mime: 'text/html', mode: 'htmlmixed'}, {name: 'HTTP', mime: 'message/http', mode: 'http'}, + {name: 'Jade', mime: 'text/x-jade', mode: 'jade'}, {name: 'JavaScript', mime: 'text/javascript', mode: 'javascript'}, {name: 'JSON', mime: 'application/x-json', mode: 'javascript'}, {name: 'JSON', mime: 'application/json', mode: 'javascript'}, From a4cbc645611017015594fe5e8f9738b27d1c571c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 24 Jun 2013 12:45:42 +0200 Subject: [PATCH 0752/5273] [tern addon] Support custom type/completion tips + a few other fixes --- addon/tern/tern.js | 83 ++++++++++++++++++++++++---------------------- demo/tern.html | 15 ++++++++- 2 files changed, 58 insertions(+), 40 deletions(-) diff --git a/addon/tern/tern.js b/addon/tern/tern.js index 662736637c..5cff75782b 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -16,23 +16,16 @@ // multi-file view, switch the view or focus to the named file. // * showError: A function(editor, message) that can be used to // override the way errors are displayed. +// * completionTip: Customize the content in tooltips for completions. +// Is passed a single argument—the completion's data as returned by +// Tern—and may return a string, DOM node, or null to indicate that +// no tip should be shown. By default the docstring is shown. +// * typeTip: Like completionTip, but for the tooltips shown for type +// queries. (function() { "use strict"; - CodeMirror.getURL = function(url, c) { - var xhr = new XMLHttpRequest(); - xhr.open("get", url, true); - xhr.send(); - xhr.onreadystatechange = function() { - if (xhr.readyState != 4) return; - if (xhr.status < 400) return c(null, xhr.responseText); - var e = new Error(xhr.responseText || "No response"); - e.status = xhr.status; - c(e); - }; - }; - CodeMirror.TernServer = function(options) { var self = this; this.options = options || {}; @@ -62,7 +55,7 @@ delDoc: function(name) { var found = this.docs[name]; if (!found) return; - CodeMirror.on(found.doc, "change", this.trackChange); + CodeMirror.off(found.doc, "change", this.trackChange); delete this.docs[name]; this.server.delFile(name); }, @@ -72,6 +65,8 @@ CodeMirror.showHint(cm, function(cm, c) { return hint(self, cm, c); }, {async: true}); }, + getHint: function(cm, c) { return hint(this, cm, c); }, + showType: function(cm) { showType(this, cm); }, updateArgHints: function(cm) { updateArgHints(this, cm); }, @@ -80,7 +75,11 @@ jumpBack: function(cm) { jumpBack(this, cm); }, - rename: function(cm) { rename(this, cm); } + rename: function(cm) { rename(this, cm); }, + + request: function(cm, query, c) { + this.server.request(buildRequest(this, findDoc(this, cm.getDoc()), query), c); + } }; var Pos = CodeMirror.Pos; @@ -139,10 +138,7 @@ // Completion function hint(ts, cm, c) { - var doc = findDoc(ts, cm.getDoc()); - var req = buildRequest(ts, doc, {type: "completions", types: true, docs: true}); - - ts.server.request(req, function(error, data) { + ts.request(cm, {type: "completions", types: true, docs: true}, function(error, data) { if (error) return showError(ts, cm, error); var completions = [], after = ""; var from = data.start, to = data.end; @@ -156,7 +152,7 @@ completions.push({text: completion.name + after, displayText: completion.name, className: className, - doc: completion.doc}); + data: completion}); } var obj = {from: from, to: to, list: completions}; @@ -164,9 +160,10 @@ CodeMirror.on(obj, "close", function() { remove(tooltip); }); CodeMirror.on(obj, "select", function(cur, node) { remove(tooltip); - if (cur.doc) { + var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc; + if (content) { tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset, - node.getBoundingClientRect().top + window.pageYOffset, cur.doc); + node.getBoundingClientRect().top + window.pageYOffset, content); tooltip.className += " " + cls + "hint-doc"; } }); @@ -187,15 +184,18 @@ // Type queries function showType(ts, cm) { - var doc = findDoc(ts, cm.getDoc()); - ts.server.request(buildRequest(ts, doc, "type"), function(error, data) { + ts.request(cm, "type", function(error, data) { if (error) return showError(ts, cm, error); - var tip = elt("span", null, elt("strong", null, data.type || "not found")); - if (data.doc) - tip.appendChild(document.createTextNode(" — " + data.doc)); - if (data.url) { - tip.appendChild(document.createTextNode(" ")); - tip.appendChild(elt("a", null, "[docs]")).href = data.url; + if (ts.options.typeTip) { + var tip = ts.options.typeTip(data); + } else { + var tip = elt("span", null, elt("strong", null, data.type || "not found")); + if (data.doc) + tip.appendChild(document.createTextNode(" — " + data.doc)); + if (data.url) { + tip.appendChild(document.createTextNode(" ")); + tip.appendChild(elt("a", null, "[docs]")).href = data.url; + } } tempTooltip(cm, tip); }); @@ -204,7 +204,7 @@ // Maintaining argument hints function updateArgHints(ts, cm) { - if (ts.activeArgHints) { remove(ts.activeArgHints); ts.activeArgHints = null; } + closeArgHints(ts); if (cm.somethingSelected()) return; var lex = cm.getTokenAt(cm.getCursor()).state.lexical; @@ -220,8 +220,7 @@ if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0) return showArgHints(ts, cm, pos); - var query = {type: "type", preferFunction: true, end: start}; - ts.server.request(buildRequest(ts, findDoc(ts, cm.getDoc()), query), function(error, data) { + ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) { if (error || !data.type || !(/^fn\(/).test(data.type)) return; ts.cachedArgHints = { start: pos, @@ -235,7 +234,7 @@ } function showArgHints(ts, cm, pos) { - if (ts.activeArgHints) { remove(ts.activeArgHints); ts.activeArgHints = null; } + closeArgHints(ts); var cache = ts.cachedArgHints, tp = cache.type; var tip = elt("span", cache.guess ? cls + "fhint-guess" : null, @@ -324,8 +323,10 @@ function moveTo(ts, curDoc, doc, start, end) { doc.doc.setSelection(end, start); - if (curDoc != doc && ts.options.switchToDoc) + if (curDoc != doc && ts.options.switchToDoc) { + closeArgHints(ts); ts.options.switchToDoc(doc.name); + } } // The {line,ch} representation of positions makes this rather awkward. @@ -371,8 +372,7 @@ var token = cm.getTokenAt(cm.getCursor()); if (!/\w/.test(token.string)) showError(ts, cm, "Not at a variable"); dialog(cm, "New name for " + token.string, function(newName) { - var req = {type: "rename", newName: newName}, doc = findDoc(ts, cm.getDoc()); - ts.server.request(buildRequest(ts, doc, req, false), function(error, data) { + ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) { if (error) return showError(ts, cm, error); applyChanges(ts, data.changes); }); @@ -400,8 +400,9 @@ // Generic request-building helper - function buildRequest(ts, doc, query, allowFragments) { - var files = [], offsetLines = 0; + function buildRequest(ts, doc, query) { + var files = [], offsetLines = 0, allowFragments = !query.fullDocs; + if (!allowFragments) delete query.fullDocs; if (typeof query == "string") query = {type: query}; query.lineCharPositions = true; if (query.end == null) { @@ -528,4 +529,8 @@ else tempTooltip(cm, String(msg)); } + + function closeArgHints(ts) { + if (ts.activeArgHints) { remove(ts.activeArgHints); ts.activeArgHints = null; } + } })(); diff --git a/demo/tern.html b/demo/tern.html index 22464f8a60..42c2b1a7bb 100644 --- a/demo/tern.html +++ b/demo/tern.html @@ -71,8 +71,21 @@

    CodeMirror: Tern Demo

    diff --git a/keymap/vim.js b/keymap/vim.js index 8c942a3ff5..977642ea38 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -206,8 +206,7 @@ // Operators { keys: ['d'], type: 'operator', operator: 'delete' }, { keys: ['y'], type: 'operator', operator: 'yank' }, - { keys: ['c'], type: 'operator', operator: 'change', - operatorArgs: { enterInsertMode: true } }, + { keys: ['c'], type: 'operator', operator: 'change' }, { keys: ['>'], type: 'operator', operator: 'indent', operatorArgs: { indentRight: true }}, { keys: ['<'], type: 'operator', operator: 'indent', @@ -231,7 +230,7 @@ motion: 'moveToEol', motionArgs: { inclusive: true }, operatorMotionArgs: { visualLine: true }}, { keys: ['C'], type: 'operatorMotion', - operator: 'change', operatorArgs: { enterInsertMode: true }, + operator: 'change', motion: 'moveToEol', motionArgs: { inclusive: true }, operatorMotionArgs: { visualLine: true }}, { keys: ['~'], type: 'operatorMotion', operator: 'swapcase', @@ -315,6 +314,27 @@ ]; var Vim = function() { + CodeMirror.defineOption('vimMode', false, function(cm, val) { + if (val) { + cm.setOption('keyMap', 'vim'); + cm.on('beforeSelectionChange', beforeSelectionChange); + maybeInitVimState(cm); + } else if (cm.state.vim) { + cm.setOption('keyMap', 'default'); + cm.off('beforeSelectionChange', beforeSelectionChange); + cm.state.vim = null; + } + }); + function beforeSelectionChange(cm, cur) { + var vim = cm.state.vim; + if (vim.insertMode || vim.exMode) return; + + var head = cur.head; + if (head.ch && head.ch == cm.doc.getLine(head.line).length) { + head.ch--; + } + } + var numberRegex = /[\d]/; var wordRegexp = [(/\w/), (/[^\w\s]/)], bigWordRegexp = [(/\S/)]; function makeKeyRange(start, size) { @@ -450,28 +470,11 @@ }; }; - // Global Vim state. Call getVimGlobalState to get and initialize. - var vimGlobalState; - function getVimGlobalState() { - if (!vimGlobalState) { - vimGlobalState = { - // The current search query. - searchQuery: null, - // Whether we are searching backwards. - searchIsReversed: false, - jumpList: createCircularJumpList(), - macroModeState: createMacroState(), - // Recording latest f, t, F or T motion command. - lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''}, - registerController: new RegisterController({}) - }; - } - return vimGlobalState; - } - function getVimState(cm) { - if (!cm.vimState) { + + function maybeInitVimState(cm) { + if (!cm.state.vim) { // Store instance state in the CodeMirror object. - cm.vimState = { + cm.state.vim = { inputState: new InputState(), // Vim's input state that triggered the last edit, used to repeat // motions and operators with '.'. @@ -500,7 +503,21 @@ visualLine: false }; } - return cm.vimState; + return cm.state.vim; + } + var vimGlobalState; + function resetVimGlobalState() { + vimGlobalState = { + // The current search query. + searchQuery: null, + // Whether we are searching backwards. + searchIsReversed: false, + jumpList: createCircularJumpList(), + macroModeState: createMacroState(), + // Recording latest f, t, F or T motion command. + lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''}, + registerController: new RegisterController({}) + }; } var vimApi= { @@ -510,16 +527,19 @@ // Testing hook, though it might be useful to expose the register // controller anyways. getRegisterController: function() { - return getVimGlobalState().registerController; + return vimGlobalState.registerController; }, // Testing hook. - clearVimGlobalState_: function() { - vimGlobalState = null; - }, + resetVimGlobalState_: resetVimGlobalState, + // Testing hook. getVimGlobalState_: function() { return vimGlobalState; }, + + // Testing hook. + maybeInitVimState_: maybeInitVimState, + InsertModeKey: InsertModeKey, map: function(lhs, rhs) { // Add user defined key bindings. @@ -532,17 +552,12 @@ exCommands[name]=func; exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'}; }, - // Initializes vim state variable on the CodeMirror object. Should only be - // called lazily by handleKey or for testing. - maybeInitState: function(cm) { - getVimState(cm); - }, // This is the outermost function called by CodeMirror, after keys have // been mapped to their Vim equivalents. handleKey: function(cm, key) { var command; - var vim = getVimState(cm); - var macroModeState = getVimGlobalState().macroModeState; + var vim = maybeInitVimState(cm); + var macroModeState = vimGlobalState.macroModeState; if (macroModeState.enteredMacroMode) { if (key == 'q') { actions.exitMacroRecordMode(); @@ -967,7 +982,7 @@ // cachedCursor is used to save the old position of the cursor // when * or # causes vim to seek for the nearest word and shift // the cursor before entering the motion. - getVimGlobalState().jumpList.cachedCursor = cm.getCursor(); + vimGlobalState.jumpList.cachedCursor = cm.getCursor(); cm.setCursor(word.start); handleQuery(query, true /** ignoreCase */, false /** smartCase */); @@ -1049,7 +1064,7 @@ return; } if (motionArgs.toJumplist) { - var jumpList = getVimGlobalState().jumpList; + var jumpList = vimGlobalState.jumpList; // if the current motion is # or *, use cachedCursor var cachedCursor = jumpList.cachedCursor; if (cachedCursor) { @@ -1145,13 +1160,10 @@ if (vim.visualMode) { exitVisualMode(cm); } - if (operatorArgs.enterInsertMode) { - actions.enterInsertMode(cm, {}, vim); - } } }, recordLastEdit: function(vim, inputState, actionCommand) { - var macroModeState = getVimGlobalState().macroModeState; + var macroModeState = vimGlobalState.macroModeState; if (macroModeState.inReplay) { return; } vim.lastEditInputState = inputState; vim.lastEditActionCommand = actionCommand; @@ -1458,7 +1470,7 @@ return [start, end]; }, repeatLastCharacterSearch: function(cm, motionArgs) { - var lastSearch = getVimGlobalState().lastChararacterSearch; + var lastSearch = vimGlobalState.lastChararacterSearch; var repeat = motionArgs.repeat; var forward = motionArgs.forward === lastSearch.forward; var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1); @@ -1476,7 +1488,7 @@ var operators = { change: function(cm, operatorArgs, _vim, curStart, curEnd) { - getVimGlobalState().registerController.pushText( + vimGlobalState.registerController.pushText( operatorArgs.registerName, 'change', cm.getRange(curStart, curEnd), operatorArgs.linewise); if (operatorArgs.linewise) { @@ -1497,6 +1509,7 @@ } cm.replaceRange('', curStart, curEnd); } + actions.enterInsertMode(cm, {}, cm.state.vim); cm.setCursor(curStart); }, // delete is a javascript keyword. @@ -1508,7 +1521,7 @@ curStart.line--; curStart.ch = lineLength(cm, curStart.line); } - getVimGlobalState().registerController.pushText( + vimGlobalState.registerController.pushText( operatorArgs.registerName, 'delete', cm.getRange(curStart, curEnd), operatorArgs.linewise); cm.replaceRange('', curStart, curEnd); @@ -1550,7 +1563,7 @@ cm.setCursor(curOriginal); }, yank: function(cm, operatorArgs, _vim, curStart, curEnd, curOriginal) { - getVimGlobalState().registerController.pushText( + vimGlobalState.registerController.pushText( operatorArgs.registerName, 'yank', cm.getRange(curStart, curEnd), operatorArgs.linewise); cm.setCursor(curOriginal); @@ -1564,7 +1577,7 @@ } var repeat = actionArgs.repeat; var forward = actionArgs.forward; - var jumpList = getVimGlobalState().jumpList; + var jumpList = vimGlobalState.jumpList; var mark = jumpList.move(cm, forward ? repeat : -repeat); var markPos = mark ? mark.find() : undefined; @@ -1590,7 +1603,7 @@ replayMacro: function(cm, actionArgs) { var registerName = actionArgs.selectedCharacter; var repeat = actionArgs.repeat; - var macroModeState = getVimGlobalState().macroModeState; + var macroModeState = vimGlobalState.macroModeState; if (registerName == '@') { registerName = macroModeState.latestRegister; } @@ -1600,13 +1613,13 @@ } }, exitMacroRecordMode: function() { - var macroModeState = getVimGlobalState().macroModeState; + var macroModeState = vimGlobalState.macroModeState; macroModeState.toggle(); parseKeyBufferToRegister(macroModeState.latestRegister, macroModeState.macroKeyBuffer); }, enterMacroRecordMode: function(cm, actionArgs) { - var macroModeState = getVimGlobalState().macroModeState; + var macroModeState = vimGlobalState.macroModeState; var registerName = actionArgs.selectedCharacter; macroModeState.toggle(cm, registerName); emptyMacroKeyBuffer(macroModeState); @@ -1632,7 +1645,7 @@ } else { cm.setOption('keyMap', 'vim-insert'); } - if (!getVimGlobalState().macroModeState.inReplay) { + if (!vimGlobalState.macroModeState.inReplay) { // Only record if not replaying. cm.on('change', onChange); cm.on('cursorActivity', onCursorActivity); @@ -1725,6 +1738,7 @@ }); }, newLineAndEnterInsertMode: function(cm, actionArgs, vim) { + vim.insertMode = true; var insertAt = cm.getCursor(); if (insertAt.line === cm.firstLine() && !actionArgs.after) { // Special case for inserting newline before start of document. @@ -1743,7 +1757,7 @@ }, paste: function(cm, actionArgs) { var cur = cm.getCursor(); - var register = getVimGlobalState().registerController.getRegister( + var register = vimGlobalState.registerController.getRegister( actionArgs.registerName); if (!register.text) { return; @@ -1988,7 +2002,7 @@ function exitVisualMode(cm) { cm.off('mousedown', exitVisualMode); - var vim = cm.vimState; + var vim = cm.state.vim; vim.visualMode = false; vim.visualLine = false; var selectionStart = cm.getCursor('anchor'); @@ -2112,12 +2126,11 @@ function recordJumpPosition(cm, oldCur, newCur) { if(!cursorEqual(oldCur, newCur)) { - getVimGlobalState().jumpList.add(cm, oldCur, newCur); + vimGlobalState.jumpList.add(cm, oldCur, newCur); } } function recordLastCharacterSearch(increment, args) { - var vimGlobalState = getVimGlobalState(); vimGlobalState.lastChararacterSearch.increment = increment; vimGlobalState.lastChararacterSearch.forward = args.forward; vimGlobalState.lastChararacterSearch.selectedCharacter = args.selectedCharacter; @@ -2571,10 +2584,10 @@ function SearchState() {} SearchState.prototype = { getQuery: function() { - return getVimGlobalState().query; + return vimGlobalState.query; }, setQuery: function(query) { - getVimGlobalState().query = query; + vimGlobalState.query = query; }, getOverlay: function() { return this.searchOverlay; @@ -2583,14 +2596,14 @@ this.searchOverlay = overlay; }, isReversed: function() { - return getVimGlobalState().isReversed; + return vimGlobalState.isReversed; }, setReversed: function(reversed) { - getVimGlobalState().isReversed = reversed; + vimGlobalState.isReversed = reversed; } }; function getSearchState(cm) { - var vim = getVimState(cm); + var vim = cm.state.vim; return vim.searchState_ || (vim.searchState_ = new SearchState()); } function dialog(cm, template, shortText, onClose, options) { @@ -2839,7 +2852,7 @@ }; Vim.ExCommandDispatcher.prototype = { processCommand: function(cm, input) { - var vim = getVimState(cm); + var vim = cm.state.vim; if (vim.visualMode) { exitVisualMode(cm); } @@ -2920,7 +2933,7 @@ case '$': return cm.lastLine(); case '\'': - var mark = getVimState(cm).marks[inputStream.next()]; + var mark = cm.state.vim.marks[inputStream.next()]; if (mark && mark.find()) { return mark.find().line; } @@ -3030,7 +3043,7 @@ exCommandDispatcher.map(mapArgs[0], mapArgs[1], cm); }, move: function(cm, params) { - commandDispatcher.processCommand(cm, getVimState(cm), { + commandDispatcher.processCommand(cm, cm.state.vim, { type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, @@ -3185,7 +3198,7 @@ return; } - var state = getVimState(cm); + var state = cm.state.vim; var stream = new CodeMirror.StringStream(params.argString.trim()); while (!stream.eol()) { stream.eatSpace(); @@ -3256,6 +3269,7 @@ function doReplace(cm, confirm, lineStart, lineEnd, searchCursor, query, replaceWith) { // Set up all the functions. + cm.state.vim.exMode = true; var done = false; var lastPos = searchCursor.from(); function replaceAll() { @@ -3290,7 +3304,8 @@ cm.focus(); if (lastPos) { cm.setCursor(lastPos); - var vim = getVimState(cm); + var vim = cm.state.vim; + vim.exMode = false; vim.lastHPos = vim.lastHSPos = lastPos.ch; } } @@ -3402,9 +3417,8 @@ CodeMirror.keyMap.vim = buildVimKeyMap(); function exitInsertMode(cm) { - var vim = getVimState(cm); - vim.insertMode = false; - var inReplay = getVimGlobalState().macroModeState.inReplay; + var vim = cm.state.vim; + var inReplay = vimGlobalState.macroModeState.inReplay; if (!inReplay) { cm.off('change', onChange); cm.off('cursorActivity', onCursorActivity); @@ -3418,6 +3432,7 @@ } delete vim.insertModeRepeat; cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true); + vim.insertMode = false; cm.setOption('keyMap', 'vim'); cm.toggleOverwrite(false); // exit replace mode if we were in it. } @@ -3445,7 +3460,7 @@ function parseRegisterToKeyBuffer(macroModeState, registerName) { var match, key; - var register = getVimGlobalState().registerController.getRegister(registerName); + var register = vimGlobalState.registerController.getRegister(registerName); var text = register.toString(); var macroKeyBuffer = macroModeState.macroKeyBuffer; emptyMacroKeyBuffer(macroModeState); @@ -3461,7 +3476,7 @@ function parseKeyBufferToRegister(registerName, keyBuffer) { var text = keyBuffer.join(''); - getVimGlobalState().registerController.setRegisterText(registerName, text); + vimGlobalState.registerController.setRegisterText(registerName, text); } function emptyMacroKeyBuffer(macroModeState) { @@ -3489,7 +3504,7 @@ * Should only be active in insert mode. */ function onChange(_cm, changeObj) { - var macroModeState = getVimGlobalState().macroModeState; + var macroModeState = vimGlobalState.macroModeState; var lastChange = macroModeState.lastInsertModeChanges; while (changeObj) { lastChange.expectCursorActivityForChange = true; @@ -3509,7 +3524,7 @@ * - Should only be active in insert mode. */ function onCursorActivity() { - var macroModeState = getVimGlobalState().macroModeState; + var macroModeState = vimGlobalState.macroModeState; var lastChange = macroModeState.lastInsertModeChanges; if (lastChange.expectCursorActivityForChange) { lastChange.expectCursorActivityForChange = false; @@ -3530,7 +3545,7 @@ * - For recording deletes in insert mode. */ function onKeyEventTargetKeyDown(e) { - var macroModeState = getVimGlobalState().macroModeState; + var macroModeState = vimGlobalState.macroModeState; var lastChange = macroModeState.lastInsertModeChanges; var keyName = CodeMirror.keyName(e); function onKeyFound() { @@ -3552,7 +3567,7 @@ * corresponding enterInsertMode call was made with a count. */ function repeatLastEdit(cm, vim, repeat, repeatForInsert) { - var macroModeState = getVimGlobalState().macroModeState; + var macroModeState = vimGlobalState.macroModeState; macroModeState.inReplay = true; var isAction = !!vim.lastEditActionCommand; var cachedInputState = vim.inputState; @@ -3620,6 +3635,7 @@ } } + resetVimGlobalState(); return vimApi; }; // Initialize Vim and make it available as an API. diff --git a/lib/codemirror.js b/lib/codemirror.js index f3f0efb640..e4f5e19349 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4976,7 +4976,8 @@ window.CodeMirror = (function() { } function historyChangeFromChange(doc, change) { - var histChange = {from: change.from, to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; + var from = { line: change.from.line, ch: change.from.ch }; + var histChange = {from: 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; diff --git a/test/vim_test.js b/test/vim_test.js index 44639c72c8..0e88243215 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -99,7 +99,7 @@ function copyCursor(cur) { function testVim(name, run, opts, expectedFail) { var vimOpts = { lineNumbers: true, - keyMap: 'vim', + vimMode: true, showCursorWhenSelecting: true, value: code }; @@ -111,8 +111,7 @@ function testVim(name, run, opts, expectedFail) { return test('vim_' + name, function() { var place = document.getElementById("testground"); var cm = CodeMirror(place, vimOpts); - CodeMirror.Vim.maybeInitState(cm); - var vim = cm.vimState; + var vim = CodeMirror.Vim.maybeInitVimState_(cm); function doKeysFn(cm) { return function(args) { @@ -140,7 +139,7 @@ function testVim(name, run, opts, expectedFail) { // Find key in keymap and handle. var handled = CodeMirror.lookupKey(key, ['vim-insert'], executeHandler); // Record for insert mode. - if (handled === true && cm.vimState.insertMode && arguments[i] != 'Esc') { + if (handled === true && cm.state.vim.insertMode && arguments[i] != 'Esc') { var lastChange = CodeMirror.Vim.getVimGlobalState_().macroModeState.lastInsertModeChanges; if (lastChange) { lastChange.changes.push(new CodeMirror.Vim.InsertModeKey(key)); @@ -184,7 +183,7 @@ function testVim(name, run, opts, expectedFail) { return CodeMirror.Vim.getRegisterController(); } } - CodeMirror.Vim.clearVimGlobalState_(); + CodeMirror.Vim.resetVimGlobalState_(); var successful = false; try { run(cm, vim, helpers); @@ -228,7 +227,7 @@ function testJumplist(name, keys, endPos, startPos, dialog) { endPos = makeCursor(endPos[0], endPos[1]); startPos = makeCursor(startPos[0], startPos[1]); testVim(name, function(cm, vim, helpers) { - CodeMirror.Vim.clearVimGlobalState_(); + CodeMirror.Vim.resetVimGlobalState_(); if(dialog)cm.openDialog = helpers.fakeOpenDialog('word'); cm.setCursor(startPos); helpers.doKeys.apply(null, keys); @@ -501,15 +500,13 @@ testVim('dl', function(cm, vim, helpers) { eqPos(curStart, cm.getCursor()); }, { value: ' word1 ' }); testVim('dl_eol', function(cm, vim, helpers) { - // TODO: This test is incorrect. The cursor should end up at (0, 5). - var curStart = makeCursor(0, 6); - cm.setCursor(curStart); + cm.setCursor(0, 6); helpers.doKeys('d', 'l'); eq(' word1', cm.getValue()); var register = helpers.getRegisterController().getRegister(); eq(' ', register.text); is(!register.linewise); - helpers.assertCursorAt(0, 6); + helpers.assertCursorAt(0, 5); }, { value: ' word1 ' }); testVim('dl_repeat', function(cm, vim, helpers) { var curStart = makeCursor(0, 0); @@ -594,38 +591,35 @@ testVim('dw_word', function(cm, vim, helpers) { testVim('dw_only_word', function(cm, vim, helpers) { // Test that if there is only 1 word left, dw deletes till the end of the // line. - var curStart = makeCursor(0, 1); - cm.setCursor(curStart); + cm.setCursor(0, 1); helpers.doKeys('d', 'w'); eq(' ', cm.getValue()); var register = helpers.getRegisterController().getRegister(); eq('word1 ', register.text); is(!register.linewise); - eqPos(curStart, cm.getCursor()); + helpers.assertCursorAt(0, 0); }, { value: ' word1 ' }); testVim('dw_eol', function(cm, vim, helpers) { // Assert that dw does not delete the newline if last word to delete is at end // of line. - var curStart = makeCursor(0, 1); - cm.setCursor(curStart); + cm.setCursor(0, 1); helpers.doKeys('d', 'w'); eq(' \nword2', cm.getValue()); var register = helpers.getRegisterController().getRegister(); eq('word1', register.text); is(!register.linewise); - eqPos(curStart, cm.getCursor()); + helpers.assertCursorAt(0, 0); }, { value: ' word1\nword2' }); testVim('dw_eol_with_multiple_newlines', function(cm, vim, helpers) { // Assert that dw does not delete the newline if last word to delete is at end // of line and it is followed by multiple newlines. - var curStart = makeCursor(0, 1); - cm.setCursor(curStart); + cm.setCursor(0, 1); helpers.doKeys('d', 'w'); eq(' \n\nword2', cm.getValue()); var register = helpers.getRegisterController().getRegister(); eq('word1', register.text); is(!register.linewise); - eqPos(curStart, cm.getCursor()); + helpers.assertCursorAt(0, 0); }, { value: ' word1\n\nword2' }); testVim('dw_empty_line_followed_by_whitespace', function(cm, vim, helpers) { cm.setCursor(0, 0); @@ -665,14 +659,13 @@ testVim('dw_end_of_document', function(cm, vim, helpers) { testVim('dw_repeat', function(cm, vim, helpers) { // Assert that dw does delete newline if it should go to the next line, and // that repeat works properly. - var curStart = makeCursor(0, 1); - cm.setCursor(curStart); + cm.setCursor(0, 1); helpers.doKeys('d', '2', 'w'); eq(' ', cm.getValue()); var register = helpers.getRegisterController().getRegister(); eq('word1\nword2', register.text); is(!register.linewise); - eqPos(curStart, cm.getCursor()); + helpers.assertCursorAt(0, 0); }, { value: ' word1\nword2' }); testVim('de_word_start_and_empty_lines', function(cm, vim, helpers) { cm.setCursor(0, 0); @@ -1001,14 +994,13 @@ testEdit('daW_end_punct', 'foo \tbAr.', /A/, 'daW', 'foo'); // Operator-motion tests testVim('D', function(cm, vim, helpers) { - var curStart = makeCursor(0, 3); - cm.setCursor(curStart); + cm.setCursor(0, 3); helpers.doKeys('D'); eq(' wo\nword2\n word3', cm.getValue()); var register = helpers.getRegisterController().getRegister(); eq('rd1', register.text); is(!register.linewise); - helpers.assertCursorAt(0, 3); + helpers.assertCursorAt(0, 2); }, { value: ' word1\nword2\n word3' }); testVim('C', function(cm, vim, helpers) { var curStart = makeCursor(0, 3); @@ -1018,7 +1010,7 @@ testVim('C', function(cm, vim, helpers) { var register = helpers.getRegisterController().getRegister(); eq('rd1', register.text); is(!register.linewise); - helpers.assertCursorAt(0, 3); + eqPos(curStart, cm.getCursor()); eq('vim-insert', cm.getOption('keyMap')); }, { value: ' word1\nword2\n word3' }); testVim('Y', function(cm, vim, helpers) { From ca6db50f5874b003f5d4daae23391c10dfa7d957 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Jul 2013 13:58:49 +0200 Subject: [PATCH 0772/5273] Fix bug in findWordAt Which could result in a selection at a negative character offset when double-clicking. Issue #1638 --- lib/codemirror.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index e4f5e19349..1aa350a2df 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1064,7 +1064,6 @@ window.CodeMirror = (function() { } function finishRect(rect) { rect.bottom = vranges[rect.top+1]; - if (isNaN(rect.bottom)) debugger; rect.top = vranges[rect.top]; } @@ -2757,7 +2756,7 @@ window.CodeMirror = (function() { function findWordAt(line, pos) { var start = pos.ch, end = pos.ch; if (line) { - if (pos.xRel < 0 || end == line.length) --start; else ++end; + if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; var startChar = line.charAt(start); var check = isWordChar(startChar) ? isWordChar : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} From e0e2181cf0033ebb0f24c7909b0ce546d8c62edd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Jul 2013 14:04:20 +0200 Subject: [PATCH 0773/5273] [real-world uses] Add Fiddle Salad --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 6e76980b4a..2150abe401 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -54,6 +54,7 @@

    { } CodeMi
  • Fastfig (online computation/math tool)
  • Farabi (modern Perl IDE)
  • FathomJS integration (slides with editors, again)
  • +
  • Fiddle Salad (web development environment)
  • Firepad (collaborative text editor)
  • Go language tour
  • GitHub's Android app
  • From 836932ff202d860d86fa40c1788e238096394d15 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Jul 2013 14:25:35 +0200 Subject: [PATCH 0774/5273] [compression helper] Sort and complete addon scripts --- doc/compress.html | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 8b7a11d670..c7eec47d5e 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -140,38 +140,43 @@

    { } CodeMi - + + + + + - - + - - + - - - - - + + + - + + + + + - + + + + - + - - - - - - - + + + + + From 4d85080d2a031fecf7fe21f5fa3fe8e6376db4ea Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Jul 2013 15:32:12 +0200 Subject: [PATCH 0775/5273] [merge addon] Make sure synchronized scrolling scrolls other pane to top/bot --- addon/merge/merge.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index 0e813f3e25..66721e3584 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -93,7 +93,21 @@ var off = getOffsets(editor, type == DIFF_INSERT ? around.edit : around.orig); var offOther = getOffsets(other, type == DIFF_INSERT ? around.orig : around.edit); var ratio = (midY - off.top) / (off.bot - off.top); - other.scrollTo(null, (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top)); + var targetPos = (offOther.top - halfScreen) + ratio * (offOther.bot - offOther.top); + + var botDist, mix; + // Some careful tweaking to make sure no space is left out of view + // when scrolling to top or bottom. + if (targetPos > sInfo.top && (mix = sInfo.top / halfScreen) < 1) { + targetPos = targetPos * mix + sInfo.top * (1 - mix); + } else if ((botDist = sInfo.height - sInfo.clientHeight - sInfo.top) < halfScreen) { + var otherInfo = other.getScrollInfo(); + var botDistOther = otherInfo.height - otherInfo.clientHeight - targetPos; + if (botDistOther > botDist && (mix = botDist / halfScreen) < 1) + targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix); + } + + other.scrollTo(null, targetPos); other.state.scrollSetAt = now; other.state.scrollSetBy = dv; return true; @@ -208,8 +222,8 @@ var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport(); var sTopEdit = dv.edit.getScrollInfo().top, sTopOrig = dv.orig.getScrollInfo().top; iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) { - if (topEdit >= vpEdit.to || botEdit < vpEdit.from || - topOrig >= vpOrig.to || botOrig < vpOrig.from) + if (topEdit > vpEdit.to || botEdit < vpEdit.from || + topOrig > vpOrig.to || botOrig < vpOrig.from) return; var topLpx = dv.orig.heightAtLine(topOrig, "local") - sTopOrig, top = topLpx; if (dv.svg) { From f3bc32b662b5b04d83e63dab71c523ee5edbe405 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Jul 2013 15:33:59 +0200 Subject: [PATCH 0776/5273] [merge addon] Synchronize vertical scrolling --- 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 66721e3584..cae9ea7167 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -107,7 +107,7 @@ targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix); } - other.scrollTo(null, targetPos); + other.scrollTo(sInfo.left, targetPos); other.state.scrollSetAt = now; other.state.scrollSetBy = dv; return true; From b4cca0242a4570dae04cfa38024f29f196c896e8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Jul 2013 15:35:51 +0200 Subject: [PATCH 0777/5273] [merge addon] Use CodeMirror-merge-* CSS class names Since the addon is called merge, not diff. --- addon/merge/merge.css | 56 +++++++++++++++++++++---------------------- addon/merge/merge.js | 44 +++++++++++++++++----------------- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/addon/merge/merge.css b/addon/merge/merge.css index 3bd6bbb9a5..63237fc8e9 100644 --- a/addon/merge/merge.css +++ b/addon/merge/merge.css @@ -1,30 +1,30 @@ -.CodeMirror-diff { +.CodeMirror-merge { position: relative; border: 1px solid #ddd; white-space: pre; } -.CodeMirror-diff, .CodeMirror-diff .CodeMirror { +.CodeMirror-merge, .CodeMirror-merge .CodeMirror { height: 350px; } -.CodeMirror-diff-2pane .CodeMirror-diff-pane { width: 47%; } -.CodeMirror-diff-2pane .CodeMirror-diff-gap { width: 6%; } -.CodeMirror-diff-3pane .CodeMirror-diff-pane { width: 31%; } -.CodeMirror-diff-3pane .CodeMirror-diff-gap { width: 3.5%; } +.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; } +.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; } +.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; } +.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; } -.CodeMirror-diff-pane { +.CodeMirror-merge-pane { display: inline-block; white-space: normal; vertical-align: top; } -.CodeMirror-diff-pane-rightmost { +.CodeMirror-merge-pane-rightmost { position: absolute; right: 0px; z-index: 1; } -.CodeMirror-diff-gap { +.CodeMirror-merge-gap { z-index: 2; display: inline-block; height: 100%; @@ -37,11 +37,11 @@ background: #f8f8f8; } -.CodeMirror-diff-scrolllock-wrap { +.CodeMirror-merge-scrolllock-wrap { position: absolute; bottom: 0; left: 50%; } -.CodeMirror-diff-scrolllock { +.CodeMirror-merge-scrolllock { position: relative; left: -50%; cursor: pointer; @@ -49,44 +49,44 @@ line-height: 1; } -.CodeMirror-diff-copybuttons-left, .CodeMirror-diff-copybuttons-right { +.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right { position: absolute; left: 0; top: 0; right: 0; bottom: 0; line-height: 1; } -.CodeMirror-diff-copy { +.CodeMirror-merge-copy { position: absolute; cursor: pointer; color: #44c; } -.CodeMirror-diff-copybuttons-left .CodeMirror-diff-copy { left: 2px; } -.CodeMirror-diff-copybuttons-right .CodeMirror-diff-copy { right: 2px; } +.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; } +.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; } -.CodeMirror-diff-r-inserted, .CodeMirror-diff-l-inserted { +.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==); background-position: bottom left; background-repeat: repeat-x; } -.CodeMirror-diff-r-deleted, .CodeMirror-diff-l-deleted { +.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==); background-position: bottom left; background-repeat: repeat-x; } -.CodeMirror-diff-r-chunk { background: #ffffe0; } -.CodeMirror-diff-r-chunk-start { border-top: 1px solid #ee8; } -.CodeMirror-diff-r-chunk-end { border-bottom: 1px solid #ee8; } -.CodeMirror-diff-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; } +.CodeMirror-merge-r-chunk { background: #ffffe0; } +.CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; } +.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; } +.CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; } -.CodeMirror-diff-l-chunk { background: #eef; } -.CodeMirror-diff-l-chunk-start { border-top: 1px solid #88e; } -.CodeMirror-diff-l-chunk-end { border-bottom: 1px solid #88e; } -.CodeMirror-diff-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; } +.CodeMirror-merge-l-chunk { background: #eef; } +.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; } +.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; } +.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; } -.CodeMirror-diff-l-chunk.CodeMirror-diff-r-chunk { background: #dfd; } -.CodeMirror-diff-l-chunk-start.CodeMirror-diff-r-chunk-start { border-top: 1px solid #4e4; } -.CodeMirror-diff-l-chunk-end.CodeMirror-diff-r-chunk-end { border-bottom: 1px solid #4e4; } +.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; } +.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; } +.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; } diff --git a/addon/merge/merge.js b/addon/merge/merge.js index cae9ea7167..16c3356c20 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -8,18 +8,18 @@ this.mv = mv; this.type = type; this.classes = type == "left" - ? {chunk: "CodeMirror-diff-l-chunk", - start: "CodeMirror-diff-l-chunk-start", - end: "CodeMirror-diff-l-chunk-end", - insert: "CodeMirror-diff-l-inserted", - del: "CodeMirror-diff-l-deleted", - connect: "CodeMirror-diff-l-connect"} - : {chunk: "CodeMirror-diff-r-chunk", - start: "CodeMirror-diff-r-chunk-start", - end: "CodeMirror-diff-r-chunk-end", - insert: "CodeMirror-diff-r-inserted", - del: "CodeMirror-diff-r-deleted", - connect: "CodeMirror-diff-r-connect"}; + ? {chunk: "CodeMirror-merge-l-chunk", + start: "CodeMirror-merge-l-chunk-start", + end: "CodeMirror-merge-l-chunk-end", + insert: "CodeMirror-merge-l-inserted", + del: "CodeMirror-merge-l-deleted", + connect: "CodeMirror-merge-l-connect"} + : {chunk: "CodeMirror-merge-r-chunk", + start: "CodeMirror-merge-r-chunk-start", + end: "CodeMirror-merge-r-chunk-end", + insert: "CodeMirror-merge-r-inserted", + del: "CodeMirror-merge-r-deleted", + connect: "CodeMirror-merge-r-connect"}; } DiffView.prototype = { @@ -239,7 +239,7 @@ "class", dv.classes.connect); } var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc", - "CodeMirror-diff-copy")); + "CodeMirror-merge-copy")); copy.title = "Revert chunk"; copy.chunk = {topEdit: topEdit, botEdit: botEdit, topOrig: topOrig, botOrig: botOrig}; copy.style.top = top + "px"; @@ -264,25 +264,25 @@ if (hasLeft) { left = this.left = new DiffView(this, "left"); - var leftPane = elt("div", null, "CodeMirror-diff-pane"); + var leftPane = elt("div", null, "CodeMirror-merge-pane"); wrap.push(leftPane); wrap.push(buildGap(left)); } - var editPane = elt("div", null, "CodeMirror-diff-pane"); + var editPane = elt("div", null, "CodeMirror-merge-pane"); wrap.push(editPane); if (hasRight) { right = this.right = new DiffView(this, "right"); wrap.push(buildGap(right)); - var rightPane = elt("div", null, "CodeMirror-diff-pane"); + var rightPane = elt("div", null, "CodeMirror-merge-pane"); wrap.push(rightPane); } - (hasRight ? rightPane : editPane).className += " CodeMirror-diff-pane-rightmost"; + (hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost"; wrap.push(elt("div", null, null, "height: 0; clear: both;")); - var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-diff CodeMirror-diff-" + panes + "pane")); + var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane")); this.edit = CodeMirror(editPane, copyObj(options)); if (left) left.init(leftPane, origLeft, options); @@ -300,11 +300,11 @@ }; function buildGap(dv) { - var lock = dv.lockButton = elt("div", null, "CodeMirror-diff-scrolllock"); + var lock = dv.lockButton = elt("div", null, "CodeMirror-merge-scrolllock"); lock.title = "Toggle locked scrolling"; - var lockWrap = elt("div", [lock], "CodeMirror-diff-scrolllock-wrap"); + var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap"); CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); }); - dv.copyButtons = elt("div", null, "CodeMirror-diff-copybuttons-" + dv.type); + dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type); CodeMirror.on(dv.copyButtons, "click", function(e) { var node = e.target || e.srcElement; if (node.chunk) copyChunk(dv, node.chunk); @@ -315,7 +315,7 @@ dv.svg = svg; if (svg) gapElts.push(svg); - return dv.gap = elt("div", gapElts, "CodeMirror-diff-gap"); + return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap"); } MergeView.prototype = { From bc85bdb354799ab2e1c8dd4a1dd2600db826e42c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Jul 2013 08:48:19 +0200 Subject: [PATCH 0778/5273] [matchtags addon] Only highlight matching tag, try to be more efficient --- addon/edit/matchtags.js | 36 ++++++++++++++++++++++++++---------- addon/fold/xml-fold.js | 20 +++++++++++--------- demo/matchtags.html | 1 + 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/addon/edit/matchtags.js b/addon/edit/matchtags.js index 8cdc8b20c8..66e57c8e9e 100644 --- a/addon/edit/matchtags.js +++ b/addon/edit/matchtags.js @@ -2,25 +2,41 @@ "use strict"; CodeMirror.defineOption("matchTags", false, function(cm, val, old) { - if (old && old != CodeMirror.Init) + if (old && old != CodeMirror.Init) { cm.off("cursorActivity", doMatchTags); - if (val) + cm.off("viewportChange", maybeUpdateMatch); + clear(cm); + } + if (val) { cm.on("cursorActivity", doMatchTags); + cm.on("viewportChange", maybeUpdateMatch); + doMatchTags(cm); + } }); + function clear(cm) { + if (cm.state.matchedTag) { + cm.state.matchedTag.clear(); + cm.state.matchedTag = null; + } + } + function doMatchTags(cm) { cm.operation(function() { - if (cm.state.matchedTags) { cm.state.matchedTags(); cm.state.matchedTags = null; } - - var cur = cm.getCursor(); - var match = CodeMirror.findMatchingTag(cm, cur) || CodeMirror.findEnclosingTag(cm, cur); - if (!match) return; - var one = cm.markText(match.open.from, match.open.to, {className: "CodeMirror-matchingbracket"}); - var two = cm.markText(match.close.from, match.close.to, {className: "CodeMirror-matchingbracket"}); - cm.state.matchedTags = function() { one.clear(); two.clear(); }; + clear(cm); + var cur = cm.getCursor(), range = cm.getViewport(); + range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to); + var match = CodeMirror.findMatchingTag(cm, cur, range); + if (cm.state.failedTagMatch = !match) return; + var other = match.at == "close" ? match.open : match.close; + cm.state.matchedTag = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"}); }); } + function maybeUpdateMatch(cm) { + if (cm.state.failedTagMatch) doMatchTags(cm); + } + CodeMirror.commands.toMatchingTag = function(cm) { var found = CodeMirror.findMatchingTag(cm, cm.getCursor()); if (found) { diff --git a/addon/fold/xml-fold.js b/addon/fold/xml-fold.js index 572feaa244..bf8ca9c2ac 100644 --- a/addon/fold/xml-fold.js +++ b/addon/fold/xml-fold.js @@ -8,9 +8,11 @@ var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); - function Iter(cm, line, ch) { + 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(); } function tagAt(iter, ch) { @@ -19,13 +21,13 @@ } function nextLine(iter) { - if (iter.line >= iter.cm.lastLine()) return; + if (iter.line >= iter.max) return; iter.ch = 0; iter.text = iter.cm.getLine(++iter.line); return true; } function prevLine(iter) { - if (iter.line <= iter.cm.firstLine()) return; + if (iter.line <= iter.min) return; iter.text = iter.cm.getLine(--iter.line); iter.ch = iter.text.length; return true; @@ -135,8 +137,8 @@ } }; - CodeMirror.findMatchingTag = function(cm, pos) { - var iter = new Iter(cm, pos.line, pos.ch); + CodeMirror.findMatchingTag = function(cm, pos, range) { + var iter = new Iter(cm, pos.line, pos.ch, range); var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); var start = end && toTagStart(iter); if (!end || end == "selfClose" || !start || cmp(iter, pos) > 0) return; @@ -146,18 +148,18 @@ var open = findMatchingOpen(iter, start[2]); return open && {open: open, close: here, at: "close"}; } else { // opening tag - iter = new Iter(cm, to.line, to.ch); + iter = new Iter(cm, to.line, to.ch, range); var close = findMatchingClose(iter, start[2]); return close && {open: here, close: close, at: "open"}; } }; - CodeMirror.findEnclosingTag = function(cm, pos) { - var iter = new Iter(cm, pos.line, pos.ch); + CodeMirror.findEnclosingTag = function(cm, pos, range) { + var iter = new Iter(cm, pos.line, pos.ch, range); for (;;) { var open = findMatchingOpen(iter); if (!open) break; - var forward = new Iter(cm, pos.line, pos.ch); + var forward = new Iter(cm, pos.line, pos.ch, range); var close = findMatchingClose(forward, open.tag); if (close) return {open: open, close: close}; } diff --git a/demo/matchtags.html b/demo/matchtags.html index 053c0ed667..8f4217debe 100644 --- a/demo/matchtags.html +++ b/demo/matchtags.html @@ -12,6 +12,7 @@ From c969e83279331d1535096fb8925816630667760a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Jul 2013 09:43:27 +0200 Subject: [PATCH 0779/5273] Stabilize scroll position when removing widgets (When they are above visible range, scroll up to correspond for height reduction.) Closes #1645 --- lib/codemirror.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 1aa350a2df..c702260103 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4057,7 +4057,9 @@ window.CodeMirror = (function() { if (no == null || !ws) return; for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); if (!ws.length) this.line.widgets = null; + var aboveVisible = heightAtLine(this.cm, this.line) < this.cm.doc.scrollTop; updateLineHeight(this.line, Math.max(0, this.line.height - widgetHeight(this))); + if (aboveVisible) addToScrollPos(this.cm, 0, -this.height); regChange(this.cm, no, no + 1); }); LineWidget.prototype.changed = widgetOperation(function() { @@ -4086,7 +4088,7 @@ window.CodeMirror = (function() { else widgets.splice(Math.max(widgets.length - 1, widget.insertAt), 0, widget); widget.line = line; if (!lineIsHidden(cm.doc, line) || widget.showIfHidden) { - var aboveVisible = heightAtLine(cm, line) < cm.display.scroller.scrollTop; + var aboveVisible = heightAtLine(cm, line) < cm.doc.scrollTop; updateLineHeight(line, line.height + widgetHeight(widget)); if (aboveVisible) addToScrollPos(cm, 0, widget.height); } From a7dba9653f39b100879b82b6e6e5d6d542474488 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Jul 2013 10:21:33 +0200 Subject: [PATCH 0780/5273] Fix problem in widget-preserving line redraws Issue #1645 --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index c702260103..4721f67e2f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -668,10 +668,10 @@ window.CodeMirror = (function() { if (!/\bCodeMirror-linewidget\b/.test(n.className)) { reuse.removeChild(n); } else { - for (var i = 0, first = true; i < line.widgets.length; ++i) { + for (var i = 0; i < line.widgets.length; ++i) { var widget = line.widgets[i]; - if (!widget.above) { insertBefore = n; first = false; } if (widget.node == n.firstChild) { + if (!widget.above && !insertBefore) insertBefore = n; positionLineWidget(widget, n, reuse, dims); ++widgetsSeen; break; From ac14de0d671c0219c4c10c28ed2f63aa9b4e3993 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Jul 2013 10:41:28 +0200 Subject: [PATCH 0781/5273] Fix bug in character measurement Issue #1617 --- lib/codemirror.js | 5 +++-- test/test.js | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 4721f67e2f..180594f198 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -964,8 +964,9 @@ window.CodeMirror = (function() { if (r) break; if (dir < 0 && pos == 0) dir = 1; } - if ((pos > ch || bias == "left") && r.leftSide) r = r.leftSide; - else if ((pos < ch || bias == "right") && r.rightSide) r = r.rightSide; + bias = pos > ch ? "left" : pos < ch ? "right" : bias; + if (bias == "left" && r.leftSide) r = r.leftSide; + else if (bias == "right" && r.rightSide) r = r.rightSide; return {left: pos < ch ? r.right : r.left, right: pos > ch ? r.left : r.right, top: r.top, diff --git a/test/test.js b/test/test.js index cc4b57a4b6..641818484d 100644 --- a/test/test.js +++ b/test/test.js @@ -501,7 +501,8 @@ testCM("bookmarkInsertLeft", function(cm) { testCM("bookmarkCursor", function(cm) { var pos01 = cm.cursorCoords(Pos(0, 1)), pos11 = cm.cursorCoords(Pos(1, 1)), - pos20 = cm.cursorCoords(Pos(2, 0)), pos30 = cm.cursorCoords(Pos(3, 0)); + pos20 = cm.cursorCoords(Pos(2, 0)), pos30 = cm.cursorCoords(Pos(3, 0)), + pos41 = cm.cursorCoords(Pos(4, 1)); cm.setBookmark(Pos(0, 1), {widget: document.createTextNode("←"), insertLeft: true}); cm.setBookmark(Pos(2, 0), {widget: document.createTextNode("←"), insertLeft: true}); cm.setBookmark(Pos(1, 1), {widget: document.createTextNode("→")}); @@ -512,7 +513,9 @@ testCM("bookmarkCursor", function(cm) { is(new11.left > pos11.left && new11.top == pos11.top, "at right, middle of line"); is(new20.left == pos20.left && new20.top == pos20.top, "at left, empty line"); is(new30.left > pos30.left && new30.top == pos30.top, "at right, empty line"); -}, {value: "foo\nbar\n\n\nx"}); + cm.setBookmark(Pos(4, 0), {widget: document.createTextNode("→")}); + is(cm.cursorCoords(Pos(4, 1)).left > pos41.left, "single-char bug"); +}, {value: "foo\nbar\n\n\nx\ny"}); testCM("getAllMarks", function(cm) { addDoc(cm, 10, 10); From ba3a62bde5305d4e02ec8555564aa25cb5743862 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Jul 2013 11:37:13 +0200 Subject: [PATCH 0782/5273] [anyword-hint addon] Add --- addon/hint/anyword-hint.js | 34 +++++++++++++++++++ demo/anywordhint.html | 69 ++++++++++++++++++++++++++++++++++++++ doc/manual.html | 9 +++++ 3 files changed, 112 insertions(+) create mode 100644 addon/hint/anyword-hint.js create mode 100644 demo/anywordhint.html diff --git a/addon/hint/anyword-hint.js b/addon/hint/anyword-hint.js new file mode 100644 index 0000000000..b3b2c1e1c0 --- /dev/null +++ b/addon/hint/anyword-hint.js @@ -0,0 +1,34 @@ +(function() { + "use strict"; + + var WORD = /[\w$]+/, RANGE = 500; + + CodeMirror.anyWordHint = function(editor, options) { + var word = options && options.word || WORD; + var range = options && options.range || RANGE; + var cur = editor.getCursor(), curLine = editor.getLine(cur.line); + var start = cur.ch, end = start; + while (end < curLine.length && word.test(curLine.charAt(end))) ++end; + while (start && word.test(curLine.charAt(start - 1))) --start; + var curWord = start != end && curLine.slice(start, end); + + var list = [], seen = {}; + function scan(dir) { + var line = cur.line, end = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; + for (; line != end; line += dir) { + var text = editor.getLine(line), m; + var re = new RegExp(word.source, "g"); + while (m = re.exec(text)) { + if (line == cur.line && m[0] === curWord) continue; + if ((!curWord || m[0].indexOf(curWord) == 0) && !seen.hasOwnProperty(m[0])) { + seen[m[0]] = true; + list.push(m[0]); + } + } + } + } + scan(-1); + scan(1); + return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; + }; +})(); diff --git a/demo/anywordhint.html b/demo/anywordhint.html new file mode 100644 index 0000000000..820df39e90 --- /dev/null +++ b/demo/anywordhint.html @@ -0,0 +1,69 @@ + + + + + CodeMirror: Any Word Completion Demo + + + + + + + + + +

    CodeMirror: Any Word Completion Demo

    + +
    + +

    Press ctrl-space to activate autocompletion. The +completion uses +the anyword-hint.js +module, which simply looks at nearby words in the buffer and completes +to those.

    + + + + diff --git a/doc/manual.html b/doc/manual.html index 4284535f3f..74b2aab783 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1915,6 +1915,15 @@

    Add-ons

    A very simple hinting function for Python code. Defines CodeMirror.pythonHint.
    +
    hint/anyword-hint.js
    +
    A very simple hinting function + (CodeMirror.anyWordHint) that simply looks for + words in the nearby code and completes to those. Takes two + optional options, word, a regular expression that + matches words (sequences of one or more character), + and range, which defines how many lines the addon + should scan when completing (defaults to 500).
    +
    match-highlighter.js
    Adds a highlightSelectionMatches option that can be enabled to highlight all instances of a currently From 022bc2862faa29970193fa10f8bbb3f469600e26 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Jul 2013 13:45:22 +0200 Subject: [PATCH 0783/5273] Add registerHelper/getHelper mechanism Move hinting functions into it. --- addon/hint/anyword-hint.js | 4 +-- addon/hint/html-hint.js | 8 +++-- addon/hint/javascript-hint.js | 10 +++++-- addon/hint/pig-hint.js | 6 ++-- addon/hint/python-hint.js | 6 ++-- addon/hint/show-hint.js | 2 ++ addon/hint/xml-hint.js | 7 +++-- demo/anywordhint.html | 6 ++-- demo/complete.html | 2 +- demo/html5complete.html | 2 +- demo/xmlcomplete.html | 4 +-- doc/manual.html | 55 ++++++++++++++++++++++++++--------- lib/codemirror.js | 18 +++++++++++- mode/xml/xml.js | 3 +- 14 files changed, 96 insertions(+), 37 deletions(-) diff --git a/addon/hint/anyword-hint.js b/addon/hint/anyword-hint.js index b3b2c1e1c0..36ff618e09 100644 --- a/addon/hint/anyword-hint.js +++ b/addon/hint/anyword-hint.js @@ -3,7 +3,7 @@ var WORD = /[\w$]+/, RANGE = 500; - CodeMirror.anyWordHint = function(editor, options) { + CodeMirror.registerHelper("hint", "anyword", function(editor, options) { var word = options && options.word || WORD; var range = options && options.range || RANGE; var cur = editor.getCursor(), curLine = editor.getLine(cur.line); @@ -30,5 +30,5 @@ scan(-1); scan(1); return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; - }; + }); })(); diff --git a/addon/hint/html-hint.js b/addon/hint/html-hint.js index 23238df054..cf256851ef 100755 --- a/addon/hint/html-hint.js +++ b/addon/hint/html-hint.js @@ -327,9 +327,11 @@ populate(data[tag]); CodeMirror.htmlSchema = data; - CodeMirror.htmlHint = function(cm, options) { + function htmlHint(cm, options) { var local = {schemaInfo: data}; if (options) for (var opt in options) local[opt] = options[opt]; - return CodeMirror.xmlHint(cm, local); - }; + return CodeMirror.hint.xml(cm, local); + } + CodeMirror.htmlHint = htmlHint; // deprecated + CodeMirror.registerHelper("hint", "html", htmlHint); })(); diff --git a/addon/hint/javascript-hint.js b/addon/hint/javascript-hint.js index b961c5abe9..042fe1325d 100644 --- a/addon/hint/javascript-hint.js +++ b/addon/hint/javascript-hint.js @@ -56,11 +56,13 @@ to: Pos(cur.line, token.end)}; } - CodeMirror.javascriptHint = function(editor, options) { + function javascriptHint(editor, options) { return scriptHint(editor, javascriptKeywords, function (e, cur) {return e.getTokenAt(cur);}, options); }; + CodeMirror.javascriptHint = javascriptHint; // deprecated + CodeMirror.registerHelper("hint", "javascript", javascriptHint); function getCoffeeScriptToken(editor, cur) { // This getToken, it is for coffeescript, imitates the behavior of @@ -80,9 +82,11 @@ return token; } - CodeMirror.coffeescriptHint = function(editor, options) { + function coffeescriptHint(editor, options) { return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); - }; + } + CodeMirror.coffeescriptHint = coffeescriptHint; // deprecated + CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint); var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + "toUpperCase toLowerCase split concat match replace search").split(" "); diff --git a/addon/hint/pig-hint.js b/addon/hint/pig-hint.js index d831ccfe93..155973f22d 100644 --- a/addon/hint/pig-hint.js +++ b/addon/hint/pig-hint.js @@ -41,9 +41,11 @@ to: CodeMirror.Pos(cur.line, token.end)}; } - CodeMirror.pigHint = function(editor) { + function pigHint(editor) { return scriptHint(editor, pigKeywordsU, function (e, cur) {return e.getTokenAt(cur);}); - }; + } + CodeMirror.pigHint = pigHint; // deprecated + CodeMirror.registerHelper("hint", "pig", hinter); var pigKeywords = "VOID IMPORT RETURNS DEFINE LOAD FILTER FOREACH ORDER CUBE DISTINCT COGROUP " + "JOIN CROSS UNION SPLIT INTO IF OTHERWISE ALL AS BY USING INNER OUTER ONSCHEMA PARALLEL " diff --git a/addon/hint/python-hint.js b/addon/hint/python-hint.js index 60221b89ec..98d2a5897f 100644 --- a/addon/hint/python-hint.js +++ b/addon/hint/python-hint.js @@ -41,9 +41,11 @@ to: CodeMirror.Pos(cur.line, token.end)}; } - CodeMirror.pythonHint = function(editor) { + function pythonHint(editor) { return scriptHint(editor, pythonKeywordsU, function (e, cur) {return e.getTokenAt(cur);}); - }; + } + CodeMirror.pythonHint = pythonHint; // deprecated + CodeMirror.registerHelper("hint", "python", pythonHint); var pythonKeywords = "and del from not while as elif global or with assert else if pass yield" + "break except import print class exec in raise continue finally is return def for lambda try"; diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 35e5cbb721..5a34f552f7 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -4,6 +4,8 @@ CodeMirror.showHint = function(cm, getHints, options) { // We want a single cursor position. if (cm.somethingSelected()) return; + if (getHints == null) getHints = cm.getHelper(cm.getCursor(), "hint"); + if (getHints == null) return; if (cm.state.completionActive) cm.state.completionActive.close(); diff --git a/addon/hint/xml-hint.js b/addon/hint/xml-hint.js index ea5b8d546a..b6c1da2ce2 100644 --- a/addon/hint/xml-hint.js +++ b/addon/hint/xml-hint.js @@ -3,7 +3,7 @@ var Pos = CodeMirror.Pos; - CodeMirror.xmlHint = function(cm, options) { + function getHints(cm, options) { var tags = options && options.schemaInfo; var quote = (options && options.quoteChar) || '"'; if (!tags) return; @@ -61,5 +61,8 @@ from: replaceToken ? Pos(cur.line, token.start) : cur, to: replaceToken ? Pos(cur.line, token.end) : cur }; - }; + } + + CodeMirror.xmlHint = getHints; // deprecated + CodeMirror.registerHelper("hint", "xml", getHints); })(); diff --git a/demo/anywordhint.html b/demo/anywordhint.html index 820df39e90..5bb0a62a10 100644 --- a/demo/anywordhint.html +++ b/demo/anywordhint.html @@ -20,7 +20,7 @@

    CodeMirror: Any Word Completion Demo

    var WORD = /[\w$]+/g, RANGE = 500; - CodeMirror.anyWordHint = function(editor, options) { + CodeMirror.registerHelper("hint", "anyword", function(editor, options) { var word = options && options.word || WORD; var range = options && options.range || RANGE; var cur = editor.getCursor(), curLine = editor.getLine(cur.line); @@ -46,7 +46,7 @@

    CodeMirror: Any Word Completion Demo

    scan(-1); scan(1); return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; - }; + }); })(); @@ -58,7 +58,7 @@

    CodeMirror: Any Word Completion Demo

    diff --git a/doc/manual.html b/doc/manual.html index c4e2ece461..c7466ce243 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1745,24 +1745,28 @@

    Addons

    fails, line-comments it.
    fold/foldcode.js
    -
    Helps with code folding. Add a foldCode method +
    Helps with code folding. Adds a foldCode method to editor instances, which will try to do a code fold starting at the given line, or unfold the fold that is already present. The method takes as first argument the position that should be folded (may be a line number or - a Pos), and as second argument - either a range-finder function, or an options object, supporting - the following properties: + a Pos), and as second optional + argument either a range-finder function, or an options object, + supporting the following properties:
    rangeFinder: fn(CodeMirror, Pos)
    -
    The function that is used to find foldable ranges. There - are files in the addon/fold/ - directory providing CodeMirror.braceRangeFinder, - which finds blocks in brace languages (JavaScript, C, Java, - etc), CodeMirror.indentRangeFinder, for languages - where indentation determines block structure (Python, - Haskell), and CodeMirror.tagRangeFinder, for - XML-style languages.
    +
    The function that is used to find foldable ranges. If this + is not directly passed, it will + call getHelper with + a "fold" type to find one that's appropriate for + the mode. There are files in + the addon/fold/ + directory providing CodeMirror.fold.brace, which + finds blocks in brace languages (JavaScript, C, Java, + etc), CodeMirror.fold.indent, for languages where + indentation determines block structure (Python, Haskell), + and CodeMirror.fold.xml, for XML-style + languages.
    widget: string|Element
    The widget to show for folded ranges. Can be either a string, in which case it'll become a span with diff --git a/lib/codemirror.js b/lib/codemirror.js index a43abb9724..659f8c96bc 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2874,7 +2874,7 @@ window.CodeMirror = (function() { if (!helpers.hasOwnProperty(type)) return; var state = this.getTokenAt(pos).state, help = helpers[type]; var mode = CodeMirror.innerMode(this.getMode(), state).mode; - return mode.type && help[mode[type]] || + return mode[type] && help[mode[type]] || mode.helperType && help[mode.helperType] || help[mode.name]; }, diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 3fcc1a757b..f6626cd0ea 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -158,7 +158,8 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { electricChars: "{}", blockCommentStart: "/*", blockCommentEnd: "*/", - lineComment: "//" + lineComment: "//", + fold: "brace" }; }); diff --git a/mode/coffeescript/coffeescript.js b/mode/coffeescript/coffeescript.js index 509d9207bb..4f54b0c690 100644 --- a/mode/coffeescript/coffeescript.js +++ b/mode/coffeescript/coffeescript.js @@ -339,7 +339,8 @@ CodeMirror.defineMode('coffeescript', function(conf) { return state.scopes[0].offset; }, - lineComment: "#" + lineComment: "#", + fold: "indent" }; return external; }); diff --git a/mode/css/css.js b/mode/css/css.js index b38a968e5e..b52e787a70 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -289,7 +289,8 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { electricChars: "}", blockCommentStart: "/*", - blockCommentEnd: "*/" + blockCommentEnd: "*/", + fold: "brace" }; }); diff --git a/mode/groovy/groovy.js b/mode/groovy/groovy.js index 92b948192e..6800e0aaf5 100644 --- a/mode/groovy/groovy.js +++ b/mode/groovy/groovy.js @@ -203,7 +203,8 @@ CodeMirror.defineMode("groovy", function(config) { else return ctx.indented + (closing ? 0 : config.indentUnit); }, - electricChars: "{}" + electricChars: "{}", + fold: "brace" }; }); diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 6435e138d6..f8c710f912 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -461,6 +461,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { blockCommentStart: jsonMode ? null : "/*", blockCommentEnd: jsonMode ? null : "*/", lineComment: jsonMode ? null : "//", + fold: "brace", jsonMode: jsonMode }; diff --git a/mode/python/python.js b/mode/python/python.js index b623972b88..565d963fdf 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -333,7 +333,8 @@ CodeMirror.defineMode("python", function(conf, parserConf) { return state.scopes[0].offset; }, - lineComment: "#" + lineComment: "#", + fold: "indent" }; return external; }); diff --git a/mode/rust/rust.js b/mode/rust/rust.js index 7bee489b47..c7530b6cc6 100644 --- a/mode/rust/rust.js +++ b/mode/rust/rust.js @@ -428,7 +428,8 @@ CodeMirror.defineMode("rust", function() { electricChars: "{}", blockCommentStart: "/*", blockCommentEnd: "*/", - lineComment: "//" + lineComment: "//", + fold: "brace" }; }); From e0e28c5dc02b54922f8853c1560d1d1fe74b9ef1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Jul 2013 14:26:22 +0200 Subject: [PATCH 0785/5273] [lint addon] Move over to registerHelper --- addon/lint/coffeescript-lint.js | 5 +++-- addon/lint/javascript-lint.js | 9 +++------ addon/lint/json-lint.js | 5 +++-- addon/lint/lint.js | 18 ++++++++++++------ demo/lint.html | 6 +++--- doc/manual.html | 13 ++++++++----- mode/javascript/javascript.js | 1 + 7 files changed, 33 insertions(+), 24 deletions(-) diff --git a/addon/lint/coffeescript-lint.js b/addon/lint/coffeescript-lint.js index 9c30de51c2..75f8db6565 100644 --- a/addon/lint/coffeescript-lint.js +++ b/addon/lint/coffeescript-lint.js @@ -1,6 +1,6 @@ // Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js -CodeMirror.coffeeValidator = function(text) { +CodeMirror.registerHelper("lint", "coffeescript", function(text) { var found = []; var parseError = function(err) { var loc = err.lineNumber; @@ -21,4 +21,5 @@ CodeMirror.coffeeValidator = function(text) { message: e.message}); } return found; -}; +}); +CodeMirror.coffeeValidator = CodeMirror.lint.coffeescript; // deprecated diff --git a/addon/lint/javascript-lint.js b/addon/lint/javascript-lint.js index 9a815c824e..d7a6f6af28 100644 --- a/addon/lint/javascript-lint.js +++ b/addon/lint/javascript-lint.js @@ -9,18 +9,15 @@ "Unmatched ", " and instead saw", " is not defined", "Unclosed string", "Stopping, unable to continue" ]; - function validator(options, text) { + function validator(text, options) { JSHINT(text, options); var errors = JSHINT.data().errors, result = []; if (errors) parseErrors(errors, result); return result; } - CodeMirror.javascriptValidatorWithOptions = function(options) { - return function(text) { return validator(options, text); }; - }; - - CodeMirror.javascriptValidator = CodeMirror.javascriptValidatorWithOptions(null); + CodeMirror.registerHelper("lint", "javascript", validator); + CodeMirror.javascriptValidator = CodeMirror.lint.javascript; // deprecated function cleanup(error) { // All problems are warnings by default diff --git a/addon/lint/json-lint.js b/addon/lint/json-lint.js index 42b36abb39..1dfc6b8fdc 100644 --- a/addon/lint/json-lint.js +++ b/addon/lint/json-lint.js @@ -1,6 +1,6 @@ // Depends on jsonlint.js from https://github.com/zaach/jsonlint -CodeMirror.jsonValidator = function(text) { +CodeMirror.registerHelper("lint", "json", function(text) { var found = []; jsonlint.parseError = function(str, hash) { var loc = hash.loc; @@ -11,4 +11,5 @@ CodeMirror.jsonValidator = function(text) { try { jsonlint.parse(text); } catch(e) {} return found; -}; +}); +CodeMirror.jsonValidator = CodeMirror.lint.json; // deprecated diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 2e7cea1925..67a92970a3 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -1,4 +1,5 @@ -CodeMirror.validate = (function() { +(function() { + "use strict"; var GUTTER_ID = "CodeMirror-lint-markers"; var SEVERITIES = /^(?:error|warning)$/; @@ -52,9 +53,11 @@ CodeMirror.validate = (function() { this.onMouseOver = function(e) { onMouseOver(cm, e); }; } - function parseOptions(options) { + function parseOptions(cm, options) { if (options instanceof Function) return {getAnnotations: options}; - else if (!options || !options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)"); + if (!options || options === true) options = {}; + if (!options.getAnnotations) options.getAnnotations = cm.getHelper(CodeMirror.Pos(0, 0), "lint"); + if (!options.getAnnotations) throw new Error("Required option 'getAnnotations' missing (lint addon)"); return options; } @@ -175,7 +178,7 @@ CodeMirror.validate = (function() { } } - CodeMirror.defineOption("lintWith", false, function(cm, val, old) { + function optionHandler(cm, val, old) { if (old && old != CodeMirror.Init) { clearMarks(cm); cm.off("change", onChange); @@ -186,12 +189,15 @@ CodeMirror.validate = (function() { if (val) { var gutters = cm.getOption("gutters"), hasLintGutter = false; for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; - var state = cm.state.lint = new LintState(cm, parseOptions(val), hasLintGutter); + var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter); cm.on("change", onChange); if (state.options.tooltips != false) CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); startLinting(cm); } - }); + } + + CodeMirror.defineOption("lintWith", false, optionHandler); // deprecated + CodeMirror.defineOption("lint", false, optionHandler); // deprecated })(); diff --git a/demo/lint.html b/demo/lint.html index ece8b1cef7..d379c31934 100644 --- a/demo/lint.html +++ b/demo/lint.html @@ -7,7 +7,7 @@ - + @@ -75,14 +75,14 @@

    CodeMirror: Linter Demo

    lineNumbers: true, mode: "javascript", gutters: ["CodeMirror-lint-markers"], - lintWith: CodeMirror.javascriptValidator + lint: true }); var editor_json = CodeMirror.fromTextArea(document.getElementById("code-json"), { lineNumbers: true, mode: "application/json", gutters: ["CodeMirror-lint-markers"], - lintWith: CodeMirror.jsonValidator + lint: true }); diff --git a/doc/manual.html b/doc/manual.html index c7466ce243..d028b9615c 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1974,11 +1974,14 @@

    Addons

    with pluggable warning sources (see json-lint.js and javascript-lint.js - in the same directory). Defines a lintWith option - that can be set to a warning source (for - example CodeMirror.javascriptValidator). Depends - on addon/lint/lint.css. A demo can be - found here.
    + in the same directory). Defines a lint option that + can be set to a warning source (for + example CodeMirror.lint.javascript), or + to true, in which + case getHelper with + type "lint" is used to determined a validator + function. Depends on addon/lint/lint.css. A demo + can be found here.
    selection/mark-selection.js
    Causes the selected text to be marked with the CSS class diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index f8c710f912..f5507ce699 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -463,6 +463,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { lineComment: jsonMode ? null : "//", fold: "brace", + helperType: jsonMode ? "json" : "javascript", jsonMode: jsonMode }; }); From 348db87b65b38d0b27f1a796797ee36f2a11195c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Jul 2013 14:40:45 +0200 Subject: [PATCH 0786/5273] [manual] Fix missing tag --- doc/manual.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index d028b9615c..68be9718f6 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1584,7 +1584,7 @@

    Static properties

    (with the instance as argument) whenever a new CodeMirror instance is initialized.
    -
    CodeMirror.registerHelper(type: string, name: string, value: helper)
    +
    CodeMirror.registerHelper(type: string, name: string, value: helper)
    Registers a helper value with the given name in the given namespace (type). This is used to define functionality that may be looked up by mode. Will create (if it From 9d6f762ebec15dd5e00157c4baf5e3f5e73513dd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 4 Jul 2013 08:32:26 +0200 Subject: [PATCH 0787/5273] [matchtags addon] Fix inefficiency Issue #1653 --- addon/edit/matchtags.js | 10 +++++++--- addon/fold/xml-fold.js | 6 ++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/addon/edit/matchtags.js b/addon/edit/matchtags.js index 66e57c8e9e..3eabfeb8d3 100644 --- a/addon/edit/matchtags.js +++ b/addon/edit/matchtags.js @@ -22,14 +22,18 @@ } function doMatchTags(cm) { + cm.state.failedTagMatch = false; cm.operation(function() { clear(cm); var cur = cm.getCursor(), range = cm.getViewport(); range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to); var match = CodeMirror.findMatchingTag(cm, cur, range); - if (cm.state.failedTagMatch = !match) return; + if (!match) return; var other = match.at == "close" ? match.open : match.close; - cm.state.matchedTag = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"}); + if (other) + cm.state.matchedTag = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"}); + else + cm.state.failedTagMatch = true; }); } @@ -41,7 +45,7 @@ var found = CodeMirror.findMatchingTag(cm, cm.getCursor()); if (found) { var other = found.at == "close" ? found.open : found.close; - cm.setSelection(other.to, other.from); + if (other) cm.setSelection(other.to, other.from); } }; })(); diff --git a/addon/fold/xml-fold.js b/addon/fold/xml-fold.js index 08a87bd0a0..5707701aa5 100644 --- a/addon/fold/xml-fold.js +++ b/addon/fold/xml-fold.js @@ -146,12 +146,10 @@ var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]}; if (start[1]) { // closing tag - var open = findMatchingOpen(iter, start[2]); - return open && {open: open, close: here, at: "close"}; + return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"}; } else { // opening tag iter = new Iter(cm, to.line, to.ch, range); - var close = findMatchingClose(iter, start[2]); - return close && {open: here, close: close, at: "open"}; + return {open: here, close: findMatchingClose(iter, start[2]), at: "open"}; } }; From 5e706977b5f67d250c12f17ba71cbd1784783b29 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 4 Jul 2013 10:58:31 +0200 Subject: [PATCH 0788/5273] [foldgutter addon] Add --- addon/fold/foldcode.js | 3 + addon/fold/foldgutter.js | 122 +++++++++++++++++++++++++++++++++++++++ demo/folding.html | 30 ++++++++-- doc/manual.html | 33 ++++++++++- 4 files changed, 181 insertions(+), 7 deletions(-) create mode 100644 addon/fold/foldgutter.js diff --git a/addon/fold/foldcode.js b/addon/fold/foldcode.js index d83a0f49dc..99b4c79cf5 100644 --- a/addon/fold/foldcode.js +++ b/addon/fold/foldcode.js @@ -16,7 +16,9 @@ if (marks[i].__isFold) { if (!allowFolded) return null; range.cleared = true; + var found = marks[i].find(); marks[i].clear(); + CodeMirror.signal(cm, "unfold", cm, found.from, found.to); } } return range; @@ -36,6 +38,7 @@ clearOnEnter: true, __isFold: true }); + CodeMirror.signal(cm, "fold", cm, range.from, range.to); } function makeWidget(options) { diff --git a/addon/fold/foldgutter.js b/addon/fold/foldgutter.js new file mode 100644 index 0000000000..b809c93f56 --- /dev/null +++ b/addon/fold/foldgutter.js @@ -0,0 +1,122 @@ +(function() { + "use strict"; + + CodeMirror.defineOption("foldGutter", false, function(cm, val, old) { + if (old && old != CodeMirror.Init) { + cm.clearGutter(cm.state.foldGutter.options.gutter); + cm.state.foldGutter = null; + cm.off("gutterClick", onGutterClick); + cm.off("change", onChange); + cm.off("viewportChange", onViewportChange); + cm.off("fold", onFold); + cm.off("unfold", onFold); + } + if (val) { + cm.state.foldGutter = new State(parseOptions(val)); + updateInViewport(cm); + cm.on("gutterClick", onGutterClick); + cm.on("change", onChange); + cm.on("viewportChange", onViewportChange); + cm.on("fold", onFold); + cm.on("unfold", onFold); + } + }); + + var Pos = CodeMirror.Pos; + + function State(options) { + this.options = options; + this.from = this.to = 0; + } + + function parseOptions(opts) { + if (opts === true) opts = {}; + if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter"; + if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open"; + if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded"; + return opts; + } + + function isFolded(cm, line) { + var marks = cm.findMarksAt(Pos(line)); + for (var i = 0; i < marks.length; ++i) + if (marks[i].__isFold && marks[i].find().from.line == line) return true; + } + + function marker(spec) { + if (typeof spec == "string") { + var elt = document.createElement("div"); + elt.className = spec; + return elt; + } else { + return spec.cloneNode(true); + } + } + + function updateFoldInfo(cm, from, to) { + var opts = cm.state.foldGutter.options, cur = from; + cm.eachLine(from, to, function(line) { + var mark = null; + if (isFolded(cm, cur)) { + mark = marker(opts.indicatorFolded); + } else { + var pos = Pos(cur, 0), func = opts.rangeFinder || cm.getHelper(pos, "fold"); + var range = func && func(cm, pos); + if (range && range.from.line + 1 < range.to.line) + mark = marker(opts.indicatorOpen); + } + cm.setGutterMarker(line, opts.gutter, mark); + ++cur; + }); + } + + function updateInViewport(cm) { + var vp = cm.getViewport(), state = cm.state.foldGutter; + if (!state) return; + cm.operation(function() { + updateFoldInfo(cm, vp.from, vp.to); + }); + state.from = vp.from; state.to = vp.to; + } + + function onGutterClick(cm, line, gutter) { + var opts = cm.state.foldGutter.options; + if (gutter != opts.gutter) return; + cm.foldCode(Pos(line, 0), opts.rangeFinder); + } + + function onChange(cm) { + var state = cm.state.foldGutter; + state.from = state.to = 0; + clearTimeout(state.changeUpdate); + state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, 600); + } + + function onViewportChange(cm) { + var state = cm.state.foldGutter; + clearTimeout(state.changeUpdate); + state.changeUpdate = setTimeout(function() { + var vp = cm.getViewport(); + if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { + updateInViewport(cm); + } else { + cm.operation(function() { + if (vp.from < state.from) { + updateFoldInfo(cm, vp.from, state.from); + state.from = vp.from; + } + if (vp.to > state.to) { + updateFoldInfo(cm, state.to, vp.to); + state.to = vp.to; + } + }); + } + }, 400); + } + + function onFold(cm, from) { + var state = cm.state.foldGutter, line = from.line; + if (line >= state.from && line < state.to) + updateFoldInfo(cm, line, line + 1); + } +})(); diff --git a/demo/folding.html b/demo/folding.html index d9823cf377..e6cecf26d0 100644 --- a/demo/folding.html +++ b/demo/folding.html @@ -6,6 +6,7 @@ + @@ -21,14 +22,29 @@ line-height: .3; cursor: pointer; } + .CodeMirror-foldgutter { + width: .7em; + } + .CodeMirror-foldgutter-open, + .CodeMirror-foldgutter-folded { + color: #555; + cursor: pointer; + } + .CodeMirror-foldgutter-open:after { + content: "\25BE"; + } + .CodeMirror-foldgutter-folded:after { + content: "\25B8"; + }

    CodeMirror: Code Folding Demo

    Demonstration of code folding using the code - in foldcode.js. - Press ctrl-q or click on the gutter to fold a block, again + in foldcode.js + and foldgutter.js. + Press ctrl-q or click on the gutter markers to fold a block, again to unfold.

    JavaScript:
    @@ -47,18 +63,20 @@

    CodeMirror: Code Folding Demo

    mode: "javascript", lineNumbers: true, lineWrapping: true, - extraKeys: {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }} + extraKeys: {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }}, + foldGutter: true, + gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"] }); - editor.on("gutterClick", function(cm, n) { cm.foldCode(CodeMirror.Pos(n, 0)); }); editor.foldCode(CodeMirror.Pos(8, 0)); window.editor_html = CodeMirror.fromTextArea(te_html, { mode: "text/html", lineNumbers: true, lineWrapping: true, - extraKeys: {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }} + extraKeys: {"Ctrl-Q": function(cm){ cm.foldCode(cm.getCursor()); }}, + foldGutter: true, + gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"] }); - editor_html.on("gutterClick", function(cm, n) { cm.foldCode(CodeMirror.Pos(n, 0)); }); editor_html.foldCode(CodeMirror.Pos(13, 0)); editor_html.foldCode(CodeMirror.Pos(1, 0)); }; diff --git a/doc/manual.html b/doc/manual.html index 68be9718f6..12e2af7359 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1432,7 +1432,7 @@

    Mode, state, and token-related methods

    unstyled tokens, and a string, potentially containing multiple space-separated style names, otherwise.
    -
    cm.getHelperAt(pos: {line, ch}, type: string) → helper
    +
    cm.getHelper(pos: {line, ch}, type: string) → helper
    Fetch appropriate helper for the given position. Helpers provide a way to look up functionality appropriate for a mode. The type argument provides the helper namespace @@ -1783,6 +1783,37 @@

    Addons

    See the demo for an example.
    +
    fold/foldgutter.js
    +
    Provides an option foldGutter, which can be + used to create a gutter with markers indicating the blocks that + can be folded. Create a gutter using + the gutters option, + giving it the class CodeMirror-foldgutter or + something else if you configure the addon to use a different + class, and this addon will show markers next to folded and + foldable blocks, and handle clicks in this gutter. The option + can be either set to true, or an object containing + the following optional option fields: +
    +
    gutter: string
    +
    The CSS class of the gutter. Defaults + to "CodeMirror-foldgutter". You will have to + style this yourself to give it a width (and possibly a + background).
    +
    indicatorOpen: string | Element
    +
    A CSS class or DOM element to be used as the marker for + open, foldable blocks. Defaults + to "CodeMirror-foldgutter-open".
    +
    indicatorFolded: string | Element
    +
    A CSS class or DOM element to be used as the marker for + folded blocks. Defaults to "CodeMirror-foldgutter-folded".
    +
    rangeFinder: fn(CodeMirror, Pos)
    +
    The range-finder function to use when determining whether + something can be folded. When not + given, getHelper will be + used to determine a default.
    +
    +
    runmode/runmode.js
    Can be used to run a CodeMirror mode over text without actually opening an editor instance. From 7499eace15c819055b9693daf375d9dcf4512aee Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 4 Jul 2013 11:00:56 +0200 Subject: [PATCH 0789/5273] Rename combineRangeFinders to CodeMirror.fold.combine --- addon/fold/foldcode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/fold/foldcode.js b/addon/fold/foldcode.js index 99b4c79cf5..51a7f5fd0e 100644 --- a/addon/fold/foldcode.js +++ b/addon/fold/foldcode.js @@ -60,7 +60,7 @@ // New-style interface CodeMirror.defineExtension("foldCode", function(pos, options) { doFold(this, pos, options); }); - CodeMirror.combineRangeFinders = function() { + CodeMirror.fold.combine = function() { var funcs = Array.prototype.slice.call(arguments, 0); return function(cm, start) { for (var i = 0; i < funcs.length; ++i) { From d9a839fbe29a4ad186f1175458480f3557295587 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 4 Jul 2013 11:21:51 +0200 Subject: [PATCH 0790/5273] [match-highlighter addon] Improve showToken option --- addon/search/match-highlighter.js | 20 +++++++++++--------- demo/matchhighlighter.html | 2 +- doc/manual.html | 13 ++++++++----- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/addon/search/match-highlighter.js b/addon/search/match-highlighter.js index 212167580a..3df6985984 100644 --- a/addon/search/match-highlighter.js +++ b/addon/search/match-highlighter.js @@ -55,11 +55,13 @@ cm.removeOverlay(state.overlay); state.overlay = null; } - if (!cm.somethingSelected() && state.showToken) { - var tok = cm.getTokenAt(cm.getCursor()).string; - if (/\w/.test(tok)) - cm.addOverlay(state.overlay = makeOverlay(tok, true, state.style)); + var re = state.showToken === true ? /[\w$]/ : state.showToken; + var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start; + while (start && re.test(line.charAt(start - 1))) --start; + while (end < line.length && re.test(line.charAt(end))) ++end; + if (start < end) + cm.addOverlay(state.overlay = makeOverlay(line.slice(start, end), re, state.style)); return; } if (cm.getCursor("head").line != cm.getCursor("anchor").line) return; @@ -69,15 +71,15 @@ }); } - function boundariesAround(stream) { - return (stream.start || /.\b./.test(stream.string.slice(stream.start - 1, stream.start + 1))) && - (stream.pos == stream.string.length || /.\b./.test(stream.string.slice(stream.pos - 1, stream.pos + 1))); + function boundariesAround(stream, re) { + return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) && + (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos))); } - function makeOverlay(query, wordBoundaries, style) { + function makeOverlay(query, hasBoundary, style) { return {token: function(stream) { if (stream.match(query) && - (!wordBoundaries || boundariesAround(stream))) + (!hasBoundary || boundariesAround(stream, hasBoundary))) return style; stream.next(); stream.skipTo(query.charAt(0)) || stream.skipToEnd(); diff --git a/demo/matchhighlighter.html b/demo/matchhighlighter.html index c574fbae81..9d2fdd098a 100644 --- a/demo/matchhighlighter.html +++ b/demo/matchhighlighter.html @@ -28,7 +28,7 @@

    CodeMirror: Match Highlighter Demo

    diff --git a/doc/manual.html b/doc/manual.html index 12e2af7359..5b08097a90 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1812,7 +1812,8 @@

    Addons

    something can be folded. When not given, getHelper will be used to determine a default.
    -

    + + Demo here.
    runmode/runmode.js
    Can be used to run a CodeMirror mode over text without @@ -1994,10 +1995,12 @@

    Addons

    minimum amount of selected characters that triggers a highlight (default 2), style, for the style to be used to highlight the matches (default "matchhighlight", - which will correspond to CSS class cm-matchhighlight), - and showToken which, when enabled, causes the - current token to be highlighted when nothing is selected - (defaults to off). + which will correspond to CSS + class cm-matchhighlight), + and showToken which can be set to true + or to a regexp matching the characters that make up a word. When + enabled, it causes the current word to be highlighted when + nothing is selected (defaults to off). Demo here.
    lint/lint.js
    From b2b6b54b6e4617acc46a36cb1d924712c03f5237 Mon Sep 17 00:00:00 2001 From: Aurelian Oancea Date: Thu, 4 Jul 2013 16:09:28 +0200 Subject: [PATCH 0791/5273] [midnight theme] fixed syntax error --- theme/midnight.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/midnight.css b/theme/midnight.css index f10edf932a..bc2d49be1c 100644 --- a/theme/midnight.css +++ b/theme/midnight.css @@ -2,7 +2,7 @@ /**/ .cm-s-midnight span.CodeMirror-matchhighlight { background: #494949 } -.cm-s-midnight.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67; !important } +.cm-s-midnight.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67 !important; } /**/ .cm-s-midnight .activeline {background: #253540 !important;} From 8b8b7b061e441f8409b080ade327cacbc732272c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 5 Jul 2013 08:43:04 +0200 Subject: [PATCH 0792/5273] [xml-fold addon] Add fast-case return to findMatchingTag --- addon/fold/xml-fold.js | 1 + lib/codemirror.js | 1 + 2 files changed, 2 insertions(+) diff --git a/addon/fold/xml-fold.js b/addon/fold/xml-fold.js index 5707701aa5..b87da9088c 100644 --- a/addon/fold/xml-fold.js +++ b/addon/fold/xml-fold.js @@ -140,6 +140,7 @@ CodeMirror.findMatchingTag = function(cm, pos, range) { var iter = new Iter(cm, pos.line, pos.ch, range); + if (!tagAt(iter, iter.ch)) return; var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); var start = end && toTagStart(iter); if (!end || end == "selfClose" || !start || cmp(iter, pos) > 0) return; diff --git a/lib/codemirror.js b/lib/codemirror.js index 659f8c96bc..96e579e753 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2862,6 +2862,7 @@ window.CodeMirror = (function() { 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; + if (ch == 0) return styles[2]; for (;;) { var mid = (before + after) >> 1; if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; From 4f43c8ce8780c531b6a1772e1e3eb34dcbfe037f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 5 Jul 2013 16:11:26 +0200 Subject: [PATCH 0793/5273] Add getModeAt method Use it to prevent some unneeded state computation. --- addon/comment/comment.js | 6 +++--- addon/fold/foldcode.js | 4 ++-- doc/manual.html | 10 ++++++++-- lib/codemirror.js | 9 +++++++-- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/addon/comment/comment.js b/addon/comment/comment.js index 3c76744654..cd2123e175 100644 --- a/addon/comment/comment.js +++ b/addon/comment/comment.js @@ -17,7 +17,7 @@ CodeMirror.defineExtension("lineComment", function(from, to, options) { if (!options) options = noOptions; - var self = this, mode = CodeMirror.innerMode(self.getMode(), self.getTokenAt(from).state).mode; + var self = this, mode = self.getModeAt(from); var commentString = options.lineComment || mode.lineComment; if (!commentString) { if (options.blockCommentStart || mode.blockCommentStart) { @@ -52,7 +52,7 @@ CodeMirror.defineExtension("blockComment", function(from, to, options) { if (!options) options = noOptions; - var self = this, mode = CodeMirror.innerMode(self.getMode(), self.getTokenAt(from).state).mode; + var self = this, mode = self.getModeAt(from); var startString = options.blockCommentStart || mode.blockCommentStart; var endString = options.blockCommentEnd || mode.blockCommentEnd; if (!startString || !endString) { @@ -85,7 +85,7 @@ CodeMirror.defineExtension("uncomment", function(from, to, options) { if (!options) options = noOptions; - var self = this, mode = CodeMirror.innerMode(self.getMode(), self.getTokenAt(from).state).mode; + var self = this, mode = self.getModeAt(from); var end = Math.min(to.line, self.lastLine()), start = Math.min(from.line, end); // Try finding line comments diff --git a/addon/fold/foldcode.js b/addon/fold/foldcode.js index 51a7f5fd0e..69513cb8bb 100644 --- a/addon/fold/foldcode.js +++ b/addon/fold/foldcode.js @@ -60,7 +60,7 @@ // New-style interface CodeMirror.defineExtension("foldCode", function(pos, options) { doFold(this, pos, options); }); - CodeMirror.fold.combine = function() { + CodeMirror.registerHelper("fold", "combine", function() { var funcs = Array.prototype.slice.call(arguments, 0); return function(cm, start) { for (var i = 0; i < funcs.length; ++i) { @@ -68,5 +68,5 @@ if (found) return found; } }; - }; + }); })(); diff --git a/doc/manual.html b/doc/manual.html index 5b08097a90..64c684b10b 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1401,11 +1401,17 @@

    Mode, state, and token-related methods

    doc.getMode() → object
    -
    Gets the mode object for the editor. Note that this is - distinct from getOption("mode"), which gives you +
    Gets the (outer) mode object for the editor. Note that this + is distinct from getOption("mode"), which gives you the mode specification, rather than the resolved, instantiated mode object.
    +
    doc.getModeAt(pos: {line, ch}) → object
    +
    Gets the inner mode at a given position. This will return + the same as getMode for + simple modes, but will return an inner mode for nesting modes + (such as htmlmixed).
    +
    cm.getTokenAt(pos: {line, ch}, ?precise: boolean) → object
    Retrieves information about the token the current mode found before the given position (a {line, ch} object). The diff --git a/lib/codemirror.js b/lib/codemirror.js index 96e579e753..1caa59d2d2 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2871,10 +2871,15 @@ window.CodeMirror = (function() { } }, + getModeAt: function(pos) { + var mode = this.doc.mode; + if (!mode.innerMode) return mode; + return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; + }, + getHelper: function(pos, type) { if (!helpers.hasOwnProperty(type)) return; - var state = this.getTokenAt(pos).state, help = helpers[type]; - var mode = CodeMirror.innerMode(this.getMode(), state).mode; + var help = helpers[type], mode = this.getModeAt(pos); return mode[type] && help[mode[type]] || mode.helperType && help[mode.helperType] || help[mode.name]; From 76894881e46571dc5bb8df953b32d71dc0113a0a Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Sun, 7 Jul 2013 21:11:40 -0400 Subject: [PATCH 0794/5273] [markdown] Highlight trailing spaces that affect line breaks --- mode/markdown/index.html | 7 ++++++- mode/markdown/markdown.js | 27 ++++++++++++++++++++++++++- mode/markdown/test.js | 14 ++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/mode/markdown/index.html b/mode/markdown/index.html index 6f97b10e73..bb785b13fc 100644 --- a/mode/markdown/index.html +++ b/mode/markdown/index.html @@ -8,7 +8,12 @@ - + diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 72b0d6ced2..bf1750d5b6 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -103,6 +103,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.f = inlineNormal; state.block = blockNormal; } + // Reset state.trailingSpace + state.trailingSpace = 0; + state.trailingSpaceNewLine = false; // Mark this line as blank state.thisLineHasContent = false; return null; @@ -217,6 +220,12 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } } + if (state.trailingSpaceNewLine) { + styles.push("trailing-space-new-line"); + } else if (state.trailingSpace) { + styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b")); + } + return styles.length ? styles.join(' ') : null; } @@ -369,6 +378,14 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } } + if (ch === ' ') { + if (stream.match(/ +$/, false)) { + state.trailingSpace++; + } else if (state.trailingSpace) { + state.trailingSpaceNewLine = true; + } + } + return getType(state); } @@ -453,7 +470,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { taskList: false, list: false, listDepth: 0, - quote: 0 + quote: 0, + trailingSpace: 0, + trailingSpaceNewLine: false }; }, @@ -481,6 +500,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { list: s.list, listDepth: s.listDepth, quote: s.quote, + trailingSpace: s.trailingSpace, + trailingSpaceNewLine: s.trailingSpaceNewLine, md_inside: s.md_inside }; }, @@ -504,6 +525,10 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { // Reset state.code state.code = false; + // Reset state.trailingSpace + state.trailingSpace = 0; + state.trailingSpaceNewLine = false; + state.f = state.block; var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length; var difference = Math.floor((indentation - state.indentation) / 4) * 4; diff --git a/mode/markdown/test.js b/mode/markdown/test.js index 99ae056132..f167917289 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -5,6 +5,20 @@ MT("plainText", "foo"); + // Don't style single trailing space + MT("trailingSpace1", + "foo "); + + // Two or more trailing spaces should be styled with line break character + MT("trailingSpace2", + "foo[trailing-space-a ][trailing-space-new-line ]"); + + MT("trailingSpace3", + "foo[trailing-space-a ][trailing-space-b ][trailing-space-new-line ]"); + + MT("trailingSpace4", + "foo[trailing-space-a ][trailing-space-b ][trailing-space-a ][trailing-space-new-line ]"); + // Code blocks using 4 spaces (regardless of CodeMirror.tabSize value) MT("codeBlocksUsing4Spaces", " [comment foo]"); From 25e4be044206c7b26b003df7cb8e2fcb0cbe71cf Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 8 Jul 2013 09:22:56 +0200 Subject: [PATCH 0795/5273] [javascript mode] Don't get confused by empty brackets --- 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 f5507ce699..d51745d837 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -311,7 +311,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == ";") return; if (type == "(") return cont(pushlex(")", "call"), commasep(expressionNoComma, ")"), poplex, me); if (type == ".") return cont(property, me); - if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, me); + if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me); } function maybelabel(type) { if (type == ":") return cont(poplex, statement); From e99efe2543edea09ce6780e826288add7ddec48d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Jul 2013 10:36:05 +0200 Subject: [PATCH 0796/5273] [javascript mode] Fix bad indentation below if Closes #1662 --- mode/javascript/javascript.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index d51745d837..3d04603c28 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -258,17 +258,17 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (type == "keyword b") return cont(pushlex("form"), statement, poplex); if (type == "{") return cont(pushlex("}"), block, poplex); if (type == ";") return cont(); - if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse(cx.state.indented)); + if (type == "if") return cont(pushlex("form"), expression, statement, poplex, maybeelse); if (type == "function") return cont(functiondef); if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"), - poplex, statement, poplex); + poplex, statement, poplex); if (type == "variable") return cont(pushlex("stat"), maybelabel); if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), - block, poplex, poplex); + block, poplex, poplex); if (type == "case") return cont(expression, expect(":")); if (type == "default") return cont(expect(":")); if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), - statement, poplex, popcontext); + statement, poplex, popcontext); return pass(pushlex("stat"), expression, expect(";"), poplex); } function expression(type) { @@ -373,14 +373,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (value == "=") return cont(expressionNoComma, vardef2); if (type == ",") return cont(vardef1); } - function maybeelse(indent) { - return function(type, value) { - if (type == "keyword b" && value == "else") { - cx.state.lexical = new JSLexical(indent, 0, "form", null, cx.state.lexical); - return cont(statement, poplex); - } - return pass(); - }; + function maybeelse(type, value) { + if (type == "keyword b" && value == "else") return cont(pushlex("form"), statement, poplex); } function forspec1(type) { if (type == "var") return cont(vardef1, expect(";"), forspec2); @@ -441,6 +435,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { if (state.tokenize == jsTokenComment) return CodeMirror.Pass; if (state.tokenize != jsTokenBase) return 0; var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical; + // Kludge to prevent 'maybelse' from blocking lexical scope pops + 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 || /^else\b/.test(textAfter)) break; + } if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev; if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat") lexical = lexical.prev; From c921c10de61a733a55015b5607f1c360baf2e285 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Jul 2013 11:09:30 +0200 Subject: [PATCH 0797/5273] Add another exception to the spanAffectsWrapping hack And turn the hack off in recent Chrome builds. Issue #1663 --- lib/codemirror.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 1caa59d2d2..ab1cce5fb6 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -5391,10 +5391,12 @@ window.CodeMirror = (function() { spanAffectsWrapping = function(str, i) { return /\-[^ \-?]|\?[^ !\'\"\),.\-\/:;\?\]\}]/.test(str.slice(i - 1, i + 1)); }; - else if (webkit) + else if (webkit && !/Chrome\/(?:29|[3-9]\d|\d\d\d)\./.test(navigator.userAgent)) spanAffectsWrapping = function(str, i) { - if (i > 1 && str.charCodeAt(i - 1) == 45 && /\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) - return true; + if (i > 1 && str.charCodeAt(i - 1) == 45) { + if (/\w/.test(str.charAt(i - 2)) && /[^\-?\.]/.test(str.charAt(i))) return true; + if (i > 2 && /[\d\.,]/.test(str.charAt(i - 2)) && /[\d\.,]/.test(str.charAt(i))) return false; + } return /[~!#%&*)=+}\]|\"\.>,:;][({[<]|-[^\-?\.\u2010-\u201f\u2026]|\?[\w~`@#$%\^&*(_=+{[|><]|…[\w~`@#$%\^&*(_=+{[><]/.test(str.slice(i - 1, i + 1)); }; From 8068b3d55d397ad14350e6b1593fa53095927f4b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 11 Jul 2013 08:09:06 +0200 Subject: [PATCH 0798/5273] Fix removeKeyMap for string keymap values --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index ab1cce5fb6..330a09e385 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2798,7 +2798,7 @@ window.CodeMirror = (function() { removeKeyMap: function(map) { var maps = this.state.keyMaps; for (var i = 0; i < maps.length; ++i) - if ((typeof map == "string" ? maps[i].name : maps[i]) == map) { + if (maps[i] == map || (typeof maps[i] != "string" && maps[i].name == map)) { maps.splice(i, 1); return true; } From 4651de869bcd7a1503bbe14540aebc3a8879705f Mon Sep 17 00:00:00 2001 From: Matthias BUSSONNIER Date: Tue, 25 Jun 2013 17:12:09 +0200 Subject: [PATCH 0799/5273] [python mode] Add MIME for Cython dialect --- doc/modes.html | 1 + index.html | 1 + mode/meta.js | 3 ++- mode/python/index.html | 46 +++++++++++++++++++++++++++++++++++++++--- mode/python/python.js | 16 +++++++++++++++ 5 files changed, 63 insertions(+), 4 deletions(-) diff --git a/doc/modes.html b/doc/modes.html index 69c7d5e9ad..1c76f2fb1b 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -31,6 +31,7 @@

    { } CodeMi
  • CoffeeScript
  • Common Lisp
  • CSS
  • +
  • Cython
  • D
  • diff
  • ECL
  • diff --git a/index.html b/index.html index 6a9dbcb603..544aac1200 100644 --- a/index.html +++ b/index.html @@ -40,6 +40,7 @@

    Supported modes:

  • CoffeeScript
  • Common Lisp
  • CSS
  • +
  • Cython
  • D
  • diff
  • ECL
  • diff --git a/mode/meta.js b/mode/meta.js index cb1051e68f..1ea0f672b0 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -16,7 +16,7 @@ CodeMirror.modeInfo = [ {name: 'ECL', mime: 'text/x-ecl', mode: 'ecl'}, {name: 'Erlang', mime: 'text/x-erlang', mode: 'erlang'}, {name: 'Gas', mime: 'text/x-gas', mode: 'gas'}, - {name: 'GitHub Flavored Markdown', mode: 'gfm'}, + {name: 'GitHub Flavored Markdown', mime: 'text/x-gfm', mode: 'gfm'}, {name: 'GO', mime: 'text/x-go', mode: 'go'}, {name: 'Groovy', mime: 'text/x-groovy', mode: 'groovy'}, {name: 'Haskell', mime: 'text/x-haskell', mode: 'haskell'}, @@ -47,6 +47,7 @@ CodeMirror.modeInfo = [ {name: 'Plain Text', mime: 'text/plain', mode: 'null'}, {name: 'Properties files', mime: 'text/x-properties', mode: 'clike'}, {name: 'Python', mime: 'text/x-python', mode: 'python'}, + {name: 'Cython', mime: 'text/x-cython', mode: 'python'}, {name: 'R', mime: 'text/x-rsrc', mode: 'r'}, {name: 'reStructuredText', mime: 'text/x-rst', mode: 'rst'}, {name: 'Ruby', mime: 'text/x-ruby', mode: 'ruby'}, diff --git a/mode/python/index.html b/mode/python/index.html index 4244c6fc5a..1229a8bf83 100644 --- a/mode/python/index.html +++ b/mode/python/index.html @@ -12,7 +12,7 @@

    CodeMirror: Python mode

    - +

    Python mode

    + + +

    Cython mode

    + +
    + -

    Configuration Options:

    +

    Configuration Options for Python mode:

    • version - 2/3 - The version of Python to recognize. Default is 2.
    • singleLineStringErrors - true/false - If you have a single-line string that is not terminated at the end of the line, this will show subsequent lines as errors if true, otherwise it will consider the newline as the end of the string. Default is false.
    • @@ -127,9 +165,11 @@

      Advanced Configuration Options:

    • doubleDelimiters - RegEx - Regular Expressoin for double delimiters matching, default :
      ^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))
    • tripleDelimiters - RegEx - Regular Expression for triple delimiters matching, default :
      ^((//=)|(>>=)|(<<=)|(\\*\\*=))
    • identifiers - RegEx - Regular Expression for identifier, default :
      ^[_A-Za-z][_A-Za-z0-9]*
    • +
    • extra_keywords - list of string - List of extra words ton consider as keywords
    • +
    • extra_builtins - list of string - List of extra words ton consider as builtins
    -

    MIME types defined: text/x-python.

    +

    MIME types defined: text/x-python and text/x-cython.

    diff --git a/mode/python/python.js b/mode/python/python.js index 565d963fdf..2c6d1d83c7 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -36,6 +36,12 @@ CodeMirror.defineMode("python", function(conf, parserConf) { var py3 = {'builtins': ['ascii', 'bytes', 'exec', 'print'], 'keywords': ['nonlocal', 'False', 'True', 'None']}; + if(parserConf.extra_keywords != undefined){ + commonkeywords = commonkeywords.concat(parserConf.extra_keywords); + } + if(parserConf.extra_builtins != undefined){ + commonBuiltins = commonBuiltins.concat(parserConf.extra_builtins); + } if (!!parserConf.version && parseInt(parserConf.version, 10) === 3) { commonkeywords = commonkeywords.concat(py3.keywords); commonBuiltins = commonBuiltins.concat(py3.builtins); @@ -340,3 +346,13 @@ CodeMirror.defineMode("python", function(conf, parserConf) { }); CodeMirror.defineMIME("text/x-python", "python"); + +var words = function(str){return str.split(' ');}; + + +CodeMirror.defineMIME("text/x-cython", { + name: "python", + extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+ + "extern gil include nogil property public"+ + "readonly struct union DEF IF ELIF ELSE") +}); From 9e8199b3d604009f1a3b8df4691f9d3469c7aefe Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Tue, 9 Jul 2013 12:42:25 -0700 Subject: [PATCH 0800/5273] Fix bug in addLineWidget. Fixed clipping of the insertAt index. --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 330a09e385..03933ff9eb 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4108,7 +4108,7 @@ window.CodeMirror = (function() { changeLine(cm, handle, function(line) { var widgets = line.widgets || (line.widgets = []); if (widget.insertAt == null) widgets.push(widget); - else widgets.splice(Math.max(widgets.length - 1, widget.insertAt), 0, widget); + else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); widget.line = line; if (!lineIsHidden(cm.doc, line) || widget.showIfHidden) { var aboveVisible = heightAtLine(cm, line) < cm.doc.scrollTop; From 486976e16d42ca9cf2b6b01bdd21912124fbc562 Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Tue, 9 Jul 2013 15:02:43 -0700 Subject: [PATCH 0801/5273] Fix addLineWidget documentation. Removed "pos" parameter. --- doc/manual.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index 64c684b10b..a4f8bc060e 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1253,7 +1253,7 @@

    Widget, gutter, and decoration methods

    widget again, simply use DOM methods (move it somewhere else, or call removeChild on its parent).
    -
    cm.addLineWidget(line: integer|LineHandle, node: Element, ?options: object, ?pos: integer) → LineWidget
    +
    cm.addLineWidget(line: integer|LineHandle, node: Element, ?options: object) → LineWidget
    Adds a line widget, an element shown below a line, spanning the whole of the editor's width, and moving the lines below it downwards. line should be either an integer or a From ab2b604ed8bc64788c3590683e446f38043bb671 Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Wed, 10 Jul 2013 21:16:48 +0200 Subject: [PATCH 0802/5273] Fix selecting until the start of a bidi line --- lib/codemirror.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 03933ff9eb..6bfd652fe5 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -5483,11 +5483,15 @@ window.CodeMirror = (function() { 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]; - if (part.from < to && part.to > from || from == to && part.to == from) + 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; + } } + if (!found) f(from, to, "ltr"); } function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } From 1a028d007a50c117775aabca1e5d932115333e9f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 11 Jul 2013 10:18:01 +0200 Subject: [PATCH 0803/5273] Support 'title' option to markText Issue #1654 --- doc/manual.html | 4 ++++ lib/codemirror.js | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index a4f8bc060e..cb3bc50509 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1151,6 +1151,10 @@

    Text-marking methods

    is part of the marker.
    endStyle: string
    Equivalent to startStyle, but for the rightmost span.
    +
    title: + string
    When given, will give the nodes created + for this span a HTML title attribute with the + given value.
    shared: boolean
    When the target document is linked to other documents, you can set shared to true to make the diff --git a/lib/codemirror.js b/lib/codemirror.js index 6bfd652fe5..fe956fd81a 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3791,7 +3791,7 @@ window.CodeMirror = (function() { } if (cm) { if (updateMaxLine) cm.curOp.updateMaxLine = true; - if (marker.className || marker.startStyle || marker.endStyle || marker.collapsed) + if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.collapsed) regChange(cm, from.line, to.line + 1); if (marker.atomic) reCheckSelection(cm); } @@ -4284,7 +4284,7 @@ window.CodeMirror = (function() { } var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g; - function buildToken(builder, text, style, startStyle, endStyle) { + function buildToken(builder, text, style, startStyle, endStyle, title) { if (!text) return; if (!tokenSpecialChars.test(text)) { builder.col += text.length; @@ -4317,7 +4317,9 @@ window.CodeMirror = (function() { var fullStyle = style || ""; if (startStyle) fullStyle += startStyle; if (endStyle) fullStyle += endStyle; - return builder.pre.appendChild(elt("span", [content], fullStyle)); + var token = elt("span", [content], fullStyle); + if (title) token.title = title; + return builder.pre.appendChild(token); } builder.pre.appendChild(content); } @@ -4355,8 +4357,8 @@ window.CodeMirror = (function() { out += " "; return out; } - return function(builder, text, style, startStyle, endStyle) { - return inner(builder, text.replace(/ {3,}/, split), style, startStyle, endStyle); + return function(builder, text, style, startStyle, endStyle, title) { + return inner(builder, text.replace(/ {3,}/, split), style, startStyle, endStyle, title); }; } @@ -4392,10 +4394,10 @@ window.CodeMirror = (function() { } var len = allText.length, pos = 0, i = 1, text = "", style; - var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed; + var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; for (;;) { if (nextChange == pos) { // Update current marker set - spanStyle = spanEndStyle = spanStartStyle = ""; + spanStyle = spanEndStyle = spanStartStyle = title = ""; collapsed = null; nextChange = Infinity; var foundBookmark = null; for (var j = 0; j < spans.length; ++j) { @@ -4405,6 +4407,7 @@ window.CodeMirror = (function() { if (m.className) spanStyle += " " + m.className; if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle; + if (m.title && !title) title = m.title; if (m.collapsed && (!collapsed || collapsed.marker.size < m.size)) collapsed = sp; } else if (sp.from > pos && nextChange > sp.from) { @@ -4428,7 +4431,7 @@ window.CodeMirror = (function() { if (!collapsed) { var tokenText = end > upto ? text.slice(0, upto - pos) : text; builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, - spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : ""); + spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title); } if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} pos = end; From 4f85a7ef97942a31b07609b11f762c785a71a34e Mon Sep 17 00:00:00 2001 From: John Snelson Date: Thu, 11 Jul 2013 09:50:43 +0100 Subject: [PATCH 0804/5273] Added SPARQL 1.1 keywords to the SPARQL mode. --- mode/sparql/sparql.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mode/sparql/sparql.js b/mode/sparql/sparql.js index f7237698d3..1168f23a52 100644 --- a/mode/sparql/sparql.js +++ b/mode/sparql/sparql.js @@ -9,7 +9,9 @@ CodeMirror.defineMode("sparql", function(config) { "isblank", "isliteral", "union", "a"]); var keywords = wordRegexp(["base", "prefix", "select", "distinct", "reduced", "construct", "describe", "ask", "from", "named", "where", "order", "limit", "offset", "filter", "optional", - "graph", "by", "asc", "desc"]); + "graph", "by", "asc", "desc", "as", "having", "undef", "values", "group", + "minus", "in", "not", "service", "silent", "using", "insert", "delete", + "data", "copy", "to", "move", "add", "create", "drop", "clear", "load"]); var operatorChars = /[*+\-<>=&|]/; function tokenBase(stream, state) { From ef328ed46d2a7cc5e3d47735a9725230fadc4d59 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 12 Jul 2013 10:38:17 +0200 Subject: [PATCH 0805/5273] Add convenient event methods to all event-emitting objects i.e. linehandle.on, markedrange.off, etc. --- doc/manual.html | 22 ++++++++++------------ lib/codemirror.js | 34 +++++++++++++++++++++------------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index cb3bc50509..d17eb79853 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -375,14 +375,15 @@

    Configuration

    Events

    -

    A CodeMirror instance emits a number of events, which allow - client code to react to various situations. These are registered - with the on method (and - removed with the off - method). These are the events that fire on the instance object. - The name of the event is followed by the arguments that will be - passed to the handler. The instance argument always - refers to the editor instance.

    +

    Various CodeMirror-related objects emit events, which allow + client code to react to various situations. Handlers for such + events can be registed with the on + and off methods on the objects + that the event fires on.

    + +

    An editor instance fires the following events. + The instance argument always refers to the editor + itself.

    "change" (instance: CodeMirror, changeObj: object)
    @@ -497,10 +498,7 @@

    Events

    CodeMirror should do no further handling.
    -

    It is also possible to register events on - other objects. Use CodeMirror.on(handle, "eventName", - func) to register handlers on objects that don't have their - own on method. Document objects (instances +

    Document objects (instances of CodeMirror.Doc) emit the following events:

    diff --git a/lib/codemirror.js b/lib/codemirror.js index fe956fd81a..35c2e30f18 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3123,9 +3123,6 @@ window.CodeMirror = (function() { this.refresh(); }, - on: function(type, f) {on(this, type, f);}, - off: function(type, f) {off(this, type, f);}, - operation: function(f){return runInOp(this, f);}, refresh: operation(null, function() { @@ -3149,6 +3146,7 @@ window.CodeMirror = (function() { getScrollerElement: function(){return this.display.scroller;}, getGutterElement: function(){return this.display.gutters;} }; + eventMixin(CodeMirror); // OPTION DEFAULTS @@ -3657,6 +3655,7 @@ window.CodeMirror = (function() { this.doc = doc; } CodeMirror.TextMarker = TextMarker; + eventMixin(TextMarker); TextMarker.prototype.clear = function() { if (this.explicitlyCleared) return; @@ -3809,6 +3808,7 @@ window.CodeMirror = (function() { } } CodeMirror.SharedTextMarker = SharedTextMarker; + eventMixin(SharedTextMarker); SharedTextMarker.prototype.clear = function() { if (this.explicitlyCleared) return; @@ -4066,6 +4066,7 @@ window.CodeMirror = (function() { this.cm = cm; this.node = node; }; + eventMixin(LineWidget); function widgetOperation(f) { return function() { var withOp = !this.cm.curOp; @@ -4124,12 +4125,12 @@ window.CodeMirror = (function() { // Line objects. These hold state related to a line, including // highlighting info (the styles array). - function makeLine(text, markedSpans, estimateHeight) { - var line = {text: text}; - attachMarkedSpans(line, markedSpans); - line.height = estimateHeight ? estimateHeight(line) : 1; - return line; + function Line(text, markedSpans, estimateHeight) { + this.text = text; + attachMarkedSpans(this, markedSpans); + this.height = estimateHeight ? estimateHeight(this) : 1; } + eventMixin(Line); function updateLine(line, text, markedSpans, estimateHeight) { line.text = text; @@ -4461,7 +4462,7 @@ window.CodeMirror = (function() { // This is a whole-line replace. Treated specially to make // sure line objects move the way they are supposed to. for (var i = 0, e = text.length - 1, added = []; i < e; ++i) - added.push(makeLine(text[i], spansFor(i), estimateHeight)); + added.push(new Line(text[i], spansFor(i), estimateHeight)); update(lastLine, lastLine.text, lastSpans); if (nlines) doc.remove(from.line, nlines); if (added.length) doc.insert(from.line, added); @@ -4470,8 +4471,8 @@ window.CodeMirror = (function() { update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); } else { for (var added = [], i = 1, e = text.length - 1; i < e; ++i) - added.push(makeLine(text[i], spansFor(i), estimateHeight)); - added.push(makeLine(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); + added.push(new Line(text[i], spansFor(i), estimateHeight)); + 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); } @@ -4482,7 +4483,7 @@ window.CodeMirror = (function() { update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); for (var i = 1, e = text.length - 1, added = []; i < e; ++i) - added.push(makeLine(text[i], spansFor(i), estimateHeight)); + added.push(new Line(text[i], spansFor(i), estimateHeight)); if (nlines > 1) doc.remove(from.line + 1, nlines - 1); doc.insert(from.line + 1, added); } @@ -4625,7 +4626,7 @@ window.CodeMirror = (function() { if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); if (firstLine == null) firstLine = 0; - BranchChunk.call(this, [new LeafChunk([makeLine("", null)])]); + BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); this.first = firstLine; this.scrollTop = this.scrollLeft = 0; this.cantEdit = false; @@ -4860,6 +4861,8 @@ window.CodeMirror = (function() { return function() {return method.apply(this.doc, arguments);}; })(Doc.prototype[prop]); + eventMixin(Doc); + function linkedDocs(doc, f, sharedHistOnly) { function propagate(doc, skip, sharedHist) { if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { @@ -5243,6 +5246,11 @@ window.CodeMirror = (function() { CodeMirror.on = on; CodeMirror.off = off; CodeMirror.signal = signal; + function eventMixin(ctor) { + ctor.prototype.on = function(type, f) {on(this, type, f);}; + ctor.prototype.off = function(type, f) {off(this, type, f);}; + } + // MISC UTILITIES // Number of pixels added to scroller and sizer to hide scrollbar From 649b848b91d33471ad43708dc2af3abfeebc17ad Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 12 Jul 2013 10:45:55 +0200 Subject: [PATCH 0806/5273] [activeline addon] Don't get confused by collapsed spans Issue #1668 --- addon/selection/active-line.js | 2 +- lib/codemirror.js | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/addon/selection/active-line.js b/addon/selection/active-line.js index 65fab6f162..e50508653a 100644 --- a/addon/selection/active-line.js +++ b/addon/selection/active-line.js @@ -29,7 +29,7 @@ } function updateActiveLine(cm) { - var line = cm.getLineHandle(cm.getCursor().line); + var line = cm.getLineHandleVisualStart(cm.getCursor().line); if (cm.state.activeLine == line) return; clearActiveLine(cm); cm.addLineClass(line, "wrap", WRAP_CLASS); diff --git a/lib/codemirror.js b/lib/codemirror.js index 35c2e30f18..9a6a932010 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4125,11 +4125,11 @@ window.CodeMirror = (function() { // Line objects. These hold state related to a line, including // highlighting info (the styles array). - function Line(text, markedSpans, estimateHeight) { + var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) { this.text = text; attachMarkedSpans(this, markedSpans); this.height = estimateHeight ? estimateHeight(this) : 1; - } + }; eventMixin(Line); function updateLine(line, text, markedSpans, estimateHeight) { @@ -4691,6 +4691,11 @@ window.CodeMirror = (function() { 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(this, line); + }, + lineCount: function() {return this.size;}, firstLine: function() {return this.first;}, lastLine: function() {return this.first + this.size - 1;}, From 47655e693d5d29fc549797aa0cd79800d7828427 Mon Sep 17 00:00:00 2001 From: Ruslan Osmanov Date: Sat, 29 Jun 2013 19:28:16 +0500 Subject: [PATCH 0807/5273] [smartymixed mode] Add --- .gitignore | 2 + mode/smartymixed/index.html | 107 ++++++++++++++++++++ mode/smartymixed/smartymixed.js | 170 ++++++++++++++++++++++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 mode/smartymixed/index.html create mode 100644 mode/smartymixed/smartymixed.js diff --git a/.gitignore b/.gitignore index bc20ab58d5..b471fe6e63 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ /npm-debug.log test.html .tern-* +*~ +*.swp diff --git a/mode/smartymixed/index.html b/mode/smartymixed/index.html new file mode 100644 index 0000000000..6567b27d6b --- /dev/null +++ b/mode/smartymixed/index.html @@ -0,0 +1,107 @@ + + + + + CodeMirror: Smarty mixed mode + + + + + + + + + + + + + + + +

    CodeMirror: Smarty mixed mode

    + + + + +

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

    + +

    It takes the same options, as Smarty and HTML mixed modes.

    + +

    MIME types defined: text/x-smarty.

    + + + diff --git a/mode/smartymixed/smartymixed.js b/mode/smartymixed/smartymixed.js new file mode 100644 index 0000000000..c5d008885a --- /dev/null +++ b/mode/smartymixed/smartymixed.js @@ -0,0 +1,170 @@ +/** +* @file smartymixed.js +* @brief Smarty Mixed Codemirror mode (Smarty + Mixed HTML) +* @author Ruslan Osmanov +* @version 3.0 +* @date 05.07.2013 +*/ +CodeMirror.defineMode("smartymixed", function(config) { + var settings, regs, helpers, parsers, + htmlMixedMode = CodeMirror.getMode(config, "htmlmixed"), + smartyMode = CodeMirror.getMode(config, "smarty"), + + settings = { + rightDelimiter: '}', + leftDelimiter: '{' + }; + + if (config.hasOwnProperty("leftDelimiter")) { + settings.leftDelimiter = config.leftDelimiter; + } + if (config.hasOwnProperty("rightDelimiter")) { + settings.rightDelimiter = config.rightDelimiter; + } + + regs = { + smartyComment: new RegExp("^" + settings.leftDelimiter + "\\*"), + literalOpen: new RegExp(settings.leftDelimiter + "literal" + settings.rightDelimiter), + literalClose: new RegExp(settings.leftDelimiter + "\/literal" + settings.rightDelimiter), + hasLeftDelimeter: new RegExp(".*" + settings.leftDelimiter), + htmlHasLeftDelimeter: new RegExp("[^<>]*" + settings.leftDelimiter) + }; + + helpers = { + chain: function(stream, state, parser) { + state.tokenize = parser; + return parser(stream, state); + }, + + cleanChain: function(stream, state, parser) { + state.tokenize = null; + state.localState = null; + state.localMode = null; + return (typeof parser == "string") ? (parser ? parser : null) : parser(stream, state); + }, + + maybeBackup: function(stream, pat, style) { + var cur = stream.current(); + var close = cur.search(pat), + m; + if (close > - 1) stream.backUp(cur.length - close); + else if (m = cur.match(/<\/?$/)) { + stream.backUp(cur.length); + if (!stream.match(pat, false)) stream.match(cur[0]); + } + return style; + } + }; + + parsers = { + html: function(stream, state) { + if (!state.inLiteral && stream.match(regs.htmlHasLeftDelimeter, false)) { + state.tokenize = parsers.smarty; + state.localMode = smartyMode; + state.localState = smartyMode.startState(htmlMixedMode.indent(state.htmlMixedState, "")); + return helpers.maybeBackup(stream, settings.leftDelimiter, smartyMode.token(stream, state.localState)); + } + return htmlMixedMode.token(stream, state.htmlMixedState); + }, + + smarty: function(stream, state) { + if (stream.match(settings.leftDelimiter, false)) { + if (stream.match(regs.smartyComment, false)) { + return helpers.chain(stream, state, parsers.inBlock("comment", "*" + settings.rightDelimiter)); + } + } else if (stream.match(settings.rightDelimiter, false)) { + stream.eat(settings.rightDelimiter); + state.tokenize = parsers.html; + state.localMode = htmlMixedMode; + state.localState = state.htmlMixedState; + return "tag"; + } + + return helpers.maybeBackup(stream, settings.rightDelimiter, smartyMode.token(stream, state.localState)); + }, + + inBlock: function(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + helpers.cleanChain(stream, state, ""); + break; + } + stream.next(); + } + return style; + }; + } + }; + + return { + startState: function() { + var state = htmlMixedMode.startState(); + return { + token: parsers.html, + localMode: null, + localState: null, + htmlMixedState: state, + tokenize: null, + inLiteral: false + }; + }, + + copyState: function(state) { + var local = null, tok = (state.tokenize || state.token); + if (state.localState) { + local = CodeMirror.copyState((tok != parsers.html ? smartyMode : htmlMixedMode), state.localState); + } + return { + token: state.token, + tokenize: state.tokenize, + localMode: state.localMode, + localState: local, + htmlMixedState: CodeMirror.copyState(htmlMixedMode, state.htmlMixedState), + inLiteral: state.inLiteral + }; + }, + + token: function(stream, state) { + if (stream.match(settings.leftDelimiter, false)) { + if (!state.inLiteral && stream.match(regs.literalOpen, true)) { + state.inLiteral = true; + return "keyword"; + } else if (state.inLiteral && stream.match(regs.literalClose, true)) { + state.inLiteral = false; + return "keyword"; + } + } + if (state.inLiteral && state.localState != state.htmlMixedState) { + state.tokenize = parsers.html; + state.localMode = htmlMixedMode; + state.localState = state.htmlMixedState; + } + + var style = (state.tokenize || state.token)(stream, state); + return style; + }, + + indent: function(state, textAfter) { + if (state.localMode == smartyMode + || (state.inLiteral && !state.localMode) + || regs.hasLeftDelimeter.test(textAfter)) { + return CodeMirror.Pass; + } + return htmlMixedMode.indent(state.htmlMixedState, textAfter); + }, + + electricChars: "/{}:", + + innerMode: function(state) { + return { + state: state.localState || state.htmlMixedState, + mode: state.localMode || htmlMixedMode + }; + } + }; +}, +"htmlmixed"); + +CodeMirror.defineMIME("text/x-smarty", "smartymixed"); +// vim: et ts=2 sts=2 sw=2 From 7f560afa1ce8c6ce7a43c561e35bd43f4b9652c3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 12 Jul 2013 10:50:43 +0200 Subject: [PATCH 0808/5273] [smartymixed mode] Integrate --- doc/compress.html | 1 + doc/modes.html | 1 + mode/meta.js | 1 + 3 files changed, 3 insertions(+) diff --git a/doc/compress.html b/doc/compress.html index c7eec47d5e..9ccafba4ae 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -123,6 +123,7 @@

    { } CodeMi + diff --git a/doc/modes.html b/doc/modes.html index 1c76f2fb1b..cb72754eb7 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -76,6 +76,7 @@

    { } CodeMi
  • Sieve
  • Smalltalk
  • Smarty
  • +
  • Smarty/HTML mixed
  • SQL (several dialects)
  • SPARQL
  • sTeX, LaTeX
  • diff --git a/mode/meta.js b/mode/meta.js index 1ea0f672b0..63123a0254 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -59,6 +59,7 @@ CodeMirror.modeInfo = [ {name: 'Sieve', mime: 'application/sieve', mode: 'sieve'}, {name: 'Smalltalk', mime: 'text/x-stsrc', mode: 'smalltalk'}, {name: 'Smarty', mime: 'text/x-smarty', mode: 'smarty'}, + {name: 'SmartyMixed', mime: 'text/x-smarty', mode: 'smartymixed'}, {name: 'SPARQL', mime: 'application/x-sparql-query', mode: 'sparql'}, {name: 'SQL', mime: 'text/x-sql', mode: 'sql'}, {name: 'MariaDB', mime: 'text/x-mariadb', mode: 'sql'}, From 47f1a861d4493dc5b582b0b04d48155311301c1e Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Fri, 12 Jul 2013 22:34:09 -0400 Subject: [PATCH 0809/5273] [vim] Disable insert mode if document is readonly --- keymap/vim.js | 1 + 1 file changed, 1 insertion(+) diff --git a/keymap/vim.js b/keymap/vim.js index 977642ea38..ab7f757b1e 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1625,6 +1625,7 @@ emptyMacroKeyBuffer(macroModeState); }, enterInsertMode: function(cm, actionArgs, vim) { + if (cm.getOption('readOnly')) { return; } vim.insertMode = true; vim.insertModeRepeat = actionArgs && actionArgs.repeat || 1; var insertAt = (actionArgs) ? actionArgs.insertAt : null; From 13dc1753c35768c4802dfc8749b26011bf18bd42 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 13 Jul 2013 11:40:48 +0200 Subject: [PATCH 0810/5273] Fire DOM event from contextmenu handler Issue #1674 --- doc/manual.html | 2 +- lib/codemirror.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index d17eb79853..55f7196aaf 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -489,7 +489,7 @@

    Events

    should not try to change the state of the editor.
    "mousedown", - "dblclick", "keydown", "keypress", + "dblclick", "contextmenu", "keydown", "keypress", "keyup", "dragstart", "dragenter", "dragover", "drop" (instance: CodeMirror, event: Event)
    diff --git a/lib/codemirror.js b/lib/codemirror.js index 9a6a932010..4e3a07eccb 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2107,6 +2107,7 @@ window.CodeMirror = (function() { var detectingSelectAll; function onContextMenu(cm, e) { + if (signalDOMEvent(cm, e, "contextmenu")) return; var display = cm.display, sel = cm.doc.sel; if (eventInWidget(display, e)) return; @@ -5232,8 +5233,8 @@ window.CodeMirror = (function() { delayedCallbacks.push(bnd(arr[i])); } - function signalDOMEvent(cm, e) { - signal(cm, e.type, cm, e); + function signalDOMEvent(cm, e, override) { + signal(cm, override || e.type, cm, e); return e_defaultPrevented(e); } From 35ae796c194fa638dde8a97da00286012f41c5c4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 13 Jul 2013 11:43:39 +0200 Subject: [PATCH 0811/5273] [real-world used] Add CodeZample --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 2150abe401..9aca75a75d 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -41,6 +41,7 @@

    { } CodeMi
  • Code Snippets (WordPress snippet management plugin)
  • Code together (collaborative editing)
  • Codev (collaborative IDE)
  • +
  • CodeZample (code snippet sharing)
  • Collaborative CodeMirror demo (CodeMirror + operational transforms)
  • Community Code Camp (code snippet sharing)
  • CKWNC (UML editor)
  • From b05b96e0306d3b33b8a7810884a0d1cfb7b42969 Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Fri, 12 Jul 2013 12:47:00 +0400 Subject: [PATCH 0812/5273] [closebrackets addon] Do not insert pair of quotes right after the word --- addon/edit/closebrackets.js | 4 +++- lib/codemirror.js | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 6fbf38ae67..88718b7729 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -54,7 +54,9 @@ if (cm.somethingSelected()) return surround(cm); if (left == right && maybeOverwrite(cm) != CodeMirror.Pass) return; var cur = cm.getCursor(), ahead = CodeMirror.Pos(cur.line, cur.ch + 1); - var line = cm.getLine(cur.line), nextChar = line.charAt(cur.ch); + var line = cm.getLine(cur.line), nextChar = line.charAt(cur.ch), curChar = cur.ch > 0 ? line.charAt(cur.ch - 1) : ""; + if (left == right && CodeMirror.isWordChar(curChar)) + return CodeMirror.Pass; if (line.length == cur.ch || closingBrackets.indexOf(nextChar) >= 0 || SPACE_CHAR_REGEX.test(nextChar)) cm.replaceSelection(left + right, {head: ahead, anchor: ahead}); else diff --git a/lib/codemirror.js b/lib/codemirror.js index 4e3a07eccb..aed7e83b13 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3319,6 +3319,10 @@ window.CodeMirror = (function() { helpers[type][name] = value; }; + // UTILITIES + + CodeMirror.isWordChar = isWordChar; + // MODE STATE HANDLING // Utility functions for working with state. Exported because modes From 2e3cce0cd6aea4093ad72daa8e6b537f3cefe635 Mon Sep 17 00:00:00 2001 From: Leonya Khachaturov Date: Fri, 12 Jul 2013 12:18:19 +0200 Subject: [PATCH 0813/5273] [css mode] Add several non-standard but very common CSS properties --- mode/css/css.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index b52e787a70..70a55d30d4 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -386,15 +386,15 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "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-shadow", - "text-space-collapse", "text-transform", "text-underline-position", + "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", + "word-spacing", "word-wrap", "z-index", "zoom", // SVG-specific "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", From 36c356cc6166775cbc89756165465172ee423228 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 25 Jul 2013 08:02:41 +0200 Subject: [PATCH 0814/5273] Remove trailing whitespace --- 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 70a55d30d4..a81fa40408 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -386,7 +386,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "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-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", From 0ca2c2546475945dca9dacfd93de8cee3a6e5492 Mon Sep 17 00:00:00 2001 From: "Jan T. Sott" Date: Mon, 15 Jul 2013 10:36:47 +0200 Subject: [PATCH 0815/5273] [base16 themes] Add --- theme/3024-day.css | 33 +++++++++++++++++++++++++++++++ theme/3024-night.css | 33 +++++++++++++++++++++++++++++++ theme/base16-dark.css | 33 +++++++++++++++++++++++++++++++ theme/base16-light.css | 33 +++++++++++++++++++++++++++++++ theme/tomorrow-night-eighties.css | 33 +++++++++++++++++++++++++++++++ 5 files changed, 165 insertions(+) create mode 100644 theme/3024-day.css create mode 100644 theme/3024-night.css create mode 100644 theme/base16-dark.css create mode 100644 theme/base16-light.css create mode 100644 theme/tomorrow-night-eighties.css diff --git a/theme/3024-day.css b/theme/3024-day.css new file mode 100644 index 0000000000..e931a49de4 --- /dev/null +++ b/theme/3024-day.css @@ -0,0 +1,33 @@ +/* + + Name: 3024 day + Author: Jan T. Sott (http://github.com/idleberg) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-3024-day.CodeMirror {background: #f7f7f7; color: #3a3432;} +.cm-s-3024-day div.CodeMirror-selected {background: #d6d5d4 !important;} +.cm-s-3024-day .CodeMirror-gutters {background: #f7f7f7; border-right: 0px;} +.cm-s-3024-day .CodeMirror-linenumber {color: #807d7c;} +.cm-s-3024-day .CodeMirror-cursor {border-left: 1px solid #5c5855 !important;} + +.cm-s-3024-day span.cm-comment {color: #cdab53;} +.cm-s-3024-day span.cm-atom {color: #a16a94;} +.cm-s-3024-day span.cm-number {color: #a16a94;} + +.cm-s-3024-day span.cm-property, .cm-s-3024-day span.cm-attribute {color: #01a252;} +.cm-s-3024-day span.cm-keyword {color: #db2d20;} +.cm-s-3024-day span.cm-string {color: #fded02;} + +.cm-s-3024-day span.cm-variable {color: #01a252;} +.cm-s-3024-day span.cm-variable-2 {color: #01a0e4;} +.cm-s-3024-day span.cm-def {color: #e8bbd0;} +.cm-s-3024-day span.cm-error {background: #db2d20; color: #5c5855;} +.cm-s-3024-day span.cm-bracket {color: #3a3432;} +.cm-s-3024-day span.cm-tag {color: #db2d20;} +.cm-s-3024-day span.cm-link {color: #a16a94;} + +.cm-s-3024-day .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/theme/3024-night.css b/theme/3024-night.css new file mode 100644 index 0000000000..87c7f8abe0 --- /dev/null +++ b/theme/3024-night.css @@ -0,0 +1,33 @@ +/* + + Name: 3024 night + Author: Jan T. Sott (http://github.com/idleberg) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-3024-night.CodeMirror {background: #090300; color: #d6d5d4;} +.cm-s-3024-night div.CodeMirror-selected {background: #3a3432 !important;} +.cm-s-3024-night .CodeMirror-gutters {background: #090300; border-right: 0px;} +.cm-s-3024-night .CodeMirror-linenumber {color: #5c5855;} +.cm-s-3024-night .CodeMirror-cursor {border-left: 1px solid #807d7c !important;} + +.cm-s-3024-night span.cm-comment {color: #cdab53;} +.cm-s-3024-night span.cm-atom {color: #a16a94;} +.cm-s-3024-night span.cm-number {color: #a16a94;} + +.cm-s-3024-night span.cm-property, .cm-s-3024-night span.cm-attribute {color: #01a252;} +.cm-s-3024-night span.cm-keyword {color: #db2d20;} +.cm-s-3024-night span.cm-string {color: #fded02;} + +.cm-s-3024-night span.cm-variable {color: #01a252;} +.cm-s-3024-night span.cm-variable-2 {color: #01a0e4;} +.cm-s-3024-night span.cm-def {color: #e8bbd0;} +.cm-s-3024-night span.cm-error {background: #db2d20; color: #807d7c;} +.cm-s-3024-night span.cm-bracket {color: #d6d5d4;} +.cm-s-3024-night span.cm-tag {color: #db2d20;} +.cm-s-3024-night span.cm-link {color: #a16a94;} + +.cm-s-3024-night .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/theme/base16-dark.css b/theme/base16-dark.css new file mode 100644 index 0000000000..7a818b75f5 --- /dev/null +++ b/theme/base16-dark.css @@ -0,0 +1,33 @@ +/* + + Name: Base16 Default Dark + Author: Chris Kempson (http://chriskempson.com) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-base16-dark.CodeMirror {background: #151515; color: #e0e0e0;} +.cm-s-base16-dark div.CodeMirror-selected {background: #202020 !important;} +.cm-s-base16-dark .CodeMirror-gutters {background: #151515; border-right: 0px;} +.cm-s-base16-dark .CodeMirror-linenumber {color: #505050;} +.cm-s-base16-dark .CodeMirror-cursor {border-left: 1px solid #b0b0b0 !important;} + +.cm-s-base16-dark span.cm-comment {color: #8f5536;} +.cm-s-base16-dark span.cm-atom {color: #aa759f;} +.cm-s-base16-dark span.cm-number {color: #aa759f;} + +.cm-s-base16-dark span.cm-property, .cm-s-base16-dark span.cm-attribute {color: #90a959;} +.cm-s-base16-dark span.cm-keyword {color: #ac4142;} +.cm-s-base16-dark span.cm-string {color: #f4bf75;} + +.cm-s-base16-dark span.cm-variable {color: #90a959;} +.cm-s-base16-dark span.cm-variable-2 {color: #6a9fb5;} +.cm-s-base16-dark span.cm-def {color: #d28445;} +.cm-s-base16-dark span.cm-error {background: #ac4142; color: #b0b0b0;} +.cm-s-base16-dark span.cm-bracket {color: #e0e0e0;} +.cm-s-base16-dark span.cm-tag {color: #ac4142;} +.cm-s-base16-dark span.cm-link {color: #aa759f;} + +.cm-s-base16-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/theme/base16-light.css b/theme/base16-light.css new file mode 100644 index 0000000000..a3b2d4dcba --- /dev/null +++ b/theme/base16-light.css @@ -0,0 +1,33 @@ +/* + + Name: Base16 Default Light + Author: Chris Kempson (http://chriskempson.com) + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-chrome-devtools) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-base16-light.CodeMirror {background: #f5f5f5; color: #202020;} +.cm-s-base16-light div.CodeMirror-selected {background: #e0e0e0 !important;} +.cm-s-base16-light .CodeMirror-gutters {background: #f5f5f5; border-right: 0px;} +.cm-s-base16-light .CodeMirror-linenumber {color: #b0b0b0;} +.cm-s-base16-light .CodeMirror-cursor {border-left: 1px solid #505050 !important;} + +.cm-s-base16-light span.cm-comment {color: #8f5536;} +.cm-s-base16-light span.cm-atom {color: #aa759f;} +.cm-s-base16-light span.cm-number {color: #aa759f;} + +.cm-s-base16-light span.cm-property, .cm-s-base16-light span.cm-attribute {color: #90a959;} +.cm-s-base16-light span.cm-keyword {color: #ac4142;} +.cm-s-base16-light span.cm-string {color: #f4bf75;} + +.cm-s-base16-light span.cm-variable {color: #90a959;} +.cm-s-base16-light span.cm-variable-2 {color: #6a9fb5;} +.cm-s-base16-light span.cm-def {color: #d28445;} +.cm-s-base16-light span.cm-error {background: #ac4142; color: #505050;} +.cm-s-base16-light span.cm-bracket {color: #202020;} +.cm-s-base16-light span.cm-tag {color: #ac4142;} +.cm-s-base16-light span.cm-link {color: #aa759f;} + +.cm-s-base16-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/theme/tomorrow-night-eighties.css b/theme/tomorrow-night-eighties.css new file mode 100644 index 0000000000..3aa84cc829 --- /dev/null +++ b/theme/tomorrow-night-eighties.css @@ -0,0 +1,33 @@ +/* + + Name: Tomorrow Night - Eighties + Author: Chris Kempson + + CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror) + Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) + +*/ + +.cm-s-tomorrownight-eighties-night.CodeMirror {background: #000000; color: #CCCCCC;} +.cm-s-tomorrownight-eighties-night div.CodeMirror-selected {background: #2D2D2D !important;} +.cm-s-tomorrownight-eighties-night .CodeMirror-gutters {background: #000000; border-right: 0px;} +.cm-s-tomorrownight-eighties-night .CodeMirror-linenumber {color: #515151;} +.cm-s-tomorrownight-eighties-night .CodeMirror-cursor {border-left: 1px solid #6A6A6A !important;} + +.cm-s-tomorrownight-eighties-night span.cm-comment {color: #d27b53;} +.cm-s-tomorrownight-eighties-night span.cm-atom {color: #a16a94;} +.cm-s-tomorrownight-eighties-night span.cm-number {color: #a16a94;} + +.cm-s-tomorrownight-eighties-night span.cm-property, .cm-s-tomorrownight-eighties-night span.cm-attribute {color: #99cc99;} +.cm-s-tomorrownight-eighties-night span.cm-keyword {color: #f2777a;} +.cm-s-tomorrownight-eighties-night span.cm-string {color: #ffcc66;} + +.cm-s-tomorrownight-eighties-night span.cm-variable {color: #99cc99;} +.cm-s-tomorrownight-eighties-night span.cm-variable-2 {color: #6699cc;} +.cm-s-tomorrownight-eighties-night span.cm-def {color: #f99157;} +.cm-s-tomorrownight-eighties-night span.cm-error {background: #f2777a; color: #6A6A6A;} +.cm-s-tomorrownight-eighties-night span.cm-bracket {color: #CCCCCC;} +.cm-s-tomorrownight-eighties-night span.cm-tag {color: #f2777a;} +.cm-s-tomorrownight-eighties-night span.cm-link {color: #a16a94;} + +.cm-s-tomorrownight-eighties-night .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} From 23c845ce7cd3f13cf660caa934acd12b7e70b86c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 25 Jul 2013 08:13:13 +0200 Subject: [PATCH 0816/5273] [base16 themes] Integrate --- demo/theme.html | 10 +++++++ theme/tomorrow-night-eighties.css | 46 +++++++++++++++---------------- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/demo/theme.html b/demo/theme.html index 147a89ff14..62544be1a7 100644 --- a/demo/theme.html +++ b/demo/theme.html @@ -22,6 +22,11 @@ + + + + + @@ -49,7 +54,11 @@

    CodeMirror: Theme demo

    Select a theme: + + +

    MIME types defined: text/nginx.

    + + + diff --git a/mode/nginx/nginx.js b/mode/nginx/nginx.js new file mode 100644 index 0000000000..4ea49886c3 --- /dev/null +++ b/mode/nginx/nginx.js @@ -0,0 +1,162 @@ +CodeMirror.defineMode("nginx", function(config) { + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var keywords = words( + /* ngxDirectiveControl */ "break return rewrite set" + + /* ngxDirective */ " accept_mutex accept_mutex_delay access_log add_after_body add_before_body add_header addition_types aio alias allow ancient_browser ancient_browser_value auth_basic auth_basic_user_file auth_http auth_http_header auth_http_timeout autoindex autoindex_exact_size autoindex_localtime charset charset_types client_body_buffer_size client_body_in_file_only client_body_in_single_buffer client_body_temp_path client_body_timeout client_header_buffer_size client_header_timeout client_max_body_size connection_pool_size create_full_put_path daemon dav_access dav_methods debug_connection debug_points default_type degradation degrade deny devpoll_changes devpoll_events directio directio_alignment empty_gif env epoll_events error_log eventport_events expires fastcgi_bind fastcgi_buffer_size fastcgi_buffers fastcgi_busy_buffers_size fastcgi_cache fastcgi_cache_key fastcgi_cache_methods fastcgi_cache_min_uses fastcgi_cache_path fastcgi_cache_use_stale fastcgi_cache_valid fastcgi_catch_stderr fastcgi_connect_timeout fastcgi_hide_header fastcgi_ignore_client_abort fastcgi_ignore_headers fastcgi_index fastcgi_intercept_errors fastcgi_max_temp_file_size fastcgi_next_upstream fastcgi_param fastcgi_pass_header fastcgi_pass_request_body fastcgi_pass_request_headers fastcgi_read_timeout fastcgi_send_lowat fastcgi_send_timeout fastcgi_split_path_info fastcgi_store fastcgi_store_access fastcgi_temp_file_write_size fastcgi_temp_path fastcgi_upstream_fail_timeout fastcgi_upstream_max_fails flv geoip_city geoip_country google_perftools_profiles gzip gzip_buffers gzip_comp_level gzip_disable gzip_hash gzip_http_version gzip_min_length gzip_no_buffer gzip_proxied gzip_static gzip_types gzip_vary gzip_window if_modified_since ignore_invalid_headers image_filter image_filter_buffer image_filter_jpeg_quality image_filter_transparency imap_auth imap_capabilities imap_client_buffer index ip_hash keepalive_requests keepalive_timeout kqueue_changes kqueue_events large_client_header_buffers limit_conn limit_conn_log_level limit_rate limit_rate_after limit_req limit_req_log_level limit_req_zone limit_zone lingering_time lingering_timeout lock_file log_format log_not_found log_subrequest map_hash_bucket_size map_hash_max_size master_process memcached_bind memcached_buffer_size memcached_connect_timeout memcached_next_upstream memcached_read_timeout memcached_send_timeout memcached_upstream_fail_timeout memcached_upstream_max_fails merge_slashes min_delete_depth modern_browser modern_browser_value msie_padding msie_refresh multi_accept open_file_cache open_file_cache_errors open_file_cache_events open_file_cache_min_uses open_file_cache_valid open_log_file_cache output_buffers override_charset perl perl_modules perl_require perl_set pid pop3_auth pop3_capabilities port_in_redirect postpone_gzipping postpone_output protocol proxy proxy_bind proxy_buffer proxy_buffer_size proxy_buffering proxy_buffers proxy_busy_buffers_size proxy_cache proxy_cache_key proxy_cache_methods proxy_cache_min_uses proxy_cache_path proxy_cache_use_stale proxy_cache_valid proxy_connect_timeout proxy_headers_hash_bucket_size proxy_headers_hash_max_size proxy_hide_header proxy_ignore_client_abort proxy_ignore_headers proxy_intercept_errors proxy_max_temp_file_size proxy_method proxy_next_upstream proxy_pass_error_message proxy_pass_header proxy_pass_request_body proxy_pass_request_headers proxy_read_timeout proxy_redirect proxy_send_lowat proxy_send_timeout proxy_set_body proxy_set_header proxy_ssl_session_reuse proxy_store proxy_store_access proxy_temp_file_write_size proxy_temp_path proxy_timeout proxy_upstream_fail_timeout proxy_upstream_max_fails random_index read_ahead real_ip_header recursive_error_pages request_pool_size reset_timedout_connection resolver resolver_timeout rewrite_log rtsig_overflow_events rtsig_overflow_test rtsig_overflow_threshold rtsig_signo satisfy secure_link_secret send_lowat send_timeout sendfile sendfile_max_chunk server_name_in_redirect server_names_hash_bucket_size server_names_hash_max_size server_tokens set_real_ip_from smtp_auth smtp_capabilities smtp_client_buffer smtp_greeting_delay so_keepalive source_charset ssi ssi_ignore_recycled_buffers ssi_min_file_chunk ssi_silent_errors ssi_types ssi_value_length ssl ssl_certificate ssl_certificate_key ssl_ciphers ssl_client_certificate ssl_crl ssl_dhparam ssl_engine ssl_prefer_server_ciphers ssl_protocols ssl_session_cache ssl_session_timeout ssl_verify_client ssl_verify_depth starttls stub_status sub_filter sub_filter_once sub_filter_types tcp_nodelay tcp_nopush thread_stack_size timeout timer_resolution types_hash_bucket_size types_hash_max_size underscores_in_headers uninitialized_variable_warn use user userid userid_domain userid_expires userid_mark userid_name userid_p3p userid_path userid_service valid_referers variables_hash_bucket_size variables_hash_max_size worker_connections worker_cpu_affinity worker_priority worker_processes worker_rlimit_core worker_rlimit_nofile worker_rlimit_sigpending worker_threads working_directory xclient xml_entities xslt_stylesheet xslt_typesdrew@li229-23" + ); + + var keywords_block = words( + /* ngxDirectiveBlock */ "http mail events server types location upstream charset_map limit_except if geo map" + ); + + var keywords_important = words( + /* ngxDirectiveImportant */ "include root server server_name listen internal proxy_pass memcached_pass fastcgi_pass try_files" + ); + + var indentUnit = config.indentUnit, type; + function ret(style, tp) {type = tp; return style;} + + function tokenBase(stream, state) { + + + stream.eatWhile(/[\w\$_]/); + + var cur = stream.current(); + + + if (keywords.propertyIsEnumerable(cur)) { + return "keyword"; + } + else if (keywords_block.propertyIsEnumerable(cur)) { + return "variable-2"; + } + else if (keywords_important.propertyIsEnumerable(cur)) { + return "string-2"; + } + /**/ + + var ch = stream.next(); + if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("meta", stream.current());} + else if (ch == "/" && stream.eat("*")) { + state.tokenize = tokenCComment; + return tokenCComment(stream, state); + } + else if (ch == "<" && stream.eat("!")) { + state.tokenize = tokenSGMLComment; + return tokenSGMLComment(stream, state); + } + else if (ch == "=") ret(null, "compare"); + else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare"); + else if (ch == "\"" || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + else if (ch == "#") { + stream.skipToEnd(); + return ret("comment", "comment"); + } + else if (ch == "!") { + stream.match(/^\s*\w*/); + return ret("keyword", "important"); + } + else if (/\d/.test(ch)) { + stream.eatWhile(/[\w.%]/); + return ret("number", "unit"); + } + else if (/[,.+>*\/]/.test(ch)) { + return ret(null, "select-op"); + } + else if (/[;{}:\[\]]/.test(ch)) { + return ret(null, ch); + } + else { + stream.eatWhile(/[\w\\\-]/); + return ret("variable", "variable"); + } + } + + function tokenCComment(stream, state) { + var maybeEnd = false, ch; + while ((ch = stream.next()) != null) { + if (maybeEnd && ch == "/") { + state.tokenize = tokenBase; + break; + } + maybeEnd = (ch == "*"); + } + return ret("comment", "comment"); + } + + function tokenSGMLComment(stream, state) { + var dashes = 0, ch; + while ((ch = stream.next()) != null) { + if (dashes >= 2 && ch == ">") { + state.tokenize = tokenBase; + break; + } + dashes = (ch == "-") ? dashes + 1 : 0; + } + return ret("comment", "comment"); + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) + break; + escaped = !escaped && ch == "\\"; + } + if (!escaped) state.tokenize = tokenBase; + return ret("string", "string"); + }; + } + + return { + startState: function(base) { + return {tokenize: tokenBase, + baseIndent: base || 0, + stack: []}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + + var context = state.stack[state.stack.length-1]; + if (type == "hash" && context == "rule") style = "atom"; + else if (style == "variable") { + if (context == "rule") style = "number"; + else if (!context || context == "@media{") style = "tag"; + } + + if (context == "rule" && /^[\{\};]$/.test(type)) + state.stack.pop(); + if (type == "{") { + if (context == "@media") state.stack[state.stack.length-1] = "@media{"; + else state.stack.push("{"); + } + else if (type == "}") state.stack.pop(); + else if (type == "@media") state.stack.push("@media"); + else if (context == "{" && type != "comment") state.stack.push("rule"); + return style; + }, + + indent: function(state, textAfter) { + var n = state.stack.length; + if (/^\}/.test(textAfter)) + n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1; + return state.baseIndent + n * indentUnit; + }, + + electricChars: "}" + }; +}); + +CodeMirror.defineMIME("text/nginx", "nginx"); From 562af66579ad69425134bdbac03a82db10bf0fe3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 29 Jul 2013 08:38:29 +0200 Subject: [PATCH 0843/5273] [nginx mode] Integrate --- doc/compress.html | 1 + doc/modes.html | 1 + mode/meta.js | 1 + mode/nginx/index.html | 259 +++++++++++++++++++++--------------------- mode/nginx/nginx.js | 3 +- 5 files changed, 134 insertions(+), 131 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 9ccafba4ae..f76629754a 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -101,6 +101,7 @@

    { } CodeMi + diff --git a/doc/modes.html b/doc/modes.html index cb72754eb7..82738f19e6 100644 --- a/doc/modes.html +++ b/doc/modes.html @@ -54,6 +54,7 @@

    { } CodeMi
  • Lua
  • Markdown (GitHub-flavour)
  • mIRC
  • +
  • Nginx
  • NTriples
  • OCaml
  • Pascal
  • diff --git a/mode/meta.js b/mode/meta.js index 63123a0254..8e8c8f5f5c 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -37,6 +37,7 @@ CodeMirror.modeInfo = [ {name: 'Lua', mime: 'text/x-lua', mode: 'lua'}, {name: 'Markdown (GitHub-flavour)', mime: 'text/x-markdown', mode: 'markdown'}, {name: 'mIRC', mime: 'text/mirc', mode: 'mirc'}, + {name: 'Nginx', mime: 'text/x-nginx-conf', mode: 'nginx'}, {name: 'NTriples', mime: 'text/n-triples', mode: 'ntriples'}, {name: 'OCaml', mime: 'text/x-ocaml', mode: 'ocaml'}, {name: 'Pascal', mime: 'text/x-pascal', mode: 'pascal'}, diff --git a/mode/nginx/index.html b/mode/nginx/index.html index c33a224ff4..aa712e1e32 100644 --- a/mode/nginx/index.html +++ b/mode/nginx/index.html @@ -8,155 +8,154 @@ - + - +

    CodeMirror: NGINX mode

    + @@ -119,6 +120,7 @@

    CodeMirror: Tcl mode

    theme: "night", lineNumbers: true, indentUnit: 2, + scrollPastEnd: true, mode: "text/x-tcl" }); From 730d5dd19e3dcfaa972e33060d1d58cb51bc71d9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 31 Jul 2013 15:34:04 +0200 Subject: [PATCH 0864/5273] [show-hint addon] Fix bug with updating completions when typing --- addon/hint/show-hint.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index a4960ddeb0..6247459dd0 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -69,13 +69,9 @@ completion.cm.off("cursorActivity", activity); CodeMirror.signal(data, "close"); } - function isDone() { - if (finished) return true; - if (!completion.widget) { done(); return true; } - } function update() { - if (isDone()) return; + if (finished) return; CodeMirror.signal(data, "update"); if (completion.options.async) completion.getHints(completion.cm, finishUpdate, completion.options); @@ -84,7 +80,7 @@ } function finishUpdate(data_) { data = data_; - if (isDone()) return; + if (finished) return; if (!data || !data.list.length) return done(); completion.widget = new Widget(completion, data); } From 98394a96cd1998f4a59a1688dba662f18ae52deb Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 31 Jul 2013 15:40:33 +0200 Subject: [PATCH 0865/5273] [show-hint addon] Don't try to signal event on null data Closes #1714 --- 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 6247459dd0..a33c4c3559 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -67,7 +67,7 @@ finished = true; completion.close(); completion.cm.off("cursorActivity", activity); - CodeMirror.signal(data, "close"); + if (data) CodeMirror.signal(data, "close"); } function update() { From 3e4540fcf90495280269c4a9c0ba8aae2f0e989f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 1 Aug 2013 09:00:13 +0200 Subject: [PATCH 0866/5273] Remove remaining local LICENSE files --- mode/livescript/LICENSE | 23 ----------------------- mode/sieve/LICENSE | 19 ------------------- mode/xquery/LICENSE | 20 -------------------- 3 files changed, 62 deletions(-) delete mode 100644 mode/livescript/LICENSE delete mode 100644 mode/sieve/LICENSE delete mode 100644 mode/xquery/LICENSE diff --git a/mode/livescript/LICENSE b/mode/livescript/LICENSE deleted file mode 100644 index a675c40233..0000000000 --- a/mode/livescript/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License - -Copyright (c) 2013 Kenneth Bentley -Modified from the CoffeeScript CodeMirror mode, Copyright (c) 2011 Jeff Pickhardt -Modified from the Python CodeMirror mode, Copyright (c) 2010 Timothy Farrell - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/mode/sieve/LICENSE b/mode/sieve/LICENSE deleted file mode 100644 index 8a74612cba..0000000000 --- a/mode/sieve/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (C) 2012 Thomas Schmid - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/mode/xquery/LICENSE b/mode/xquery/LICENSE deleted file mode 100644 index 2a2d47be53..0000000000 --- a/mode/xquery/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (C) 2011 by MarkLogic Corporation -Author: Mike Brevoort - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file From 1984f2957ff49fb8dac3491c2329ef76f86b0a33 Mon Sep 17 00:00:00 2001 From: "Jan T. Sott" Date: Wed, 31 Jul 2013 16:01:52 +0200 Subject: [PATCH 0867/5273] [paraiso theme] Add --- demo/theme.html | 36 ++++++++++++++++++++---------------- theme/paraiso-dark.css | 33 +++++++++++++++++++++++++++++++++ theme/paraiso-light.css | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 theme/paraiso-dark.css create mode 100644 theme/paraiso-light.css diff --git a/demo/theme.html b/demo/theme.html index 62544be1a7..53bd90a5a4 100644 --- a/demo/theme.html +++ b/demo/theme.html @@ -5,28 +5,30 @@ CodeMirror: Theme Demo - + + + + + + + + - + + - - + + + + - - - - - - - - - - - - + + + + @@ -69,6 +71,8 @@

    CodeMirror: Theme demo

    + + diff --git a/theme/paraiso-dark.css b/theme/paraiso-dark.css new file mode 100644 index 0000000000..1e457918de --- /dev/null +++ b/theme/paraiso-dark.css @@ -0,0 +1,33 @@ +/* + + Name: Paraíso (Dark) + Author: Jan T. Sott + + Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso.tmTheme) + Inspired by the art of Rubens LP (http://www.rubenslp.com.br) + +*/ + +.cm-s-paraiso-dark.CodeMirror {background: #2f1e2e; color: #b9b6b0;} +.cm-s-paraiso-dark div.CodeMirror-selected {background: #41323f !important;} +.cm-s-paraiso-dark .CodeMirror-gutters {background: #2f1e2e; border-right: 0px;} +.cm-s-paraiso-dark .CodeMirror-linenumber {color: #776e71;} +.cm-s-paraiso-dark .CodeMirror-cursor {border-left: 1px solid #8d8687 !important;} + +.cm-s-paraiso-dark span.cm-comment {color: #e96ba8;} +.cm-s-paraiso-dark span.cm-atom {color: #815ba4;} +.cm-s-paraiso-dark span.cm-number {color: #815ba4;} + +.cm-s-paraiso-dark span.cm-property, .cm-s-paraiso-dark span.cm-attribute {color: #48b685;} +.cm-s-paraiso-dark span.cm-keyword {color: #ef6155;} +.cm-s-paraiso-dark span.cm-string {color: #fec418;} + +.cm-s-paraiso-dark span.cm-variable {color: #48b685;} +.cm-s-paraiso-dark span.cm-variable-2 {color: #06b6ef;} +.cm-s-paraiso-dark span.cm-def {color: #f99b15;} +.cm-s-paraiso-dark span.cm-error {background: #ef6155; color: #8d8687;} +.cm-s-paraiso-dark span.cm-bracket {color: #b9b6b0;} +.cm-s-paraiso-dark span.cm-tag {color: #ef6155;} +.cm-s-paraiso-dark span.cm-link {color: #815ba4;} + +.cm-s-paraiso-dark .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} diff --git a/theme/paraiso-light.css b/theme/paraiso-light.css new file mode 100644 index 0000000000..540d58b7d3 --- /dev/null +++ b/theme/paraiso-light.css @@ -0,0 +1,33 @@ +/* + + Name: Paraíso (Light) + Author: Jan T. Sott + + Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso.tmTheme) + Inspired by the art of Rubens LP (http://www.rubenslp.com.br) + +*/ + +.cm-s-paraiso-light.CodeMirror {background: #e7e9db; color: #41323f;} +.cm-s-paraiso-light div.CodeMirror-selected {background: #b9b6b0 !important;} +.cm-s-paraiso-light .CodeMirror-gutters {background: #e7e9db; border-right: 0px;} +.cm-s-paraiso-light .CodeMirror-linenumber {color: #8d8687;} +.cm-s-paraiso-light .CodeMirror-cursor {border-left: 1px solid #776e71 !important;} + +.cm-s-paraiso-light span.cm-comment {color: #e96ba8;} +.cm-s-paraiso-light span.cm-atom {color: #815ba4;} +.cm-s-paraiso-light span.cm-number {color: #815ba4;} + +.cm-s-paraiso-light span.cm-property, .cm-s-paraiso-light span.cm-attribute {color: #48b685;} +.cm-s-paraiso-light span.cm-keyword {color: #ef6155;} +.cm-s-paraiso-light span.cm-string {color: #fec418;} + +.cm-s-paraiso-light span.cm-variable {color: #48b685;} +.cm-s-paraiso-light span.cm-variable-2 {color: #06b6ef;} +.cm-s-paraiso-light span.cm-def {color: #f99b15;} +.cm-s-paraiso-light span.cm-error {background: #ef6155; color: #776e71;} +.cm-s-paraiso-light span.cm-bracket {color: #41323f;} +.cm-s-paraiso-light span.cm-tag {color: #ef6155;} +.cm-s-paraiso-light span.cm-link {color: #815ba4;} + +.cm-s-paraiso-light .CodeMirror-matchingbracket { text-decoration: underline; color: white !important;} From 92c906f82687f22be78df5fd8495a0aeccabf071 Mon Sep 17 00:00:00 2001 From: "Jan T. Sott" Date: Thu, 1 Aug 2013 11:53:01 +0200 Subject: [PATCH 0868/5273] [paraiso theme] Fix url --- theme/paraiso-dark.css | 2 +- theme/paraiso-light.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/theme/paraiso-dark.css b/theme/paraiso-dark.css index 1e457918de..abee9ab860 100644 --- a/theme/paraiso-dark.css +++ b/theme/paraiso-dark.css @@ -3,7 +3,7 @@ Name: Paraíso (Dark) Author: Jan T. Sott - Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso.tmTheme) + Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror) Inspired by the art of Rubens LP (http://www.rubenslp.com.br) */ diff --git a/theme/paraiso-light.css b/theme/paraiso-light.css index 540d58b7d3..e9da474c82 100644 --- a/theme/paraiso-light.css +++ b/theme/paraiso-light.css @@ -3,7 +3,7 @@ Name: Paraíso (Light) Author: Jan T. Sott - Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso.tmTheme) + Color scheme by Jan T. Sott (https://github.com/idleberg/Paraiso-CodeMirror) Inspired by the art of Rubens LP (http://www.rubenslp.com.br) */ From 849035a1541b66a9e3ed50d371d51e8fdbd4ee09 Mon Sep 17 00:00:00 2001 From: Jochen Berger Date: Fri, 2 Aug 2013 15:49:29 +0200 Subject: [PATCH 0869/5273] the mode for "Properties files" should be "properties", not "clike" --- mode/meta.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/meta.js b/mode/meta.js index 8e8c8f5f5c..9c5d986f66 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -46,7 +46,7 @@ CodeMirror.modeInfo = [ {name: 'PHP(HTML)', mime: 'application/x-httpd-php', mode: 'php'}, {name: 'Pig', mime: 'text/x-pig', mode: 'pig'}, {name: 'Plain Text', mime: 'text/plain', mode: 'null'}, - {name: 'Properties files', mime: 'text/x-properties', mode: 'clike'}, + {name: 'Properties files', mime: 'text/x-properties', mode: 'properties'}, {name: 'Python', mime: 'text/x-python', mode: 'python'}, {name: 'Cython', mime: 'text/x-cython', mode: 'python'}, {name: 'R', mime: 'text/x-rsrc', mode: 'r'}, From b86ffff14a7a73b08c905641037ccdef1d25fa79 Mon Sep 17 00:00:00 2001 From: Benjamin DeCoste Date: Fri, 2 Aug 2013 00:57:27 -0300 Subject: [PATCH 0870/5273] [vim mode] Fix visual mode downwards movement bug Previously, if you tried to move further down the document than exist the cursor would not move down. This sets selectionEnd.line to be no greater than the total length of the document. --- keymap/vim.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/keymap/vim.js b/keymap/vim.js index 8db2767a9e..9c9454d6c8 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1104,6 +1104,11 @@ if (vim.visualLine) { if (cursorIsBefore(selectionStart, selectionEnd)) { selectionStart.ch = 0; + + var lastLine = cm.lastLine(); + if (selectionEnd.line > lastLine) { + selectionEnd.line = lastLine; + } selectionEnd.ch = lineLength(cm, selectionEnd.line); } else { selectionEnd.ch = 0; From 455a880611641aeb01e47f0f17999c15318a7af6 Mon Sep 17 00:00:00 2001 From: Hasan Karahan Date: Sat, 3 Aug 2013 21:57:29 +0500 Subject: [PATCH 0871/5273] [rst mode] LaTex/Python inner mode glitches The were some minor issues w.r.t. where exactly an `stex` or `python` inner mode starts and where the outer `rst` mode resumes; fixed. --- mode/rst/rst.js | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/mode/rst/rst.js b/mode/rst/rst.js index 508896d25b..54990bb257 100644 --- a/mode/rst/rst.js +++ b/mode/rst/rst.js @@ -124,9 +124,7 @@ CodeMirror.defineMode('rst-base', function (config) { token = 'keyword'; if (stream.current().match(/^(?:math|latex)/)) { - state.tmp = { - mode: mode_stex, local: mode_stex.startState() - }; + state.tmp_stex = true; } break; case 2: @@ -135,6 +133,12 @@ CodeMirror.defineMode('rst-base', function (config) { token = 'meta'; break; case 3: + if (state.tmp_stex) { + state.tmp_stex = undefined; state.tmp = { + mode: mode_stex, local: mode_stex.startState() + }; + } + if (state.tmp) { if (stream.peek() == '`') { change(state, to_normal, context(rx_role_pre, 4)); @@ -345,24 +349,24 @@ CodeMirror.defineMode('rst-base', function (config) { change(state, to_explicit, context(rx_directive, 2)); assert(stream.match(rx_directive_tail)); token = 'meta'; - break; - default: + if (stream.match(/^latex\s*$/) || state.tmp_stex) { - state.tmp_stex = undefined; - change(state, to_mode, { + state.tmp_stex = undefined; change(state, to_mode, { mode: mode_stex, local: mode_stex.startState() }); - } else if (stream.match(/^python\s*$/) || state.tmp_py) { - state.tmp_py = undefined; - change(state, to_mode, { + } + break; + case 2: + change(state, to_explicit, context(rx_directive, 3)); + if (stream.match(/^python\s*$/) || state.tmp_py) { + state.tmp_py = undefined; change(state, to_mode, { mode: mode_python, local: mode_python.startState() }); } - - else { - change(state, to_normal); - assert(stream.current() == ''); - } + break; + default: + change(state, to_normal); + assert(stream.current() == ''); } } else if (phase(state) == rx_link || stream.match(rx_link, false)) { @@ -441,6 +445,7 @@ CodeMirror.defineMode('rst-base', function (config) { return state.ctx.mode.token(stream, state.ctx.local); } catch (ex) { change(state, to_normal); + console.error (ex); return null; } } From f813f18719f3e6e55794a79fe6411fac4711333b Mon Sep 17 00:00:00 2001 From: Hasan Karahan Date: Sun, 4 Aug 2013 13:22:45 +0500 Subject: [PATCH 0872/5273] [rst mode] Removed unknown bugs catcher --- mode/rst/rst.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/mode/rst/rst.js b/mode/rst/rst.js index 54990bb257..75563ba982 100644 --- a/mode/rst/rst.js +++ b/mode/rst/rst.js @@ -441,13 +441,7 @@ CodeMirror.defineMode('rst-base', function (config) { return null; } - try { - return state.ctx.mode.token(stream, state.ctx.local); - } catch (ex) { - change(state, to_normal); - console.error (ex); - return null; - } + return state.ctx.mode.token(stream, state.ctx.local); } change(state, to_normal); From 29392e85975be5ed5b747966e7bff7949473685c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 5 Aug 2013 13:15:38 +0200 Subject: [PATCH 0873/5273] Prevent onFocus/resetInput from interfering with nested editor --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index ba02ba63c2..fccf66314e 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2118,7 +2118,7 @@ window.CodeMirror = (function() { cm.state.focused = true; if (cm.display.wrapper.className.search(/\bCodeMirror-focused\b/) == -1) cm.display.wrapper.className += " CodeMirror-focused"; - resetInput(cm, true); + if (!cm.curOp) resetInput(cm, true); } slowPoll(cm); restartBlink(cm); From 36409a986e38b7f5665db94c6d7d4f3ecfe1da7f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 5 Aug 2013 13:42:48 +0200 Subject: [PATCH 0874/5273] [brace-fold addon] Use getTokenStyleAt instead of getTokenAt when scanning --- addon/fold/brace-fold.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/fold/brace-fold.js b/addon/fold/brace-fold.js index 0b4d7dc34d..2c76229eb1 100644 --- a/addon/fold/brace-fold.js +++ b/addon/fold/brace-fold.js @@ -12,7 +12,7 @@ CodeMirror.registerHelper("fold", "brace", function(cm, start) { continue; } if (pass == 1 && found < start.ch) break; - tokenType = cm.getTokenAt(CodeMirror.Pos(line, found + 1)).type; + tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)); if (!/^(comment|string)/.test(tokenType)) return found + 1; at = found - 1; } @@ -34,7 +34,7 @@ CodeMirror.registerHelper("fold", "brace", function(cm, start) { if (nextClose < 0) nextClose = text.length; pos = Math.min(nextOpen, nextClose); if (pos == text.length) break; - if (cm.getTokenAt(CodeMirror.Pos(i, pos + 1)).type == tokenType) { + if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) { if (pos == nextOpen) ++count; else if (!--count) { end = i; endCh = pos; break outer; } } From ba21985bfa7c2b8ad6b1ecd564a41b06083d2475 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 5 Aug 2013 13:45:54 +0200 Subject: [PATCH 0875/5273] Use a bigger search range when finding a start-of-parse point in mixed modes --- lib/codemirror.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index fccf66314e..483819e8c2 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -930,8 +930,8 @@ window.CodeMirror = (function() { // smallest indentation, which tends to need the least context to // parse correctly. function findStartLine(cm, n, precise) { - var minindent, minline, doc = cm.doc; - for (var search = n, lim = n - 100; search > lim; --search) { + var minindent, minline, doc = cm.doc, maxScan = cm.doc.mode.innerMode ? 1000 : 100; + for (var search = n, lim = n - maxScan; 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; @@ -946,7 +946,7 @@ window.CodeMirror = (function() { function getStateBefore(cm, n, precise) { var doc = cm.doc, display = cm.display; - if (!doc.mode.startState) return true; + 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); From fd11debd80ddf65fb783fe83a6668e9fc3fa99cc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 5 Aug 2013 14:01:35 +0200 Subject: [PATCH 0876/5273] [brace-fold addon] Fix bad use of lastIndexOf --- addon/fold/brace-fold.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/fold/brace-fold.js b/addon/fold/brace-fold.js index 2c76229eb1..2560b2b94c 100644 --- a/addon/fold/brace-fold.js +++ b/addon/fold/brace-fold.js @@ -4,7 +4,7 @@ CodeMirror.registerHelper("fold", "brace", function(cm, start) { function findOpening(openCh) { for (var at = start.ch, pass = 0;;) { - var found = lineText.lastIndexOf(openCh, at - 1); + var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1); if (found == -1) { if (pass == 1) break; pass = 1; From 0d45af397e9e02670a1b4e925ddd4fcc5d088820 Mon Sep 17 00:00:00 2001 From: Steve O'Hara Date: Sat, 3 Aug 2013 13:50:37 +0100 Subject: [PATCH 0877/5273] [velocity mode] Update * Updated for CodeMirror 3 - added comment clock declarations * Corrected handling of macro calls with a body * Added extra features for detecting variables within strings and methods & properties of objects * Corrected the detection of methods and properties of Java objects --- mode/velocity/index.html | 4 +++ mode/velocity/velocity.js | 66 ++++++++++++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/mode/velocity/index.html b/mode/velocity/index.html index fb59cb590d..96df4c88b8 100644 --- a/mode/velocity/index.html +++ b/mode/velocity/index.html @@ -62,13 +62,17 @@

    CodeMirror: Velocity mode

    $someObject.getValues("this is a string split across lines") +$someObject("This plus $something in the middle").method(7567).property + #macro( tablerows $color $somelist ) #foreach( $something in $somelist ) $something + $bodyContent #end #end #tablerows("red" ["dadsdf","dsa"]) +#@tablerows("red" ["dadsdf","dsa"]) some body content #end Variable reference: #set( $monkey = $bill ) String literal: #set( $monkey.Friend = 'monica' ) diff --git a/mode/velocity/velocity.js b/mode/velocity/velocity.js index 43a97ba676..968d8799e9 100644 --- a/mode/velocity/velocity.js +++ b/mode/velocity/velocity.js @@ -9,7 +9,7 @@ CodeMirror.defineMode("velocity", function() { "#{end} #{else} #{break} #{stop}"); var functions = parseWords("#if #elseif #foreach #set #include #parse #macro #define #evaluate " + "#{if} #{elseif} #{foreach} #{set} #{include} #{parse} #{macro} #{define} #{evaluate}"); - var specials = parseWords("$foreach.count $foreach.hasNext $foreach.first $foreach.last $foreach.topmost $foreach.parent $velocityCount"); + var specials = parseWords("$foreach.count $foreach.hasNext $foreach.first $foreach.last $foreach.topmost $foreach.parent.count $foreach.parent.hasNext $foreach.parent.first $foreach.parent.last $foreach.parent $velocityCount $!bodyContent $bodyContent"); var isOperatorChar = /[+\-*&%=<>!?:\/|]/; function chain(stream, state, f) { @@ -20,30 +20,50 @@ CodeMirror.defineMode("velocity", function() { var beforeParams = state.beforeParams; state.beforeParams = false; var ch = stream.next(); - // start of string? - if ((ch == '"' || ch == "'") && state.inParams) + // start of unparsed string? + if ((ch == "'") && state.inParams) { + state.lastTokenWasBuiltin = false; return chain(stream, state, tokenString(ch)); + } + // start of parsed string? + else if ((ch == '"')) { + state.lastTokenWasBuiltin = false; + if (state.inString) { + state.inString = false; + return "string"; + } + else if (state.inParams) + return chain(stream, state, tokenString(ch)); + } // is it one of the special signs []{}().,;? Seperator? else if (/[\[\]{}\(\),;\.]/.test(ch)) { - if (ch == "(" && beforeParams) state.inParams = true; - else if (ch == ")") state.inParams = false; + if (ch == "(" && beforeParams) + state.inParams = true; + else if (ch == ")") { + state.inParams = false; + state.lastTokenWasBuiltin = true; + } return null; } // start of a number value? else if (/\d/.test(ch)) { + state.lastTokenWasBuiltin = false; stream.eatWhile(/[\w\.]/); return "number"; } // multi line comment? else if (ch == "#" && stream.eat("*")) { + state.lastTokenWasBuiltin = false; return chain(stream, state, tokenComment); } // unparsed content? else if (ch == "#" && stream.match(/ *\[ *\[/)) { + state.lastTokenWasBuiltin = false; return chain(stream, state, tokenUnparsed); } // single line comment? else if (ch == "#" && stream.eat("#")) { + state.lastTokenWasBuiltin = false; stream.skipToEnd(); return "comment"; } @@ -51,33 +71,44 @@ CodeMirror.defineMode("velocity", function() { else if (ch == "$") { stream.eatWhile(/[\w\d\$_\.{}]/); // is it one of the specials? - if (specials && specials.propertyIsEnumerable(stream.current().toLowerCase())) { + if (specials && specials.propertyIsEnumerable(stream.current())) { return "keyword"; } else { + state.lastTokenWasBuiltin = true; state.beforeParams = true; return "builtin"; } } // is it a operator? else if (isOperatorChar.test(ch)) { + state.lastTokenWasBuiltin = false; stream.eatWhile(isOperatorChar); return "operator"; } else { // get the whole word - stream.eatWhile(/[\w\$_{}]/); - var word = stream.current().toLowerCase(); + stream.eatWhile(/[\w\$_{}@]/); + var word = stream.current(); // is it one of the listed keywords? if (keywords && keywords.propertyIsEnumerable(word)) return "keyword"; // is it one of the listed functions? if (functions && functions.propertyIsEnumerable(word) || - stream.current().match(/^#[a-z0-9_]+ *$/i) && stream.peek()=="(") { + (stream.current().match(/^#@?[a-z0-9_]+ *$/i) && stream.peek()=="(") && + !(functions && functions.propertyIsEnumerable(word.toLowerCase()))) { state.beforeParams = true; + state.lastTokenWasBuiltin = false; return "keyword"; } + if (state.inString) { + state.lastTokenWasBuiltin = false; + return "string"; + } + if (stream.pos > word.length && stream.string.charAt(stream.pos-word.length-1)=="." && state.lastTokenWasBuiltin) + return "builtin"; // default: just a "word" + state.lastTokenWasBuiltin = false; return null; } } @@ -86,7 +117,12 @@ CodeMirror.defineMode("velocity", function() { return function(stream, state) { var escaped = false, next, end = false; while ((next = stream.next()) != null) { - if (next == quote && !escaped) { + if ((next == quote) && !escaped) { + end = true; + break; + } + if (quote=='"' && stream.peek() == '$' && !escaped) { + state.inString = true; end = true; break; } @@ -130,14 +166,20 @@ CodeMirror.defineMode("velocity", function() { return { tokenize: tokenBase, beforeParams: false, - inParams: false + inParams: false, + inString: false, + lastTokenWasBuiltin: false }; }, token: function(stream, state) { if (stream.eatSpace()) return null; return state.tokenize(stream, state); - } + }, + blockCommentStart: "#*", + blockCommentEnd: "*#", + lineComment: "##", + fold: "velocity" }; }); From 55583715087cf148be173f1eacd1840ee1a944ec Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 5 Aug 2013 15:28:06 +0200 Subject: [PATCH 0878/5273] (Mostly) handle cursor positioning around multiple bookmarks in same position Closes #1726 --- lib/codemirror.js | 10 ++++++---- test/test.js | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 483819e8c2..cead3e409b 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4415,11 +4415,13 @@ window.CodeMirror = (function() { if (size) { builder.measure[builder.pos] = widget; } else { - var elt = builder.measure[builder.pos] = zeroWidthElement(builder.cm.display.measure); - if (marker.type != "bookmark" || marker.insertLeft) - builder.pre.insertBefore(elt, widget); + var elt = zeroWidthElement(builder.cm.display.measure); + if (marker.type == "bookmark" && !marker.insertLeft) + builder.measure[builder.pos] = builder.pre.appendChild(elt); + else if (builder.measure[builder.pos]) + return; else - builder.pre.appendChild(elt); + builder.measure[builder.pos] = builder.pre.insertBefore(elt, widget); } builder.measuredSomething = true; } diff --git a/test/test.js b/test/test.js index 69897648dc..57777f86f9 100644 --- a/test/test.js +++ b/test/test.js @@ -517,6 +517,23 @@ testCM("bookmarkCursor", function(cm) { is(cm.cursorCoords(Pos(4, 1)).left > pos41.left, "single-char bug"); }, {value: "foo\nbar\n\n\nx\ny"}); +testCM("multiBookmarkCursor", function(cm) { + var ms = [], m; + function add(insertLeft) { + for (var i = 0; i < 3; ++i) { + var node = document.createElement("span"); + node.innerHTML = "X"; + ms.push(cm.setBookmark(Pos(0, 1), {widget: node, insertLeft: insertLeft})); + } + } + var base1 = cm.cursorCoords(Pos(0, 1)).left, base4 = cm.cursorCoords(Pos(0, 4)).left; + add(true); + eq(base1, cm.cursorCoords(Pos(0, 1)).left); + while (m = ms.pop()) m.clear(); + add(false); + eq(base4, cm.cursorCoords(Pos(0, 1)).left); +}, {value: "abcdefg"}); + testCM("getAllMarks", function(cm) { addDoc(cm, 10, 10); var m1 = cm.setBookmark(Pos(0, 2)); From 84d12b21be4033fb09145759ce0c7e4be12e7f9f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 5 Aug 2013 15:31:42 +0200 Subject: [PATCH 0879/5273] Disable another test on Phantom (Works in real browsers.) --- test/test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test.js b/test/test.js index 57777f86f9..1c37b4dfe1 100644 --- a/test/test.js +++ b/test/test.js @@ -518,6 +518,7 @@ testCM("bookmarkCursor", function(cm) { }, {value: "foo\nbar\n\n\nx\ny"}); testCM("multiBookmarkCursor", function(cm) { + if (phantom) return; var ms = [], m; function add(insertLeft) { for (var i = 0; i < 3; ++i) { From 5804a9322cdb68be041ffc7a515e982cf7a63bc8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 8 Aug 2013 10:15:05 +0200 Subject: [PATCH 0880/5273] Re-reset the input right after a focus event It seems recent versions of Chrome/Blink fire the handler first, and then clear the selection. Issue #1730 --- lib/codemirror.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index cead3e409b..75882a4416 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2118,7 +2118,10 @@ window.CodeMirror = (function() { cm.state.focused = true; if (cm.display.wrapper.className.search(/\bCodeMirror-focused\b/) == -1) cm.display.wrapper.className += " CodeMirror-focused"; - if (!cm.curOp) resetInput(cm, true); + if (!cm.curOp) { + resetInput(cm, true); + if (webkit) setTimeout(bind(resetInput, cm, true), 0); // Issue #1730 + } } slowPoll(cm); restartBlink(cm); From 7f82421f694e680fda16c05bfbd9c061382949ba Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Wed, 7 Aug 2013 20:47:05 +0400 Subject: [PATCH 0881/5273] [xml mode] Fix value-less attributes Issue #902 --- mode/xml/xml.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/xml/xml.js b/mode/xml/xml.js index 84f34a2934..53285c848c 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -261,7 +261,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { function attribute(type) { if (type == "equals") return cont(attvalue, attributes); if (!Kludges.allowMissing) setStyle = "error"; - else if (type == "word") setStyle = "attribute"; + else if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);} return (type == "endTag" || type == "selfcloseTag") ? pass() : cont(); } function attvalue(type) { From 4e061c0b09871d4c3df9b14cae54a00e5286171a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 9 Aug 2013 12:40:36 +0200 Subject: [PATCH 0882/5273] Clear measure div after line measurement To prevent a lot of DOM nodes from sticking around after measuring a long line, easing the pressure on the GC. --- lib/codemirror.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 75882a4416..7946092ea1 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1096,6 +1096,7 @@ window.CodeMirror = (function() { if (cur.measureRight) rect.right = getRect(cur.measureRight).left; if (cur.leftSide) rect.leftSide = measureRect(getRect(cur.leftSide)); } + removeChildren(cm.display.measure); for (var i = 0, cur; i < data.length; ++i) if (cur = data[i]) { finishRect(cur); if (cur.leftSide) finishRect(cur.leftSide); From d64948850d2abcf9ca1e51d712ed658ae5b12218 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 9 Aug 2013 12:49:38 +0200 Subject: [PATCH 0883/5273] [continuecomment addon] Move to addon/comment (from addon/edit) --- addon/{edit => comment}/continuecomment.js | 0 doc/compress.html | 4 ++-- doc/manual.html | 2 +- mode/javascript/index.html | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename addon/{edit => comment}/continuecomment.js (100%) diff --git a/addon/edit/continuecomment.js b/addon/comment/continuecomment.js similarity index 100% rename from addon/edit/continuecomment.js rename to addon/comment/continuecomment.js diff --git a/doc/compress.html b/doc/compress.html index 864f4f28cd..e2d79f581d 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -148,8 +148,8 @@

    { } CodeMi - - + + diff --git a/doc/manual.html b/doc/manual.html index dc4100f70b..532285163c 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2060,7 +2060,7 @@

    Addons

    editor instance to refresh its mode when the loading succeeded. See the
    demo. -
    edit/continuecomment.js
    +
    comment/continuecomment.js
    Adds an continueComments option, which can be set to true to have the editor prefix new lines inside C-like block comments with an asterisk when Enter is pressed. It can diff --git a/mode/javascript/index.html b/mode/javascript/index.html index db063b772d..0db35219b9 100644 --- a/mode/javascript/index.html +++ b/mode/javascript/index.html @@ -6,7 +6,7 @@ - + From 57036ab839b159632cc13404e547114f17aba415 Mon Sep 17 00:00:00 2001 From: Chris Coyier Date: Fri, 9 Aug 2013 18:10:46 -0500 Subject: [PATCH 0884/5273] "grey" is an accepted named color value (same as "gray") --- 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 bdcd500868..c393cedff5 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -432,7 +432,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", - "gold", "goldenrod", "gray", "green", "greenyellow", "honeydew", + "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink", From 3f5c8432b6080e22da5ded416c4e4d7a0f4ff341 Mon Sep 17 00:00:00 2001 From: Maksym Taran Date: Sun, 11 Aug 2013 15:20:05 -0700 Subject: [PATCH 0885/5273] Python function/class definition highlighting. --- mode/python/python.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/mode/python/python.js b/mode/python/python.js index 4fe4d28912..28108e4c1a 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -151,6 +151,9 @@ CodeMirror.defineMode("python", function(conf, parserConf) { } if (stream.match(identifiers)) { + if (state.lastToken == 'def' || state.lastToken == 'class') { + return 'def'; + } return 'variable'; } @@ -258,7 +261,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) { // Handle '.' connected identifiers if (current === '.') { style = stream.match(identifiers, false) ? null : ERRORCLASS; - if (style === null && state.lastToken === 'meta') { + if (style === null && state.lastStyle === 'meta') { // Apply 'meta' style to '.' connected identifiers when // appropriate. style = 'meta'; @@ -272,7 +275,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) { } if ((style === 'variable' || style === 'builtin') - && state.lastToken === 'meta') { + && state.lastStyle === 'meta') { style = 'meta'; } @@ -313,6 +316,7 @@ CodeMirror.defineMode("python", function(conf, parserConf) { return { tokenize: tokenBase, scopes: [{offset:basecolumn || 0, type:'py'}], + lastStyle: null, lastToken: null, lambda: false, dedent: 0 @@ -322,12 +326,16 @@ CodeMirror.defineMode("python", function(conf, parserConf) { token: function(stream, state) { var style = tokenLexer(stream, state); - state.lastToken = style; + state.lastStyle = style; + + var current = stream.current(); + if (current && style) { + state.lastToken = current; + } if (stream.eol() && state.lambda) { state.lambda = false; } - return style; }, From b8a38503a24d143b975603c1509b9340ae9abbf2 Mon Sep 17 00:00:00 2001 From: mats cronqvist Date: Sun, 11 Aug 2013 19:41:13 +0200 Subject: [PATCH 0886/5273] erlang mode bug fixes --- mode/erlang/erlang.js | 56 ++++++++++++++++++++++-------------------- mode/erlang/index.html | 2 +- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/mode/erlang/erlang.js b/mode/erlang/erlang.js index 79e0434d1f..f6e304c93a 100644 --- a/mode/erlang/erlang.js +++ b/mode/erlang/erlang.js @@ -11,18 +11,10 @@ CodeMirror.defineMIME("text/x-erlang", "erlang"); CodeMirror.defineMode("erlang", function(cmCfg) { - function rval(state,stream,type) { + function rval(state,_stream,type) { // distinguish between "." as terminator and record field operator - if (type == "record") { - state.context = "record"; - }else{ - state.context = false; - } + state.in_record = (type == "record"); - // remember last significant bit on last line for indenting - if (type != "whitespace" && type != "comment") { - state.lastToken = stream.current(); - } // erlang -> CodeMirror tag switch (type) { case "atom": return "atom"; @@ -133,6 +125,19 @@ CodeMirror.defineMode("erlang", function(cmCfg) { } function tokenize(stream, state) { + // in multi-line string + if (state.in_string) { + state.in_string = (!doubleQuote(stream)); + return rval(state,stream,"string"); + } + + // in multi-line atom + if (state.in_atom) { + state.in_atom = (!singleQuote(stream)); + return rval(state,stream,"atom"); + } + + // whitespace if (stream.eatSpace()) { return rval(state,stream,"whitespace"); } @@ -183,20 +188,14 @@ CodeMirror.defineMode("erlang", function(cmCfg) { // quoted atom if (ch == '\'') { - if (singleQuote(stream)) { - return rval(state,stream,"atom"); - }else{ - return rval(state,stream,"error"); - } + state.in_atom = (!singleQuote(stream)); + return rval(state,stream,"atom"); } // string if (ch == '"') { - if (doubleQuote(stream)) { - return rval(state,stream,"string"); - }else{ - return rval(state,stream,"error"); - } + state.in_string = (!doubleQuote(stream)); + return rval(state,stream,"string"); } // variable @@ -282,7 +281,7 @@ CodeMirror.defineMode("erlang", function(cmCfg) { // separators if (greedy(stream,sepRE,separatorWords)) { // distinguish between "." as terminator and record field operator - if (state.context == false) { + if (!state.in_record) { pushToken(state,stream); } return rval(state,stream,"separator"); @@ -359,15 +358,19 @@ CodeMirror.defineMode("erlang", function(cmCfg) { var token = (peekToken(state)).token; var wordAfter = takewhile(textAfter,/[^a-z]/); - if (isMember(token,openParenWords)) { - return (peekToken(state)).column+token.length; - }else if (token == "." || token == ""){ + if (state.in_string || state.in_atom) { return 0; + }else if (token == "." || token == "") { + return 0; + }else if (isMember(token,openParenWords)) { + return (peekToken(state)).column+token.length; }else if (token == "->") { if (wordAfter == "end") { return peekToken(state,2).column; }else if (peekToken(state,2).token == "fun") { return peekToken(state,2).column+indent; + }else if (peekToken(state,2).token == ".") { + return indent; }else{ return (peekToken(state)).indent+indent; } @@ -445,8 +448,9 @@ CodeMirror.defineMode("erlang", function(cmCfg) { startState: function() { return {tokenStack: [], - context: false, - lastToken: null}; + in_record: false, + in_string: false, + in_atom: false}; }, token: diff --git a/mode/erlang/index.html b/mode/erlang/index.html index fd21521c88..5bb81f669a 100644 --- a/mode/erlang/index.html +++ b/mode/erlang/index.html @@ -32,7 +32,7 @@

    CodeMirror: Erlang mode

    rec_info(demo) -> record_info(fields,demo). demo() -> expand_recs(?MODULE,#demo{a="A",b="BB"}). - + expand_recs(M,List) when is_list(List) -> [expand_recs(M,L)||L<-List]; expand_recs(M,Tup) when is_tuple(Tup) -> From 8a55c04f984e9a7ee0091eb1bbe277657357485a Mon Sep 17 00:00:00 2001 From: Chandra Sekhar Pydi Date: Fri, 9 Aug 2013 11:32:58 -0700 Subject: [PATCH 0887/5273] Configurable delay between selection of a word to highlighting of word. current delay of 100ms between selection of word to highlighting is almost instantaneous. --- addon/search/match-highlighter.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addon/search/match-highlighter.js b/addon/search/match-highlighter.js index 3df6985984..e5cbeacab2 100644 --- a/addon/search/match-highlighter.js +++ b/addon/search/match-highlighter.js @@ -15,15 +15,18 @@ (function() { var DEFAULT_MIN_CHARS = 2; var DEFAULT_TOKEN_STYLE = "matchhighlight"; + var DEFAULT_DELAY = 100; function State(options) { if (typeof options == "object") { this.minChars = options.minChars; this.style = options.style; this.showToken = options.showToken; + this.delay = options.delay; } if (this.style == null) this.style = DEFAULT_TOKEN_STYLE; if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS; + if (this.delay == null) this.delay = DEFAULT_DELAY; this.overlay = this.timeout = null; } @@ -45,7 +48,7 @@ function cursorActivity(cm) { var state = cm.state.matchHighlighter; clearTimeout(state.timeout); - state.timeout = setTimeout(function() {highlightMatches(cm);}, 100); + state.timeout = setTimeout(function() {highlightMatches(cm);}, state.delay); } function highlightMatches(cm) { From 1f27f945e646e08b2ca6fb53c07d2e6f9e45e764 Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Fri, 12 Jul 2013 13:51:19 +0200 Subject: [PATCH 0888/5273] Fix linenumbers when undoing multiple changes --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 7946092ea1..e5137c6219 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -461,7 +461,7 @@ window.CodeMirror = (function() { var positionsChangedFrom = Infinity; if (cm.options.lineNumbers) for (var i = 0; i < changes.length; ++i) - if (changes[i].diff) { positionsChangedFrom = changes[i].from; break; } + if (changes[i].diff && changes[i].from < positionsChangedFrom) { positionsChangedFrom = changes[i].from; } var end = doc.first + doc.size; var from = Math.max(visible.from - cm.options.viewportMargin, doc.first); From 0252410f301ed01603e6ace8e5bc0b728f0fefcc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 12 Aug 2013 11:49:15 +0200 Subject: [PATCH 0889/5273] Fix bug in handling of Esc key in IE --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index e5137c6219..4e610ee64b 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2081,8 +2081,8 @@ window.CodeMirror = (function() { function onKeyDown(e) { var cm = this; if (!cm.state.focused) onFocus(cm); - if (ie && e.keyCode == 27) { e.returnValue = false; } if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; + if (ie && e.keyCode == 27) e.returnValue = false; var code = e.keyCode; // IE does strange things with escape. cm.doc.sel.shift = code == 16 || e.shiftKey; From 015b2e6399c1da1f0481f372313014e5bba74c38 Mon Sep 17 00:00:00 2001 From: Ingo Richter Date: Mon, 12 Aug 2013 18:16:52 -0700 Subject: [PATCH 0890/5273] [css mode] Add properties for CSS regions --- mode/css/css.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index c393cedff5..c6d34a3a97 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -366,9 +366,9 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "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", "font", "font-feature-settings", "font-family", - "font-kerning", "font-language-override", "font-size", "font-size-adjust", - "font-stretch", "font-style", "font-synthesis", "font-variant", + "float", "float-offset", "flow-into", "flow-from", "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-cell", "grid-column", "grid-column-align", @@ -393,8 +393,8 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "perspective-origin", "pitch", "pitch-range", "play-during", "position", "presentation-level", "punctuation-trim", "quotes", "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness", "right", - "rotation", "rotation-point", "ruby-align", "ruby-overhang", - "ruby-position", "ruby-span", "size", "speak", "speak-as", "speak-header", + "rotation", "rotation-point", "ruby-align", "ruby-overhang", "ruby-position", + "ruby-span", "shape-inside", "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", @@ -504,8 +504,8 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", - "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", - "outside", "overlay", "overline", "padding", "padding-box", "painted", + "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", "outside", + "outside-shape", "overlay", "overline", "padding", "padding-box", "painted", "paused", "persian", "plus-darker", "plus-lighter", "pointer", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button", "radio", "read-only", "read-write", "read-write-plaintext-only", "relative", From 12a25eaf34f9dc7cf0fd6f6663ad1160408c7e4f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 13 Aug 2013 18:34:34 +0200 Subject: [PATCH 0891/5273] Move to a new website layout --- demo/activeline.html | 41 +- demo/anywordhint.html | 44 +- demo/bidi.html | 41 +- demo/btree.html | 45 +- demo/buffers.html | 43 +- demo/changemode.html | 41 +- demo/closebrackets.html | 54 +-- demo/closetag.html | 55 ++- demo/complete.html | 52 +- demo/emacs.html | 53 ++- demo/folding.html | 54 ++- demo/fullscreen.html | 41 +- demo/html5complete.html | 56 ++- demo/indentwrap.html | 41 +- demo/lint.html | 51 +- demo/loadmode.html | 39 +- demo/marker.html | 41 +- demo/markselection.html | 41 +- demo/matchhighlighter.html | 41 +- demo/matchtags.html | 45 +- demo/merge.html | 41 +- demo/multiplex.html | 41 +- demo/mustache.html | 43 +- demo/placeholder.html | 39 +- demo/preview.html | 46 +- demo/resize.html | 39 +- demo/runmode.html | 40 +- demo/search.html | 47 +- demo/spanaffectswrapping_shim.html | 32 +- demo/tern.html | 76 +-- demo/theme.html | 89 ++-- demo/trailingspace.html | 39 +- demo/variableheight.html | 45 +- demo/vim.html | 47 +- demo/visibletabs.html | 39 +- demo/widget.html | 41 +- demo/xmlcomplete.html | 46 +- doc/activebookmark.js | 42 ++ doc/baboon.png | Bin 23299 -> 0 bytes doc/baboon_vector.svg | 153 ------ doc/compress.html | 38 +- doc/docs.css | 274 ++++++----- doc/internals.html | 108 +++-- doc/logo.png | Bin 0 -> 12003 bytes doc/logo.svg | 147 ++++++ doc/manual.html | 158 +++--- doc/modes.html | 100 ---- doc/realworld.html | 37 +- doc/{oldrelease.html => releases.html} | 350 +++++++++++--- doc/reporting.html | 41 +- doc/upgrade_v2.2.html | 48 +- doc/upgrade_v3.html | 135 +++--- index.html | 634 +++++++------------------ mode/apl/index.html | 41 +- mode/asterisk/index.html | 42 +- mode/clike/index.html | 41 +- mode/clike/scala.html | 54 +-- mode/clojure/index.html | 42 +- mode/cobol/index.html | 85 ++-- mode/coffeescript/index.html | 42 +- mode/commonlisp/index.html | 42 +- mode/css/index.html | 42 +- mode/css/scss.html | 42 +- mode/d/index.html | 41 +- mode/diff/index.html | 42 +- mode/ecl/index.html | 43 +- mode/erlang/index.html | 43 +- mode/gas/index.html | 43 +- mode/gfm/index.html | 56 ++- mode/go/index.html | 43 +- mode/groovy/index.html | 41 +- mode/haml/index.html | 50 +- mode/haskell/index.html | 43 +- mode/haxe/index.html | 41 +- mode/htmlembedded/index.html | 47 +- mode/htmlmixed/index.html | 50 +- mode/http/index.html | 41 +- mode/index.html | 106 +++++ mode/jade/index.html | 42 +- mode/javascript/index.html | 47 +- mode/javascript/typescript.html | 41 +- mode/jinja2/index.html | 42 +- mode/less/index.html | 46 +- mode/livescript/index.html | 43 +- mode/lua/index.html | 46 +- mode/markdown/index.html | 46 +- mode/mirc/index.html | 44 +- mode/nginx/index.html | 40 +- mode/ntriples/index.html | 42 +- mode/ocaml/index.html | 29 +- mode/pascal/index.html | 41 +- mode/perl/index.html | 41 +- mode/php/index.html | 51 +- mode/pig/index.html | 37 +- mode/properties/index.html | 42 +- mode/python/index.html | 44 +- mode/q/index.html | 43 +- mode/r/index.html | 42 +- mode/rpm/changes/index.html | 34 +- mode/rpm/spec/index.html | 33 +- mode/rst/index.html | 40 +- mode/ruby/index.html | 44 +- mode/rust/index.html | 41 +- mode/sass/index.html | 44 +- mode/scheme/index.html | 42 +- mode/shell/index.html | 29 +- mode/sieve/index.html | 42 +- mode/smalltalk/index.html | 41 +- mode/smarty/index.html | 44 +- mode/smartymixed/index.html | 51 +- mode/sparql/index.html | 44 +- mode/sql/index.html | 57 +-- mode/stex/index.html | 42 +- mode/tcl/index.html | 44 +- mode/tiddlywiki/index.html | 45 +- mode/tiki/index.html | 44 +- mode/turtle/index.html | 42 +- mode/vb/index.html | 49 +- mode/vbscript/index.html | 42 +- mode/velocity/index.html | 44 +- mode/verilog/index.html | 39 +- mode/xml/index.html | 42 +- mode/xquery/index.html | 71 ++- mode/yaml/index.html | 42 +- mode/z80/index.html | 41 +- test/index.html | 105 ++-- 126 files changed, 4225 insertions(+), 3079 deletions(-) create mode 100644 doc/activebookmark.js delete mode 100644 doc/baboon.png delete mode 100644 doc/baboon_vector.svg create mode 100644 doc/logo.png create mode 100644 doc/logo.svg delete mode 100644 doc/modes.html rename doc/{oldrelease.html => releases.html} (70%) create mode 100644 mode/index.html diff --git a/demo/activeline.html b/demo/activeline.html index b0ea9b9070..a9b000e65b 100644 --- a/demo/activeline.html +++ b/demo/activeline.html @@ -1,23 +1,33 @@ - - - - CodeMirror: Active Line Demo - - - - - - - - -

    CodeMirror: Active Line Demo

    + -
    +
    +

    B-Tree visualization

    +

    @@ -83,5 +83,4 @@

    CodeMirror: B-Tree visualization

    - - + diff --git a/demo/buffers.html b/demo/buffers.html index bfd8248e43..951209cad5 100644 --- a/demo/buffers.html +++ b/demo/buffers.html @@ -1,20 +1,32 @@ - - - - CodeMirror: Multiple Buffer & Split View Demo - - - - - - - - - -

    CodeMirror: Multiple Buffer & Split View Demo

    + + +
    +

    Multiple Buffer & Split View Demo

    +
    @@ -94,5 +106,4 @@

    CodeMirror: Multiple Buffer & Split View Demo

    using swapDoc to use a single editor to display multiple documents.

    - - +
    diff --git a/demo/changemode.html b/demo/changemode.html index 364c5cdb07..61c1786074 100644 --- a/demo/changemode.html +++ b/demo/changemode.html @@ -1,22 +1,32 @@ - - - - CodeMirror: Mode-Changing Demo - - - - - - - - -

    CodeMirror: Mode-Changing demo

    + -
    +
    +

    Close-Tag Demo

    +
    - - +
    diff --git a/demo/complete.html b/demo/complete.html index 1a65f6e0d9..56999b9cc9 100644 --- a/demo/complete.html +++ b/demo/complete.html @@ -1,20 +1,31 @@ - - - - CodeMirror: Autocomplete Demo - - - - - - - - - -

    CodeMirror: Autocomplete demo

    -
    -

    Press ctrl-space to activate autocompletion. See -the code (here -and here) to figure out -how it works.

    +

    Press ctrl-space to activate autocompletion. Built +on top of the show-hint +and javascript-hint +addons.

    - - + diff --git a/demo/emacs.html b/demo/emacs.html index 0a8cfc5d99..5b622a9992 100644 --- a/demo/emacs.html +++ b/demo/emacs.html @@ -1,28 +1,38 @@ - - - - CodeMirror: Emacs bindings demo - - - - - - - - - - - - - - -

    CodeMirror: Emacs bindings demo

    + -
    HTML:
    @@ -81,5 +86,4 @@

    CodeMirror: Code Folding Demo

    editor_html.foldCode(CodeMirror.Pos(1, 0)); }; - - + diff --git a/demo/fullscreen.html b/demo/fullscreen.html index 2709ebb4b5..8cf8005bdb 100644 --- a/demo/fullscreen.html +++ b/demo/fullscreen.html @@ -1,15 +1,14 @@ - - - - CodeMirror: Full Screen Editing - - - - - - - - -

    CodeMirror: Full Screen Editing

    + -
    @@ -32,5 +42,4 @@

    CodeMirror: Mark Selection Demo

    Simple addon to easily mark (and style) selected text.

    - - + diff --git a/demo/matchhighlighter.html b/demo/matchhighlighter.html index 9d2fdd098a..170213bfc5 100644 --- a/demo/matchhighlighter.html +++ b/demo/matchhighlighter.html @@ -1,15 +1,14 @@ - - - - CodeMirror: Match Highlighter Demo - - - - - - - - -

    CodeMirror: Match Highlighter Demo

    + -
    @@ -34,5 +44,4 @@

    CodeMirror: Match Highlighter Demo

    Search and highlight occurences of the selected text.

    - - + diff --git a/demo/matchtags.html b/demo/matchtags.html index 8f4217debe..40ee8c0b7e 100644 --- a/demo/matchtags.html +++ b/demo/matchtags.html @@ -1,22 +1,34 @@ - - - - CodeMirror: Tag Matcher Demo - - - - - - - - - - -

    CodeMirror: Tag Matcher Demo

    + + +
    +

    Tag Matcher Demo

    +
    @@ -34,5 +46,4 @@

    CodeMirror: Tag Matcher Demo

    Put the cursor on or inside a pair of tags to highlight them. Press Ctrl-J to jump to the tag that matches the one under the cursor.

    - - +
    diff --git a/demo/merge.html b/demo/merge.html index 907f769d57..d3c8eb03cc 100644 --- a/demo/merge.html +++ b/demo/merge.html @@ -1,15 +1,16 @@ - - - - - - - - - - CodeMirror: merge view demo - - + + +
    +

    merge view demo

    -

    CodeMirror: merge view demo

    @@ -61,3 +75,4 @@

    CodeMirror: merge view demo

    initUI(2); }; +
    diff --git a/demo/multiplex.html b/demo/multiplex.html index ec0519cb98..2ad9608a82 100644 --- a/demo/multiplex.html +++ b/demo/multiplex.html @@ -1,23 +1,33 @@ - - - - CodeMirror: Multiplexing Parser Demo - - - - - - - - -

    CodeMirror: Multiplexing Parser Demo

    + -
    +
    +

    Placeholder demo

    +

    The placeholder plug-in adds an option placeholder that can be set to @@ -32,5 +42,4 @@

    CodeMirror: Placeholder demo

    }); - - +
    diff --git a/demo/preview.html b/demo/preview.html index f70cdb009a..ccf9122e9b 100644 --- a/demo/preview.html +++ b/demo/preview.html @@ -1,16 +1,16 @@ - - - - CodeMirror: HTML5 preview - - - - - - - - - - -

    CodeMirror: HTML5 preview

    + + +
    +

    HTML5 preview

    + @@ -35,5 +45,4 @@

    CodeMirror: Trailing Whitespace Demo

    the trailingspace addon to highlight trailing whitespace.

    - - +
    diff --git a/demo/variableheight.html b/demo/variableheight.html index b00f7e4542..1ef8fc445d 100644 --- a/demo/variableheight.html +++ b/demo/variableheight.html @@ -1,24 +1,34 @@ - - - - CodeMirror: Variable Height Demo - - - - - - - - - -

    CodeMirror: Variable Height Demo

    - -

    Press ctrl-space, or type a '<' character to @@ -102,5 +113,4 @@

    CodeMirror: XML Autocomplete demo

    } }); - - + diff --git a/doc/activebookmark.js b/doc/activebookmark.js new file mode 100644 index 0000000000..69a126e8ce --- /dev/null +++ b/doc/activebookmark.js @@ -0,0 +1,42 @@ +(function() { + var pending = false, prevVal = null; + + function updateSoon() { + if (!pending) { + pending = true; + setTimeout(update, 250); + } + } + + function update() { + pending = false; + var marks = document.getElementById("nav").getElementsByTagName("a"), found; + for (var i = 0; i < marks.length; ++i) { + var mark = marks[i], m; + if (mark.getAttribute("data-default")) { + if (found == null) found = i; + } else if (m = mark.href.match(/#(.*)/)) { + var ref = document.getElementById(m[1]); + if (ref && ref.getBoundingClientRect().top < 50) + found = i; + } + } + if (found != null && found != prevVal) { + prevVal = found; + var lis = document.getElementById("nav").getElementsByTagName("li"); + for (var i = 0; i < lis.length; ++i) lis[i].className = ""; + for (var i = 0; i < marks.length; ++i) { + if (found == i) { + marks[i].className = "active"; + for (var n = marks[i]; n; n = n.parentNode) + if (n.nodeName == "LI") n.className = "active"; + } else { + marks[i].className = ""; + } + } + } + } + + window.addEventListener("scroll", updateSoon); + window.addEventListener("load", updateSoon); +})(); diff --git a/doc/baboon.png b/doc/baboon.png deleted file mode 100644 index 55d97f70b817ff2b78ebb409bf34a5147fe40d07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23299 zcmXtA2RM~|*nf^qWM`JWx9se!jBH8STe3ywi4vlWP|C$=|2+k1}Z{KtL&)_oF8uIf@zuu>ohLUlz?%M3wK;qdQRG7|WEstIZd{y`L| zdBuVZenpVE#KZ5&{q(K}A_$=c{x4Jtp~C?DN0uOM>mYMqx1bQm09Pa=Bt+cP=T@Mz zqo1p|Z-D!Yb!Aor;Y6-zX;_55T+IoIV6Yth6df`|pO&Jo_lj4Y`xQxw`h63kq1gdQ2wV+9`BOW&{MU9$qEjO0G3}ueiaHZu{OP#N93A zj(hr--M@--A-;+i12@JmElh@s^Kc6?Ka}c5EC_LD^53!yzKpLNvkN39CVucnp|=A4 zQnDM1`awivv9(bXJxWAFh8d6X$|f*LYK@7BDYx)&?q?1pqM^ulOt`Nxm4B`79;*@R z$SXFC0e&T!aV4oZe<4&SRF++~At%Q17J4DywdM~P^*fl$&f;7VQ?2dC*aJbqvBUt^ zRTk$qg!NUqX%!*5rzBe_ySGB!^|i~lxw}Z!Q$1dU5zP~@T%7N4YxU>Y#qJ|i5YhKi zE!N)BC(rLocVpuPjeWF*&m>j9MVv4!yFSPf6>qb*c`*ZnOLrwag(z~+t#b2fB(Em% z`t8}L*hC8#W@p+^rLbren$Y-M*O-Wfu#4k+GASE=ohI|ZX_fDR z)I4#%h{DX|d2CTLGlO%LN$I=NY6<_oplt;PllQ%E zFXlG6FY8$!k#~=IBA@Cswd(mq?KL_o-z8SNCq0O{xL%F3QXAu|yEUp~VZopjw1}Sn z`l2xE_@KnDRq5r+PHN^$!OJeaV@SU=(y(;YOUw`l zx;;U#Pye5Y;21*>tYFFm-bM&|RG$cmm%2l4oP0`-EX0@SkxVc! zh{jx}V|ysIqn!H~=lZYxl9Cd)s3_%mr6BcR|J@#_^)&xcYEG)Es%lc&dG~Q*Vxr&L zPuZit{b~(<(*)vnE%6^dXnx7L#Pn}@_~NsLZ#kDr%s&-nO>1-il+aJrCvjf2MNaRz zP79SAT|g=h7l;&g`;D&4nwij`@u&F=sU#gn9qAY`NqmCCIkfEjyyY=kd7f3?C+TP1 zt&e?uXRs$M(q~&%kS1qGjd zD5;hhcbg=~2>L~ZhTIUGU0;99WFJ9GNJ6O|6eJT98%umR@^@=1<=L~6|NF3P@;>#508_2O(1z5!-ShcT%XXO zIS@m>0)YUL!hDP_3x1_ZBndEnNN`03y1iX3?BDVOyVkH*mSt9(J3DbTH5aQ4=9h=d z6z;4ti{EU>zql;#J1O(4f zPq;Thl>g+Wk_G1vWSK5?;432q#SRext z$4{R~b8~a~|1vN#a&d8?9-civctu}7vCcx~ik=>sRh3=xowc7C`#x}>7AISqOIL&E za=(b&9XUkRW|}{t_@K-kX79ttz;GXfh$51d=;`UV#0r-#%{*YT!<1FECAxjheswiR zsl@!vS!HEq!}-3Ro{nngPeF0VW7W=|zkSQJQL$roRvI-53sV{#8hT|_HjTrfpQxQM zUv&R=zi?(~xJ=#$tA2d&&xmoKmG*W`<;am_w-=&7!q(Dg=@)?9r%4@1U?nCF@1RvD z;+5W>oSckLOw@#3WR>;0|L&cnjK_E6+qc)(22~>VOniSt&3|EGVC-psswgAFkQaTT zc(A)s6(}+{KhLeAa^BO^Q_sKvUv`3)2nh-I6TKJNYFxAjK7z$8E3`sVt@h51r z1BsyUNi&p*ii(O)O453CPV9S$DUb5$(O-}6Xtm7o;j(N0k`6OOJ{YeB1_j-Roel^L zOwGwjhFcnF!K4lASsk$-&=$Onpx;`SabLVRG&Z^t@A0mvH=&3(qRSq4_KxYhm!e3A z)>E!}ZVHOm4#-cGLT8pqu~`S4a;P^RBjqf1q0_{*w?@yNoWyB9Q0tH(oEosLrG&1WC^ zk8y5xmWE?|e7x4Z|H1*(qtaWWl@`VNjOlZ%X(c6sHjM#%b8~ZlM%)v>d@=l4?M#|{ zK_weLGQSP=<-vMidtpIANt*?z?cT!CT!=e&Oa-yJGeTX|K$`e8)dI1c4XsQRAJO{Dy&rT~eOv^uS-K)qe<4%mHU01_|Mc72dyp|2tIF9xE3&x51(->7oaYVSm5MQ)Nc(Z@IR$T>hL% z{VZ_Eb?ly0`QjFWE)&bE_`mnNNoJRx{9H;0ic%4ug2LGEvjt|Qi>uYmC>4X%Hp!Jo&IMat>E_W6$k1F3Ljjdn1zJ?UTD9&fatwi(`CUtfQ{ z)tM@GLG(MJdfRzsOfPReN+AP#I)b#3rigOd3!?*(JNM3zT|3a7CKgnqNYvvrK1Hnl z%JvRcKFScemOUW^RnG&K&P4*&#WXau;ri(B#YMe@goLm;XnDOBxi?(a9#T*uCJv{Rq$+#Jp6AwSx#L1 z@oF-U?&B2wV(FDIySsCYt?yqOKL3#Q=|%ZJ^~MEj7g8N#+I?O|xm-50&Xc(%j+^n< zC*y)PCRGOMSXqUexWYn1P5k|(#(A7SJ(g{bUHe&QaP8Z{zm@&LdY)U#hPc~E*Bu9M zhSY281b#I-Z01EriR)wn+)ae&5RsL($itxM_PyVaB6|8#Uc7kp@+JGgzIVr)yr|v~ zB*Aq4TTaTu@54y0gbYY`D-k>sbA3*6 zQy~TJL~li$btS>x6{x7I)Gye=k-g*Hsjt26XWYI#yC-bqXO@HT}GZE%MvH{!6}~8lk79)zi}>6MYf^s3*-t%NOZ=xM=QeEfacgACj&9N66#M z^c#m$hZ-v5gHly)K%| z?%(f_Fp-Q3-n)0NA^KDm;gpqSl=b?7shQiPJ$H^@_;G8+6(b{UKR-z*^>>FV?b|N^ zp7?$!3Vl_~rdBdz?K1bl6IYu6$!>8JPEAkU4e%0Nta9$k%E}VUvU4_dUd17FHg0bG zXE{`p_Vz+MKYf~kn=GeD*m1UjAYa74Y?Xn5k~N$OSwgUet}UT|xLM`A$q?uS&wT>S zD8qMFHL}EQwHE060C~TQK8<2m@Iy$cFLb607~@t~%P%s_bSHnjPfp)E`$F24qV0I+ z#^e_C{6uJ1E0LMGxo4qVnvX~E7szYbC2BA`DX|wI28O|1NwS8XC&yy5sLZ zaOuN{b{V~&Wekt?=2 zr0Uxk{+_w996mV1WHT`)as54!Z|lFz9vR&y7i2wF)%I|NqINCJUUffRPT<^T?U#EE zzxDI;L+cbuWg4Z;WhGU6rHp@X2Xty(<3Fwi zT8is36*>8T(eMX)0woSK;q}Fbgx|3*!zD6WPEQWQ zs*icNxo3B-iI`bkKzVq2-Y_qUcr;Dj_)*+YjuRGiqVt-KP4>9I>uck@tC~Guz7$=4 zcy{1-*CWq$Y@=&i^m`|jiPGUTif{IVk(sHf8g_PeKgzC2*t~Zk=i}oeuY3|OC?s^n z1bf(ia!_Vyhf3A>NHq~HMUel7oum^=e$?LdL+Md=dU~FENAu2iE*O1BB?ci5r@hNQ zHN(zrBtZw;o`Zw$T@7kjU*+X-%q=XWOW{v??^7WLI=X_a{+^x$X=&;B_!0$)JhQ1> zjVokDyhMYyPu(p1{v=i=0c0thJHsU>m$|D1B=iy z{r&xejt_!?Y0;cl4A2Vs`Z10w{a1;Q)6MrCMn8LfLK&)Cm78PFA?jLP$PUXvrHt9? z>&WdzS~>4Ahs|c$TO*vx%ItsVzkdAsLjGTyh^S~M5J3dlCw(&0Q!v-GAtUr;)8n(b zT5Bb-9GlC8pw!L@{YX3}5$fQP&5_W&?(-V$Q z|K0xOUGX@^PZ{Zy>JICzh>uy5@>n&XVN`k*xbV$Q503j^TpM>n}0)&j>a}_Iu~(54GG4oRkS!e`-5@j*jj_R>e)$!vby} z`KbO}75`0~#*gyr^oP3}x}%l0ea@lxdgIQZza~{{1c($kI44oFt$1G#rIPZ|(`tevSX@;y~fj>UfPy%5SHpB~$x_?g9Og-;5;b9I6q|M#`@{4@O#K zKcwc^vbzkGw|7=VSeU!}S!u+mXrwHmALeDaPif2UWO!4;_}Z`f^s=%ttT=^sX95XE z(BM}d_nfX_G&y$m7XIGxiNRt@l}&ebcbj?MSsiIFqMN#*HMTq@?iFAdZ^j@!y61!W;EIEw0P~ zbF&*NM7_h*E4E>Ohkz~gej#R#?axS0O?C9EzYRFV$kiN$ql)sS>}Do3>BAm5{n_5` zge~6O`Q=N9K-+zAkC4^qpvPqtBvDx(I^hfJzrw6#u z-*HJQb7iT!qg<{1_@^*d-6xugIuyg-dEOmm#4#%THd(@8t?yK>#0$QtLj<{cZkEXq z5QhKacP@Y+=aKsBw>#r$U&|#6J*ECBcyg#8Q|hROX2mJae;XdQTsZvJ(<8N#aZ)#G z$5ZW*W$V>rcY1?G{wf`TQ1H>if<8I?gNIf*pPn4MZUNhmmzb(|nZLz?9&y^JQ``bX zJp`pNcvQyy8++pfb)ufg6_c~VRhv!$F2-8asAoyBDS3HM3U!|lAlQisVlnfGb5hj? zTU%Rrinq77mv8>&DiAFaMBxFOYCDg-PrbwW+A>4RflAv;es=UT%&g<1W!Iimc^T;J zSlK5GRosw=zQY3|4zfA!o;UrGTCMg@9mRiqM40dZkyj43dsqcD)lEgGq+=lZ)gc>p zG_+^g70{rx5FjrzwgVpZ#o;3t<`}GR|`EOA|gWjGh0KdR?Upn z)YQ`NI(+I@<>n>;ZhgP`5>uEv6r^Xew=!kR%4HN36h2pcsQKcMWSMn?oOp$+bL>WB znpF~rJ6xQc2rv{f3W~wo&zyWJ{mRXU9CCkrjrN$h;5t_0PHpp_cLG2MM}Rc^E5Hrp z_FG@2wiXuhc#X)EUn7@gc9u0f=gnTma)?GF-oO5%vV3cy0r0W=35SFrK}n1xtBePy z3#WrY3o1gqo{qxmet$oq&!{cRaPR2l%a?+eF1?6vnAz{FY>c{-)7r=z!shhdmxE(4 zP4n_)&+WwlnaG2n12~CGrzabyCEAb9g@uKNg_+semk&FpH!3_jI@)w8dHP3w+rWn1olVIDTTjEr01!&Xc_pl^KH4ua?uUflP<70Qo(j|^w;=NuX(A( z9$Y8?-F4eZ_iHQz9x~SN98e(CbvF+hkij945?~|TWTSl$^Ma6-BtNyQS8$9&Gwu|3 zwYE1VVN@+cUmL)ymX?Kyi8_#~82j_lr^g|`XK)>{c*Gd8jurZA>*XbUyb*m`_`NB3 zN%-PwcjG;Eil8cPy*#)dti#R&1==n9pB|qt%hIi|`a9R7(?gp&PlkT3xlt#T@c1!5 z?8g%hwb!3N>phx4`S|$M-u>&w^_MZj=BBN!kfP%A$%wy3S9+HRiytZ8ohhG|GwE#8 z3e|LAvo9Qf?|R0QHZZ>H&&;QUCq+fP1PzxjhV8B!nZGuCWvq7mR4I75NWQ18*yl`P z)S*1PveEMN@86n8Nyx^e&Oe2a^_Tg#K<;BN9rm(Sh3na-{O@a2ygIc(l2&WjKWIm~ zPhY+?GpY7|Vjh4$cC$KnYe7rRu^NR`!(gd-N)Q+qrvmOp_ilw&&JqIqyjlOvB z{P}Z|f8RZ1W>;?f$9`EF)ID2Olv-3P{&|c7lP?dywG@()O7)p)`x=r|fZMwIQb7ZH zERVdrd=I6Q_Bmf)Uws3EAu2i147hy>cDyKux7cny+Lc6;JQWAN_SV?gSkAoG^mKZ! zA2|ERQIadw0~GmC@m0MkFOIEhavm3?$D&`gGw8it6g>mM{bZA3G@e zVO(bN#9vA`4)v>AyO^Ad!W6o?y586Z+N)QudQ7#cRNici0r?5@>C-1s6)1b}KpWB0 z(QyK?<#S)(On(s?v=BT|DY2j0BOsKD*y<6mZVD0toXy4mOYe&CwRiTNN76_rl1r

    #6335mO-CwW+nmUD zuSga1@C@c2VT_K!w{PE?LQkQ=E*P{=rrF;{n(r@K*kp>^>T7BJ`ST}e`G-(%Z*KwM zytmhDUM~(5J$m%W=XM)ulid8)f|7kL;G(_#)EoV#lmTg_55(fQC}w396_nrk3QzNI zBkRBFsX>9(badoWJ=t@Pb(QRvjM($Di?p@14d%)wF0YGzEH(e(Mu|TW+u;S3Fb4og zNd6h#H(f7N$bk4^Zut7UpTN;HRm}cwctM43E#V>s?KBX2U0~;#qSv`)esOj`D{}#K z!sKK}h^hD}yD!Yl%BpVzf~l*tm~#>wa3d}3)|JbB!Uly@6*t0M4M3Dd<&#jcE~*BG z_`lL3Vh*08B&rv!1-Yw*?unauis=f|&UN08v8?PCX6{gQPqgD;^o6ugdo9v^R2dGiYJ$v5zh zDMC^Eb4{VKaJ#eJf{AR(;px5$jWAnQdb6#ySTb8-6^)J`ljs)wNDtYvfBP^Z%N|7F_7p6 z5iLj!GzILej>l@mHV}sY=R5USqHT`=Xj?~b+y83<>Z2#_cNc#-y;<_#@@R=S_}iiSr%BfHdcK(D2jL`;NP+( zo(qFE@C^1OMbwtr*-A}7qhrTgJ6bCwp?weaclJGuFu|XCAGXLdyEHI!9p^rU1 zMfOU9W>8Aki-1b;&v#c)bS6H|3e!Gpl2Eo?r9$P2;_4@MJmqU`YUk zl1MbTEWcQZpH@4Vq)Xh`YH zTERvd%6e`eWX1UScm%Wm$)IZO^s7d)CNszF9W)yO4t+a%9e>VEDr{s8bCeiUQ&W|8 zJGYmHg4>RuH?oM8K}T2c|9xMBqiw|3{>|0%t+ym&_$pu4Aen#ppdIi7grGuS;xo*b z80GxAkdlJAWSh^)Lwc57-PDw}rKN?2fq|E|k4&Vj$icbXXBBnwogBKLCcnf#ot>Wv zUEn)RIF5lz2&iXD}NT$``|JMRdX-yzBIXRRl*vwUKkd$sYSJ{D|~{*UXqJ? z9(%{7iaGpn9^hY-(T(8cAGB$%h_m4s7Y)T6L16N+Bf?LZxB9Ezc;VyRubacKE|Y3h zHyE&m!#+<`UcWsF*!XFJMh&WwzmJ_VBs7N0zM>myNN}@0^#$b;Hk55^nB_J3DUuA( zWF3Hy?g0W0&dab%Eu3g^C3tkSqg8~GWI%Te4dvwINP)&Uae5=Hvi!*tYBMvll$S5P zO%*9dbXR)){b_4MswmJ=BR_OI{(I)SnxIGZ4aYVIU`rwTL>U1^1Usw$^h!EE`P=$! z>KM4y$L%{)M@L7}^u?sFbflB2r2oWF_{R3-J$ptbARqun1*f?9)rGY2w#a7jk{?aM zD=E3TK4!*XRs$(u6|pKu*VNQ}bEozrHTvtY#48qGf~eagq3=o8N?%t!oD*5NC{=c;*rlulybGrWFt;OC9k(faW>*OK_ z?Z@njG4MjE>HsCl?xzo}G*TwU`kzT%wkRHc>;I{8et!PLuNP-RK~#Hn!#OW4t$=Ba z5|P_t4rh`yB;Mso%gLz-Z1%`9B*5S)cC>_Tlf|a=N06PI0BhijIievF&{F*Kho;tb zqzTnPhJcWZx8qR=6d&t)pB(METe|U@Ns)&;YqX4vuBMR`nW;d>;m9Ul=k7x&>kITL zB}H0WGZz#T&@eFxgzmn+Lu4Q3l9!uXd2t8KZHXGU({qV_ zA3C$ckx(ih50uYn#fapaqN2q%iSwwx@ac7UoV>0W8;@4>JxNFySOQ9^!c{eJt~sEV z##9)c#eV+$##1|=#?U`b3=GfO1R~<4{Kl75%Z^VJ8?QYfUqw%Xso#BCfJZT z@Vs>-obMzhwJ}5X|~~8EC6s2 z9OO9`f7Ms52coLi_~du^zVH=1G&B6-#Uks);A@xz64tVqnq|t9M@$l1O`KFTeawH~ z$Ei~M_mLYq*C_IgeFWqpy?UXZXVtsAyAPo=<}20l9F~`hLK#4CBh(>lKP}ylqL2RQ z#-`tUnBN^$GEK~wi6K3WlgCmfVGU+T8RtLh_TvP2d2u^yzgn7hHm2-%N&LWA0|bPk zsXdZ@DK-E3#=X$@hyPYWj=&^IWBk03O%6#Hz;fG}dBUG{9UWgO`Ud+TBsLo7iP@Z% zK3~8ozLgXZAO+c#6hlmPvG(XHo1p=jjdOeOiWNRs;ujeB5ddPf&xF#11`h57iSCrJ zU!UkM#yCXz71y9?(npgSjf9#{D9rBWJ>Qx3?;AMdlP4hnV$KEJIj;G z&~5!o?8bjB+`)~nJ%-;hB7!`JTm58>j3)0Wg_2skD%tNT9{@=Nx1C(C zaa&4KK_=qF#geD*SCl;N#}QN07w)GEs)rQ)4la5{eSxQr7xRV(eGsZNX7``>b35-) z=ZJs9*Zcy0TkU)3);l^nHu(|rr~Jq;r*pV1MoS+4AdT!cPONJzEBvQ)cc}dp##N?L zogIFr^(~h03MmFns29Opq~}Df(HgNN_oU)})%(uC(=>5B29}<4hL7UgSd5nk#n3-* z?F%F`QeNs0dNwm9C=t8diak;G?50V=wVJws7t+G8~7wCzP_d7G)pjbS`Im3k%-2S1bN}`TDgB zG>`9~^C4K9^+9@I5xymx_IsFwPx8@htfCrnRoJ%otYLgmiY0CsTG6 zRx_K9l{rMj#2MG!D|0Z6y^v$6Ji~Z2b$Y@CQu_lC=AbLSyEQ7_nxSw!O;VNC*Fs7) zd6{HVQ^}2!o-Os!QCe1-u)`kJ@E-z7Uq0hFlHJ_v@Ah}6qR%8UFD)!Q1R%T25`IIh zU38r0Z#9GK^H_MufRZa+oRz$vb2SyUg`Ir|fcYi2W@Tl4yJl}~=$}fLw#PB=$4Fs=R0b9PZu)yT7 zdYRez=#~2Z5|#S*1jZ2@s6dI;Rm|QQH&DcVDZOK#2qitMjrP~NSi{kQ;~rEMceGBu z(E@5EG*(__|EL;fh>oh6RhiFFC&iFvZ|?m;;Y2B_M=)oxoUj61%ggJ#(;!MK9Aq5g11v1AN_@y)vQn*WI|1Zl#7)VHX4PS`b%q zp7LEY{t*MV#ZUR3#O~=L{*-^}&851-XR{Q8>U}1fm=#R0gU*n}oapop4Gn#sY)|s; zGeiuVP&EJD_^L11-KP2OMZDoBHq&?EMXck5%9ZTNIbv;Qp*KCsoUf7cYFwpOK6H z`_-rPmbAfIyI22Zz?0t}N)bKJRimqe1l_iZ5!IH4QeHmB2ow8UMtwpozP4rAE%G*Ea4K zy8!ABD9d+H?LvOzgDV8_dUUAz4Z$$VjXhU z9b_1DgHWia_c77|6ert!EkYFEiU=;gy@UjWguDR~VICING~P7X;2#U7!PTVam1SBN z67G@|ohnD2GifvG938!O=RAYdjo)8y$0m+t>D^#{_toN~W0EPzgS50NQAgJOxMPq4 zT*&dd73ftnB&5QuNJutH;(#NnWJ?pUwXB9_RMF ze67?%#t*076fl=KuEfZ|@EvY}@r4T)<`+}Q^HJBQ6$K08)k`J*JI3qG#r+rFVSJ;3 zhCUM6m}r)NeKp6+UlHgivs#og9X&n1eBXcYAVIvap@A8UQf-JM;4=q-PK{NBG*`9e z**9dqB`H%-^atd|?}bnaKcy}@`G;&G{5llV)6+$+P!^l|n}e1#%}lJV^}sDEgxmP& zLYGCERkG^wwz>Y5D^krTkpBGH7$`7Yetig=`ok5m?KwK+xb4=;Xa#D!>*%YOy;<}B zUDjSTE|Q?J{yG}JKGCeJr3ISDEI9lKBoliIuKaX2EgP^-~}a^cN_B>UtH}vrN779O@Z4=7DJQDZhZ**C2t6TX#>7ckw?-U&P>N0rw8y zAk*irR=M$beALE+5Cwzl@UtjMK7 zzOd;BOrlE`mpJeFG7#{)T?$&{tVdNhf=91@=X~!gED9rfJ3VpiiJm>D$%`s32%#m` zMu4~5)K5yqsx_C;9I{~suv>J=Bm}k1v$U?V(YXp3Vor`*E(`E!ymxFv@=P?_Tg)B!@Wt z2h^3$%KcP9N$JDzaGl|%3bEZ&+Zsm7p5#b!{>uW`mb>&ZBOhu3-z;h+-F^<}-d@r4%Yryn@%>|#hG>b90a(qGBoH8awhYv;h=K#;1ogSTI@ zpNdGMR`K4BXKL3Np|S2R97KrH{fJZr{Ys?NMHS@0z4;fuCZJsb{?gTZMtE77MDm=v z3~f%j)nx<|+D3G8ast7LOvbnW+1K{Jb??uG?922O+q*bLq1%^e$4^E6ixDh$UEM{w z5@;_we#r;~rE_(veM;Xe0TKfa5cPo7Ai%PlQ=pc| z&K5N^JOgJ>2c9wWYCsO*_s8YRe+Y1Dn!)-;M#a!DKdbD!n-9DX`{y+tTutg97+7eK zCC+kaM}-;sdE1KiSKm;&N|8G?TF=>@UqFCIN{SYr=7U@FXMZ8@{`#N`@q{rXLa5?jufaa*|+0&=@p<3&| zML&7+#Fj%aYGp+1eq7uK$Q6SHJoex17g*t*#GRvgon%%P>7CwA9pbL+?h{FL1X9^e zw>r_xJ3UK!%Nlo5Bt10k}1v zzh!#U8hWN7hP(x9BZ62OC*6OTq14u=N$iSrpoq(_bV}X$U%lzR3plWABV*KTa+FZc z>JB1BZ?6J^{vTHTh*M zJBHa=3+s}iN&F$3o&b5>ahAWRTrj#LiKdfo;@2|rzH1qBA(sJhW^Jn)X3HczzMvw! zTO%n975M3k7X~)^q_`S^eK0Gp6b?XHs3^C2a_3Fh&6_W)Wn^b_4K1|7sz(M5#9CI? z`hI!grzavKr92SQ0bLc4W8n;zs_c#hp*e=B1-TKR{aM zjvkQ6zm0bKCJU5*2;6P(O&)#AQ!@rd=m%usAFV&Cua}4HV=U;W0=s{ug!-~11jML0 zRAodc|C5~qj5)I8?&zSB{@#B^2Vdq5i|<;lo0cRWnlmC_k!=!5;+q^(XMOhfSP&-6 z1N0RFrv7CvbdaC#NGWoaV2lXIhR~y0DDtHc>c%Rg4W-+DJn}sg3A}0T9S;;!PG6x6 z#2Pa%g{*&vj^hcAUajLtlAjI!g($Z-G0Rbfddq~=Mp>`bZr@nZ>22$nYT0Q>> zv)*g=k;Ox65aX-0Q33kHz|QV1{MEYgS3}03F(=v-i6TyMnp-${SCmVO9J#dmuwlo@ z146jTd8yGg*yP&TC{=18+Xdh3pl?E#D9BX_H}m(e=4GpZvZ4iH^tz4>XmGB7*zPkx zKvEwZK0YyefvZn#1uDK|%No2H1rMd%?4f>f0ay)xiVqFf@Ay23q9?~0Aa6R>*0W|< zZehB*S*bB!=XWtA@`@JgS9w!wt7A#}5caxl8@$4Q=A0-e`jX)>$mVIu0q$S3T{qEB z0alKG)l=f-y-gip%#%LauII9S1uL^tH_JiusdG!`- z{|H){K=O<_x?=r-?C3Zl62Hjm?0r$8-I}X`#Bwi5`S5v)Oy<*KlpiDd8K;yj!p;;; zD*8}rghpK#sY2d`p4)~dXx$nni}+N10KrQV^dcG0!Oq_~b$O9HEFhNkzHAKtJ8uM+ zOyBHbF}{z%_51`8vG3*AFM5x?Ljj3=8tH7k^zR=axc{kz-T@ zQGVl>W#&SqhV&&>m!wEi+?n?~gSQ)_@46m!O(Fj6ozdea^)!fY)}mmeF=P`=H%@QV zd1-5DvB`PA`>EFr0V`0jD{LNG!*;)d(@aPE$H@Ap7Tz}<-0EiY9cwxX=ezAIh;E-- z&pWrBqlBF8ITrnz!iF?m|2O&h*w4kAp-@{jNg1iM`XNAcbCEC|HCxUHvTEA?dU6l6 z-BM^bVBd;{d>Tx6_>lA%dW4o1K8bKW__DN?lqm$;M4Neur*_hJb}C!V}VzB(&ENu?N($ic8MMZp!4NAv%$odPvxBvy2pSu7Ky3I{1P|!-@JUDGJ^h^kdE$UKYxEp_^ z-cO4+b2p295n}D}Co=6&qX(-eP8NxPRMdRK+PYz7=80P6EyoRi8R1ybyV5k^1e8x28jE-ukLT2IGP>(A>*8-GsbPzn-cWMmwGRqGiV`b&#u(jK8FxFoaL z-wQrw{O6{^aHQ6yhpu@7&3OL25o8>Tz&rWbvR*$G_2T{e_mq`xbRy753-Bu6*K0=W zs-8L=QP@@x%CeP zmuFIG6X`HU!OhL89Qy8AMDpBvI`^UP%jDc-5=^k4Kz|N_A022vW^knlIjQ;q!G(b4fb$L=Z!F;uiy&Qfyth$%6Dd31$V!B-E>Mx&*m0 zY}&V9!C4YuZc{c7P5yNKv|Ad}E;L^YM2V4_->FBd#$ZMDNnmD8Ah*+FH>x zsoG_3%Oe#AprU0RW($`;JK!2w?`{R^_Dq_zZ$eFbdq&X>TT_O(Athq5ZKf%As=HMO zl<;rYuvGPV;>wyun{Z?vM42`NU?Ai*Bxu8j4S}Pngl?*@ue^O1usS9MT}pay0{Cn~ z{Nj+Y8l$;eBl&GgPWBJFeWRHDAxr6%Rb+izwbY8HmG^B_BS$u+e8dB6&X2RMh5zv& z%;Y#}1UOq(+~@ZL$Iu2v){Y*^f*2#Nr9~o-c@P&zM{5eC8g@THC?pMgZ0=%za&IAQ z9bqQLnEKe}4TO_5pp!EHi=8Q0&N%$w+AuIWw_b9G|3$}n7Dy|1P*kop}LX{ zL*+$&e7kfv-(Z=!3RLe;^s|5EtgHsG?2f(L;mB-b!p`r>nEOWdFyA^xBn}~-Ff?K z*dNWmy^e4Wec0KgCTe=)((b_Gv*{ZUVs$B%3P;(hrjYl#BPdBqDSSuNQ-)Rl>ebhS zcvUfG*=*#efdJf9{0G(2YHV!$0oSH=11u;*<6PxeaPZGvN|iNhnlVp z)fea1Yo+xspt*|IyUua#Gdtts#5N6nT#zP6Mohqlgb5%MGqW_s>LEs2p(LpTP#ogp zJpfIUESS8tDAl~^_T^pCg_`=`B2MymJevoUX4~{we3owogxq{Si_*_2JcBzgwGU2N zU&IJlarh_-Or7*b-e$A|clt6YB!v)cVKFiXqr)J!o<)`+aja9WB0ax?UCO2n%Ov=b z>R(p#OfRRqi5CxfLj(7|+0%*FMr``V#%}9qd0#l75{QCQ&NoE3(|1z|SQicAoE^J5{8 zfGque0gPI0ul-^=J=tyVV5Wb%04c5bgoIQxD&jxvq%_)EJPCr=eOwv9A|Z8nPpoYr zYZ+Qhj|`+lYq^RE5iA^@k@1^|dKd9L%aojosu=nd#nq|CKzCMrOmMf%3@@riaUki< z62eYDbk^SC_LW$K(=!-uE;%HfM{UM1xDHp^9xg)*Xd`AC{n?MUAgzBrk&Pu{diyV0 zD`?7upnGf-QLTMV2YmH&Z?7iYTVI=QW^e?a0KDWD5$VhJ5_(zyM%P$dWVjAEpAoYo z+8vTf)ee4rLS@fVRZ=KhN-f=-r`WKAmupJRiYeMo4sNyV&%b!V?0kH8xr|~)jpzc7 z-yLgkA|_U>CW0*V5B19W(JMvM?;g0nJz2&@(I|guw7Mnb+RFftjx?R$DD6guzJ`ej z&DA{BWC$j{#%HGfU76~7N-FoI8yJ+%>pgDbp1DOwxOwJFgeBBXHc#Vv zNTeNz>G>_*%cu%TY8>@4Dz&O$g?xayme&2%CJWxu8};Ii&CM&3^Q)_dP+(rchof~) zLhkoYh%-u!yIbPsnYvU@iDKt^A~mF^3`y2a{5s^Nm6WpYY)nEhXZiw|lIInbl;#N+ zd3XP9-dt&)lT+_@fgDN@go7(k+{ocAc8SP}$FB+`!%dtD(UmIQzuuoDUL#yJ>(#!q4YZtb}my;^MtpvVo9h9k{rUwD` zr2Vp$S-;3w(m`LKqg^`h7z(-u>!my8lhkPL4=#{Q(bC$6_)|b|FdzC65P6x1z0E;S z($Da@Xn%xUdp>YBGfPN!{Y}ZBWqmF$|#&K*-M%21K4de}2UVyf0mdyu~Gb zR~h@WOk&-3{o~t!b*y68-X_=n-d;*`bF=tcXUMiacd$=n&H^yKylxv6rP_M9-n86it7hRpkegWt{u$&WZ(=(`lBJ|DMLp4NO@n7e^m{=weoXJN1CUE0aQ8T@K+OKw38Hv(3CX2W{5mGj|c z_i~Gk^HgD4o*OVU#7Lp7sGaQbz-sE*)XQbN-^~b_nzPdZ54ehn^6Su0IzD&iyub5# zLXMGk_=)_B0Xdtct-eUqj&SIFyeci7Q2jbdWtX;(Gq2W%4-ii zaJsB&41ESnrz=(=!0k(*GrylA420Nk%+}w(p5R%>T%{J_(}{Hxa*8I%FJ@VrF}ICs zl)%^#WB<6#2enDej!b<1r$;w8`1AM7%;omu9X3y))(DtE9r)$jZUic8(?-4TlwFt* zR~7JdHcHHE7;l8J1&cZ_%khnS%>E#k!*-fQM6@WTY7Nc$WF^M0e~M0s=>AlDSL7C_ z3>P~?>JA-R5r$j$J}50)8^&QN$hbgugWS~zQjQ2T=)XiHB+G3g;^N%}+K;~HYY-l7 z^+_OTz#B7QNbW5bJ~1h#IQ_N-NfXGWI)hD!pHvq2y8)4IIF@k`bGg3op&W19{{dHp zM?!)cCA}k@u%&<7MbauIYpy+cUM1->3+L)6mD3 z*sh0Dwa<`G6lKlYy*KfWQAMa(aFm z+5u2=T-u|Y@grvtGk61422VXaAvZF+u;6~>dGMUii^TZlPxollOb?Z4g}QSWy4Qt* zKfXsDQ8*}|mjhPZy6f1}f0-ntLPC$58}jYXdx9X>DC68s*=l(Sq_-ap{?3z1cpP75 z31(VQv|7~BGx(|smv+*)BFJdL*HZA#xz+p^P;aEIwL8bdo%hFv+bl_?-zbO7K?r>f zY4}|6RJ|VeeF_U^uB^fO=>1wsxy@$Facy{ZeA(_s>jpg3uAf* zJ@}J3k)=knpTt3L`J3ib237Z17(zHZa#;|-QfK+~8X9`~ScrO_`L_G*(uM;}>_D#9 z<9j{|#^b~V!HJ{El(4T1$=3&CBrPosFN#5Iefc;X1VUJyM{VMlW^K7`I3b4r!7*u= zlXFo$yzjCUKK zVG=I_`6I=qg5Q~ei3vYXvGh5W2k!^~3RD6|;IoRpyzYtd`hTVI*N^whKQCZSS;nu? zF*~1DF@?y6WdUaLN}zY(hnSTlobhU*HZU6#fG5~ycj+JPrZCk< zLrZ%Pq^TJgAdZFcOJG#E<>j~OU{N{3#>1F`@!j)FRlEhXFjK*KwtK7{iQwk$vmTFr z#ZW!2hojPyVNH7Sgekb8K`|{OLmQB(+d>E&DKOx`a?8c?xQA!i;OxgU z@J`0V=ptbcP;d8Ok`2P$+?J_f;JZQ$iGHC!PrjM5&L$b6VucXtgm1xUy8qKsfdHKE zF|I4zLuzlB4|_jq`#GA4xqW-72nhQFQ2S!RN=i_L5#$k=<{)OivTu)Kmhnho@Upas znYB{y5bb0=H0c_rxbXal$gJXcy#IRzOZ4gN^D`I~FmWH_ygFb!Jw(*ZS*gdtJypS9!=9ei4jg`6xW zXx<U=0uaU{$N@WjOGH;cFQ>ev|(KKA>LQ67-YKHKr(nyL)WPBAG|w;v&gRl8{akvX48mXLdrQ@sSZ_L>%9z-|r9L z?%wa$csw5~-0Hgr6UNk!(-HJ+FpGd_GhWCr4ORhJv54tH-n~Ef-B-A928MSKYPMzj z;5EPrYxBcAt`^a@4VUGJOtEWHli_0-c#sROxI3UtByLDga(TFD?9$E*Cs}`)bcyMJ z(`+FBt-O@fkwvP!ASaIE@s+4u!wqY)Wu5EP+tIiGrh->)I)_k+mIBKw9 zC?@|yjmnDcUF_$X9~`e?^sV7Ps@H%Nj2%a9Qe_=qZ+A=NA3XM558{nXXUijf2s1_A z7|?`+Aq6sDZF6%joA=7ySNs#)SNiyHO0)%8Sh*N>I38PWDzlPYCSJQj!Vp~ZuNE1m zp%6gUx7b`?6FK`B7S-@OO3@$aJ3I(@L+qASJxk08Yo`ZFfWGpyBdo{n`SD$;HJZBO+bZPbtqM85yFjz#sJfN83ZmM8lnn&jcw~W{*?%hfI4w#ePRUw?M31y% zq>vjWKbv`3BaJ6aeF0Y?vU3JR(dSIT`9d=OQj!e9; zk6zn36}N%J1c<@t`gJ)-lYwjTbviue**V{ue}mvcTkbBeh*RYCutfB8<;dq^S(ba@ zr|J7#oLE0#DM(aZ&e4ug14btS*039#C=;*o77HK|+Bn~#fqCkzx3?7F^kfX8`Guzl zMd|VMa7L6XF8*$CLqk$`rknn6g zl{QjT$YP~V+PDp*eenZts;APOpF;ufEx@T)A9h8ZRhNk*choK9hj=Yk7*Qo%>WXEh zc!$jSj}ntH6kYnd^NJ!pQi!ImzfVRhY#o7dUs=7EIgfh&*%P^;ABFDUmFMoXv2^=|y<- z3pw`VrPAz}C{!d0%V_)1xMoTbTxBR?+ra%W3SuO_W2LcB?laR8<rYMU`Cp${wtq(LIaUwN>~09pQ-zdQuDS zJZvNHEh-fZ>wW*uKzFzlxc>KU?;Pt%`CL-7OX^|3+RTeGnF{KI=^kd|0yb>77~u^) zeYb%uZ(*z*@9#?2*g>|Ek3MeMuNa5ptmxz@o+G929jrmU6J%rlKiHL)plaJX%dzvLRj87A5wi{>if?ERS`kMEmy<+yxcKes) ze3+{CvV-IgoZ2sIYbOS?yv2)2CZq~240s`yAcVgXE~WzT0Q- zWL1dALy%`2xRj{_d-+U9Q?5?YCf#TLc8b@M$zPVtGQEQm+HF_a3ey zTZpcov}rO9`k89{PvZn?AU9;z8JR}2;}W7~gm&@kzn@Zh+nXJq%P3dlF4y#4!9ZXC zBjJuR*pmw+h#1Si9hO>O83*qDm%)}hRnjApjuuZ z;ud)>{lIjkB`T)+xFJiZZfS`LnEU}(VO?Q0Gn{@7~yihq-xr&z~* zII6E*w;J=VgrHwh^ux3`^YG@~AE5%Dq$V$2%61rP*=WJzJv}{r0SKP_sT{uPEiWfW zP}!Dz7Fj5E4)=E2>}$n!y3S8zJO6S@Lxc$3`T;khPQ~X^lgm3Xe@o1p?2Pz1+T)s< z_Gq+;iAfE-D0yET6b8J(HP`J}o^JlA0VIT{Z2%zCH;Ez7} zlgMehlpL!Egjxv-TKDktJA3)oh}$Y5&XW9HtpSlgXZA2D2aY0qd_5q1n1J)7ySv*J zgxx&dn9ug&75WfG11pl@E&2}SZ8yT4;G1B=X#e^8pXy}{OCt?~bK}e3SIUSl_IZ{| zr5OqS0a@{v*&4QKw1kh^i*7NpzT8=R_H8DjfSw z-RO~37moX3gDP$cllZDFsaJ zR#8>eh{aQ?Zzir>Z;dJ}h{eq))JaqIdM*qxB+)mv%WBJscq}PNwoH zC%`l`3Pj}Ru&>NOZ+bir-O_;01hGU`N#Y!@?T+SAL;if@cGXrRV(FygWT0WoC8)V+S=> zVrR}w%dAoz7qDgCe~EW~>yY!q(6Ez2K^Jf_K*41_KVW3w^4Wh1P04rIAB}G2 z+)gLi$BLD)<_SdKZ{3~^`7bsbuB zVy3+tSme){v%S%24rFeOe|YwnN$PW@+sK(|!cj+I)y?m{@7JJ}$&6&C=IcPY&$#m- zH!?--0d`;LtuU4`ur!@lgq%gO{Easvu>^&3BUzF*^olY(K$eULM8Ym8XbLSTMSR*gykToPFzT>l5#n@kpog4qX-)2G zaZMpYbfz>1$S^kgTH_kuc~;UIW)=VMsag0=Ja#7j)!6`}xG8mBg8<_Uy{?aERQO$t zT0}h5a&pVBxxojo5jI$yE3)W>!!ToGR(+iZ^LJUZLG+bOoJs!M{adrEZNdF#jUSV$ zk$Bj-jw_b7*QW^O{8?q~s{>8D3zo?Hl+pK;_UoofvZO2aU3lLgN}~NU;^QNqRKz4V zyswdYzT#xcN8J}X`Sh55;<@9fQN`%p0hJfe>5g6`Ks#{qR7LHD-XM}g`#ObnB2WLz zk|CTAUKScnx@cZ}bvsU=>jRaQ&16vPEBtx1P1%yUD@wxpGm9owb*vMK0cj_O`n!WG zTg7&pq5fzE3VP&~D{i7mT4-`?MuKo&MzaAG_JW**Z()b!JoEw?KT1#U0ck@*B4K}@ z6ye3m&CR~cqp(ZWIdO*j)DE}i(363mUe5Gk`DzJ`&#*X}Ojk$k5tO~t6Xom! z#u)0*SH7MmW^yPYMQt}P3f-cg4@ebVS6mbD(Ko(iXTg?zk4B~;voBD_-E8HH(bnfG}Yer%T9`zujxUyY`8$K=v2F5b)^$!zhRX>XF-jK?9g<2P0P$g zg06o;Ts#eSGL(%`E+NoPPR!yjHHQ7(#q-xPwaqN~+;R#>@=?omu6((t^2GWeNU*yh zA&;Py(^qG)#(1k~;ddx5h$wKFUchglrf7q{t@>3E16w^3+pQ*3xH+j;= zQGYbd?%CD+oWbj3Yx*&7vYnY((IF! z%DfUAizxrTS|ZE)FSaUet5c&!3=E@b1ZfXw>N)nrWO8x%KcFRSz#tA&%{Lq7rvxpJ zNqvt_+j3`zk{&M3ig>(r>5?z$0mGAHr#GsF-tuG@;W@0fE{95g;oS?xVQ+Dz@x*$N zF8jo{?37qIIP?M81x7Xj7}T#qFP&MVj{0Q#Wa8(qynB5g-L^3JCG@yDI)rnbO~T^G zIen!8V_}Q&2nTnn+T(&Ab1cX-bEF+k>5mEKl3LkSX_)1qg=4a)q{Q?3R8_H>re@>t zq;r2Kb851YzP$t6efh{$>(s*sp#rh^UsmJBBvDZYrkQi)*_5v0fn|7|Qv8`!>qXQc zt^b+!EVmuLz{J@`6)`#tFM1V(HtiUQ-Ce$R?V4(~9gw)jz?4Fb=i`3oBMkQrgD=k& zX&T?KHn}8)I-5O@naVyz<$pZszi>y=iLmArpTQ9VGv9u@()KDRl8>>-%|-mZg{k=a z1KY!E2ZC6eaZT9~AYD5$VEyuNa<&Vf3B5iKx@nu=8}^`TC=3B@wSFBfk$)vXD#HJ&}I-{drm8fMTDZ!ShOHq7$l~Tkqg0 z3PTTJDi;rrZX|%1VNhVyvobSj(MvHLpl~j}mK+g9 zMW8UH`c=FeEFu%zaARw~CFj2&@A#v;x%GUCp;^0?$jWTLC7Q|)!^M-F`u)NfVqVE~ z%CU^;@0hz9`?HX;m*`spx4rKOdaTU{@@cS-bA&NfpY>MFAo-EP>%!kO96l7ga#vB7 zY&-YWeBWV9gszs77+UsUn1SS(cLD$RS6nww_zJF5OUNlc?8U~DgiYU#INaD$X>h)i zVrb-k(Q&i$y6a!UN~NrMEJKL)gDD3M`l6=sU>QWS&?i2aHUjHe;B&dYT8ebKs8iFq sx1ooqzT2c(n2t;eclj@Tu-}Q1d=)#eD(-6ph1CdSqf3Tw^j+ir2c10anE(I) diff --git a/doc/baboon_vector.svg b/doc/baboon_vector.svg deleted file mode 100644 index dc1667af91..0000000000 --- a/doc/baboon_vector.svg +++ /dev/null @@ -1,153 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/doc/compress.html b/doc/compress.html index e2d79f581d..91a76b254e 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -1,23 +1,26 @@ - - - - CodeMirror: Compression Helper - - - - -

    { } CodeMirror

    +CodeMirror: Compression Helper + + -
    - -
    -/* Script compression
    -   helper */
    -
    + + diff --git a/doc/docs.css b/doc/docs.css index 170cd41244..9cd7319f38 100644 --- a/doc/docs.css +++ b/doc/docs.css @@ -1,167 +1,213 @@ +@font-face { + font-family: 'Source Sans Pro'; + font-style: normal; + font-weight: 400; + src: local('Source Sans Pro'), local('SourceSansPro-Regular'), url(http://themes.googleusercontent.com/static/fonts/sourcesanspro/v5/ODelI1aHBYDBqgeIAH2zlBM0YzuT7MdOe03otPbuUS0.woff) format('woff'); +} + +body, html { margin: 0; padding: 0; height: 100%; } +section, article { display: block; padding: 0; } + body { - font-family: Droid Sans, Arial, sans-serif; - line-height: 1.5; - max-width: 64.3em; - margin: 3em auto; - padding: 0 1em; + background: #f8f8f8; } -h1 { - letter-spacing: -3px; - font-size: 3.23em; - font-weight: bold; - margin: 0; +article { + max-width: 700px; + margin: 0 auto; + border-left: 2px solid #E30808; + border-right: 1px solid #ddd; + padding: 30px 50px 100px 50px; + background: white; + z-index: 2; + position: relative; + min-height: 100%; + box-sizing: border-box; } -h2 { - font-size: 1.23em; - font-weight: bold; - margin: .5em 0; - letter-spacing: -1px; +body { + font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif; + line-height: 1.5; } -h3 { - font-size: 1.1em; - font-weight: bold; - margin: .4em 0; +p { margin-top: 0; } + +h2, h3 { + font-weight: normal; + text-decoration: underline; + margin-bottom: .7em; } +h2 { font-size: 120%; } +h3 { font-size: 110%; } +article > h2:first-child, section:first-child > h2 { margin-top: 0; } -pre { - background-color: #eee; - -moz-border-radius: 6px; - -webkit-border-radius: 6px; - border-radius: 6px; - padding: 1em; +a, a:visited, a:link, .quasilink { + color: #A21313; + text-decoration: none; } -pre.code { - margin: 0 1em; +.quasilink { + cursor: pointer; } -.grey { - background-color: #eee; - border-radius: 6px; - margin-bottom: 1.65em; - margin-top: 0.825em; - padding: 0.825em 1.65em; - position: relative; +#nav { + position: fixed; + top: 30px; + right: 50%; + padding-right: 350px; + text-align: right; + z-index: 1; } -img.logo { - position: absolute; - right: -1em; - bottom: 4px; - max-width: 23.6875em; /* Scale image down with text to prevent clipping */ +#nav ul { + display: block; + margin: 0; padding: 0; + margin-bottom: 32px; } -.grey > pre { - background:none; - border-radius:0; - padding:0; - margin:0; - font-size:2.2em; - line-height:1.2em; +#nav li { + display: block; + margin-bottom: 4px; } -a:link, a:visited, .quasilink { - color: #df0019; - cursor: pointer; - text-decoration: none; +#nav li ul { + font-size: 80%; + margin-bottom: 0; + display: none; +} + +#nav li.active ul { + display: block; } -a:hover, .quasilink:hover { - color: #800004; +#nav li li a { + padding-right: 20px; } -h1 a:link, h1 a:visited, h1 a:hover { +#nav ul a { color: black; + padding: 0 7px 1px 11px; } -ul { - margin: 0; - padding-left: 1.2em; +#nav ul a.active, #nav ul a:hover { + border-bottom: 1px solid #E30808; + color: #E30808; } -a.download { - color: white; - background-color: #df0019; - width: 100%; - display: block; - text-align: center; - font-size: 1.23em; - font-weight: bold; - text-decoration: none; - -moz-border-radius: 6px; - -webkit-border-radius: 6px; - border-radius: 6px; - padding: .5em 0; - margin-bottom: 1em; +#logo { + margin-right: 7px; + margin-bottom: 25px; } -a.download:hover { - background-color: #bb0010; +section { + border-top: 1px solid #E30808; + margin: 1.5em 0; } -.rel { - margin-bottom: 0; +section.first { + border: none; + margin-top: 0; } -.rel-note { - color: #777; - font-size: .9em; - margin-top: .1em; +#demo { + position: relative; +} + +#demolist { + position: absolute; + right: 5px; + top: 5px; + z-index: 25; +} + +#bankinfo { + text-align: left; + display: none; + padding: 0 .5em; + position: absolute; + border: 2px solid #aaa; + border-radius: 5px; + background: #eee; + top: 10px; + left: 30px; +} + +#bankinfo_close { + position: absolute; + top: 0; right: 6px; + font-weight: bold; + cursor: pointer; } -.logo-braces { - color: #df0019; +.bigbutton { + cursor: pointer; + text-align: center; + padding: 0 1em; + display: inline-block; + color: white; position: relative; - top: -4px; + line-height: 1.9; + color: white !important; + background: #A21313; } -.blk { - float: left; +.bigbutton.right { + border-bottom-left-radius: 100px; + border-top-left-radius: 100px; } -.left { - margin-right: 20.68em; - max-width: 37em; - padding-right: 6.53em; - padding-bottom: 1em; +.bigbutton.left { + border-bottom-right-radius: 100px; + border-top-right-radius: 100px; } -.left1 { - width: 15.24em; - padding-right: 6.45em; +.bigbutton:hover { + background: #E30808; } -.left2 { - max-width: 15.24em; +th { + text-decoration: underline; + font-weight: normal; + text-align: left; } -.right { - width: 20.68em; - margin-left: -20.68em; +#features ul { + list-style: none; + margin: 0 0 1em; + padding: 0 0 0 1.2em; } -.leftbig { - width: 42.44em; - padding-right: 6.53em; +#features li:before { + content: "-"; + width: 1em; + display: inline-block; + padding: 0; + margin: 0; + margin-left: -1em; } -.rightsmall { - width: 15.24em; +.rel { + margin-bottom: 0; +} +.rel-note { + margin-top: 0; + color: #555; } -.clear:after { - visibility: hidden; - display: block; - font-size: 0; - content: " "; - clear: both; - height: 0; -} -.clear { display: inline-block; } -/* start commented backslash hack \*/ -* html .clear { height: 1%; } -.clear { display: block; } -/* close commented backslash hack */ +pre { + padding-left: 15px; + border-left: 2px solid #ddd; +} + +code { + padding: 0 2px; +} + +strong { + text-decoration: underline; + font-weight: normal; +} + +.field { + border: 1px solid #A21313; +} diff --git a/doc/internals.html b/doc/internals.html index 4336ba4d1c..3f1b7de869 100644 --- a/doc/internals.html +++ b/doc/internals.html @@ -1,25 +1,35 @@ - - - - CodeMirror: Internals - - - - - - -

    { } CodeMirror

    - -
    - -
    -/* (Re-) Implementing A Syntax-
    -   Highlighting Editor in JavaScript */
    -
    + +CodeMirror: Internals + + + + + + -
    +
    + +

    (Re-) Implementing A Syntax-Highlighting Editor in JavaScript

    Topic: JavaScript, code editor implementation
    @@ -103,7 +113,8 @@

    { } CodeMi with new scary hacks in order to keep up. This was starting to lose its appeal.

    -

    General Approach

    +
    +

    General Approach

    What CodeMirror 2 does is try to sidestep most of the hairy hacks that came up in version 1. I owe a lot to the @@ -136,8 +147,9 @@

    General Approach

    do the rest only when needed. (Fortunately, the onscroll event works almost the same on all browsers, and lends itself well to displaying things only as they are scrolled into view.)

    - -

    Input

    +
    +
    +

    Input

    ACE uses its hidden textarea only as a text input shim, and does all cursor movement and things like text deletion itself by directly @@ -165,8 +177,9 @@

    Input

    Of course, since only a small part of the document sits in the textarea, keys like page up and ctrl-end won't do the right thing. CodeMirror is catching those events and handling them itself.

    - -

    Selection

    +
    +
    +

    Selection

    Getting and setting the selection range of a textarea in modern browsers is trivial—you just use the selectionStart @@ -213,8 +226,9 @@

    Selection

    This, of course, doesn't work if the first time the key is used was for extending an inverted selection, but it works most of the time.

    - -

    Intelligent Updating

    +
    +
    +

    Intelligent Updating

    One thing that always comes up when you have a complicated internal state that's reflected in some user-visible external representation @@ -274,8 +288,9 @@

    Intelligent Updating

    uses this to reset individual lines, the refresh updater builds an HTML chunk for the whole visible document at once, and then uses a single innerHTML update to do the refresh.

    - -

    Parsers can be Simple

    +
    +
    +

    Parsers can be Simple

    When I wrote CodeMirror 1, I thought interruptable @@ -315,8 +330,9 @@

    Parsers can be Simple

    manages some 1500 lines during that time on Chrome. All it has to do is munge strings, so there is no real reason for it to be slow anymore.

    - -

    What Gives?

    +
    +
    +

    What Gives?

    Given all this, what can you expect from CodeMirror 2?

    @@ -368,8 +384,9 @@

    What Gives?

    longer be current. I've left the text intact, but added markers at the passages that are now inaccurate. The new situation is described below.

    - -

    Content Representation

    +
    +
    +

    Content Representation

    The original implementation of CodeMirror 2 represented the document as a flat array of line objects. This worked well—splicing @@ -419,8 +436,9 @@

    Content Representation

    patterns that may result in a seriously unbalanced tree, but even such an unbalanced tree will perform well, unless you spend a day making strangely repeating edits to a really big document.

    - -

    Keymaps

    +
    +
    +

    Keymaps

    Above, I claimed that directly catching key events for things like cursor movement is impractical because it @@ -482,24 +500,4 @@

    Keymaps

    is updated during composition. So we poll, whenever the editor is focused, to provide immediate updates of the display.

    -

    - -
     
    - - + diff --git a/doc/logo.png b/doc/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2334f5e0999358985862f477ce812805dd66d08d GIT binary patch literal 12003 zcmXY11yof{7riu6(%sV1-617NcZYO$*8@Qs1nGDnh)8#LBi&EBq@+t4{`;-MIIB46b%3XOojI{8sO(w@bv{18GOfZ({BSm5Ix>0XrY2XfvA>I z;P0A!N$TKQ;*p#EPEwcD!dFKm%_M0u?{`X3 z6(`uSm^yzT9}IOPfk~oZyGcEAQRn9$F@@DegwxZ6JI*V-r~crho4ZamPa(XTi<#`n zcpe13)PfmLc6i;dc}%Vn<9vJjiEFU9sOV|dj5DsXq(nWop!xjjV73ZJy`;+T(ALaY zA;bUrFCQZ-t7C#n@hog^&Zx!nV8)L&CSWhu$C;eRI*t&)q7qlS+#MffVPRRypSPb4 z3k&n)&sH889W^x2(fQXQTYK8jr9&H7PSYhxKAdzzu!byn&{Hf&J*{ zXh3;&wX2WA_toj?gYaKwoEW5nt{X&o!S{BP)z#GueY#p&8)KO~!y_Z5Y%DCLiV6zR z@87>S6ASnkZcyROTRCpsNA+?$6!!FRBaxe$dhO0qM`^sKEAuqbdJ4qA`WY+rbVpRSm@dQ;OMs6rP+Tr%>GKanq6H^ zN~~A-oUUQ+3VH5N6{28~@2~4v{bf?S%L-jUv{2%)8cDHq3DYt*j=xz8s0vh;8;lr! zeEg(YRwj|BYtZ_OZ;VAMqoQ`%G@a#bg=N$FK=j8cXnFZXi-?anWmeA0Qx_q790{L& zio6G3;H|5e1#4zh?NYUGaH7gI_x0a-2OVGE+fQlxl{7Tz@yPTFA|JpoX zq!%t-?yYA~VV}iYHp$!hbsjwz6wtz49WXxADJ08%h&xut8Gzrg8Z79^_}1+#ack~- z`_qJ(*+aL=B$pcXopHOz-o$1!BXoFTe0=;Z3(I}|&!7A2GIUL<2T!P-lyF8I|2@G! zFbJk5#>UDgU#v0-*^Tsaa&jJ#$wP7u>4DXU>%*Hqs8~Sx$(??Mj{nW7PZ=IA?(@N+ z|2fiKPUzud^-2`Zn~CNSEm~T2e7oN8S3+D|Tt1Cbouz;N{7DUYSYBscy9nM0MTr5f z&b^-MA8yY05MX!e5%QFNf7&00SlQT$LJ?4`;iCdbHgsg=60Qg(jH{@WWo~_LPNb+% z-`RRx^2y68k444AM90Pk*gikr$)4O*>DLV+Z}6MKR0A|4wYy0y3_46+TqmJopNv+W z_{mN>4=Z!t$R{Y#6#+CPANGQddl6n zWlo#DXp3R({ctL&#mYn24@XnSmd25b%Zg{5Qopp+WzzD|&u4ou-lgcfQr^v;M5Ksc zR6>Hz!S#J+T+OPCXGxI5pwC9&cy|Le8{6>s!Xw9!txzw5+>l7+>e7z14n~_ z`i8ofFHxwdsOzyaKR+DUuFT1aNb*D9&3G@Vofa$IQ&^Kw`1f zSVgd2*cZPWC%65l>v4ypEHCKaBC1c9Y%F1FV4M3+S(}H)%ciGc$?Ww`sB7|fc#RS{ zyy?Wa8u!fYD|-c8s{}H9Z0zce*4BFyAzshb6^}jptkF@$+!I19Go8VawYV665sSXh zaNyo=cgQ&He3;<(IazrT0pBiRx))f0=}jG5k<=&T<0bzKwGuuohB_)UKpQ~^v6f=k|K8J5tuggFT1*T1I+kIF-iP`nszVD3By~!Z!v8FQc^vGS65es^z`)C zDU6Mw5v2NB|Uw+qiKC2c*I_;#h^GA&LUcL zDCqB1y5F-;-G>jbs+oh6%}~64w+@B0uTobCLzmmYks1Fo6Ks0L{}avk&$eg?XmE&l z*!H*sUK7t_l{zjTllyJ(Oc^B~a`@%WaG0?7b47e6P8KSHRkif>qm$mq2Va5+qsl2S8;`;CR>W7fDlyB@$Y>wqQoYI9f5M(Z ziwwJ3q}!f?r9^9J*tu$x7#(ZDofKMJtMG{KCSpHWQ{fh=h-O_z<* zmxa$43|+M4WMm#EV2^%&)AB*%hKA~q`@16}Bb_T90Zpr`LE~9` zL||2I5@3u6b4jnY$IK`xWzHVCAEP6f5U?c1C={PL_}lPqZz4A!2t-qYN@pu8E2g(^ zMP?1|9>|2l;VU&tN(EfjjJSdyZ<&e>t*seKV`BbQ;f7BGod}TYnwrpgZEc_5NB^Ac zp;V#yHmC;d5HFgc^?W{Mc^vv=MrD|?QGmf!VWB{vm z+#v}L&Y(jBzoz*nfh1QjcY$Cw9R;dooMpTmBVGvr5j??nX?l(PW$(}FOwot+I1(O) z(lMv#}pI^AVvAQ=~_9o^z3wjUy{N}-}NL(Esbstv4?Yd$vm%`Ij zUQP~_@9gN(nSC-&yO}$OH?kCUF(>zde%-<8&lu+No-2o~QyOY%p$%%x2HaqAqW9+I zy4BX!KHr`Ctd-b!`h!KSmyp9m6yy|R&ev#{e1R49d~!keSAHTQBFoazV9_nAudjby zNk85YHnmy~OQfYO#|@{c826CV(#kq~7`GVmFK?<{bmX<2$~W$;Twh=aIo<6oEGQ5q zzd2cT5D9sHOot`s_aS@X07~@q5++mu&SC(Gm9HTJlLZT@kocMWhOyvh%2w zo=w=Qk(=B3MbU?J!nQV-_0Enz7dxXSH>DMEF{Cw6uC?qukr~X-p(J6PUJWWlb=<`nwUpw-%wY7}=&=*$u_i@G=I7K7f zG{YD9k_BwDA3kuv0UQc-(Y6R$rE8*U=Tg4DDLNI<-l$G`Gg^dyBc$UL8d_TXkV#-b z?bp%2^{~Ckadwt_5&+)bo`Hv&f7MK{EP2Op*m)hP!2m@8ZC_JUv)%z#`4+^!s%7rW zi&2i)#l^+9OH~ZZD8Z}TAf$I(SA{&iozVVLuJab$-0Zk#WY`CP5npxtcZlmH?<5Nm z5D@Ao%Y9)b)0QdWo(A4)z-yNI2qL`#x_@(N+8sEz{MZd=9j!5_;8#rE;i+RyL+^Lf z#vPKya~&CRGt5;VcGkti?m7A=Sxlzt8RHvVjEssjeeicY!nkx??0**axkMS$UK$4A;)x_0-R= zsX8Y+$dl=&K`!onpVhQL*EOH%3q9R)`p`J=@f#>i&@l%*49cHgfqcB-#F>1EhLx3d zhUl@L;IT2gti1d&5KJh_!q(GtgQKQ&D@@?j0>M5=AG*J4zHybh%pp^ zYQ^FXGl=i#Y?6JshevSvl>-R$^5|9~kTjL+(r zMOF<4Wyk;SHDmq!{IF%Yid!B%5pSJFQ}Xg&{)Hi-pQtD*lCD>ob_w6~_V$tj6Gb)K zJ->atbDeo{&X-0;TIuWPMqlx;rFoGEuYMvQDgq0R$}l+$z57{Pcr}*W;&3nKBLh%A zbNH3S)uKVJ?tJs{v6K%7C+WM!^|lZ@akm=)4AJA6)$3>HjllQ328FyQmIFPA~T~1jiC!#^n2eT7T2LGDf!k*K6jrl#$4Yz81 zS-pR)4P5-a#4eDOaS7#P5XxC2wjNI~>q z$xh+RGKIHX49dvu8nlf|k6z%`Kfwh0e}@ha4^xXwy0~EqwtcrOK74pQI$GjG?xSqb z3D6eUzMK4Iy-a`E9`SWY5YyuNnqPtCvz$k;in)2sqAhDWJu_iLgAm`hZ}WQ<3;iGn zw|ecfq@t0KkZ`?`i_;q*CR4h8L8Kr8MGdbE9)r>u`3TN*xqjURP=B{jwD3JVJX|&s zi{gT5bXHX&_jP_`)tv*|#i(-v*C1(D8#ie@3*aP-w)88*K7N|`HIqYj7TT$B>K0qO zTp`zAPfBzuY&<+X#BPs^noqqPZ9=pK&rc7!OOE`Bg+QCvAt69*&t*ZhRal6CV42zD zyjKwyF;T0>9#{_ZX*z$TFOJ?Y9-K4yM8h8S6P2ERfg3U>XA$1mx+GrLzG9I`23W$e z4m;;zZ8Z3H1aB=>SAVKCa7vy33uu~~yL~oUck)(H2-PnRh;dsXz)WJ0u6j{=8#C}q zc(pt?u7c!)B??ey5)zQ#gMF%;@$YC+6Km+ZhYiHEQ3)`s(Sv63*i6XkS9ZN+5*8Ll zm7Mz^!%b&rT|qbg^CRnL;)gPQY>ngEz%ngEL&nh1u(Re7YxL5joq*Eo`%bu|q!Rlw zFDO2?8j*ET59d-jY*MdcHUh4@Plg{p27u5pr@+J0S`8|VIp={Jj{$qS7bExN)u3Ah zA~u{9;)?!TROFAWKh>}?ChAGlF^1f5PFmN&k~Eq?DRz&8qd%pv(bNlW#jdAim#(0f zj+?bIo3q)&>#V3KR0IH9olme5g2I5EH2kYpk#@wL-5mj781>HF3*ahX!B#edu=1o? zu&`d~#c!a&AC)0(G9+v#{I>F=CH`ueAc97nK|K0Z$e9Oc07hXiMQ2N267%bV1kfWO z;Ios}NKS)jh8j4DWzTK)MV{XuR=s%sohx~<%U!y_yEU+LhyoBno8_?{locrpRKd5Q zxVX5`3L;9gy#9Vf{*;A_ei=5L%^gCOx+6eKCOibeUe{;ufe}yz-aw84Evkd-!Blm1 z)ev~w;hpcT(}i+R@0~M1oJRsWf{Z6C?#BbiC8g<5d#O4fFFqt{Qlp`xmzZ`1A9U_k z(et`(^()=DXjg7n7&Md9JZ$I~ z73DQ$y^gLfm50yiFo-+RQ3=j#?RV&Pi-C))F8xtBNs$oV;fwbSqlJR{33U3Dy4u+pr=V2$xC=ff^bG(wP?XU{MIy zL%p8+qw!|I5`wk2yUXtIsq~WMQ6~e~`19*)BD+!Z*^||1+Pt9-xAj;?)a~u90{It4 zj};v30j@zsA%)T{$i2<`5%;v1{Rtt$Q2~s73!CyBE`BJnNDmw%@VJ3d+PFBO*o|!6 zl;_>L==WUCI*MnRfEUfAxYdk1_}d!5Wxm$!i9&;e{JNk~D9mKX$xRVr54O^pLk*9N zl#??#-tj(OqF05A-nDHHB_=XPvX#zu!xRlQQ_|8JX*f8lpce+3n$ne==@91Q-P?8;g^pQ~0aQ~^C;fN@ld-Bh2_Q$JA=g`p5=7*Cu3lfW`=>7D6yCrNO zNhQZwbmY&5y>X@tJnJF;)Z?nEX_pZ{xZ(M!$G1YXoSPWA0ylh}m(aR_dL_r16T`@Y zchCm4SF1QcNonjc;G~6dSS--Ws)#_cxF%3!6UK%I;1dz$iMVaaXc!n6i1l=VLn4?4 z95)PY2%>jKV@PEP8{!KHuKQ7ESqh0uSDj)NeB-W8;^Nn*T^c|T;L1<7)c+$`se>%Y zxj>bC)lgD@B?^o&GYchun-xRbpa#kp4nA6L=s@?n(vSYx0uVWmlsW^HNme$ok2+X0 zfCa1n$x6$)fzy+;F6hagjSH+B(H1-|RI#o1Rv9t?f*^BR1@-c2V^!yU>C(J$+5E?i z?$8bri)#alw-)QoonOZpO6iylk)7c!P^d?RX=^7M^i*&xr1~>(MDtkiu0O`nFKL%z z_Wwq-dBl+7466~|tUqs8^GOh#EDqbo1zlY3p-Xb$%Qj~$DCvr!ffv90pDqt(i|rn7 z&xb%D6D_&69}d~L>6MY02g!Z*?Vqoz&O)9)JC}GsnQ;R0z7RJr%~AIb%|+h?^dw*L zsPrA8*b zkJ`kgu9&LRguPD(AqjZHqLdhSR0KP8A>%ZYH2yv^qNoHF6}p`ICf!9p6nc}3^49^xnd@2gZZfYC>{|GYD1V0h}^TuW8(JQ_XCxzhk zaUpe3EvV`2wxk{JX1nMV|M)Rs9mnVUtxmrxuZ4xhUc=w=`w#(%bw}`z!+_Qv&M8Au z5L1Pk#4F|wob?F^cUzV)CEva44I79hVzlLjqRX-o#tuEVOdxhqjSD4#whU}%G(9o! zpeS85t%cpRvwd%|&gKPk;{+qudC4($ho^WQBwR|xno@;#(7Hv2iiLwl+#xaP2os?jy21@=-5cLP-)zD@N~0Y z<>|@j1(LeH6lP61&5f{HeNR($O`JwRL}@hoTWU~` z*K*Ny%J%V4V%>kV??;2ny7hWF1Z{-dXFo$wd6w%16GAxIS3c!-8XSH-FJ(N4M~tO9Oj!c zPH#1xlJdB{7tDMBh_XHQq%BiQAt5Iq820V72mL=fMg=Md%a*)(Yr{5!!UL~E5Zp2{ zGW61YOiU;T6RAR+LE`ix4whYF_uXmzO^2dm($p10Sh@bTTf;24gv@+=UL09mtq#g) zuU?V34^j9SeX(kxlmI;wFjDmbfySoCvJ|CO?xADtj?8~o+XTcP&-!SBRPhddCASj4HjJvMi; zT{`t?W40J6DRc2DtapAI$qbIy$<21jP?8 zuH@C3Uafv+<*d?GlcJ0+ zsf_)HIzgnRsnvh0v$=Ul;^on!kb2IL7*NMQe||XCbzZ7JINaLW65FTU|I&*HfU=Dw zu0{-G@BWI|;o0fz##w^SE6u{&6Pl`G1bn_{8v#^7SJS-S7k?<;rs@c4rR^-Glk0ja z_;u5fT#eJ*pX+ z*xlWw6!F*{TQ4gs^J%c7za;}bod)EH$jJ3ByIBS@KPhu_nt0Gc+hZ?ui+<4h1^VFv zmAaL|-)FD&D`1Q`I67#(_^@hgspf5dY9?mpgT8dr;Ki*SNO`0UJO??Oa-QV9onk`lhxa-$7Z(6onZS|T5TOXpSDH*qkBt1PG z>@iUpJM?0dlI;c+(3K{abv95DjEQ(3=@r_6?L{?v`@gb)oGC1_>Zi1k$!}s}i^2bV z(ctp|qOZlu*}FBRH8hW)tMa?eW-=ALvsTXJuNsre@^;6viqv;upQJy%d82JtQX=() zf`!qxlV&)#=B#k``FOc$*~E7{f5=J{w&f)q%NF23mV9AA@Zt9KG)F^2 zMYUZJV?K@s6)4bPK(Xr}zC=c0kP)@Nb+X!~3KjMmftAno*f(s=>za;(2AfFG_=kW( z9;S_V8X7b5Qc_a)V9@sC$prqnuj9;6`uv?{f6 z;rrCo6i%YVvu|jm&dT8JQQc%ICu_M_gCMZ@1quz0ULpq5xb`*3rig%=PWC2=FW?fsReb;6*LxyIh-flT zLbW13CI-#_=^8ewp`jrTmw)Z0{}dtI4!;I2%P-Kxekqzg_^gt_`R(CovF^?G_I4F> z#b`PQ*onc^2IVjkxLs_}(9m>1miOGHW8GrW2b)N_;G9S<#A5}Dk79E>Fmr- z&&c?Ki-W^O02zc?o$G>K-(v$kYVV`pHEhrTu=ir4C@n3`_>dJ6!U$GbXi9SONAZAv ztPS`&WvR%Rr1db^E9QHS#$P$px*@5YALC~@5TYLl?wLVEF?uBaIWmdSN=8% z=ruQBv7N}~cQPn7IepS&r0pH$=*r0kJJg}GD_xD8MfKPw@UOUzzy*y)q>Vp`4jWG`QU#fM>++<%S>h)>5~13iz-l6b~mP+FGtb z=S*R*znx%1yx$l7vL8F0%Nvv-m37vYv&KrK#1q%>7Fk# z+ABED2Bycr541o(|u0!!Q7-Tl*Q;LGz9 zf)l@?McL7bXZ;3dFDohrq~w+OF2XH-cSyEOjkF8BE*wN3`yHI)z&yhvAHb0zQ*&|^ zQb%nI*N(QK0yr#ZPBuy^ySde{D&YFAd63+JPPCq~va)m&m6nv9!U@Wm_Zz=B1Zr(M*BLTyRFDHU^A*!g$INFUT_n3S1^he@0y=;*`eOz76`8Xe#b2|G!-=|}7XbxJ zl*eVQ-QA~4Rs62M)p4=b3*4^vwW0fl>5q;Db+3BfgiOc^(2 z3!E%mx;p9=L^EQD6fgpi!=Hh-&L%g>Mxw#)Mg-o#p#s6k)dO@f`qom_h0)W+`q;c` z2A{qG_W<^{z*{y3^_11VGObd|uMEl;wp<`q{dk3rez@>n2MI`kzm3<&o>40B?M3J4 z0e(mcnbX(dKpy~N)cnCe?sZ{(99Z2haDTv=cJ(=7;~Q6qK&%+lMI8wd-#}`B3+005 zQJfQG;07)VZr#AqPI%rwu<3y5hYCpI6!a51WqkhF8tTI`ogt3+Vy|4U}3P}R5ge4~p;F8m!ob_kM5 z?+OAn@rZ2&*XmytAmo#~;T^I-*Jc8DkR4%oTRziMrSVok!X6;sd3*H8`@u)6wmri;U1B@iR-9S;C>@fuWa7np>+HCt&@CZ zqICW~h1pB0&b3pV7bJ-y*q?h-`K3M7?l9gc#K8h1w;!(0k>9fAGzV ztf)<3wv;&p>ZggdO6aF$&rF9Y7x*r)qPFFG65xG{^UW0^(Dz@LbwZf1r5GS~1OIluSOm4XN4J?;eYrPSeEyA-d2nS`+b(Os7J z3AYWvb1@E~weVKD$kwuvm~ue|(#{(o=Bb==n9F<*O(9tnaSU@}hv`%V>aqH$tcFo> znk|!L)NA?{K0m|mc`k|?E~fPYFGV7yjoJ>b{lxcaMfnT<4_P-P$cv!Kx^4adQp!b! z5z;HQ@LzU0?F$wWkqBziN&g7e-~|!?nkK-K5*GTSxf1qXePwz^VH;u^@(6e{i!-tC zGp|h^flX7h_s^dYu@vV!tUBsu%2aNY5eb2gXitMM*)?Pwlj`3=bSIMBz~0W{iz8j< zEJ!O(k$WG_a0lW~5?Gktu!}*U<7RVYIVg%IU=Z!zY$gapLlfHFSGHaPSq4n1`QqT zH+Rcc5K}KNdJNpGA5pBlz?KD_2s9l;o023~S)g3azx=yguOH-70X4iNxZ0Igxbuq* zyuu9|yQfPOLdQBV;Vrku&(=(eE*89NVi(u-O27s&+zX;vxIQ*+e!W@?(Ae-3-|4kY zZls`&Id3?%k#>+leT)>6Y@RQ^BpoDj3bHnfsv->S$U@y)sh0cc(m(2TJJ85!%2=D9 z6M=7uJCMs3U#?NoPQqh2!wskS_KH76r<5$KYQ3H@XFWQSdtg>gb!zlOj&Ee1yBgWF*^8A;ks@@eMz*qMbh6q(soy4f3p)5TUg;gx?1lAJ6|Q zQe$D&Gpwj@jBokWV`D-pWln zlstAy6q}fM-y8!}Kl2-g!ZAKVQ%*2BX zoP`z|jej0VnkKEIjtl=7d4~y+1|gdfzwC-bEvvIf?MUGl;0#uK)2~d)3i$MO)S~bM zBf`YpKGsscq%ja#Nv?giNba2HSGvlG6YoxV(R;C&gvVd9kZ3Sso;~1Vp7!0C2py|9 zqql@2t)2(~RS_0DoJ#)fS85DK#hFN(axi9sL1KxZd(XrLPB2)+Bg0ksBwqXdhH8IH zYRsFe&UsV(co857;I@w}6TW=UWbB0q!8LL+%ZeA49ixl691Bwe2I`%|xe2x~B@i+; zIR}NdpTYSFsj)5!NM+X17&Qz5G1cStW)pknOqUu#6n9{ys9 zV~T_WdAkyq)E(Z0eec*d!F5*fS0?t*kG}(ElYVMOr@)a%UL;cebuRMmH$IMfpn>2e z2&R8ST`&dWc%ut+izc}=#qdYE?wL~VIurp@gbeUR&Coa2?OUvosd=%^aU5$=dYKWaM7)LPETH5dj;V+_o@ zL<*4wzzS)*%9a7VjD&;~59PK}{M7qj{~r|$M`>vwRNUQk&?{ODEA;OxoQ zC?TzFeL)lOR4_-wz##VlkD>DasZamGy^3_x5Qmls*x9P`vpI5QpH9|3_iUyDn+SKT0!t~_1q zcsN~7E>=M>RmEy#Jn(Ft{>rF2QBmP^Avo%PJDc~c^}EgIRO0UcqQn^qX%5sqA{KRv z`vzv*nP_lyx2@#QO2$93(Xp^7Z>FSQlW3JXhzwpX+T_J2Bqp9>MCLS*w8n7`3=XQ0 z@K`Iw3Xls64XJJ>Ta4o zN>wuJ;{kf<-$YK^FSFVNe6Eg{iEwamwhi8POoXd&D1kk7)6qg zMW06hY#CzoQNC@pb9B)to5$0wFql6oN(0>+d@8D!#;Us$)Hy2y21ZBz&B-Y%HwI%)e~q2}M|m)yvk=_ixPNt`(J(0yDOoZ^09*NuY)n z>+MU;t~~M + + + + + + + + + + + + + image/svg+xml + + + + + + + if (unit == "char") moveOnce(); else if (unit == "column") moveOnce(true); else if (unit == "word" || unit == "group") { var sawType = null, group = unit == "group"; for (var first = true;; first = false) { if (dir < 0 && !moveOnce(!first)) break; var cur = lineObj.text.charAt(ch) || "\n"; var type = isWordChar(cur) ? "w" : !group ? null : /\s/.test(cur) ? null : "p"; // punctuation if (sawType && sawType + + Code Mirror + + diff --git a/doc/manual.html b/doc/manual.html index 532285163c..37230f5426 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1,38 +1,63 @@ - - - - CodeMirror: User Manual - - - - - - - - - - - - - - - -

    { } CodeMirror

    - -
    - -
    -/* User manual and
    -   reference guide */
    -
    + +CodeMirror: User Manual + + + + + + + + + + + + + + + -
    +
    -

    Overview

    +
    +

    User manual and reference guide

    CodeMirror is a code-editor component that can be embedded in Web pages. The core library provides only the editor @@ -50,8 +75,10 @@

    Overview

    of modes (see the mode/ directory), and it isn't hard to write new ones for other languages.

    +
    -

    Basic Usage

    +
    +

    Basic Usage

    The easiest way to use CodeMirror is to simply load the script and style sheet found under lib/ in the distribution, @@ -107,7 +134,9 @@

    Basic Usage

    of a form) is submitted. See the API reference for a full description of this method.

    -

    Configuration

    +
    +
    +

    Configuration

    Both the CodeMirror function and its fromTextArea method take as second @@ -372,8 +401,10 @@

    Configuration

    This will have bad effects on performance of big documents. +
    -

    Events

    +
    +

    Events

    Various CodeMirror-related objects emit events, which allow client code to react to various situations. Handlers for such @@ -589,8 +620,10 @@

    Events

    or the line the widget is on require the widget to be redrawn. +
    -

    Keymaps

    +
    +

    Keymaps

    Keymaps are ways to associate keys with functionality. A keymap is an object mapping strings that identify the keys to functions @@ -661,8 +694,10 @@

    Keymaps

    to true, the default effect of inserting a character will be suppressed when the keymap is active as the top-level map.

    +
    -

    Customized Styling

    +
    +

    Customized Styling

    Up to a certain extent, CodeMirror's look can be changed by modifying style sheet files. The style sheets supplied by modes @@ -740,8 +775,10 @@

    Customized Styling

    Themes are also simply CSS files, which define colors for various syntactic elements. See the files in the theme directory.

    +
    -

    Programming API

    +
    +

    Programming API

    A lot of CodeMirror features are only available through its API. Thus, you need to write code (or @@ -1620,8 +1657,10 @@

    Static properties

    returned position will be the end of the changed range, after the change is applied. +
    -

    Addons

    +
    +

    Addons

    The addon directory in the distribution contains a number of reusable components that implement extra editor @@ -2088,8 +2127,10 @@

    Addons

    will highlight changes between the editable document and the original(s) (demo). +
    -

    Writing CodeMirror Modes

    +
    +

    Writing CodeMirror Modes

    Modes typically consist of a single JavaScript file. This file defines, in the simplest case, a lexer (tokenizer) for your @@ -2318,43 +2359,8 @@

    Writing CodeMirror Modes

    specifies the properties that should be added. This is mostly useful to add utilities that can later be looked up through getMode.

    +
    -
    - -
     
    + - - - diff --git a/doc/modes.html b/doc/modes.html deleted file mode 100644 index 82738f19e6..0000000000 --- a/doc/modes.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - CodeMirror: Mode list - - - - - -

    { } CodeMirror

    - -
    - -
    -/* Full list of
    -   modes */
    -
    -
    - -

    Every mode in the distribution. The list on the front-page leaves -out some of the more obscure ones.

    - - - - - diff --git a/doc/realworld.html b/doc/realworld.html index 36c95b3ea0..9b6d7386fb 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -1,23 +1,26 @@ - - - - CodeMirror: Real-world uses - - - - -

    { } CodeMirror

    +CodeMirror: Real-world Uses + + -
    - -
    -/* Real world uses,
    -   full list */
    -
    + +
    + +

    CodeMirror real-world uses

    +

    Contact me if you'd like your project to be added to this list.

    @@ -117,5 +120,5 @@

    { } CodeMi
  • xsd2codemirror (convert XSD to CM XML completion info)
  • - - +

    + diff --git a/doc/oldrelease.html b/doc/releases.html similarity index 70% rename from doc/oldrelease.html rename to doc/releases.html index c72dc8f61a..93650b8fe0 100644 --- a/doc/oldrelease.html +++ b/doc/releases.html @@ -1,24 +1,196 @@ - - - - CodeMirror - - - - - - -

    { } CodeMirror

    - -
    - -
    -/* Old release
    -   history */
    -
    + +CodeMirror: Release History + + + + + +
    + +

    Release notes and version history

    + +
    + +

    Version 3.x

    + +

    29-07-2013: Version 3.15:

    + + + +

    20-06-2013: Version 3.14:

    + + + +

    20-05-2013: Version 3.13:

    + + + +

    19-04-2013: Version 3.12:

    + + + +

    20-03-2013: Version 3.11:

    + + + +

    21-02-2013: Version 3.1:

    + + + + +

    25-01-2013: Version 3.02:

    + +

    Single-bugfix release. Fixes a problem that + prevents CodeMirror instances from being garbage-collected after + they become unused.

    + +

    21-01-2013: Version 3.01:

    + + + +

    10-12-2012: Version 3.0:

    + +

    New major version. Only + partially backwards-compatible. See + the upgrading guide for more + information. Changes since release candidate 2:

    + +
      +
    • Rewritten VIM mode.
    • +
    • Fix a few minor scrolling and sizing issues.
    • +
    • Work around Safari segfault when dragging.
    • +
    • Full list of patches.
    • +
    +

    20-11-2012: Version 3.0, release candidate 2:

    -

    20-11-2012: Version 2.36:

    - - -

    20-11-2012: Version 3.0, release candidate 1:

    -

    22-10-2012: Version 2.35:

    - -
      -
    • New (sub) mode: TypeScript.
    • -
    • Don't overwrite (insert key) when pasting.
    • -
    • Fix several bugs in markText/undo interaction.
    • -
    • Better indentation of JavaScript code without semicolons.
    • -
    • Add defineInitHook function.
    • -
    • Full list of patches.
    • -
    -

    22-10-2012: Version 3.0, beta 2:

    +

    19-09-2012: Version 3.0, beta 1:

    + +
      +
    • Bi-directional text support.
    • +
    • More powerful gutter model.
    • +
    • Support for arbitrary text/widget height.
    • +
    • In-line widgets.
    • +
    • Generalized event handling.
    • +
    + +
    + +
    + +

    Version 2.x

    + +

    21-01-2013: Version 2.38:

    + +

    Integrate some bugfixes, enhancements to the vim keymap, and new + modes + (D, Sass, APL) + from the v3 branch.

    + +

    20-12-2012: Version 2.37:

    + +
      +
    • New mode: SQL (will replace plsql and mysql modes).
    • +
    • Further work on the new VIM mode.
    • +
    • Fix Cmd/Ctrl keys on recent Operas on OS X.
    • +
    • Full list of patches.
    • +
    + +

    20-11-2012: Version 2.36:

    + + + +

    22-10-2012: Version 2.35:

    + +
      +
    • New (sub) mode: TypeScript.
    • +
    • Don't overwrite (insert key) when pasting.
    • +
    • Fix several bugs in markText/undo interaction.
    • +
    • Better indentation of JavaScript code without semicolons.
    • +
    • Add defineInitHook function.
    • +
    • Full list of patches.
    • +
    +

    19-09-2012: Version 2.34:

    -

    19-09-2012: Version 3.0, beta 1:

    - -
      -
    • Bi-directional text support.
    • -
    • More powerful gutter model.
    • -
    • Support for arbitrary text/widget height.
    • -
    • In-line widgets.
    • -
    • Generalized event handling.
    • -
    -

    23-08-2012: Version 2.33:

    +
    + +
    + +

    Version 0.x

    + +

    28-03-2011: Version 1.0:

    +
      +
    • Fix error when debug history overflows.
    • +
    • Refine handling of C# verbatim strings.
    • +
    • Fix some issues with JavaScript indentation.
    • +

    17-12-2010: Version 0.92:

      @@ -527,20 +726,17 @@

      { } CodeMi parser. And, as usual, add workarounds for various newly discovered browser incompatibilities.

      -

      31-08-2009: Version -0.63:

      -

      Overhaul of paste-handling (less fragile), fixes for several -serious IE8 issues (cursor jumping, end-of-document bugs) and a number -of small problems.

      - -

      30-05-2009: Version -0.62:

      -

      Introduces Python -and Lua parsers. Add -setParser (on-the-fly mode changing) and -clearHistory methods. Make parsing passes time-based -instead of lines-based (see the passTime option).

      - - +

      31-08-2009: Version 0.63:

      +

      Overhaul of paste-handling (less fragile), fixes for several + serious IE8 issues (cursor jumping, end-of-document bugs) and a number + of small problems.

      + +

      30-05-2009: Version 0.62:

      +

      Introduces Python + and Lua parsers. Add + setParser (on-the-fly mode changing) and + clearHistory methods. Make parsing passes time-based + instead of lines-based (see the passTime option).

      + +

    +
    diff --git a/doc/reporting.html b/doc/reporting.html index a616512530..47e37a5541 100644 --- a/doc/reporting.html +++ b/doc/reporting.html @@ -1,24 +1,26 @@ - - - - CodeMirror: Reporting Bugs - - - - - - -

    { } CodeMirror

    - -
    - -
    -/* Reporting bugs
    -   effectively */
    -
    + +CodeMirror: Reporting Bugs + + + + +
    + +

    Reporting bugs effectively

    +

    So you found a problem in CodeMirror. By all means, report it! Bug @@ -56,5 +58,4 @@

    { } CodeMi

    - - +
    diff --git a/doc/upgrade_v2.2.html b/doc/upgrade_v2.2.html index 7e4d840043..a2dddef760 100644 --- a/doc/upgrade_v2.2.html +++ b/doc/upgrade_v2.2.html @@ -1,36 +1,37 @@ - - - - CodeMirror: Upgrading to v2.2 - - - - - -

    { } CodeMirror

    - -
    - -
    -/* Upgrading to
    -   v2.2 */
    -
    + +CodeMirror: Version 2.2 upgrade guide + + + + -
    +
    + +

    Upgrading to v2.2

    There are a few things in the 2.2 release that require some care when upgrading.

    -

    No more default.css

    +

    No more default.css

    The default theme is now included in codemirror.css, so you do not have to included it separately anymore. (It was tiny, so even if you're not using it, the extra data overhead is negligible.) -

    Different key customization

    +

    Different key customization

    CodeMirror has moved to a system where keymaps are used to @@ -81,7 +82,7 @@

    Different key customization

    behaviors. Or you can write your own handler function to do something different altogether.

    -

    Tabs

    +

    Tabs

    Handling of tabs changed completely. The display width of tabs can now be set with the tabSize option, and tabs can @@ -92,7 +93,4 @@

    Tabs

    hard-wired into browsers. If you are relying on 8-space tabs, make sure you explicitly set tabSize: 8 in your options.

    -
    - - - + diff --git a/doc/upgrade_v3.html b/doc/upgrade_v3.html index 7e8a6b61ae..19757924c1 100644 --- a/doc/upgrade_v3.html +++ b/doc/upgrade_v3.html @@ -1,32 +1,44 @@ - - - - CodeMirror: Upgrading to v3 - - - - - - - - - - - - - -

    { } CodeMirror

    - -
    - -
    -/* Upgrading to
    -   version 3 */
    -
    + +CodeMirror: Version 3 upgrade guide + + + + + + + + + + + + + -
    +
    + +

    Upgrading to version 3

    Version 3 does not depart too much from 2.x API, and sites that use CodeMirror in a very simple way might be able to upgrade without @@ -37,7 +49,8 @@

    { } CodeMi Explorer 7. The editor will mostly work on that browser, but it'll be significantly glitchy.

    -

    DOM structure

    +
    +

    DOM structure

    This one is the most likely to cause problems. The internal structure of the editor has changed quite a lot, mostly to implement a @@ -53,8 +66,9 @@

    DOM structure

    See the styling section of the manual for more information.

    - -

    Gutter model

    +
    +
    +

    Gutter model

    In CodeMirror 2.x, there was a single gutter, and line markers created with setMarker would have to somehow coexist with @@ -87,8 +101,9 @@

    Gutter model

    cm.setGutterMarker(0, "note-gutter", document.createTextNode("hi")); </script> - -

    Event handling

    +
    +
    +

    Event handling

    Most of the onXYZ options have been removed. The same effect is now obtained by calling @@ -107,8 +122,9 @@

    Event handling

    console.log("something changed! (" + change.origin + ")"); }); - -

    markText method arguments

    +
    +
    +

    markText method arguments

    The markText method (which has gained some interesting new features, such as creating @@ -124,8 +140,9 @@

    markText method arguments

    atomic: true }); - -

    Line folding

    +
    +
    +

    Line folding

    The interface for hiding lines has been removed. markText can @@ -146,8 +163,9 @@

    Line folding

    console.log("boom"); }); - -

    Line CSS classes

    +
    +
    +

    Line CSS classes

    The setLineClass method has been replaced by addLineClass @@ -160,8 +178,9 @@

    Line CSS classes

    cm.removeLineClass(marked, "background", "highlighted-line"); }); - -

    Position properties

    +
    +
    +

    Position properties

    All methods that take or return objects that represent screen positions now use {left, top, bottom, right} properties @@ -171,14 +190,16 @@

    Position properties

    Affected methods are cursorCoords, charCoords, coordsChar, and getScrollInfo.

    - -

    Bracket matching no longer in core

    +
    +
    +

    Bracket matching no longer in core

    The matchBrackets option is no longer defined in the core editor. Load addon/edit/matchbrackets.js to enable it.

    - -

    Mode management

    +
    +
    +

    Mode management

    The CodeMirror.listModes and CodeMirror.listMIMEs functions, used for listing @@ -186,8 +207,9 @@

    Mode management

    inspect CodeMirror.modes (mapping mode names to mode constructors) and CodeMirror.mimeModes (mapping MIME strings to mode specs).

    - -

    New features

    +
    +
    +

    New features

    Some more reasons to upgrade to version 3.

    @@ -202,26 +224,7 @@

    New features

  • Defining custom options with CodeMirror.defineOption.
  • - -

    + + - - diff --git a/index.html b/index.html index 2f2ba05096..3bd665e871 100644 --- a/index.html +++ b/index.html @@ -1,480 +1,186 @@ - - - - CodeMirror - - - - - -

    { } CodeMirror

    +CodeMirror + -
    - -
    -/* In-browser code editing
    -   made bearable */
    -
    -
    - -
    - -

    CodeMirror is a JavaScript component that - provides a code editor in the browser. When a mode is available for - the language you are coding in, it will color your code, and - optionally help with indentation.

    - -

    A rich programming API and a CSS - theming system are available for customizing CodeMirror to fit your - application, and extending it with new functionality.

    - - - -

    Getting the code

    - -

    All of CodeMirror is released under a MIT-style license. To get it, you can download - the latest - release or the current development - snapshot as zip files. To create a custom minified script file, - you can use the compression API.

    - -

    We use git for version control. - The main repository can be fetched in this way:

    - -
    git clone http://marijnhaverbeke.nl/git/codemirror
    - -

    CodeMirror can also be found on GitHub at marijnh/CodeMirror. - If you plan to hack on the code and contribute patches, the best way - to do it is to create a GitHub fork, and send pull requests.

    - -

    Documentation

    - -

    The manual is your first stop for - learning how to use this library. It starts with a quick explanation - of how to use the editor, and then describes the API in detail.

    + + + + + + + + -

    For those who want to learn more about the code, there is - a series of - posts on CodeMirror on my blog, and the - old overview of the editor - internals. - The source code - itself is, for the most part, also very readable.

    + -

    Support and bug reports

    + -

    Community discussion, questions, and informal bug reporting is - done on - the CodeMirror - Google group. There is a separate - group, CodeMirror-announce, - which is lower-volume, and is only used for major announcements—new - versions and such. These will be cross-posted to both groups, so you - don't need to subscribe to both.

    - -

    Though bug reports through e-mail are responded to, the preferred - way to report bugs is to use - the GitHub - issue tracker. Before reporting a - bug, read these pointers. Also, - the issue tracker is for bugs, not requests for help.

    - -

    When none of these seem fitting, you can - simply e-mail the maintainer - directly.

    - -

    Supported browsers

    - -

    The following desktop browsers are able to run CodeMirror:

    + -
    - - Download the latest release - -

    Support CodeMirror

    - +
    + +
    +

    CodeMirror is a versatile text editor + implemented in JavaScript for the browser. It is specialized for + editing code, and comes with a number of language modes and addons + that implement more advanced editing functionaly.

    + +

    A rich programming API and a + CSS theming system are + available for customizing CodeMirror to fit your application, and + extending it with new functionality.

    +
    + +
    +

    This is CodeMirror

    + + + +
    + DOWNLOAD LATEST RELEASE +
    version 3.15 (Release notes)
    + +
    + DONATE WITH PAYPAL +
    + or Bank, + Gittip, + Flattr
    +
    + × + Bank: Rabobank
    + Country: Netherlands
    + SWIFT: RABONL2U
    + Account: 147850770
    + Name: Marijn Haverbeke
    + IBAN: NL26 RABO 0147 8507 70 +
    +
    + + +
    +
    +
    + Purchase commercial support +
    +
    +
    +
    + +
    +

    Features

    +
    + +
    +

    Community

    + +

    CodeMirror is an open-source project shared under + an MIT license. It is the editor used in + Light + Table, Adobe + Brackets, Google Apps + Script, Bitbucket, + and many other projects.

    + +

    Development and bug tracking happens + on github + (alternate git + repository). + Please read these + pointers before submitting a bug. Use pull requests to submit + patches. All contributions must be released under the same MIT + license that CodeMirror uses.

    + +

    Discussion around the project is done on + a mailing list. + There is also + the codemirror-announce + list, which is only used for major announcements (such as new + versions). If needed, you can + contact the maintainer + directly.

    - - -

    Reading material

    - - - -

    Releases

    - -

    29-07-2013: Version 3.15:

    - - - -

    20-06-2013: Version 3.14:

    - - - -

    20-05-2013: Version 3.13:

    - - - -

    19-04-2013: Version 3.12:

    - - - -

    20-03-2013: Version 3.11:

    - - - -

    21-02-2013: Version 3.1:

    - - - - -

    25-01-2013: Version 3.02:

    - -

    Single-bugfix release. Fixes a problem that - prevents CodeMirror instances from being garbage-collected after - they become unused.

    - -

    21-01-2013: Version 3.01:

    - - - -

    21-01-2013: Version 2.38:

    - -

    Integrate some bugfixes, enhancements to the vim keymap, and new - modes - (D, Sass, APL) - from the v3 branch.

    - -

    20-12-2012: Version 2.37:

    - -
      -
    • New mode: SQL (will replace plsql and mysql modes).
    • -
    • Further work on the new VIM mode.
    • -
    • Fix Cmd/Ctrl keys on recent Operas on OS X.
    • -
    • Full list of patches.
    • -
    - -

    10-12-2012: Version 3.0:

    - -

    New major version. Only - partially backwards-compatible. See - the upgrading guide for more - information. Changes since release candidate 2:

    - -
      -
    • Rewritten VIM mode.
    • -
    • Fix a few minor scrolling and sizing issues.
    • -
    • Work around Safari segfault when dragging.
    • -
    • Full list of patches.
    • -
    - -

    Older releases...

    - -
    - -
     
    - -
    - - -
    - - - +

    A list of CodeMirror-related software that is not part of the + main distribution is maintained + on our + wiki. Feel free to add your project.

    + + +
    +

    Browser support

    +

    The desktop versions of the following browsers, + in standards mode (HTML5 <!doctype html> + recommended) are supported:

    + + + + + + +
    Firefoxversion 3 and up
    Chromeany version
    Safariversion 5.2 and up
    Internet Explorerversion 8 and up
    Operaversion 9 and up
    +

    Modern mobile browsers tend to partly work. Bug reports and + patches for mobile support, but the maintainer does not have the + time budget to actually work on it himself.

    +
    + + diff --git a/mode/apl/index.html b/mode/apl/index.html index 119ff17f19..f8282ac42f 100644 --- a/mode/apl/index.html +++ b/mode/apl/index.html @@ -1,20 +1,32 @@ - - - - CodeMirror: APL mode - - - - - - - - -

    CodeMirror: APL mode

    + +
    +

    APL mode

    
       

    MIME type defined: text/x-vb.

    - + diff --git a/mode/vbscript/index.html b/mode/vbscript/index.html index 9ae46676b2..9b506b7985 100644 --- a/mode/vbscript/index.html +++ b/mode/vbscript/index.html @@ -1,16 +1,30 @@ - - - - CodeMirror: VBScript mode - - - - - - - -

    CodeMirror: VBScript mode

    + +CodeMirror: VBScript mode + + + + + + + + + +
    +

    VBScript mode

    +
    HTML:
    - @@ -1817,8 +1817,9 @@

    Addons

    finds blocks in brace languages (JavaScript, C, Java, etc), CodeMirror.fold.indent, for languages where indentation determines block structure (Python, Haskell), - and CodeMirror.fold.xml, for XML-style - languages. + and CodeMirror.fold.xml, for XML-style languages, + and CodeMirror.fold.comment, for folding comment + blocks.
    widget: string|Element
    The widget to show for folded ranges. Can be either a string, in which case it'll become a span with diff --git a/mode/xquery/xquery.js b/mode/xquery/xquery.js index f4e3362905..04ddb8f5ae 100644 --- a/mode/xquery/xquery.js +++ b/mode/xquery/xquery.js @@ -443,10 +443,10 @@ CodeMirror.defineMode("xquery", function() { var style = state.tokenize(stream, state); return style; }, - + blockCommentStart: "(:", blockCommentEnd: ":)" - + }; }); From cc56aa020df77db22c20a68132b0ec6e7508b6f6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 19 Aug 2013 15:00:02 +0200 Subject: [PATCH 0904/5273] [manual] Fix accidental change --- doc/manual.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index bb4680d30c..7a85ef7f70 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -14,7 +14,7 @@ From c3f4f321bf8564cb60fa8dad442985fb98a318a2 Mon Sep 17 00:00:00 2001 From: "SCLINIC\\jdecker" Date: Tue, 13 Aug 2013 09:58:55 -0500 Subject: [PATCH 0905/5273] Added ability to disable cursor blinking. When the cursor blink rate is zero (or negative) the cursor should not blink. Previously, it was blinking as fast as possible when the rate was zero. --- lib/codemirror.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index af20122ae9..15a3daaaef 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -877,9 +877,10 @@ window.CodeMirror = (function() { clearInterval(display.blinker); var on = true; display.cursor.style.visibility = display.otherCursor.style.visibility = ""; - display.blinker = setInterval(function() { - display.cursor.style.visibility = display.otherCursor.style.visibility = (on = !on) ? "" : "hidden"; - }, cm.options.cursorBlinkRate); + if (cm.options.cursorBlinkRate > 0) + display.blinker = setInterval(function() { + display.cursor.style.visibility = display.otherCursor.style.visibility = (on = !on) ? "" : "hidden"; + }, cm.options.cursorBlinkRate); } // HIGHLIGHT WORKER From b71833f9b264fc1c57eeb0e5b340030ed56f5f7d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 19 Aug 2013 15:11:14 +0200 Subject: [PATCH 0906/5273] [manual] Mention cursorBlinkRate=0 functionality Issue #1741 --- doc/manual.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index 7a85ef7f70..3d0b70b6dd 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -344,7 +344,7 @@

    Configuration

    cursorBlinkRate: number
    Half-period in milliseconds used for cursor blinking. The default blink - rate is 530ms.
    + rate is 530ms. By setting this to zero, blinking can be disabled.
    cursorScrollMargin: number
    How much extra space to always keep above and below the From 7b883926072d71fd2d41a7ed20c63d54ee128b6b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 19 Aug 2013 15:21:55 +0200 Subject: [PATCH 0907/5273] [midnight theme] Make tag style contrast with background Closes #1744 --- theme/midnight.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/midnight.css b/theme/midnight.css index d51c915e1c..f8016a81d8 100644 --- a/theme/midnight.css +++ b/theme/midnight.css @@ -34,7 +34,7 @@ .cm-s-midnight span.cm-def {color: #4DD;} .cm-s-midnight span.cm-error {background: #F92672; color: #F8F8F0;} .cm-s-midnight span.cm-bracket {color: #D1EDFF;} -.cm-s-midnight span.cm-tag {color: #008;} +.cm-s-midnight span.cm-tag {color: #449;} .cm-s-midnight span.cm-link {color: #AE81FF;} .cm-s-midnight .CodeMirror-activeline-background {background: #192741 !important;} From 7218f45a32d9c2641ea422e41c2e3c64eed8bb7d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 19 Aug 2013 15:27:05 +0200 Subject: [PATCH 0908/5273] [themes] Update existing activeline rules to use correct class Rather than adding a new rule. Issue #1747 --- theme/ambiance.css | 4 +--- theme/midnight.css | 3 +-- theme/solarized.css | 12 ++---------- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/theme/ambiance.css b/theme/ambiance.css index 9c4a047da9..53e9ce78f7 100644 --- a/theme/ambiance.css +++ b/theme/ambiance.css @@ -65,12 +65,10 @@ border-left: 1px solid #7991E8; } -.cm-s-ambiance .activeline { +.cm-s-ambiance .CodeMirror-activeline-background { background: none repeat scroll 0% 0% rgba(255, 255, 255, 0.031); } -.cm-s-ambiance .CodeMirror-activeline-background {background: #3C3636 !important;} - .cm-s-ambiance.CodeMirror, .cm-s-ambiance .CodeMirror-gutters { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAQAAAAHUWYVAABFFUlEQVQYGbzBCeDVU/74/6fj9HIcx/FRHx9JCFmzMyGRURhLZIkUsoeRfUjS2FNDtr6WkMhO9sm+S8maJfu+Jcsg+/o/c+Z4z/t97/vezy3z+z8ekGlnYICG/o7gdk+wmSHZ1z4pJItqapjoKXWahm8NmV6eOTbWUOp6/6a/XIg6GQqmenJ2lDHyvCFZ2cBDbmtHA043VFhHwXxClWmeYAdLhV00Bd85go8VmaFCkbVkzlQENzfBDZ5gtN7HwF0KDrTwJ0dypSOzpaKCMwQHKTIreYIxlmhXTzTWkVm+LTynZhiSBT3RZQ7aGfjGEd3qyXQ1FDymqbKxpspERQN2MiRjNZlFFQXfCNFm9nM1zpAsoYjmtRTc5ajwuaXc5xrWskT97RaKzAGe5ARHhVUsDbjKklziiX5WROcJwSNCNI+9w1Jwv4Zb2r7lCMZ4oq5C0EdTx+2GzNuKpJ+iFf38JEWkHJn9DNF7mmBDITrWEg0VWL3pHU20tSZnuqWu+R3BtYa8XxV1HO7GyD32UkOpL/yDloINFTmvtId+nmAjxRw40VMwVKiwrKLE4bK5UOVntYwhOcSSXKrJHKPJedocpGjVz/ZMIbnYUPB10/eKCrs5apqpgVmWzBYWpmtKHecJPjaUuEgRDDaU0oZghCJ6zNMQ5ZhDYx05r5v2muQdM0EILtXUsaKiQX9WMEUotagQzFbUNN6NUPC2nm5pxEWGCjMc3GdJHjSU2kORLK/JGSrkfGEIjncU/CYUnOipoYemwj8tST9NsJmB7TUVXtbUtXATJVZXBMvYeTXJfobgJUPmGMP/yFaWonaa6BcFO3nqcIqCozSZoZoSr1g4zJOzuyGnxTEX3lUEJ7WcZgme8ddaWvWJo2AJR9DZU3CUIbhCSG6ybSwN6qtJVnCU2svDTP2ZInOw2cBTrqtQahtNZn9NcJ4l2NaSmSkkP1noZWnVwkLmdUPOwLZEwy2Z3S3R+4rIG9hcbpPXHFVWcQdZkn2FOta3cKWQnNRC5g1LsJah4GCzSVsKnCOY5OAFRTBekyyryeyilhFKva75r4Mc0aWanGEaThcy31s439KKxTzJYY5WTHPU1FtIHjQU3Oip4xlNzj/lBw23dYZVliQa7WAXf4shetcQfatI+jWRDBPmyNeW6A1P5kdDgyYJlba0BIM8BZu1JfrFwItyjcAMR3K0BWOIrtMEXyhyrlVEx3ui5dUBjmB/Q3CXW85R4mBD0s7B+4q5tKUjOlb9qqmhi5AZ6GFIC5HXtOobdYGlVdMVbNJ8toNTFcHxnoL+muBagcctjWnbNMuR00uI7nQESwg5q2qqrKWIfrNUmeQocY6HuyxJV02wj36w00yhpmUFenv4p6fUkZYqLyuinx2RGOjhCXYyJF84oiU00YMOOhhquNdfbOB7gU88pY4xJO8LVdp6/q2voeB4R04vIdhSE40xZObx1HGGJ/ja0LBthFInKaLPPFzuCaYaoj8JjPME8yoyxo6zlBqkiUZYgq00OYMswbWO5NGmq+xhipxHLRW29ARjNKXO0wRnear8XSg4XFPLKEPUS1GqvyLwiuBUoa7zpZ0l5xxFwWmWZC1H5h5FwU8eQ7K+g8UcVY6TMQreVQT/8uQ8Z+ALIXnSEa2pYZQneE9RZbSBNYXfWYJzW/h/4j4Dp1tYVcFIC5019Vyi4ThPqSFCzjGWaHQTBU8q6vrVwgxP9Lkm840imWKpcLCjYTtrKuwvsKSnrvHCXGkSMk9p6lhckfRpIeis+N2PiszT+mFLspyGleUhDwcLrZqmyeylxwjBcKHEapqkmyangyLZRVOijwOtCY5SsG5zL0OwlCJ4y5KznF3EUNDDrinwiyLZRzOXtlBbK5ITHFGLp8Q0R6ab6mS7enI2cFrxOyHvOCFaT1HThS1krjCwqWeurCkk+willhCC+RSZnRXBiZaC5RXRIZYKp2lyfrHwiKPKR0JDzrdU2EFgpidawlFDR6FgXUMNa+g1FY3bUQh2cLCwosRdnuQTS/S+JVrGLeWIvtQUvONJxlqSQYYKpwoN2kaocLjdVsis4Mk80ESF2YpSkzwldjHkjFCUutI/r+EHDU8oCs6yzL3PhWiEooZdFMkymlas4AcI3KmoMMNSQ3tHzjGWCrcJJdYyZC7QFGwjRL9p+MrRkAGWzIaWCn9W0F3TsK01c2ZvQw0byvxuQU0r1lM0qJO7wW0kRIMdDTtXEdzi4VIh+EoIHm0mWtAtpCixlabgn83fKTI7anJe9ST7WIK1DMGpQmYeA58ImV6ezOGOzK2Kgq01pd60cKWiUi9Lievb/0vIDPHQ05Kzt4ddPckQBQtoaurjyHnek/nKzpQLrVgKPjIkh2v4uyezpv+Xoo7fPFXaGFp1vaLKxQ4uUpQQS5VuQs7BCq4xRJv7fwpVvvFEB3j+620haOuocqMhWd6TTPAEx+mdFNGHdranFe95WrWmIvlY4F1Dle2ECgc6cto7SryuqGGGha0tFQ5V53migUKmg6XKAo4qS3mik+0OZpAhOLeZKicacgaYcyx5hypYQE02ZA4xi/pNhOQxR4klNKyqacj+mpxnLTnnGSo85++3ZCZq6lrZkXlGEX3o+C9FieccJbZWVFjC0Yo1FZnJhoYMFoI1hEZ9r6hwg75HwzBNhbZCdJEfJwTPGzJvaKImw1yYX1HDAmpXR+ZJQ/SmgqMNVQb5vgamGwLtt7VwvP7Qk1xpiM5x5Cyv93E06MZmgs0Nya2azIKOYKCGBQQW97RmhKNKF02JZqHEJ4o58qp7X5EcZmc56trXEqzjCBZ1MFGR87Ql2tSTs6CGxS05PTzRQorkbw7aKoKXFDXsYW42VJih/q+FP2BdTzDTwVqOYB13liM50vG7wy28qagyuIXMeQI/Oqq8bcn5wJI50xH00CRntyfpL1T4hydYpoXgNiFzoIUTDZnLNRzh4TBHwbYGDvZkxmlyJloyr6tRihpeUG94GnKtIznREF0tzJG/OOr73JBcrSh1k6WuTprgLU+mnSGnv6Zge0NNz+kTDdH8nuAuTdJDCNb21LCiIuqlYbqGzT3RAoZofQfjFazkqeNWdYaGvYTM001EW2oKPvVk1ldUGSgUtHFwjKM1h9jnFcmy5lChoLNaQMGGDsYbKixlaMBmmsx1QjCfflwTfO/gckW0ruZ3jugKR3R5W9hGUWqCgxuFgsuaCHorotGKzGaeZB9DMsaTnKCpMtwTvOzhYk0rdrArKCqcaWmVk1+F372ur1YkKxgatI8Qfe1gIX9wE9FgS8ESmuABIXnRUbCapcKe+nO7slClSZFzpV/LkLncEb1qiO42fS3R855Su2mCLh62t1SYZZYVmKwIHjREF2uihTzB20JOkz7dkxzYQnK0UOU494wh+VWRc6Un2kpTaVgLDFEkJ/uhzRcI0YKGgpGWOlocBU/a4fKoJ/pEaNV6jip3+Es9VXY078rGnmAdf7t9ylPXS34RBSuYPs1UecZTU78WanhBCHpZ5sAoTz0LGZKjPf9TRypqWEiTvOFglL1fCEY3wY/++rbk7C8bWebA6p6om6PgOL2kp44TFJlVNBXae2rqqdZztOJpT87GQsE9jqCPIe9VReZuQ/CIgacsyZdCpIScSYqcZk8r+nsyCzhyfhOqHGOIvrLknC8wTpFcaYiGC/RU1NRbUeUpocQOnkRpGOrIOcNRx+1uA0UrzhSSt+VyS3SJpnFWkzNDqOFGIWcfR86DnmARTQ1HKIL33ExPiemeOhYSSjzlSUZZuE4TveoJLnBUOFof6KiysCbnAEcZgcUNTDOwkqWu3RWtmGpZwlHhJENdZ3miGz0lJlsKnjbwqSHQjpxnFDlTLLwqJPMZMjd7KrzkSG7VsxXBZE+F8YZkb01Oe00yyRK9psh5SYh29ySPKBo2ylNht7ZkZnsKenjKNJu9PNEyZpaCHv4Kt6RQsLvAVp7M9kIimmCUwGeWqLMmGuIotYMmWNpSahkhZw9FqZsVnKJhsjAHvtHMsTM9fCI06Dx/u3vfUXCqfsKRc4oFY2jMsoo/7DJDwZ1CsIKnJu+J9ldkpmiCxQx1rWjI+T9FwcWWzOuaYH0Hj7klNRVWEQpmaqosakiGNTFHdjS/qnUdmf0NJW5xsL0HhimCCZZSRzmSPTXJQ4aaztAwtZnoabebJ+htCaZ7Cm535ByoqXKbX1WRc4Eh2MkRXWzImVc96Cj4VdOKVxR84VdQsIUM8Psoou2byVHyZFuq7O8otbSQ2UAoeEWTudATLGSpZzVLlXVkPU2Jc+27lsw2jmg5T5VhbeE3BT083K9WsTTkFU/Osi0rC5lRlpwRHUiesNS0sOvmqGML1aRbPAxTJD9ZKtxuob+hhl8cwYGWpJ8nub7t5p6coYbMovZ1BTdaKn1jYD6h4GFDNFyT/Kqe1XCXphXHOKLZmuRSRdBPEfVUXQzJm5YGPGGJdvAEr7hHNdGZnuBvrpciGmopOLf5N0uVMy0FfYToJk90uUCbJupaVpO53UJXR2bVpoU00V2KOo4zMFrBd0Jtz2pa0clT5Q5L8IpQ177mWQejPMEJhuQjS10ref6HHjdEhy1P1EYR7GtO0uSsKJQYLiTnG1rVScj5lyazpqWGl5uBbRWl7m6ixGOOnEsMJR7z8J0n6KMnCdxhiNYQCoZ6CmYLnO8omC3MkW3bktlPmEt/VQQHejL3+dOE5FlPdK/Mq8hZxxJtLyRrepLThYKbLZxkSb5W52vYxNOaOxUF0yxMUPwBTYqCzy01XayYK0sJyWBLqX0MwU5CzoymRzV0EjjeUeLgDpTo6ij42ZAzvD01dHUUTPLU96MdLbBME8nFBn7zJCMtJcZokn8YoqU0FS5WFKyniHobguMcmW8N0XkWZjkyN3hqOMtS08r+/xTBwpZSZ3qiVRX8SzMHHjfUNFjgHEPmY9PL3ykEzxkSre/1ZD6z/NuznuB0RcE1TWTm9zRgfUWVJiG6yrzgmWPXC8EAR4Wxhlad0ZbgQyEz3pG5RVEwwDJH2mgKpjcTiCOzn1lfUWANFbZ2BA8balnEweJC9J0iuaeZoI+ippFCztEKVvckR2iice1JvhVytrQwUAZpgsubCPaU7xUe9vWnaOpaSBEspalykhC9bUlOMpT42ZHca6hyrqKmw/wMR8H5ZmdFoBVJb03O4UL0tSNnvIeRmkrLWqrs78gcrEn2tpcboh0UPOW3UUR9PMk4T4nnNKWmCjlrefhCwxRNztfmIQVdDElvS4m1/WuOujoZCs5XVOjtKPGokJzsYCtFYoWonSPT21DheU/wWhM19FcElwqNGOsp9Q8N/cwXaiND1MmeL1Q5XROtYYgGeFq1aTMsoMmcrKjQrOFQTQ1fmBYhmW6o8Jkjc7iDJRTBIo5kgJD5yMEYA3srCg7VFKwiVJkmRCc5ohGOKhsYMn/XBLdo5taZjlb9YAlGWRimqbCsoY7HFAXLa5I1HPRxMMsQDHFkWtRNniqT9UEeNjcE7RUlrCJ4R2CSJuqlKHWvJXjAUNcITYkenuBRB84TbeepcqTj3zZyFJzgYQdHnqfgI0ddUwS6GqWpsKWhjq9cV0vBAEMN2znq+EBfIWT+pClYw5xsTlJU6GeIBsjGmmANTzJZiIYpgrM0Oa8ZMjd7NP87jxhqGOhJlnQtjuQpB+8aEE00wZFznSJPyHxgH3HkPOsJFvYk8zqCHzTs1BYOa4J3PFU+UVRZxlHDM4YavlNUuMoRveiZA2d7grMNc2g+RbSCEKzmgYsUmWmazFJyoiOZ4KnyhKOGRzWJa0+moyV4TVHDzn51Awtqaphfk/lRQ08FX1iiqxTB/kLwd0VynKfEvI6cd4XMV5bMhZ7gZUWVzYQ6Nm2BYzxJbw3bGthEUUMfgbGeorae6DxHtJoZ6alhZ0+ytiVoK1R4z5PTrOECT/SugseEOlb1MMNR4VRNcJy+V1Hg9ONClSZFZjdHlc6W6FBLdJja2MC5hhpu0DBYEY1TFGwiFAxRRCsYkiM9JRb0JNMVkW6CZYT/2EiTGWmo8k+h4FhDNE7BvppoTSFnmCV5xZKzvcCdDo7VVPnIU+I+Rc68juApC90MwcFCsJ5hDqxgScYKreruyQwTqrzoqDCmhWi4IbhB0Yrt3RGa6GfDv52rKXWhh28dyZaWUvcZeMTBaZoSGyiCtRU5J8iviioHaErs7Jkj61syVzTTgOcUOQ8buFBTYWdL5g3T4qlpe0+wvD63heAXRfCCIed9RbCsp2CiI7raUOYOTU13N8PNHvpaGvayo4a3LLT1lDrVEPT2zLUlheB1R+ZTRfKWJ+dcocLJfi11vyJ51lLqJ0WD7tRwryezjiV5W28uJO9qykzX8JDe2lHl/9oyBwa2UMfOngpXCixvKdXTk3wrsKmiVYdZIqsoWEERjbcUNDuiaQomGoIbFdEHmsyWnuR+IeriKDVLnlawlyNHKwKlSU631PKep8J4Q+ayjkSLKYLhalNHlYvttb6fHm0p6OApsZ4l2VfdqZkjuysy6ysKLlckf1KUutCTs39bmCgEyyoasIWlVaMF7mgmWtBT8Kol5xpH9IGllo8cJdopcvZ2sImlDmMIbtDk3KIpeNiS08lQw11NFPTwVFlPP6pJ2gvRfI7gQUfmNAtf6Gs0wQxDsKGlVBdF8rCa3jzdwMaGHOsItrZk7hAyOzpK9VS06j5F49b0VNGOOfKs3lDToMsMBe9ZWtHFEgxTJLs7qrygKZjUnmCYoeAqeU6jqWuLJup4WghOdvCYJnrSkSzoyRkm5M2StQwVltPkfCAk58tET/CSg+8MUecmotMEnhBKfWBIZsg2ihruMJQaoIm+tkTLKEqspMh00w95gvFCQRtDwTT1gVDDSEVdlwqZfxoQRbK0g+tbiBZxzKlpnpypejdDwTaeOvorMk/IJE10h9CqRe28hhLbe0pMsdSwv4ZbhKivo2BjDWfL8UKJgeavwlwb5KlwhyE4u4XkGE2ytZCznKLCDZZq42VzT8HLCrpruFbIfOIINmh/qCdZ1ZBc65kLHR1Bkyf5zn6pN3SvGKIlFNGplhrO9QSXanLOMQTLCa0YJCRrCZm/CZmrLTm7WzCK4GJDiWUdFeYx1LCFg3NMd0XmCuF3Y5rITLDUsYS9zoHVzwnJoYpSTQoObyEzr4cFBNqYTopoaU/wkyLZ2lPhX/5Y95ulxGTV7KjhWrOZgl8MyUUafjYraNjNU1N3IWcjT5WzWqjwtoarHSUObGYO3GCJZpsBlnJGPd6ZYLyl1GdCA2625IwwJDP8GUKymbzuyPlZlvTUsaUh5zFDhRWFzPKKZLAlWdcQbObgF9tOqOsmB1dqcqYJmWstFbZRRI9poolmqiLnU0POvxScpah2iSL5UJNzgScY5+AuIbpO0YD3NCW+dLMszFSdFCWGqG6eVq2uYVNDdICGD6W7EPRWZEY5gpsE9rUkS3mijzzJnm6UpUFXG1hCUeVoS5WfNcFpblELL2qqrCvMvRfd45oalvKU2tiQ6ePJOVMRXase9iTtLJztPxJKLWpo2CRDcJwn2sWSLKIO1WQWNTCvpVUvOZhgSC40JD0dOctaSqzkCRbXsKlb11Oip6PCJ0IwSJM31j3akRxlP7Rwn6aGaUL0qiLnJkvB3xWZ2+Q1TfCwpQH3G0o92UzmX4o/oJNQMMSQc547wVHhdk+VCw01DFYEnTxzZKAm74QmeNNR1w6WzEhNK15VJzuCdxQ53dRUDws5KvwgBMOEgpcVNe0hZI6RXT1Jd0cyj5nsaEAHgVmGaJIlWdsc5Ui2ElrRR6jrRAttNMEAIWrTDFubkZaok7/AkzfIwfuWVq0jHzuCK4QabtLUMVPB3kJ0oyHTSVFlqMALilJf2Rf8k5aaHtMfayocLBS8L89oKoxpJvnAkDPa0qp5DAUTHKWmCcnthlou8iCKaFFLHWcINd1nyIwXqrSxMNmSs6KmoL2QrKuWtlQ5V0120xQ5vRyZS1rgFkWwhiOwiuQbR0OOVhQM9iS3tiXp4RawRPMp5tDletOOBL95MpM01dZTBM9pkn5qF010rIeHFcFZhmSGpYpTsI6nwhqe5C9ynhlpp5ophuRb6WcJFldkVnVEwwxVfrVkvnWUuNLCg5bgboFHPDlDPDmnK7hUrWiIbjadDclujlZcaokOFup4Ri1kacV6jmrrK1hN9bGwpKEBQ4Q6DvIUXOmo6U5LqQM6EPyiKNjVkPnJkDPNEaxhiFay5ExW1NXVUGqcpYYdPcGiCq7z/TSlbhL4pplWXKd7NZO5QQFrefhRQW/NHOsqcIglc4UhWklR8K0QzbAw08CBDnpbgqXdeD/QUsM4RZXDFBW6WJKe/mFPdH0LtBgiq57wFLzlyQzz82qYx5D5WJP5yVJDW01BfyHnS6HKO/reZqId1WGa4Hkh2kWodJ8i6KoIPlAj2hPt76CzXsVR6koPRzWTfKqIentatYpQw2me4AA3y1Kind3SwoOKZDcFXTwl9tWU6mfgRk9d71sKtlNwrjnYw5tC5n5LdKiGry3JKNlHEd3oaMCFHrazBPMp/uNJ+V7IudcSbeOIdjUEdwl0VHCOZo5t6YluEuaC9mQeMgSfOyKnYGFHcIeQ84yQWbuJYJpZw5CzglDH7gKnWqqM9ZTaXcN0TeYhR84eQtJT76JJ1lREe7WnnvsMmRc9FQ7SBBM9mV3lCUdmHk/S2RAMt0QjFNFqQpWjDPQ01DXWUdDBkXziKPjGEP3VP+zIWU2t7im41FOloyWzn/L6dkUy3VLDaZ6appgDLHPjJEsyvJngWEPUyVBiAaHCTEXwrLvSEbV1e1gKJniicWorC1MUrVjB3uDhJE/wgSOzk1DXpk0k73qCM8xw2UvD5kJmDUfOomqMpWCkJRlvKXGmoeBm18USjVIk04SClxTB6YrgLAPLWYK9HLUt5cmc0vYES8GnTeRc6skZbQkWdxRsIcyBRzx1DbTk9FbU0caTPOgJHhJKnOGIVhQqvKmo0llRw9sabrZkDtdg3PqaKi9oatjY8B+G371paMg6+mZFNNtQ04mWBq3rYLOmtWWQp8KJnpy9DdFensyjdqZ+yY40VJlH8wcdLzC8PZnvHMFUTZUrDTkLyQaGus5X5LzpYAf3i+e/ZlhqGqWhh6Ou6xTR9Z6oi5AZZtp7Mj2EEm8oSpxiYZCHU/1fbGdNNNRRoZMhmilEb2gqHOEJDtXkHK/JnG6IrvbPCwV3NhONVdS1thBMs1T4QOBcTWa2IzhMk2nW5Kyn9tXUtpv9RsG2msxk+ZsQzRQacJncpgke0+T8y5Fzj8BiGo7XlJjaTIlpQs7KFjpqGnKuoyEPeIKnFMkZHvopgh81ySxNFWvJWcKRs70j2FOT012IllEEO1n4pD1513Yg2ssQPOThOkvyrqHUdEXOSEsihmBbTbKX1kLBPWqWkLOqJbjB3GBIZmoa8qWl4CG/iZ7oiA72ZL7TJNeZUY7kFQftDcHHluBzRbCegzMtrRjVQpX2lgoPKKLJAkcbMl01XK2p7yhL8pCBbQ3BN2avJgKvttcrWDK3CiUOVxQ8ZP+pqXKyIxnmBymCg5vJjNfkPK4+c8cIfK8ocVt7kmfd/I5SR1hKvCzUtb+lhgc00ZaO6CyhIQP1Uv4yIZjload72PXX0OIJvnFU+0Zf6MhsJwTfW0r0UwQfW4LNLZl5HK261JCZ4qnBaAreVAS3WrjV0LBnNDUNNDToCEeFfwgcb4gOEqLRhirWkexrCEYKVV711DLYEE1XBEsp5tpTGjorkomKYF9FDXv7fR3BGwbettSxnyL53MBPjsxDZjMh+VUW9NRxq1DhVk+FSxQcaGjV9Pawv6eGByw5qzoy7xk4RsOShqjJwWKe/1pEEfzkobeD/dQJmpqedcyBTy2sr4nGNRH0c0SPWTLrqAc0OQcb/gemKgqucQT7ySWKCn2EUotoCvpZct7RO2sy/QW0IWcXd7pQRQyZVwT2USRO87uhjioTLKV2brpMUcMQRbKH/N2T+UlTpaMls6cmc6CCNy3JdYYSUzzJQ4oSD3oKLncULOiJvjBEC2oqnCJkJluCYy2ZQ5so9YYlZ1VLlQU1mXEW1jZERwj/MUSRc24TdexlqLKfQBtDTScJUV8FszXBEY5ktpD5Ur9hYB4Nb1iikw3JoYpkKX+RodRKFt53MMuRnKSpY31PwYaGaILh3wxJGz9TkTPEETxoCWZrgvOlmyMzxFEwVJE5xZKzvyJ4WxEc16Gd4Xe3Weq4XH2jKRikqOkGQ87hQnC7wBmGYLAnesX3M+S87eFATauuN+Qcrh7xIxXJbUIdMw3JGE3ylCWzrieaqCn4zhGM19TQ3z1oH1AX+pWEqIc7wNGAkULBo/ZxRaV9NNyh4Br3rCHZzbzmSfawBL0dNRwpW1kK9mxPXR9povcdrGSZK9c2k0xwFGzjuniCtRSZCZ6ccZ7gaktmgAOtKbG/JnOkJrjcQTdFMsxRQ2cLY3WTIrlCw1eWKn8R6pvt4GFDso3QoL4a3nLk3G6JrtME3dSenpx7PNFTmga0EaJTLQ061sEeQoWXhSo9LTXsaSjoJQRXeZLtDclbCrYzfzHHeaKjHCVOUkQHO3JeEepr56mhiyaYYKjjNU+Fed1wS5VlhWSqI/hYUdDOkaxiKehoyOnrCV5yBHtbWFqTHCCwtpDcYolesVR5yUzTZBb3RNMd0d6WP+SvhuBmRcGxnuQzT95IC285cr41cLGQ6aJJhmi4TMGempxeimBRQw1tFKV+8jd6KuzoSTqqDxzRtpZkurvKEHxlqXKRIjjfUNNXQsNOsRScoWFLT+YeRZVD3GRN0MdQcKqQjHDMrdGGVu3iYJpQx3WGUvfbmxwFfR20WBq0oYY7LMFhhgYtr8jpaEnaOzjawWWaTP8mMr0t/EPDPoqcnxTBI5o58L7uoWnMrpoqPwgVrlAUWE+V+TQl9rawoyP6QGAlQw2TPRX+YSkxyBC8Z6jhHkXBgQL7WII3DVFnRfCrBfxewv9D6xsyjys4VkhWb9pUU627JllV0YDNHMku/ldNMMXDEo4aFnAkk4U6frNEU4XgZUPmEKHUl44KrzmYamjAbh0JFvGnaTLPu1s9jPCwjFpYiN7z1DTOk/nc07CfDFzmCf7i+bfNHXhDtLeBXzTBT5rkMvWOIxpl4EMh2LGJBu2syDnAEx2naEhHDWMMzPZEhygyS1mS5RTJr5ZkoKbEUoYqr2kqdDUE8ztK7OaIntJkFrIECwv8LJTaVx5XJE86go8dFeZ3FN3rjabCAYpoYEeC9zzJVULBbmZhDyd7ko09ydpNZ3nm2Kee4FPPXHnYEF1nqOFEC08LUVcDvYXkJHW8gTaKCk9YGOeIJhqiE4ToPEepdp7IWFjdwnWaufGMwJJCMtUTTBBK9BGCOy2tGGrJTHIwyEOzp6aPzNMOtlZkDvcEWpP5SVNhfkvDxhmSazTJXYrM9U1E0xwFVwqZQwzJxw6+kGGGUj2FglGGmnb1/G51udRSMNlTw6GGnCcUwVcOpmsqTHa06o72sw1RL02p9z0VbnMLOaIX3QKaYKSCFQzBKEUNHTSc48k53RH9wxGMtpQa5KjjW0W0n6XCCCG4yxNNdhQ4R4l1Ff+2sSd6UFHiIEOyqqFgT01mEUMD+joy75jPhOA+oVVLm309FR4yVOlp4RhLiScNmSmaYF5Pw0STrOIoWMSR2UkRXOMp+M4SHW8o8Zoi6OZgjKOaFar8zZDzkWzvKOjkKBjmCXby8JahhjXULY4KlzgKLvAwxVGhvyd4zxB1d9T0piazmKLCVZY5sKiD0y2ZSYrkUEPUbIk+dlQ4SJHTR50k1DPaUWIdTZW9NJwnJMOECgd7ou/MnppMJ02O1VT4Wsh85MnZzcFTngpXGKo84qmwgKbCL/orR/SzJ2crA+t6Mp94KvxJUeIbT3CQu1uIdlQEOzlKfS3UMcrTiFmOuroocrZrT2AcmamOKg8YomeEKm/rlT2sociMaybaUlFhuqHCM2qIJ+rg4EcDFymiDSxzaHdPcpE62pD5kyM5SBMoA1PaUtfIthS85ig1VPiPPYXgYEMNk4Qq7TXBgo7oT57gPUdwgCHzhIVFPFU6OYJzHAX9m5oNrVjeE61miDrqQ4VSa1oiURTsKHC0IfjNwU2WzK6eqK8jWln4g15TVBnqmDteCJ501PGAocJhhqjZdtBEB6lnhLreFJKxmlKbeGrqLiSThVIbCdGzloasa6lpMQXHCME2boLpJgT7yWaemu6wBONbqGNVRS0PKIL7LckbjmQtR7K8I5qtqel+T/ChJTNIKLjdUMNIRyvOEko9YYl2cwQveBikCNawJKcLBbc7+JM92mysNvd/Fqp8a0k6CNEe7cnZrxlW0wQXaXjaktnRwNOGZKYiONwS7a1JVheq3WgJHlQUGKHKmp4KAxXR/ULURcNgoa4zhKSLpZR3kxRRb0NmD0OFn+UCS7CzI1nbP6+o4x47QZE5xRCt3ZagnYcvmpYQktXdk5YKXTzBC57kKEe0VVuiSYqapssMS3C9p2CKkHOg8B8Pa8p5atrIw3qezIWanMGa5HRDNF6RM9wcacl0N+Q8Z8hsIkSnaIIdHRUOEebAPy1zbCkhM062FCJtif7PU+UtoVXzWKqM1PxXO8cfdruhFQ/a6x3JKYagvVDhQEtNiyiiSQ7OsuRsZUku0CRNDs4Sog6KKjsZgk2bYJqijgsEenoKeniinRXBn/U3lgpPdyDZynQx8IiioMnCep5Ky8mjGs6Wty0l1hUQTcNWswS3WRp2kCNZwJG8omG8JphPUaFbC8lEfabwP7VtM9yoaNCAjpR41VNhrD9LkbN722v0CoZMByFzhaW+MyzRYEWFDQwN2M4/JiT76PuljT3VU/A36eaIThb+R9oZGOAJ9tewkgGvqOMNRWYjT/Cwu99Q8LqDE4TgbLWxJ1jaDDAERsFOFrobgjUsBScaguXU8kKm2RL19tRypSHnHNlHiIZqgufs4opgQdVdwxBNNFBR6kVFqb8ogimOzB6a6HTzrlDHEpYaxjiiA4TMQobkDg2vejjfwJGWmnbVFAw3H3hq2NyQfG7hz4aC+w3BbwbesG0swYayvpAs6++Ri1Vfzx93mFChvyN5xVHTS+0p9aqCAxyZ6ZacZyw5+7uuQkFPR9DDk9NOiE7X1PCYJVjVUqq7JlrHwWALF5nfHNGjApdpqgzx5OwilDhCiDYTgnc9waGW4BdLNNUQvOtpzDOWHDH8D7TR/A/85KljEQu3NREc4Pl/6B1Hhc8Umb5CsKMmGC9EPcxoT2amwHNCmeOEnOPbklnMkbOgIvO5UMOpQrS9UGVdt6iH/fURjhI/WOpaW9OKLYRod6HCUEdOX000wpDZQ6hwg6LgZfOqo1RfT/CrJzjekXOGhpc1VW71ZLbXyyp+93ILbC1kPtIEYx0FIx1VDrLoVzXRKRYWk809yYlC9ImcrinxtabKnzRJk3lAU1OLEN1j2zrYzr2myHRXJFf4h4QKT1qSTzTB5+ZNTzTRkAxX8FcLV2uS8eoQQ2aAkFzvCM72sJIcJET3WPjRk5wi32uSS9rfZajpWEvj9hW42F4o5NytSXYy8IKHay10VYdrcl4SkqscrXpMwyGOgtkajheSxdQqmpxP1L3t4R5PqasFnrQEjytq6qgp9Y09Qx9o4S1FzhUCn1kyHSzBWLemoSGvOqLNhZyBjmCaAUYpMgt4Ck7wBBMMwWKWgjsUwTaGVsxWC1mYoKiyqqeGKYqonSIRQ3KIkHO0pmAxTdBHkbOvfllfr+AA+7gnc50huVKYK393FOyg7rbPO/izI7hE4CnHHHnJ0ogNPRUGeUpsrZZTBJcrovUcJe51BPsr6GkJdhCCsZ6aTtMEb2pqWkqeVtDXE/QVggsU/Nl86d9RMF3DxvZTA58agu810RWawCiSzzXBeU3MMW9oyJUedvNEvQyNu1f10BSMddR1vaLCYpYa/mGocLSiYDcLbQz8aMn5iyF4xBNMs1P0QEOV7o5gaWGuzSeLue4tt3ro7y4Tgm4G/mopdZgl6q0o6KzJWE3mMksNr3r+a6CbT8g5wZNzT9O7fi/zpaOmnz3BRoqos+tv9zMbdpxsqDBOEewtJLt7cg5wtKKbvldpSzRRCD43VFheCI7yZLppggMVBS/KMAdHODJvOwq2NQSbKKKPLdFWQs7Fqo+mpl01JXYRgq8dnGLhTiFzqmWsUMdpllZdbKlyvSdYxhI9YghOtxR8LgSLWHK62mGGVoxzBE8LNWzqH9CUesQzFy5RQzTc56mhi6fgXEWwpKfE5Z7M05ZgZUPmo6auiv8YKzDYwWBLMErIbKHJvOwIrvEdhOBcQ9JdU1NHQ7CXn2XIDFBKU2WAgcX9UAUzDXWd5alwuyJ41Z9rjKLCL4aCp4WarhPm2rH+SaHUYE001JDZ2ZAzXPjdMpZWvC9wmqIB2lLhQ01D5jO06hghWMndbM7yRJMsoCj1vYbnFQVrW9jak3OlEJ3s/96+p33dEPRV5GxiqaGjIthUU6FFEZyqCa5qJrpBdzSw95IUnOPIrCUUjRZQFrbw5PR0R1qiYx3cb6nrWUMrBmmiBQxVHtTew5ICP/ip6g4hed/Akob/32wvBHsIOX83cI8hGeNeNPCIkPmXe8fPKx84OMSRM1MTdXSwjCZ4S30jVGhvqTRak/OVhgGazHuOCud5onEO1lJr6ecVyaOK6H7zqlBlIaHE0oroCgfvGJIdPcmfLNGLjpz7hZwZQpUbFME0A1cIJa7VNORkgfsMBatbKgwwJM9bSvQXeNOvbIjelg6WWvo5kvbKaJJNHexkKNHL9xRyFlH8Ti2riB5wVPhUk7nGkJnoCe428LR/wRGdYIlmWebCyxou1rCk4g/ShugBDX0V0ZQWkh0dOVsagkM0yV6OoLd5ye+pRlsCr0n+KiQrGuq5yJDzrTAXHtLUMduTDBVKrSm3eHL+6ijxhFDX9Z5gVU/wliHYTMiMFpKLNMEywu80wd3meoFmt6VbRMPenhrOc6DVe4pgXU8DnnHakLOIIrlF4FZPIw6R+zxBP0dyq6OOZ4Q5sLKCcz084ok+VsMMyQhNZmmBgX5xIXOEJTmi7VsGTvMTNdHHhpzdbE8Du2oKxgvBqQKdDDnTFOylCFaxR1syz2iqrOI/FEpNc3C6f11/7+ASS6l2inq2ciTrCCzgyemrCL5SVPjQkdPZUmGy2c9Sw9FtR1sS30RmsKPCS4rkIC/2U0MduwucYolGaPjKEyhzmiPYXagyWbYz8LWBDdzRimAXzxx4z8K9hpzlhLq+NiQ97HuKorMUfK/OVvC2JfiHUPCQI/q7J2gjK+tTDNxkCc4TMssqCs4TGtLVwQihyoAWgj9bosU80XGW6Ac9TJGziaUh5+hnFcHOnlaM1iRn29NaqGENTTTSUHCH2tWTeV0osUhH6psuVLjRUmGWhm6OZEshGeNowABHcJ2Bpy2ZszRcKkRXd2QuKVEeXnbfaEq825FguqfgfE2whlChSRMdron+LATTPQ2Z369t4B9C5gs/ylzv+CMmepIDPclFQl13W0rspPd1JOcbghGOEutqCv5qacURQl3dDKyvyJlqKXGPgcM9FfawJAMVmdcspcYKOZc4GjDYkFlK05olNMHyHn4zFNykyOxt99RkHlfwmiHo60l2EKI+mhreEKp080Tbug08BVPcgoqC5zWt+NLDTZ7oNSF51N1qie7Va3uCCwyZbkINf/NED6jzOsBdZjFN8oqG3wxVunqCSYYKf3EdhJyf9YWGf7tRU2oH3VHgPr1fe5J9hOgHd7xQ0y7qBwXr23aGErP0cm64JVjZwsOGqL+mhNgZmhJLW2oY4UhedsyBgzrCKrq7BmcpNVhR6jBPq64Vgi+kn6XE68pp8J5/+0wRHGOpsKenQn9DZntPzjRLZpDAdD2fnSgkG9tmIXnUwQ6WVighs7Yi2MxQ0N3CqYaCXkJ0oyOztMDJjmSSpcpvlrk0RMMOjmArQ04PRV1DO1FwhCVaUVPpKUM03JK5SxPsIWRu8/CGHi8UHChiqGFDTbSRJWeYUDDcH6vJWUxR4k1FXbMUwV6e4AJFXS8oMqsZKqzvYQ9DDQdZckY4aGsIhtlubbd2r3j4QBMoTamdPZk7O/Bf62lacZwneNjQoGcdVU7zJOd7ghsUHOkosagic6cnWc8+4gg285R6zZP5s1/LUbCKIznTwK36PkdwlOrl4U1LwfdCCa+IrvFkmgw1PCAUXKWo0sURXWcI2muKJlgyFzhynCY4RBOsqCjoI1R5zREco0n2Vt09BQtYSizgKNHfUmUrQ5UOCh51BFcLmY7umhYqXKQomOop8bUnWNNQcIiBcYaC6xzMNOS8JQQfeqKBmmglB+97ok/lfk3ygaHSyZaCRTzRxQo6GzLfa2jWBPepw+UmT7SQEJyiyRkhBLMVOfcoMjcK0eZChfUNzFAUzCsEN5vP/X1uP/n/aoMX+K+nw/Hjr/9xOo7j7Pju61tLcgvJpTWXNbfN5jLpi6VfCOviTktKlFusQixdEKWmEBUKNaIpjZRSSOXSgzaaKLdabrm1/9nZ+/f+vd/vz/v9+Xy+zZ7PRorYoZqyLrCwQdEAixxVOEXNNnjX2nUSRlkqGmWowk8lxR50JPy9Bo6qJXaXwNvREBvnThPEPrewryLhcAnj5WE15Fqi8W7R1sAuEu86S4ENikItFN4xkv9Af4nXSnUVcLiA9xzesFpivRRVeFKtsMRaKBhuSbjOELnAUtlSQUpXgdfB4Z1oSbnFEetbQ0IrAe+Y+pqnDcEJFj6S8LDZzZHwY4e3XONNlARraomNEt2bkvGsosA3ioyHm+6jCMbI59wqt4eeara28IzEmyPgoRaUOEDhTVdEJhmCoTWfC0p8aNkCp0oYqih2iqGi4yXeMkOsn4LdLLnmKfh/YogjNsPebeFGR4m9BJHLzB61XQ3BtpISfS2FugsK9FAtLWX1dCRcrCnUp44CNzuCowUZmxSRgYaE6Za0W2u/E7CVXCiI/UOR8aAm1+OSyE3mOUcwyc1zBBeoX1kiKy0Zfxck1Gsyulti11i83QTBF5Kg3pDQThFMVHiPSlK+0cSedng/VaS8bOZbtsBcTcZAR8JP5KeqQ1OYKAi20njdNNRpgnsU//K+JnaXJaGTomr7aYIphoRn9aeShJWKEq9LcozSF7QleEfDI5LYm5bgVkFkRwVDBCVu0DDIkGupo8TZBq+/pMQURYErJQmPKGKjNDkWOLx7Jd5QizdUweIaKrlP7SwJDhZvONjLkOsBBX9UpGxnydhXkfBLQ8IxgojQbLFnJf81JytSljclYYyEFyx0kVBvKWOFJmONpshGAcsduQY5giVNCV51eOdJYo/pLhbvM0uDHSevNKRcrKZIqnCtJeEsO95RoqcgGK4ocZcho1tTYtcZvH41pNQ7vA0WrhIfOSraIIntIAi+NXWCErdbkvrWwjRLrt0NKUdL6KSOscTOdMSOUtBHwL6OLA0vNSdynaWQEnCpIvKaIrJJEbvHkmuNhn6OjM8VkSGSqn1uYJCGHnq9I3aLhNME3t6GjIkO7xrNFumpyTNX/NrwX7CrIRiqqWijI9JO4d1iieykyfiposQIQ8YjjsjlBh6oHWbwRjgYJQn2NgSnNycmJAk3NiXhx44Sxykihxm8ybUwT1OVKySc7vi3OXVkdBJ4AyXBeksDXG0IhgtYY0lY5ahCD0ehborIk5aUWRJviMA7Xt5kyRjonrXENkm8yYqgs8VzgrJmClK20uMM3jRJ0FiQICQF9hdETlLQWRIb5ki6WDfWRPobvO6a4GP5mcOrNzDFELtTkONLh9dXE8xypEg7z8A9jkhrQ6Fhjlg/QVktJXxt4WXzT/03Q8IaQWSqIuEvloQ2mqC9Jfi7wRul4RX3pSPlzpoVlmCtI2jvKHCFhjcM3sN6lqF6HxnKelLjXWbwrpR4xzuCrTUZx2qq9oAh8p6ixCUGr78g8oyjRAtB5CZFwi80VerVpI0h+IeBxa6Zg6kWvpDHaioYYuEsRbDC3eOmC2JvGYLeioxGknL2UATNJN6hmtj1DlpLvDVmocYbrGCVJKOrg4X6DgddLA203BKMFngdJJFtFd7vJLm6KEpc5yjQrkk7M80SGe34X24nSex1Ra5Omgb71JKyg8SrU3i/kARKwWpH0kOGhKkObyfd0ZGjvyXlAkVZ4xRbYJ2irFMkFY1SwyWxr2oo4zlNiV+7zmaweFpT4kR3kaDAFW6xpSqzJay05FtYR4HmZhc9UxKbbfF2V8RG1MBmSaE+kmC6JnaRXK9gsiXhJHl/U0qM0WTcbyhwkYIvFGwjSbjfwhiJt8ZSQU+Bd5+marPMOkVkD0muxYLIfEuhh60x/J92itguihJSEMySVPQnTewnEm+620rTQEMsOfo4/kP/0ARvWjitlpSX7GxBgcMEsd3EEeYWvdytd+Saawi6aCIj1CkGb6Aj9rwhx16Cf3vAwFy5pyLhVonXzy51FDpdEblbkdJbUcEPDEFzQ8qNmhzzLTmmKWKbFCXeEuRabp6rxbvAtLF442QjQ+wEA9eL1xSR7Q0JXzlSHjJ4exq89yR0laScJ/FW6z4a73pFMEfDiRZvuvijIt86RaSFOl01riV2mD1UEvxGk/Geg5aWwGki1zgKPG9J2U8PEg8qYvMsZeytiTRXBMslCU8JSlxi8EabjwUldlDNLfzTUmCgxWsjqWCOHavYAqsknKFIO0yQ61VL5AVFxk6WhEaCAkdJgt9aSkzXlKNX2jEa79waYuc7gq0N3GDJGCBhoiTXUEPsdknCUE1CK0fwsiaylSF2uiDyO4XX3pFhNd7R4itFGc0k/ElBZwWvq+GC6szVeEoS/MZ+qylwpKNKv9Z469UOjqCjwlusicyTxG6VpNxcQ8IncoR4RhLbR+NdpGGmJWOcIzJGUuKPGpQg8rrG21dOMqQssJQ4RxH5jaUqnZuQ0F4Q+cjxLwPtpZbIAk3QTJHQWBE5S1BokoVtDd6lhqr9UpHSUxMcIYl9pojsb8h4SBOsMQcqvOWC2E8EVehqiJ1hrrAEbQxeK0NGZ0Gkq+guSRgniM23bIHVkqwx4hiHd7smaOyglyIyQuM978j4VS08J/A2G1KeMBRo4fBaSNhKUEZfQewVQ/C1I+MgfbEleEzCUw7mKXI0M3hd1EESVji8x5uQ41nxs1q4RMJCCXs7Iq9acpxn22oSDnQ/sJTxsCbHIYZiLyhY05TY0ZLIOQrGaSJDDN4t8pVaIrsqqFdEegtizc1iTew5Q4ayBDMUsQMkXocaYkc0hZua412siZ1rSXlR460zRJ5SlHGe5j801RLMlJTxtaOM3Q1pvxJ45zUlWFD7rsAbpfEm1JHxG0eh8w2R7QQVzBUw28FhFp5QZzq8t2rx2joqulYTWSuJdTYfWwqMFMcovFmSyJPNyLhE4E10pHzYjOC3huArRa571ZsGajQpQx38SBP5pyZB6lMU3khDnp0MBV51BE9o2E+TY5Ml2E8S7C0o6w1xvCZjf0HkVEHCzFoyNmqC+9wdcqN+Tp7jSDheE9ws8Y5V0NJCn2bk2tqSY4okdrEhx1iDN8cSudwepWmAGXKcJXK65H9to8jYQRH7SBF01ESUJdd0TayVInaWhLkOjlXE5irKGOnI6GSWGCJa482zBI9rCr0jyTVcEuzriC1vcr6mwFGSiqy5zMwxBH/TJHwjSPhL8+01kaaSUuMFKTcLEvaUePcrSmwn8DZrgikWb7CGPxkSjhQwrRk57tctmxLsb9sZvL9LSlyuSLlWkqOjwduo8b6Uv1DkmudIeFF2dHCgxVtk8dpIvHpBxhEOdhKk7OLIUSdJ+cSRY57B+0DgGUUlNfpthTfGkauzxrvTsUUaCVhlKeteTXCoJDCa2NOKhOmC4G1H8JBd4OBZReSRGkqcb/CO1PyLJTLB4j1q8JYaIutEjSLX8YKM+a6phdMsdLFUoV5RTm9JSkuDN8WcIon0NZMNZWh1q8C7SJEwV5HxrmnnTrf3KoJBlmCYI2ilSLlfEvlE4011NNgjgthzEua0oKK7JLE7HZHlEl60BLMVFewg4EWNt0ThrVNEVkkiTwpKXSWJzdRENgvKGq4IhjsiezgSFtsfCUq8qki5S1LRQeYQQ4nemmCkImWMw3tFUoUBZk4NOeZYEp4XRKTGa6wJjrWNHBVJR4m3FCnbuD6aak2WsMTh3SZImGCIPKNgsDpVwnsa70K31lCFJZYcwwSMFcQulGTsZuEaSdBXkPGZhu0FsdUO73RHjq8MPGGIfaGIbVTk6iuI3GFgucHrIQkmWSJdBd7BBu+uOryWAhY7+Lki9rK5wtEQzWwvtbqGhIMFwWRJsElsY4m9IIg9L6lCX0VklaPAYkfkZEGDnOWowlBJjtMUkcGK4Lg6EtoZInMUBVYLgn0UsdmCyCz7gIGHFfk+k1QwTh5We7A9x+IdJ6CvIkEagms0hR50eH9UnTQJ+2oiKyVlLFUE+8gBGu8MQ3CppUHesnjTHN4QB/UGPhCTHLFPHMFrCqa73gqObUJGa03wgbhHkrCfpEpzNLE7JDS25FMKhlhKKWKfCgqstLCPu1zBXy0J2ztwjtixBu8UTRn9LVtkmCN2iyFhtME70JHRQ1KVZXqKI/KNIKYMCYs1GUMEKbM1bKOI9LDXC7zbHS+bt+1MTWS9odA9DtrYtpbImQJ2VHh/lisEwaHqUk1kjKTAKknkBEXkbkdMGwq0dnhzLJF3NJH3JVwrqOB4Sca2hti75nmJN0WzxS6UxDYoEpxpa4htVlRjkYE7DZGzJVU72uC9IyhQL4i8YfGWSYLLNcHXloyz7QhNifmKSE9JgfGmuyLhc403Xm9vqcp6gXe3xuuv8F6VJNxkyTHEkHG2g0aKXL0MsXc1bGfgas2//dCONXiNLCX+5mB7eZIl1kHh7ajwpikyzlUUWOVOsjSQlsS+M0R+pPje/dzBXRZGO0rMtgQrLLG9VSu9n6CMXS3BhwYmSoIBhsjNBmZbgusE9BCPCP5triU4VhNbJfE+swSP27aayE8tuTpYYjtrYjMVGZdp2NpS1s6aBnKSHDsbKuplKbHM4a0wMFd/5/DmGyKrJSUaW4IBrqUhx0vyfzTBBLPIUcnZdrAkNsKR0sWRspumSns6Ch0v/qqIbBYUWKvPU/CFoyrDJGwSNFhbA/MlzKqjrO80hRbpKx0Jewsi/STftwGSlKc1JZyAzx05dhLEdnfQvhZOqiHWWEAHC7+30FuRcZUgaO5gpaIK+xsiHRUsqaPElTV40xQZQ107Q9BZE1nryDVGU9ZSQ47bmhBpLcYpUt7S+xuK/FiT8qKjwXYw5ypS2iuCv7q1gtgjhuBuB8LCFY5cUuCNtsQOFcT+4Ih9JX+k8Ea6v0iCIRZOtCT0Et00JW5UeC85Cg0ScK0k411HcG1zKtre3SeITBRk7WfwDhEvaYLTHP9le0m8By0JDwn4TlLW/aJOvGHxdjYUes+ScZigCkYQdNdEOhkiezgShqkx8ueKjI8lDfK2oNiOFvrZH1hS+tk7NV7nOmLHicGWEgubkXKdwdtZknCLJXaCpkrjZBtLZFsDP9CdxWsSr05Sxl6CMmoFbCOgryX40uDtamB7SVmXW4Ihlgpmq+00tBKUUa83WbjLUNkzDmY7cow1JDygyPGlhgGKYKz4vcV7QBNbJIgM11TUqZaMdwTeSguH6rOaw1JRKzaaGyxVm2EJ/uCIrVWUcZUkcp2grMsEjK+DMwS59jQk3Kd6SEq1d0S6uVmO4Bc1lDXTUcHjluCXEq+1OlBDj1pi9zgiXxnKuE0SqTXwhqbETW6RggMEnGl/q49UT2iCzgJvRwVXS2K/d6+ZkyUl7jawSVLit46EwxVljDZwoSQ20sDBihztHfk2yA8NVZghiXwrYHQdfKAOtzsayjhY9bY0yE2CWEeJ9xfzO423xhL5syS2TFJofO2pboHob0nY4GiAgRrvGQEDa/FWSsoaaYl0syRsEt3kWoH3B01shCXhTUWe9w3Bt44SC9QCh3eShQctwbaK2ApLroGCMlZrYqvlY3qYhM0aXpFkPOuoqJ3Dm6fxXrGwVF9gCWZagjPqznfkuMKQ8DPTQRO8ZqG1hPGKEm9IgpGW4DZDgTNriTxvFiq+Lz+0cKfp4wj6OCK9JSnzNSn9LFU7UhKZZMnYwcJ8s8yRsECScK4j5UOB95HFO0CzhY4xJxuCix0lDlEUeMdS6EZBkTsUkZ4K74dugyTXS7aNgL8aqjDfkCE0ZbwkCXpaWCKhl8P7VD5jxykivSyxyZrYERbe168LYu9ZYh86IkscgVLE7tWPKmJv11CgoyJltMEbrohtVAQfO4ImltiHEroYEs7RxAarVpY8AwXMcMReFOTYWe5iiLRQxJ5Q8DtJ8LQhWOhIeFESPGsILhbNDRljNbHzNRlTFbk2S3L0NOS6V1KFJYKUbSTcIIhM0wQ/s2TM0SRMNcQmSap3jCH4yhJZKSkwyRHpYYgsFeQ4U7xoCB7VVOExhXepo9ABBsYbvGWKXPME3lyH95YioZ0gssQRWWbI+FaSMkXijZXwgiTlYdPdkNLaETxlyDVIwqeaEus0aTcYcg0RVOkpR3CSJqIddK+90JCxzsDVloyrFd5ZAr4TBKfaWa6boEA7C7s6EpYaeFPjveooY72mjIccLHJ9HUwVlDhKkmutJDJBwnp1rvulJZggKDRfbXAkvC/4l3ozQOG9a8lxjx0i7nV4jSXc7vhe3OwIxjgSHjdEhhsif9YkPGlus3iLFDnWOFhtCZbJg0UbQcIaR67JjthoCyMEZRwhiXWyxO5QxI6w5NhT4U1WsJvDO60J34fW9hwzwlKij6ZAW9ne4L0s8C6XeBMEkd/LQy1VucBRot6QMlbivaBhoBgjqGiCJNhsqVp/S2SsG6DIONCR0dXhvWbJ+MRRZJkkuEjgDXJjFQW6SSL7GXK8Z2CZg7cVsbWGoKmEpzQ5elpiy8Ryg7dMkLLUEauzeO86CuwlSOlgYLojZWeJ9xM3S1PWfEfKl5ISLQ0MEKR8YOB2QfCxJBjrKPCN4f9MkaSsqoVXJBmP7EpFZ9UQfOoOFwSzBN4MQ8LsGrymlipcJQhmy0GaQjPqCHaXRwuCZwRbqK2Fg9wlClZqYicrIgMdZfxTQ0c7TBIbrChxmuzoKG8XRaSrIhhiyNFJkrC7oIAWMEOQa5aBekPCRknCo4IKPrYkvCDI8aYmY7WFtprgekcJZ3oLIqssCSMtFbQTJKwXYy3BY5oCh2iKPCpJOE+zRdpYgi6O2KmOAgvVCYaU4ySRek1sgyFhJ403QFHiVEmJHwtybO1gs8Hr5+BETQX3War0qZngYGgtVZtoqd6vFSk/UwdZElYqyjrF4HXUeFspIi9IGKf4j92pKGAdCYMVsbcV3kRF0N+R8LUd5PCsIGWoxDtBkCI0nKofdJQxT+LtZflvuc8Q3CjwWkq8KwUpHzkK/NmSsclCL0nseQdj5FRH5CNHSgtLiW80Of5HU9Hhlsga9bnBq3fEVltKfO5IaSTmGjjc4J0otcP7QsJUSQM8pEj5/wCuUuC2DWz8AAAAAElFTkSuQmCC"); diff --git a/theme/midnight.css b/theme/midnight.css index f8016a81d8..2824dfa5f7 100644 --- a/theme/midnight.css +++ b/theme/midnight.css @@ -5,7 +5,7 @@ .cm-s-midnight.CodeMirror-focused span.CodeMirror-matchhighlight { background: #314D67 !important; } /**/ -.cm-s-midnight .activeline {background: #253540 !important;} +.cm-s-midnight .CodeMirror-activeline-background {background: #253540 !important;} .cm-s-midnight.CodeMirror { background: #0F192A; @@ -37,7 +37,6 @@ .cm-s-midnight span.cm-tag {color: #449;} .cm-s-midnight span.cm-link {color: #AE81FF;} -.cm-s-midnight .CodeMirror-activeline-background {background: #192741 !important;} .cm-s-midnight .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; diff --git a/theme/solarized.css b/theme/solarized.css index 85b1f0a888..f6b2a3f277 100644 --- a/theme/solarized.css +++ b/theme/solarized.css @@ -186,15 +186,10 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png Active line. Negative margin compensates left padding of the text in the view-port */ -.cm-s-solarized .activeline { - margin-left: -20px; -} - -.cm-s-solarized.cm-s-dark .activeline { +.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background { background: rgba(255, 255, 255, 0.05); - } -.cm-s-solarized.cm-s-light .activeline { +.cm-s-solarized.cm-s-light .CodeMirror-activeline-background { background: rgba(0, 0, 0, 0.05); } @@ -205,6 +200,3 @@ View-port and gutter both get little noise background to give it a real feel. .cm-s-solarized .CodeMirror-gutters { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAQAAAAHUWYVAABFFUlEQVQYGbzBCeDVU/74/6fj9HIcx/FRHx9JCFmzMyGRURhLZIkUsoeRfUjS2FNDtr6WkMhO9sm+S8maJfu+Jcsg+/o/c+Z4z/t97/vezy3z+z8ekGlnYICG/o7gdk+wmSHZ1z4pJItqapjoKXWahm8NmV6eOTbWUOp6/6a/XIg6GQqmenJ2lDHyvCFZ2cBDbmtHA043VFhHwXxClWmeYAdLhV00Bd85go8VmaFCkbVkzlQENzfBDZ5gtN7HwF0KDrTwJ0dypSOzpaKCMwQHKTIreYIxlmhXTzTWkVm+LTynZhiSBT3RZQ7aGfjGEd3qyXQ1FDymqbKxpspERQN2MiRjNZlFFQXfCNFm9nM1zpAsoYjmtRTc5ajwuaXc5xrWskT97RaKzAGe5ARHhVUsDbjKklziiX5WROcJwSNCNI+9w1Jwv4Zb2r7lCMZ4oq5C0EdTx+2GzNuKpJ+iFf38JEWkHJn9DNF7mmBDITrWEg0VWL3pHU20tSZnuqWu+R3BtYa8XxV1HO7GyD32UkOpL/yDloINFTmvtId+nmAjxRw40VMwVKiwrKLE4bK5UOVntYwhOcSSXKrJHKPJedocpGjVz/ZMIbnYUPB10/eKCrs5apqpgVmWzBYWpmtKHecJPjaUuEgRDDaU0oZghCJ6zNMQ5ZhDYx05r5v2muQdM0EILtXUsaKiQX9WMEUotagQzFbUNN6NUPC2nm5pxEWGCjMc3GdJHjSU2kORLK/JGSrkfGEIjncU/CYUnOipoYemwj8tST9NsJmB7TUVXtbUtXATJVZXBMvYeTXJfobgJUPmGMP/yFaWonaa6BcFO3nqcIqCozSZoZoSr1g4zJOzuyGnxTEX3lUEJ7WcZgme8ddaWvWJo2AJR9DZU3CUIbhCSG6ybSwN6qtJVnCU2svDTP2ZInOw2cBTrqtQahtNZn9NcJ4l2NaSmSkkP1noZWnVwkLmdUPOwLZEwy2Z3S3R+4rIG9hcbpPXHFVWcQdZkn2FOta3cKWQnNRC5g1LsJah4GCzSVsKnCOY5OAFRTBekyyryeyilhFKva75r4Mc0aWanGEaThcy31s439KKxTzJYY5WTHPU1FtIHjQU3Oip4xlNzj/lBw23dYZVliQa7WAXf4shetcQfatI+jWRDBPmyNeW6A1P5kdDgyYJlba0BIM8BZu1JfrFwItyjcAMR3K0BWOIrtMEXyhyrlVEx3ui5dUBjmB/Q3CXW85R4mBD0s7B+4q5tKUjOlb9qqmhi5AZ6GFIC5HXtOobdYGlVdMVbNJ8toNTFcHxnoL+muBagcctjWnbNMuR00uI7nQESwg5q2qqrKWIfrNUmeQocY6HuyxJV02wj36w00yhpmUFenv4p6fUkZYqLyuinx2RGOjhCXYyJF84oiU00YMOOhhquNdfbOB7gU88pY4xJO8LVdp6/q2voeB4R04vIdhSE40xZObx1HGGJ/ja0LBthFInKaLPPFzuCaYaoj8JjPME8yoyxo6zlBqkiUZYgq00OYMswbWO5NGmq+xhipxHLRW29ARjNKXO0wRnear8XSg4XFPLKEPUS1GqvyLwiuBUoa7zpZ0l5xxFwWmWZC1H5h5FwU8eQ7K+g8UcVY6TMQreVQT/8uQ8Z+ALIXnSEa2pYZQneE9RZbSBNYXfWYJzW/h/4j4Dp1tYVcFIC5019Vyi4ThPqSFCzjGWaHQTBU8q6vrVwgxP9Lkm840imWKpcLCjYTtrKuwvsKSnrvHCXGkSMk9p6lhckfRpIeis+N2PiszT+mFLspyGleUhDwcLrZqmyeylxwjBcKHEapqkmyangyLZRVOijwOtCY5SsG5zL0OwlCJ4y5KznF3EUNDDrinwiyLZRzOXtlBbK5ITHFGLp8Q0R6ab6mS7enI2cFrxOyHvOCFaT1HThS1krjCwqWeurCkk+willhCC+RSZnRXBiZaC5RXRIZYKp2lyfrHwiKPKR0JDzrdU2EFgpidawlFDR6FgXUMNa+g1FY3bUQh2cLCwosRdnuQTS/S+JVrGLeWIvtQUvONJxlqSQYYKpwoN2kaocLjdVsis4Mk80ESF2YpSkzwldjHkjFCUutI/r+EHDU8oCs6yzL3PhWiEooZdFMkymlas4AcI3KmoMMNSQ3tHzjGWCrcJJdYyZC7QFGwjRL9p+MrRkAGWzIaWCn9W0F3TsK01c2ZvQw0byvxuQU0r1lM0qJO7wW0kRIMdDTtXEdzi4VIh+EoIHm0mWtAtpCixlabgn83fKTI7anJe9ST7WIK1DMGpQmYeA58ImV6ezOGOzK2Kgq01pd60cKWiUi9Lievb/0vIDPHQ05Kzt4ddPckQBQtoaurjyHnek/nKzpQLrVgKPjIkh2v4uyezpv+Xoo7fPFXaGFp1vaLKxQ4uUpQQS5VuQs7BCq4xRJv7fwpVvvFEB3j+620haOuocqMhWd6TTPAEx+mdFNGHdranFe95WrWmIvlY4F1Dle2ECgc6cto7SryuqGGGha0tFQ5V53migUKmg6XKAo4qS3mik+0OZpAhOLeZKicacgaYcyx5hypYQE02ZA4xi/pNhOQxR4klNKyqacj+mpxnLTnnGSo85++3ZCZq6lrZkXlGEX3o+C9FieccJbZWVFjC0Yo1FZnJhoYMFoI1hEZ9r6hwg75HwzBNhbZCdJEfJwTPGzJvaKImw1yYX1HDAmpXR+ZJQ/SmgqMNVQb5vgamGwLtt7VwvP7Qk1xpiM5x5Cyv93E06MZmgs0Nya2azIKOYKCGBQQW97RmhKNKF02JZqHEJ4o58qp7X5EcZmc56trXEqzjCBZ1MFGR87Ql2tSTs6CGxS05PTzRQorkbw7aKoKXFDXsYW42VJih/q+FP2BdTzDTwVqOYB13liM50vG7wy28qagyuIXMeQI/Oqq8bcn5wJI50xH00CRntyfpL1T4hydYpoXgNiFzoIUTDZnLNRzh4TBHwbYGDvZkxmlyJloyr6tRihpeUG94GnKtIznREF0tzJG/OOr73JBcrSh1k6WuTprgLU+mnSGnv6Zge0NNz+kTDdH8nuAuTdJDCNb21LCiIuqlYbqGzT3RAoZofQfjFazkqeNWdYaGvYTM001EW2oKPvVk1ldUGSgUtHFwjKM1h9jnFcmy5lChoLNaQMGGDsYbKixlaMBmmsx1QjCfflwTfO/gckW0ruZ3jugKR3R5W9hGUWqCgxuFgsuaCHorotGKzGaeZB9DMsaTnKCpMtwTvOzhYk0rdrArKCqcaWmVk1+F372ur1YkKxgatI8Qfe1gIX9wE9FgS8ESmuABIXnRUbCapcKe+nO7slClSZFzpV/LkLncEb1qiO42fS3R855Su2mCLh62t1SYZZYVmKwIHjREF2uihTzB20JOkz7dkxzYQnK0UOU494wh+VWRc6Un2kpTaVgLDFEkJ/uhzRcI0YKGgpGWOlocBU/a4fKoJ/pEaNV6jip3+Es9VXY078rGnmAdf7t9ylPXS34RBSuYPs1UecZTU78WanhBCHpZ5sAoTz0LGZKjPf9TRypqWEiTvOFglL1fCEY3wY/++rbk7C8bWebA6p6om6PgOL2kp44TFJlVNBXae2rqqdZztOJpT87GQsE9jqCPIe9VReZuQ/CIgacsyZdCpIScSYqcZk8r+nsyCzhyfhOqHGOIvrLknC8wTpFcaYiGC/RU1NRbUeUpocQOnkRpGOrIOcNRx+1uA0UrzhSSt+VyS3SJpnFWkzNDqOFGIWcfR86DnmARTQ1HKIL33ExPiemeOhYSSjzlSUZZuE4TveoJLnBUOFof6KiysCbnAEcZgcUNTDOwkqWu3RWtmGpZwlHhJENdZ3miGz0lJlsKnjbwqSHQjpxnFDlTLLwqJPMZMjd7KrzkSG7VsxXBZE+F8YZkb01Oe00yyRK9psh5SYh29ySPKBo2ylNht7ZkZnsKenjKNJu9PNEyZpaCHv4Kt6RQsLvAVp7M9kIimmCUwGeWqLMmGuIotYMmWNpSahkhZw9FqZsVnKJhsjAHvtHMsTM9fCI06Dx/u3vfUXCqfsKRc4oFY2jMsoo/7DJDwZ1CsIKnJu+J9ldkpmiCxQx1rWjI+T9FwcWWzOuaYH0Hj7klNRVWEQpmaqosakiGNTFHdjS/qnUdmf0NJW5xsL0HhimCCZZSRzmSPTXJQ4aaztAwtZnoabebJ+htCaZ7Cm535ByoqXKbX1WRc4Eh2MkRXWzImVc96Cj4VdOKVxR84VdQsIUM8Psoou2byVHyZFuq7O8otbSQ2UAoeEWTudATLGSpZzVLlXVkPU2Jc+27lsw2jmg5T5VhbeE3BT083K9WsTTkFU/Osi0rC5lRlpwRHUiesNS0sOvmqGML1aRbPAxTJD9ZKtxuob+hhl8cwYGWpJ8nub7t5p6coYbMovZ1BTdaKn1jYD6h4GFDNFyT/Kqe1XCXphXHOKLZmuRSRdBPEfVUXQzJm5YGPGGJdvAEr7hHNdGZnuBvrpciGmopOLf5N0uVMy0FfYToJk90uUCbJupaVpO53UJXR2bVpoU00V2KOo4zMFrBd0Jtz2pa0clT5Q5L8IpQ177mWQejPMEJhuQjS10ref6HHjdEhy1P1EYR7GtO0uSsKJQYLiTnG1rVScj5lyazpqWGl5uBbRWl7m6ixGOOnEsMJR7z8J0n6KMnCdxhiNYQCoZ6CmYLnO8omC3MkW3bktlPmEt/VQQHejL3+dOE5FlPdK/Mq8hZxxJtLyRrepLThYKbLZxkSb5W52vYxNOaOxUF0yxMUPwBTYqCzy01XayYK0sJyWBLqX0MwU5CzoymRzV0EjjeUeLgDpTo6ij42ZAzvD01dHUUTPLU96MdLbBME8nFBn7zJCMtJcZokn8YoqU0FS5WFKyniHobguMcmW8N0XkWZjkyN3hqOMtS08r+/xTBwpZSZ3qiVRX8SzMHHjfUNFjgHEPmY9PL3ykEzxkSre/1ZD6z/NuznuB0RcE1TWTm9zRgfUWVJiG6yrzgmWPXC8EAR4Wxhlad0ZbgQyEz3pG5RVEwwDJH2mgKpjcTiCOzn1lfUWANFbZ2BA8balnEweJC9J0iuaeZoI+ippFCztEKVvckR2iice1JvhVytrQwUAZpgsubCPaU7xUe9vWnaOpaSBEspalykhC9bUlOMpT42ZHca6hyrqKmw/wMR8H5ZmdFoBVJb03O4UL0tSNnvIeRmkrLWqrs78gcrEn2tpcboh0UPOW3UUR9PMk4T4nnNKWmCjlrefhCwxRNztfmIQVdDElvS4m1/WuOujoZCs5XVOjtKPGokJzsYCtFYoWonSPT21DheU/wWhM19FcElwqNGOsp9Q8N/cwXaiND1MmeL1Q5XROtYYgGeFq1aTMsoMmcrKjQrOFQTQ1fmBYhmW6o8Jkjc7iDJRTBIo5kgJD5yMEYA3srCg7VFKwiVJkmRCc5ohGOKhsYMn/XBLdo5taZjlb9YAlGWRimqbCsoY7HFAXLa5I1HPRxMMsQDHFkWtRNniqT9UEeNjcE7RUlrCJ4R2CSJuqlKHWvJXjAUNcITYkenuBRB84TbeepcqTj3zZyFJzgYQdHnqfgI0ddUwS6GqWpsKWhjq9cV0vBAEMN2znq+EBfIWT+pClYw5xsTlJU6GeIBsjGmmANTzJZiIYpgrM0Oa8ZMjd7NP87jxhqGOhJlnQtjuQpB+8aEE00wZFznSJPyHxgH3HkPOsJFvYk8zqCHzTs1BYOa4J3PFU+UVRZxlHDM4YavlNUuMoRveiZA2d7grMNc2g+RbSCEKzmgYsUmWmazFJyoiOZ4KnyhKOGRzWJa0+moyV4TVHDzn51Awtqaphfk/lRQ08FX1iiqxTB/kLwd0VynKfEvI6cd4XMV5bMhZ7gZUWVzYQ6Nm2BYzxJbw3bGthEUUMfgbGeorae6DxHtJoZ6alhZ0+ytiVoK1R4z5PTrOECT/SugseEOlb1MMNR4VRNcJy+V1Hg9ONClSZFZjdHlc6W6FBLdJja2MC5hhpu0DBYEY1TFGwiFAxRRCsYkiM9JRb0JNMVkW6CZYT/2EiTGWmo8k+h4FhDNE7BvppoTSFnmCV5xZKzvcCdDo7VVPnIU+I+Rc68juApC90MwcFCsJ5hDqxgScYKreruyQwTqrzoqDCmhWi4IbhB0Yrt3RGa6GfDv52rKXWhh28dyZaWUvcZeMTBaZoSGyiCtRU5J8iviioHaErs7Jkj61syVzTTgOcUOQ8buFBTYWdL5g3T4qlpe0+wvD63heAXRfCCIed9RbCsp2CiI7raUOYOTU13N8PNHvpaGvayo4a3LLT1lDrVEPT2zLUlheB1R+ZTRfKWJ+dcocLJfi11vyJ51lLqJ0WD7tRwryezjiV5W28uJO9qykzX8JDe2lHl/9oyBwa2UMfOngpXCixvKdXTk3wrsKmiVYdZIqsoWEERjbcUNDuiaQomGoIbFdEHmsyWnuR+IeriKDVLnlawlyNHKwKlSU631PKep8J4Q+ayjkSLKYLhalNHlYvttb6fHm0p6OApsZ4l2VfdqZkjuysy6ysKLlckf1KUutCTs39bmCgEyyoasIWlVaMF7mgmWtBT8Kol5xpH9IGllo8cJdopcvZ2sImlDmMIbtDk3KIpeNiS08lQw11NFPTwVFlPP6pJ2gvRfI7gQUfmNAtf6Gs0wQxDsKGlVBdF8rCa3jzdwMaGHOsItrZk7hAyOzpK9VS06j5F49b0VNGOOfKs3lDToMsMBe9ZWtHFEgxTJLs7qrygKZjUnmCYoeAqeU6jqWuLJup4WghOdvCYJnrSkSzoyRkm5M2StQwVltPkfCAk58tET/CSg+8MUecmotMEnhBKfWBIZsg2ihruMJQaoIm+tkTLKEqspMh00w95gvFCQRtDwTT1gVDDSEVdlwqZfxoQRbK0g+tbiBZxzKlpnpypejdDwTaeOvorMk/IJE10h9CqRe28hhLbe0pMsdSwv4ZbhKivo2BjDWfL8UKJgeavwlwb5KlwhyE4u4XkGE2ytZCznKLCDZZq42VzT8HLCrpruFbIfOIINmh/qCdZ1ZBc65kLHR1Bkyf5zn6pN3SvGKIlFNGplhrO9QSXanLOMQTLCa0YJCRrCZm/CZmrLTm7WzCK4GJDiWUdFeYx1LCFg3NMd0XmCuF3Y5rITLDUsYS9zoHVzwnJoYpSTQoObyEzr4cFBNqYTopoaU/wkyLZ2lPhX/5Y95ulxGTV7KjhWrOZgl8MyUUafjYraNjNU1N3IWcjT5WzWqjwtoarHSUObGYO3GCJZpsBlnJGPd6ZYLyl1GdCA2625IwwJDP8GUKymbzuyPlZlvTUsaUh5zFDhRWFzPKKZLAlWdcQbObgF9tOqOsmB1dqcqYJmWstFbZRRI9poolmqiLnU0POvxScpah2iSL5UJNzgScY5+AuIbpO0YD3NCW+dLMszFSdFCWGqG6eVq2uYVNDdICGD6W7EPRWZEY5gpsE9rUkS3mijzzJnm6UpUFXG1hCUeVoS5WfNcFpblELL2qqrCvMvRfd45oalvKU2tiQ6ePJOVMRXase9iTtLJztPxJKLWpo2CRDcJwn2sWSLKIO1WQWNTCvpVUvOZhgSC40JD0dOctaSqzkCRbXsKlb11Oip6PCJ0IwSJM31j3akRxlP7Rwn6aGaUL0qiLnJkvB3xWZ2+Q1TfCwpQH3G0o92UzmX4o/oJNQMMSQc547wVHhdk+VCw01DFYEnTxzZKAm74QmeNNR1w6WzEhNK15VJzuCdxQ53dRUDws5KvwgBMOEgpcVNe0hZI6RXT1Jd0cyj5nsaEAHgVmGaJIlWdsc5Ui2ElrRR6jrRAttNMEAIWrTDFubkZaok7/AkzfIwfuWVq0jHzuCK4QabtLUMVPB3kJ0oyHTSVFlqMALilJf2Rf8k5aaHtMfayocLBS8L89oKoxpJvnAkDPa0qp5DAUTHKWmCcnthlou8iCKaFFLHWcINd1nyIwXqrSxMNmSs6KmoL2QrKuWtlQ5V0120xQ5vRyZS1rgFkWwhiOwiuQbR0OOVhQM9iS3tiXp4RawRPMp5tDletOOBL95MpM01dZTBM9pkn5qF010rIeHFcFZhmSGpYpTsI6nwhqe5C9ynhlpp5ophuRb6WcJFldkVnVEwwxVfrVkvnWUuNLCg5bgboFHPDlDPDmnK7hUrWiIbjadDclujlZcaokOFup4Ri1kacV6jmrrK1hN9bGwpKEBQ4Q6DvIUXOmo6U5LqQM6EPyiKNjVkPnJkDPNEaxhiFay5ExW1NXVUGqcpYYdPcGiCq7z/TSlbhL4pplWXKd7NZO5QQFrefhRQW/NHOsqcIglc4UhWklR8K0QzbAw08CBDnpbgqXdeD/QUsM4RZXDFBW6WJKe/mFPdH0LtBgiq57wFLzlyQzz82qYx5D5WJP5yVJDW01BfyHnS6HKO/reZqId1WGa4Hkh2kWodJ8i6KoIPlAj2hPt76CzXsVR6koPRzWTfKqIentatYpQw2me4AA3y1Kind3SwoOKZDcFXTwl9tWU6mfgRk9d71sKtlNwrjnYw5tC5n5LdKiGry3JKNlHEd3oaMCFHrazBPMp/uNJ+V7IudcSbeOIdjUEdwl0VHCOZo5t6YluEuaC9mQeMgSfOyKnYGFHcIeQ84yQWbuJYJpZw5CzglDH7gKnWqqM9ZTaXcN0TeYhR84eQtJT76JJ1lREe7WnnvsMmRc9FQ7SBBM9mV3lCUdmHk/S2RAMt0QjFNFqQpWjDPQ01DXWUdDBkXziKPjGEP3VP+zIWU2t7im41FOloyWzn/L6dkUy3VLDaZ6appgDLHPjJEsyvJngWEPUyVBiAaHCTEXwrLvSEbV1e1gKJniicWorC1MUrVjB3uDhJE/wgSOzk1DXpk0k73qCM8xw2UvD5kJmDUfOomqMpWCkJRlvKXGmoeBm18USjVIk04SClxTB6YrgLAPLWYK9HLUt5cmc0vYES8GnTeRc6skZbQkWdxRsIcyBRzx1DbTk9FbU0caTPOgJHhJKnOGIVhQqvKmo0llRw9sabrZkDtdg3PqaKi9oatjY8B+G371paMg6+mZFNNtQ04mWBq3rYLOmtWWQp8KJnpy9DdFensyjdqZ+yY40VJlH8wcdLzC8PZnvHMFUTZUrDTkLyQaGus5X5LzpYAf3i+e/ZlhqGqWhh6Ou6xTR9Z6oi5AZZtp7Mj2EEm8oSpxiYZCHU/1fbGdNNNRRoZMhmilEb2gqHOEJDtXkHK/JnG6IrvbPCwV3NhONVdS1thBMs1T4QOBcTWa2IzhMk2nW5Kyn9tXUtpv9RsG2msxk+ZsQzRQacJncpgke0+T8y5Fzj8BiGo7XlJjaTIlpQs7KFjpqGnKuoyEPeIKnFMkZHvopgh81ySxNFWvJWcKRs70j2FOT012IllEEO1n4pD1513Yg2ssQPOThOkvyrqHUdEXOSEsihmBbTbKX1kLBPWqWkLOqJbjB3GBIZmoa8qWl4CG/iZ7oiA72ZL7TJNeZUY7kFQftDcHHluBzRbCegzMtrRjVQpX2lgoPKKLJAkcbMl01XK2p7yhL8pCBbQ3BN2avJgKvttcrWDK3CiUOVxQ8ZP+pqXKyIxnmBymCg5vJjNfkPK4+c8cIfK8ocVt7kmfd/I5SR1hKvCzUtb+lhgc00ZaO6CyhIQP1Uv4yIZjload72PXX0OIJvnFU+0Zf6MhsJwTfW0r0UwQfW4LNLZl5HK261JCZ4qnBaAreVAS3WrjV0LBnNDUNNDToCEeFfwgcb4gOEqLRhirWkexrCEYKVV711DLYEE1XBEsp5tpTGjorkomKYF9FDXv7fR3BGwbettSxnyL53MBPjsxDZjMh+VUW9NRxq1DhVk+FSxQcaGjV9Pawv6eGByw5qzoy7xk4RsOShqjJwWKe/1pEEfzkobeD/dQJmpqedcyBTy2sr4nGNRH0c0SPWTLrqAc0OQcb/gemKgqucQT7ySWKCn2EUotoCvpZct7RO2sy/QW0IWcXd7pQRQyZVwT2USRO87uhjioTLKV2brpMUcMQRbKH/N2T+UlTpaMls6cmc6CCNy3JdYYSUzzJQ4oSD3oKLncULOiJvjBEC2oqnCJkJluCYy2ZQ5so9YYlZ1VLlQU1mXEW1jZERwj/MUSRc24TdexlqLKfQBtDTScJUV8FszXBEY5ktpD5Ur9hYB4Nb1iikw3JoYpkKX+RodRKFt53MMuRnKSpY31PwYaGaILh3wxJGz9TkTPEETxoCWZrgvOlmyMzxFEwVJE5xZKzvyJ4WxEc16Gd4Xe3Weq4XH2jKRikqOkGQ87hQnC7wBmGYLAnesX3M+S87eFATauuN+Qcrh7xIxXJbUIdMw3JGE3ylCWzrieaqCn4zhGM19TQ3z1oH1AX+pWEqIc7wNGAkULBo/ZxRaV9NNyh4Br3rCHZzbzmSfawBL0dNRwpW1kK9mxPXR9povcdrGSZK9c2k0xwFGzjuniCtRSZCZ6ccZ7gaktmgAOtKbG/JnOkJrjcQTdFMsxRQ2cLY3WTIrlCw1eWKn8R6pvt4GFDso3QoL4a3nLk3G6JrtME3dSenpx7PNFTmga0EaJTLQ061sEeQoWXhSo9LTXsaSjoJQRXeZLtDclbCrYzfzHHeaKjHCVOUkQHO3JeEepr56mhiyaYYKjjNU+Fed1wS5VlhWSqI/hYUdDOkaxiKehoyOnrCV5yBHtbWFqTHCCwtpDcYolesVR5yUzTZBb3RNMd0d6WP+SvhuBmRcGxnuQzT95IC285cr41cLGQ6aJJhmi4TMGempxeimBRQw1tFKV+8jd6KuzoSTqqDxzRtpZkurvKEHxlqXKRIjjfUNNXQsNOsRScoWFLT+YeRZVD3GRN0MdQcKqQjHDMrdGGVu3iYJpQx3WGUvfbmxwFfR20WBq0oYY7LMFhhgYtr8jpaEnaOzjawWWaTP8mMr0t/EPDPoqcnxTBI5o58L7uoWnMrpoqPwgVrlAUWE+V+TQl9rawoyP6QGAlQw2TPRX+YSkxyBC8Z6jhHkXBgQL7WII3DVFnRfCrBfxewv9D6xsyjys4VkhWb9pUU627JllV0YDNHMku/ldNMMXDEo4aFnAkk4U6frNEU4XgZUPmEKHUl44KrzmYamjAbh0JFvGnaTLPu1s9jPCwjFpYiN7z1DTOk/nc07CfDFzmCf7i+bfNHXhDtLeBXzTBT5rkMvWOIxpl4EMh2LGJBu2syDnAEx2naEhHDWMMzPZEhygyS1mS5RTJr5ZkoKbEUoYqr2kqdDUE8ztK7OaIntJkFrIECwv8LJTaVx5XJE86go8dFeZ3FN3rjabCAYpoYEeC9zzJVULBbmZhDyd7ko09ydpNZ3nm2Kee4FPPXHnYEF1nqOFEC08LUVcDvYXkJHW8gTaKCk9YGOeIJhqiE4ToPEepdp7IWFjdwnWaufGMwJJCMtUTTBBK9BGCOy2tGGrJTHIwyEOzp6aPzNMOtlZkDvcEWpP5SVNhfkvDxhmSazTJXYrM9U1E0xwFVwqZQwzJxw6+kGGGUj2FglGGmnb1/G51udRSMNlTw6GGnCcUwVcOpmsqTHa06o72sw1RL02p9z0VbnMLOaIX3QKaYKSCFQzBKEUNHTSc48k53RH9wxGMtpQa5KjjW0W0n6XCCCG4yxNNdhQ4R4l1Ff+2sSd6UFHiIEOyqqFgT01mEUMD+joy75jPhOA+oVVLm309FR4yVOlp4RhLiScNmSmaYF5Pw0STrOIoWMSR2UkRXOMp+M4SHW8o8Zoi6OZgjKOaFar8zZDzkWzvKOjkKBjmCXby8JahhjXULY4KlzgKLvAwxVGhvyd4zxB1d9T0piazmKLCVZY5sKiD0y2ZSYrkUEPUbIk+dlQ4SJHTR50k1DPaUWIdTZW9NJwnJMOECgd7ou/MnppMJ02O1VT4Wsh85MnZzcFTngpXGKo84qmwgKbCL/orR/SzJ2crA+t6Mp94KvxJUeIbT3CQu1uIdlQEOzlKfS3UMcrTiFmOuroocrZrT2AcmamOKg8YomeEKm/rlT2sociMaybaUlFhuqHCM2qIJ+rg4EcDFymiDSxzaHdPcpE62pD5kyM5SBMoA1PaUtfIthS85ig1VPiPPYXgYEMNk4Qq7TXBgo7oT57gPUdwgCHzhIVFPFU6OYJzHAX9m5oNrVjeE61miDrqQ4VSa1oiURTsKHC0IfjNwU2WzK6eqK8jWln4g15TVBnqmDteCJ501PGAocJhhqjZdtBEB6lnhLreFJKxmlKbeGrqLiSThVIbCdGzloasa6lpMQXHCME2boLpJgT7yWaemu6wBONbqGNVRS0PKIL7LckbjmQtR7K8I5qtqel+T/ChJTNIKLjdUMNIRyvOEko9YYl2cwQveBikCNawJKcLBbc7+JM92mysNvd/Fqp8a0k6CNEe7cnZrxlW0wQXaXjaktnRwNOGZKYiONwS7a1JVheq3WgJHlQUGKHKmp4KAxXR/ULURcNgoa4zhKSLpZR3kxRRb0NmD0OFn+UCS7CzI1nbP6+o4x47QZE5xRCt3ZagnYcvmpYQktXdk5YKXTzBC57kKEe0VVuiSYqapssMS3C9p2CKkHOg8B8Pa8p5atrIw3qezIWanMGa5HRDNF6RM9wcacl0N+Q8Z8hsIkSnaIIdHRUOEebAPy1zbCkhM062FCJtif7PU+UtoVXzWKqM1PxXO8cfdruhFQ/a6x3JKYagvVDhQEtNiyiiSQ7OsuRsZUku0CRNDs4Sog6KKjsZgk2bYJqijgsEenoKeniinRXBn/U3lgpPdyDZynQx8IiioMnCep5Ky8mjGs6Wty0l1hUQTcNWswS3WRp2kCNZwJG8omG8JphPUaFbC8lEfabwP7VtM9yoaNCAjpR41VNhrD9LkbN722v0CoZMByFzhaW+MyzRYEWFDQwN2M4/JiT76PuljT3VU/A36eaIThb+R9oZGOAJ9tewkgGvqOMNRWYjT/Cwu99Q8LqDE4TgbLWxJ1jaDDAERsFOFrobgjUsBScaguXU8kKm2RL19tRypSHnHNlHiIZqgufs4opgQdVdwxBNNFBR6kVFqb8ogimOzB6a6HTzrlDHEpYaxjiiA4TMQobkDg2vejjfwJGWmnbVFAw3H3hq2NyQfG7hz4aC+w3BbwbesG0swYayvpAs6++Ri1Vfzx93mFChvyN5xVHTS+0p9aqCAxyZ6ZacZyw5+7uuQkFPR9DDk9NOiE7X1PCYJVjVUqq7JlrHwWALF5nfHNGjApdpqgzx5OwilDhCiDYTgnc9waGW4BdLNNUQvOtpzDOWHDH8D7TR/A/85KljEQu3NREc4Pl/6B1Hhc8Umb5CsKMmGC9EPcxoT2amwHNCmeOEnOPbklnMkbOgIvO5UMOpQrS9UGVdt6iH/fURjhI/WOpaW9OKLYRod6HCUEdOX000wpDZQ6hwg6LgZfOqo1RfT/CrJzjekXOGhpc1VW71ZLbXyyp+93ILbC1kPtIEYx0FIx1VDrLoVzXRKRYWk809yYlC9ImcrinxtabKnzRJk3lAU1OLEN1j2zrYzr2myHRXJFf4h4QKT1qSTzTB5+ZNTzTRkAxX8FcLV2uS8eoQQ2aAkFzvCM72sJIcJET3WPjRk5wi32uSS9rfZajpWEvj9hW42F4o5NytSXYy8IKHay10VYdrcl4SkqscrXpMwyGOgtkajheSxdQqmpxP1L3t4R5PqasFnrQEjytq6qgp9Y09Qx9o4S1FzhUCn1kyHSzBWLemoSGvOqLNhZyBjmCaAUYpMgt4Ck7wBBMMwWKWgjsUwTaGVsxWC1mYoKiyqqeGKYqonSIRQ3KIkHO0pmAxTdBHkbOvfllfr+AA+7gnc50huVKYK393FOyg7rbPO/izI7hE4CnHHHnJ0ogNPRUGeUpsrZZTBJcrovUcJe51BPsr6GkJdhCCsZ6aTtMEb2pqWkqeVtDXE/QVggsU/Nl86d9RMF3DxvZTA58agu810RWawCiSzzXBeU3MMW9oyJUedvNEvQyNu1f10BSMddR1vaLCYpYa/mGocLSiYDcLbQz8aMn5iyF4xBNMs1P0QEOV7o5gaWGuzSeLue4tt3ro7y4Tgm4G/mopdZgl6q0o6KzJWE3mMksNr3r+a6CbT8g5wZNzT9O7fi/zpaOmnz3BRoqos+tv9zMbdpxsqDBOEewtJLt7cg5wtKKbvldpSzRRCD43VFheCI7yZLppggMVBS/KMAdHODJvOwq2NQSbKKKPLdFWQs7Fqo+mpl01JXYRgq8dnGLhTiFzqmWsUMdpllZdbKlyvSdYxhI9YghOtxR8LgSLWHK62mGGVoxzBE8LNWzqH9CUesQzFy5RQzTc56mhi6fgXEWwpKfE5Z7M05ZgZUPmo6auiv8YKzDYwWBLMErIbKHJvOwIrvEdhOBcQ9JdU1NHQ7CXn2XIDFBKU2WAgcX9UAUzDXWd5alwuyJ41Z9rjKLCL4aCp4WarhPm2rH+SaHUYE001JDZ2ZAzXPjdMpZWvC9wmqIB2lLhQ01D5jO06hghWMndbM7yRJMsoCj1vYbnFQVrW9jak3OlEJ3s/96+p33dEPRV5GxiqaGjIthUU6FFEZyqCa5qJrpBdzSw95IUnOPIrCUUjRZQFrbw5PR0R1qiYx3cb6nrWUMrBmmiBQxVHtTew5ICP/ip6g4hed/Akob/32wvBHsIOX83cI8hGeNeNPCIkPmXe8fPKx84OMSRM1MTdXSwjCZ4S30jVGhvqTRak/OVhgGazHuOCud5onEO1lJr6ecVyaOK6H7zqlBlIaHE0oroCgfvGJIdPcmfLNGLjpz7hZwZQpUbFME0A1cIJa7VNORkgfsMBatbKgwwJM9bSvQXeNOvbIjelg6WWvo5kvbKaJJNHexkKNHL9xRyFlH8Ti2riB5wVPhUk7nGkJnoCe428LR/wRGdYIlmWebCyxou1rCk4g/ShugBDX0V0ZQWkh0dOVsagkM0yV6OoLd5ye+pRlsCr0n+KiQrGuq5yJDzrTAXHtLUMduTDBVKrSm3eHL+6ijxhFDX9Z5gVU/wliHYTMiMFpKLNMEywu80wd3meoFmt6VbRMPenhrOc6DVe4pgXU8DnnHakLOIIrlF4FZPIw6R+zxBP0dyq6OOZ4Q5sLKCcz084ok+VsMMyQhNZmmBgX5xIXOEJTmi7VsGTvMTNdHHhpzdbE8Du2oKxgvBqQKdDDnTFOylCFaxR1syz2iqrOI/FEpNc3C6f11/7+ASS6l2inq2ciTrCCzgyemrCL5SVPjQkdPZUmGy2c9Sw9FtR1sS30RmsKPCS4rkIC/2U0MduwucYolGaPjKEyhzmiPYXagyWbYz8LWBDdzRimAXzxx4z8K9hpzlhLq+NiQ97HuKorMUfK/OVvC2JfiHUPCQI/q7J2gjK+tTDNxkCc4TMssqCs4TGtLVwQihyoAWgj9bosU80XGW6Ac9TJGziaUh5+hnFcHOnlaM1iRn29NaqGENTTTSUHCH2tWTeV0osUhH6psuVLjRUmGWhm6OZEshGeNowABHcJ2Bpy2ZszRcKkRXd2QuKVEeXnbfaEq825FguqfgfE2whlChSRMdron+LATTPQ2Z369t4B9C5gs/ylzv+CMmepIDPclFQl13W0rspPd1JOcbghGOEutqCv5qacURQl3dDKyvyJlqKXGPgcM9FfawJAMVmdcspcYKOZc4GjDYkFlK05olNMHyHn4zFNykyOxt99RkHlfwmiHo60l2EKI+mhreEKp080Tbug08BVPcgoqC5zWt+NLDTZ7oNSF51N1qie7Va3uCCwyZbkINf/NED6jzOsBdZjFN8oqG3wxVunqCSYYKf3EdhJyf9YWGf7tRU2oH3VHgPr1fe5J9hOgHd7xQ0y7qBwXr23aGErP0cm64JVjZwsOGqL+mhNgZmhJLW2oY4UhedsyBgzrCKrq7BmcpNVhR6jBPq64Vgi+kn6XE68pp8J5/+0wRHGOpsKenQn9DZntPzjRLZpDAdD2fnSgkG9tmIXnUwQ6WVighs7Yi2MxQ0N3CqYaCXkJ0oyOztMDJjmSSpcpvlrk0RMMOjmArQ04PRV1DO1FwhCVaUVPpKUM03JK5SxPsIWRu8/CGHi8UHChiqGFDTbSRJWeYUDDcH6vJWUxR4k1FXbMUwV6e4AJFXS8oMqsZKqzvYQ9DDQdZckY4aGsIhtlubbd2r3j4QBMoTamdPZk7O/Bf62lacZwneNjQoGcdVU7zJOd7ghsUHOkosagic6cnWc8+4gg285R6zZP5s1/LUbCKIznTwK36PkdwlOrl4U1LwfdCCa+IrvFkmgw1PCAUXKWo0sURXWcI2muKJlgyFzhynCY4RBOsqCjoI1R5zREco0n2Vt09BQtYSizgKNHfUmUrQ5UOCh51BFcLmY7umhYqXKQomOop8bUnWNNQcIiBcYaC6xzMNOS8JQQfeqKBmmglB+97ok/lfk3ygaHSyZaCRTzRxQo6GzLfa2jWBPepw+UmT7SQEJyiyRkhBLMVOfcoMjcK0eZChfUNzFAUzCsEN5vP/X1uP/n/aoMX+K+nw/Hjr/9xOo7j7Pju61tLcgvJpTWXNbfN5jLpi6VfCOviTktKlFusQixdEKWmEBUKNaIpjZRSSOXSgzaaKLdabrm1/9nZ+/f+vd/vz/v9+Xy+zZ7PRorYoZqyLrCwQdEAixxVOEXNNnjX2nUSRlkqGmWowk8lxR50JPy9Bo6qJXaXwNvREBvnThPEPrewryLhcAnj5WE15Fqi8W7R1sAuEu86S4ENikItFN4xkv9Af4nXSnUVcLiA9xzesFpivRRVeFKtsMRaKBhuSbjOELnAUtlSQUpXgdfB4Z1oSbnFEetbQ0IrAe+Y+pqnDcEJFj6S8LDZzZHwY4e3XONNlARraomNEt2bkvGsosA3ioyHm+6jCMbI59wqt4eeara28IzEmyPgoRaUOEDhTVdEJhmCoTWfC0p8aNkCp0oYqih2iqGi4yXeMkOsn4LdLLnmKfh/YogjNsPebeFGR4m9BJHLzB61XQ3BtpISfS2FugsK9FAtLWX1dCRcrCnUp44CNzuCowUZmxSRgYaE6Za0W2u/E7CVXCiI/UOR8aAm1+OSyE3mOUcwyc1zBBeoX1kiKy0Zfxck1Gsyulti11i83QTBF5Kg3pDQThFMVHiPSlK+0cSedng/VaS8bOZbtsBcTcZAR8JP5KeqQ1OYKAi20njdNNRpgnsU//K+JnaXJaGTomr7aYIphoRn9aeShJWKEq9LcozSF7QleEfDI5LYm5bgVkFkRwVDBCVu0DDIkGupo8TZBq+/pMQURYErJQmPKGKjNDkWOLx7Jd5QizdUweIaKrlP7SwJDhZvONjLkOsBBX9UpGxnydhXkfBLQ8IxgojQbLFnJf81JytSljclYYyEFyx0kVBvKWOFJmONpshGAcsduQY5giVNCV51eOdJYo/pLhbvM0uDHSevNKRcrKZIqnCtJeEsO95RoqcgGK4ocZcho1tTYtcZvH41pNQ7vA0WrhIfOSraIIntIAi+NXWCErdbkvrWwjRLrt0NKUdL6KSOscTOdMSOUtBHwL6OLA0vNSdynaWQEnCpIvKaIrJJEbvHkmuNhn6OjM8VkSGSqn1uYJCGHnq9I3aLhNME3t6GjIkO7xrNFumpyTNX/NrwX7CrIRiqqWijI9JO4d1iieykyfiposQIQ8YjjsjlBh6oHWbwRjgYJQn2NgSnNycmJAk3NiXhx44Sxykihxm8ybUwT1OVKySc7vi3OXVkdBJ4AyXBeksDXG0IhgtYY0lY5ahCD0ehborIk5aUWRJviMA7Xt5kyRjonrXENkm8yYqgs8VzgrJmClK20uMM3jRJ0FiQICQF9hdETlLQWRIb5ki6WDfWRPobvO6a4GP5mcOrNzDFELtTkONLh9dXE8xypEg7z8A9jkhrQ6Fhjlg/QVktJXxt4WXzT/03Q8IaQWSqIuEvloQ2mqC9Jfi7wRul4RX3pSPlzpoVlmCtI2jvKHCFhjcM3sN6lqF6HxnKelLjXWbwrpR4xzuCrTUZx2qq9oAh8p6ixCUGr78g8oyjRAtB5CZFwi80VerVpI0h+IeBxa6Zg6kWvpDHaioYYuEsRbDC3eOmC2JvGYLeioxGknL2UATNJN6hmtj1DlpLvDVmocYbrGCVJKOrg4X6DgddLA203BKMFngdJJFtFd7vJLm6KEpc5yjQrkk7M80SGe34X24nSex1Ra5Omgb71JKyg8SrU3i/kARKwWpH0kOGhKkObyfd0ZGjvyXlAkVZ4xRbYJ2irFMkFY1SwyWxr2oo4zlNiV+7zmaweFpT4kR3kaDAFW6xpSqzJay05FtYR4HmZhc9UxKbbfF2V8RG1MBmSaE+kmC6JnaRXK9gsiXhJHl/U0qM0WTcbyhwkYIvFGwjSbjfwhiJt8ZSQU+Bd5+marPMOkVkD0muxYLIfEuhh60x/J92itguihJSEMySVPQnTewnEm+620rTQEMsOfo4/kP/0ARvWjitlpSX7GxBgcMEsd3EEeYWvdytd+Saawi6aCIj1CkGb6Aj9rwhx16Cf3vAwFy5pyLhVonXzy51FDpdEblbkdJbUcEPDEFzQ8qNmhzzLTmmKWKbFCXeEuRabp6rxbvAtLF442QjQ+wEA9eL1xSR7Q0JXzlSHjJ4exq89yR0laScJ/FW6z4a73pFMEfDiRZvuvijIt86RaSFOl01riV2mD1UEvxGk/Geg5aWwGki1zgKPG9J2U8PEg8qYvMsZeytiTRXBMslCU8JSlxi8EabjwUldlDNLfzTUmCgxWsjqWCOHavYAqsknKFIO0yQ61VL5AVFxk6WhEaCAkdJgt9aSkzXlKNX2jEa79waYuc7gq0N3GDJGCBhoiTXUEPsdknCUE1CK0fwsiaylSF2uiDyO4XX3pFhNd7R4itFGc0k/ElBZwWvq+GC6szVeEoS/MZ+qylwpKNKv9Z469UOjqCjwlusicyTxG6VpNxcQ8IncoR4RhLbR+NdpGGmJWOcIzJGUuKPGpQg8rrG21dOMqQssJQ4RxH5jaUqnZuQ0F4Q+cjxLwPtpZbIAk3QTJHQWBE5S1BokoVtDd6lhqr9UpHSUxMcIYl9pojsb8h4SBOsMQcqvOWC2E8EVehqiJ1hrrAEbQxeK0NGZ0Gkq+guSRgniM23bIHVkqwx4hiHd7smaOyglyIyQuM978j4VS08J/A2G1KeMBRo4fBaSNhKUEZfQewVQ/C1I+MgfbEleEzCUw7mKXI0M3hd1EESVji8x5uQ41nxs1q4RMJCCXs7Iq9acpxn22oSDnQ/sJTxsCbHIYZiLyhY05TY0ZLIOQrGaSJDDN4t8pVaIrsqqFdEegtizc1iTew5Q4ayBDMUsQMkXocaYkc0hZua412siZ1rSXlR460zRJ5SlHGe5j801RLMlJTxtaOM3Q1pvxJ45zUlWFD7rsAbpfEm1JHxG0eh8w2R7QQVzBUw28FhFp5QZzq8t2rx2joqulYTWSuJdTYfWwqMFMcovFmSyJPNyLhE4E10pHzYjOC3huArRa571ZsGajQpQx38SBP5pyZB6lMU3khDnp0MBV51BE9o2E+TY5Ml2E8S7C0o6w1xvCZjf0HkVEHCzFoyNmqC+9wdcqN+Tp7jSDheE9ws8Y5V0NJCn2bk2tqSY4okdrEhx1iDN8cSudwepWmAGXKcJXK65H9to8jYQRH7SBF01ESUJdd0TayVInaWhLkOjlXE5irKGOnI6GSWGCJa482zBI9rCr0jyTVcEuzriC1vcr6mwFGSiqy5zMwxBH/TJHwjSPhL8+01kaaSUuMFKTcLEvaUePcrSmwn8DZrgikWb7CGPxkSjhQwrRk57tctmxLsb9sZvL9LSlyuSLlWkqOjwduo8b6Uv1DkmudIeFF2dHCgxVtk8dpIvHpBxhEOdhKk7OLIUSdJ+cSRY57B+0DgGUUlNfpthTfGkauzxrvTsUUaCVhlKeteTXCoJDCa2NOKhOmC4G1H8JBd4OBZReSRGkqcb/CO1PyLJTLB4j1q8JYaIutEjSLX8YKM+a6phdMsdLFUoV5RTm9JSkuDN8WcIon0NZMNZWh1q8C7SJEwV5HxrmnnTrf3KoJBlmCYI2ilSLlfEvlE4011NNgjgthzEua0oKK7JLE7HZHlEl60BLMVFewg4EWNt0ThrVNEVkkiTwpKXSWJzdRENgvKGq4IhjsiezgSFtsfCUq8qki5S1LRQeYQQ4nemmCkImWMw3tFUoUBZk4NOeZYEp4XRKTGa6wJjrWNHBVJR4m3FCnbuD6aak2WsMTh3SZImGCIPKNgsDpVwnsa70K31lCFJZYcwwSMFcQulGTsZuEaSdBXkPGZhu0FsdUO73RHjq8MPGGIfaGIbVTk6iuI3GFgucHrIQkmWSJdBd7BBu+uOryWAhY7+Lki9rK5wtEQzWwvtbqGhIMFwWRJsElsY4m9IIg9L6lCX0VklaPAYkfkZEGDnOWowlBJjtMUkcGK4Lg6EtoZInMUBVYLgn0UsdmCyCz7gIGHFfk+k1QwTh5We7A9x+IdJ6CvIkEagms0hR50eH9UnTQJ+2oiKyVlLFUE+8gBGu8MQ3CppUHesnjTHN4QB/UGPhCTHLFPHMFrCqa73gqObUJGa03wgbhHkrCfpEpzNLE7JDS25FMKhlhKKWKfCgqstLCPu1zBXy0J2ztwjtixBu8UTRn9LVtkmCN2iyFhtME70JHRQ1KVZXqKI/KNIKYMCYs1GUMEKbM1bKOI9LDXC7zbHS+bt+1MTWS9odA9DtrYtpbImQJ2VHh/lisEwaHqUk1kjKTAKknkBEXkbkdMGwq0dnhzLJF3NJH3JVwrqOB4Sca2hti75nmJN0WzxS6UxDYoEpxpa4htVlRjkYE7DZGzJVU72uC9IyhQL4i8YfGWSYLLNcHXloyz7QhNifmKSE9JgfGmuyLhc403Xm9vqcp6gXe3xuuv8F6VJNxkyTHEkHG2g0aKXL0MsXc1bGfgas2//dCONXiNLCX+5mB7eZIl1kHh7ajwpikyzlUUWOVOsjSQlsS+M0R+pPje/dzBXRZGO0rMtgQrLLG9VSu9n6CMXS3BhwYmSoIBhsjNBmZbgusE9BCPCP5triU4VhNbJfE+swSP27aayE8tuTpYYjtrYjMVGZdp2NpS1s6aBnKSHDsbKuplKbHM4a0wMFd/5/DmGyKrJSUaW4IBrqUhx0vyfzTBBLPIUcnZdrAkNsKR0sWRspumSns6Ch0v/qqIbBYUWKvPU/CFoyrDJGwSNFhbA/MlzKqjrO80hRbpKx0Jewsi/STftwGSlKc1JZyAzx05dhLEdnfQvhZOqiHWWEAHC7+30FuRcZUgaO5gpaIK+xsiHRUsqaPElTV40xQZQ107Q9BZE1nryDVGU9ZSQ47bmhBpLcYpUt7S+xuK/FiT8qKjwXYw5ypS2iuCv7q1gtgjhuBuB8LCFY5cUuCNtsQOFcT+4Ih9JX+k8Ea6v0iCIRZOtCT0Et00JW5UeC85Cg0ScK0k411HcG1zKtre3SeITBRk7WfwDhEvaYLTHP9le0m8By0JDwn4TlLW/aJOvGHxdjYUes+ScZigCkYQdNdEOhkiezgShqkx8ueKjI8lDfK2oNiOFvrZH1hS+tk7NV7nOmLHicGWEgubkXKdwdtZknCLJXaCpkrjZBtLZFsDP9CdxWsSr05Sxl6CMmoFbCOgryX40uDtamB7SVmXW4Ihlgpmq+00tBKUUa83WbjLUNkzDmY7cow1JDygyPGlhgGKYKz4vcV7QBNbJIgM11TUqZaMdwTeSguH6rOaw1JRKzaaGyxVm2EJ/uCIrVWUcZUkcp2grMsEjK+DMwS59jQk3Kd6SEq1d0S6uVmO4Bc1lDXTUcHjluCXEq+1OlBDj1pi9zgiXxnKuE0SqTXwhqbETW6RggMEnGl/q49UT2iCzgJvRwVXS2K/d6+ZkyUl7jawSVLit46EwxVljDZwoSQ20sDBihztHfk2yA8NVZghiXwrYHQdfKAOtzsayjhY9bY0yE2CWEeJ9xfzO423xhL5syS2TFJofO2pboHob0nY4GiAgRrvGQEDa/FWSsoaaYl0syRsEt3kWoH3B01shCXhTUWe9w3Bt44SC9QCh3eShQctwbaK2ApLroGCMlZrYqvlY3qYhM0aXpFkPOuoqJ3Dm6fxXrGwVF9gCWZagjPqznfkuMKQ8DPTQRO8ZqG1hPGKEm9IgpGW4DZDgTNriTxvFiq+Lz+0cKfp4wj6OCK9JSnzNSn9LFU7UhKZZMnYwcJ8s8yRsECScK4j5UOB95HFO0CzhY4xJxuCix0lDlEUeMdS6EZBkTsUkZ4K74dugyTXS7aNgL8aqjDfkCE0ZbwkCXpaWCKhl8P7VD5jxykivSyxyZrYERbe168LYu9ZYh86IkscgVLE7tWPKmJv11CgoyJltMEbrohtVAQfO4ImltiHEroYEs7RxAarVpY8AwXMcMReFOTYWe5iiLRQxJ5Q8DtJ8LQhWOhIeFESPGsILhbNDRljNbHzNRlTFbk2S3L0NOS6V1KFJYKUbSTcIIhM0wQ/s2TM0SRMNcQmSap3jCH4yhJZKSkwyRHpYYgsFeQ4U7xoCB7VVOExhXepo9ABBsYbvGWKXPME3lyH95YioZ0gssQRWWbI+FaSMkXijZXwgiTlYdPdkNLaETxlyDVIwqeaEus0aTcYcg0RVOkpR3CSJqIddK+90JCxzsDVloyrFd5ZAr4TBKfaWa6boEA7C7s6EpYaeFPjveooY72mjIccLHJ9HUwVlDhKkmutJDJBwnp1rvulJZggKDRfbXAkvC/4l3ozQOG9a8lxjx0i7nV4jSXc7vhe3OwIxjgSHjdEhhsif9YkPGlus3iLFDnWOFhtCZbJg0UbQcIaR67JjthoCyMEZRwhiXWyxO5QxI6w5NhT4U1WsJvDO60J34fW9hwzwlKij6ZAW9ne4L0s8C6XeBMEkd/LQy1VucBRot6QMlbivaBhoBgjqGiCJNhsqVp/S2SsG6DIONCR0dXhvWbJ+MRRZJkkuEjgDXJjFQW6SSL7GXK8Z2CZg7cVsbWGoKmEpzQ5elpiy8Ryg7dMkLLUEauzeO86CuwlSOlgYLojZWeJ9xM3S1PWfEfKl5ISLQ0MEKR8YOB2QfCxJBjrKPCN4f9MkaSsqoVXJBmP7EpFZ9UQfOoOFwSzBN4MQ8LsGrymlipcJQhmy0GaQjPqCHaXRwuCZwRbqK2Fg9wlClZqYicrIgMdZfxTQ0c7TBIbrChxmuzoKG8XRaSrIhhiyNFJkrC7oIAWMEOQa5aBekPCRknCo4IKPrYkvCDI8aYmY7WFtprgekcJZ3oLIqssCSMtFbQTJKwXYy3BY5oCh2iKPCpJOE+zRdpYgi6O2KmOAgvVCYaU4ySRek1sgyFhJ403QFHiVEmJHwtybO1gs8Hr5+BETQX3War0qZngYGgtVZtoqd6vFSk/UwdZElYqyjrF4HXUeFspIi9IGKf4j92pKGAdCYMVsbcV3kRF0N+R8LUd5PCsIGWoxDtBkCI0nKofdJQxT+LtZflvuc8Q3CjwWkq8KwUpHzkK/NmSsclCL0nseQdj5FRH5CNHSgtLiW80Of5HU9Hhlsga9bnBq3fEVltKfO5IaSTmGjjc4J0otcP7QsJUSQM8pEj5/wCuUuC2DWz8AAAAAElFTkSuQmCC"); } - -.cm-s-solarized.cm-s-dark .CodeMirror-activeline-background {background: #013542 !important;} -.cm-s-solarized.cm-s-light .CodeMirror-activeline-background {background: #EBE0C3 !important;} \ No newline at end of file From ba9033cf06bdf8ba1c05673426e22c3a07396ec8 Mon Sep 17 00:00:00 2001 From: Maksym Taran Date: Tue, 13 Aug 2013 23:52:16 -0700 Subject: [PATCH 0909/5273] [clike mode] Add syntax examples for C++ & Java. --- mode/clike/index.html | 89 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/mode/clike/index.html b/mode/clike/index.html index 58ba24c380..45add4910b 100644 --- a/mode/clike/index.html +++ b/mode/clike/index.html @@ -25,7 +25,8 @@

    C-like mode

    -
    +
    + +

    C++ example

    + +
    + +

    Java example

    + +

    Simple mode that tries to handle C-like languages as well as it @@ -111,4 +192,4 @@

    C-like mode

    (C code), text/x-c++src (C++ code), text/x-java (Java code), text/x-csharp (C#).

    - + From 993dceea2f84c6f43ca0da7bcd7123ea873ed5ab Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Tue, 13 Aug 2013 19:09:16 +0200 Subject: [PATCH 0910/5273] [tests] Support the other format of error.stack This makes error.stack parsing work in Firefox and Opera 12-, and maybe in Safari too (didn't test). --- test/driver.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/driver.js b/test/driver.js index 8c32ec7faa..5befa77278 100644 --- a/test/driver.js +++ b/test/driver.js @@ -84,7 +84,7 @@ function runTests(callback) { if (expFail) callback("expected", test.name); else if (e instanceof Failure) callback("fail", test.name, e.message); else { - var pos = /\bat .*?([^\/:]+):(\d+):/.exec(e.stack); + var pos = /(?:\bat |@).*?([^\/:]+):(\d+)/.exec(e.stack); callback("error", test.name, e.toString() + (pos ? " (" + pos[1] + ":" + pos[2] + ")" : "")); } } From f790cbeeafd50c5c5956b08d98c116f10b38b3b8 Mon Sep 17 00:00:00 2001 From: Chandra Sekhar Pydi Date: Wed, 14 Aug 2013 15:05:00 -0700 Subject: [PATCH 0911/5273] [continuecomment addon] Continue blocks only if mode has blockCommentContinue Changes in https://github.com/marijnh/CodeMirror/pull/1731 are missing. --- addon/comment/continuecomment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/comment/continuecomment.js b/addon/comment/continuecomment.js index 308026229f..9dba156189 100644 --- a/addon/comment/continuecomment.js +++ b/addon/comment/continuecomment.js @@ -10,7 +10,7 @@ var mode = CodeMirror.innerMode(cm.getMode(), token.state).mode; var space; - if (token.type == "comment" && mode.blockCommentStart) { + if (token.type == "comment" && 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) { From f2c3bf51e6be8c0388b300ab1d3915775c4fd33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=20Erik=20St=C3=B8wer?= Date: Wed, 14 Aug 2013 21:26:55 +0200 Subject: [PATCH 0912/5273] [css mode] Added keep-all to valueKeywords. Valid value of e.g. word-break --- 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 0889c12e52..8abfb315c2 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -488,7 +488,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", "inline-block", "inline-table", "inset", "inside", "intrinsic", "invert", - "italic", "justify", "kannada", "katakana", "katakana-iroha", "khmer", + "italic", "justify", "kannada", "katakana", "katakana-iroha", "keep-all", "khmer", "landscape", "lao", "large", "larger", "left", "level", "lighter", "line-through", "linear", "lines", "list-item", "listbox", "listitem", "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", From aef141a143b477a5d1bbfa61054734771676db23 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 19 Aug 2013 15:44:33 +0200 Subject: [PATCH 0913/5273] [project page] Clarify sentence --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 127672dc8b..96e2eecd24 100644 --- a/index.html +++ b/index.html @@ -182,7 +182,7 @@

    Browser support

    Modern mobile browsers tend to partly work. Bug reports and patches for mobile support are welcome, but the maintainer does not - have the time budget to actually work on it himself.

    + have the time or budget to actually work on it himself.

    From 8214c1fa2c9dc34dbae56958f3a21555cb092b48 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 19 Aug 2013 15:57:38 +0200 Subject: [PATCH 0914/5273] [javascript mode] Improve number tokenizing A leading minus isn't part of the number token, but numbers can start with a dot, which wasn't handled before. Closes #1753 --- mode/javascript/javascript.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 0be9b79f7c..e8ace32d89 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -78,18 +78,19 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { type = tp; content = cont; return style; } - function jsTokenBase(stream, state) { var ch = stream.next(); if (ch == '"' || ch == "'") return chain(stream, state, jsTokenString(ch)); + else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) + return ret("number", "number"); else if (/[\[\]{}\(\),;\:\.]/.test(ch)) return ret(ch); else if (ch == "0" && stream.eat(/x/i)) { stream.eatWhile(/[\da-f]/i); return ret("number", "number"); } - else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) { + else if (/\d/.test(ch)) { stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/); return ret("number", "number"); } From 3b501519ffe8a0e1380ac2d746d754626f6f3528 Mon Sep 17 00:00:00 2001 From: mats cronqvist Date: Fri, 16 Aug 2013 13:43:06 +0200 Subject: [PATCH 0915/5273] [erlang-mode] Improvements --- mode/erlang/erlang.js | 184 +++++++++++++++++++++++------------------- theme/erlang-dark.css | 10 ++- 2 files changed, 108 insertions(+), 86 deletions(-) diff --git a/mode/erlang/erlang.js b/mode/erlang/erlang.js index f6e304c93a..af8953c33b 100644 --- a/mode/erlang/erlang.js +++ b/mode/erlang/erlang.js @@ -19,6 +19,7 @@ CodeMirror.defineMode("erlang", function(cmCfg) { switch (type) { case "atom": return "atom"; case "attribute": return "attribute"; + case "boolean": return "special"; case "builtin": return "builtin"; case "comment": return "comment"; case "fun": return "meta"; @@ -47,6 +48,7 @@ CodeMirror.defineMode("erlang", function(cmCfg) { "after","begin","catch","case","cond","end","fun","if", "let","of","query","receive","try","when"]; + var separatorRE = /[\->\.,:;]/; var separatorWords = [ "->",";",":",".",","]; @@ -54,12 +56,15 @@ CodeMirror.defineMode("erlang", function(cmCfg) { "and","andalso","band","bnot","bor","bsl","bsr","bxor", "div","not","or","orelse","rem","xor"]; + var symbolRE = /[\+\-\*\/<>=\|:!]/; var symbolWords = [ - "+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-"]; + "+","-","*","/",">",">=","<","=<","=:=","==","=/=","/=","||","<-","!"]; + var openParenRE = /[<\(\[\{]/; var openParenWords = [ "<<","(","[","{"]; + var closeParenRE = /[>\)\]\}]/; var closeParenWords = [ "}","]",")",">>"]; @@ -94,37 +99,14 @@ CodeMirror.defineMode("erlang", function(cmCfg) { "term_to_binary","time","throw","tl","trunc","tuple_size", "tuple_to_list","unlink","unregister","whereis"]; - // ignored for indenting purposes - var ignoreWords = [ - ",", ":", "catch", "after", "of", "cond", "let", "query"]; - - - var smallRE = /[a-z_]/; - var largeRE = /[A-Z_]/; - var digitRE = /[0-9]/; - var octitRE = /[0-7]/; - var anumRE = /[a-z_A-Z0-9]/; - var symbolRE = /[\+\-\*\/<>=\|:]/; - var openParenRE = /[<\(\[\{]/; - var closeParenRE = /[>\)\]\}]/; - var sepRE = /[\->\.,:;]/; - - function isMember(element,list) { - return (-1 < list.indexOf(element)); - } - - function isPrev(stream,string) { - var start = stream.start; - var len = string.length; - if (len <= start) { - var word = stream.string.slice(start-len,start); - return word == string; - }else{ - return false; - } - } +// [Ø-Þ] [À-Ö] +// [ß-ö] [ø-ÿ] + var anumRE = /[\w@Ø-ÞÀ-Öß-öø-ÿ]/; + var escapesRE = + /[0-7]{1,3}|[bdefnrstv\\"']|\^[a-zA-Z]|x[0-9a-zA-Z]{2}|x{[0-9a-zA-Z]+}/; function tokenize(stream, state) { + // in multi-line string if (state.in_string) { state.in_string = (!doubleQuote(stream)); @@ -143,17 +125,13 @@ CodeMirror.defineMode("erlang", function(cmCfg) { } // attributes and type specs - if ((peekToken(state).token == "" || peekToken(state).token == ".") && - stream.peek() == '-') { - stream.next(); - if (stream.eat(smallRE) && stream.eatWhile(anumRE)) { - if (isMember(stream.current(),typeWords)) { - return rval(state,stream,"type"); - }else{ - return rval(state,stream,"attribute"); - } + if ((peekToken(state).token == "") && + stream.match(/-\s*[a-zß-öø-ÿ][\wØ-ÞÀ-Öß-öø-ÿ]*/)) { + if (isMember(stream.current(),typeWords)) { + return rval(state,stream,"type"); + }else{ + return rval(state,stream,"attribute"); } - stream.backUp(1); } var ch = stream.next(); @@ -171,24 +149,31 @@ CodeMirror.defineMode("erlang", function(cmCfg) { } // record - if ( ch == "#") { + if (ch == "#") { stream.eatWhile(anumRE); return rval(state,stream,"record"); } - // char - if ( ch == "$") { - if (stream.next() == "\\") { - if (!stream.eatWhile(octitRE)) { - stream.next(); - } + // dollar escape + if ( ch == "$" ) { + if (stream.next() == "\\" && !stream.match(escapesRE)) { + return rval(state,stream,"error"); } - return rval(state,stream,"string"); + return rval(state,stream,"number"); } // quoted atom if (ch == '\'') { - state.in_atom = (!singleQuote(stream)); + if (!(state.in_atom = (!singleQuote(stream)))) { + if (stream.match(/\s*\/\s*[0-9]/,false)) { + stream.match(/\s*\/\s*[0-9]/,true); + popToken(state); + return rval(state,stream,"fun"); // 'f'/0 style fun + } + if (stream.match(/\s*\(/,false) || stream.match(/\s*:/,false)) { + return rval(state,stream,"function"); + } + } return rval(state,stream,"atom"); } @@ -199,23 +184,19 @@ CodeMirror.defineMode("erlang", function(cmCfg) { } // variable - if (largeRE.test(ch)) { + if (/[A-Z_Ø-ÞÀ-Ö]/.test(ch)) { stream.eatWhile(anumRE); return rval(state,stream,"variable"); } // atom/keyword/BIF/function - if (smallRE.test(ch)) { + if (/[a-z_ß-öø-ÿ]/.test(ch)) { stream.eatWhile(anumRE); - if (stream.peek() == "/") { - stream.next(); - if (stream.eatWhile(digitRE)) { - return rval(state,stream,"fun"); // f/0 style fun - }else{ - stream.backUp(1); - return rval(state,stream,"atom"); - } + if (stream.match(/\s*\/\s*[0-9]/,false)) { + stream.match(/\s*\/\s*[0-9]/,true); + popToken(state); + return rval(state,stream,"fun"); // f/0 style fun } var w = stream.current(); @@ -223,37 +204,38 @@ CodeMirror.defineMode("erlang", function(cmCfg) { if (isMember(w,keywordWords)) { pushToken(state,stream); return rval(state,stream,"keyword"); - } - if (stream.peek() == "(") { + }else if (stream.match(/\s*\(/,false)) { // 'put' and 'erlang:put' are bifs, 'foo:put' is not if (isMember(w,bifWords) && (!isPrev(stream,":") || isPrev(stream,"erlang:"))) { return rval(state,stream,"builtin"); + }else if (isMember(w,guardWords)) { + return rval(state,stream,"guard"); }else{ return rval(state,stream,"function"); } - } - if (isMember(w,guardWords)) { - return rval(state,stream,"guard"); - } - if (isMember(w,operatorWords)) { + }else if (isMember(w,operatorWords)) { return rval(state,stream,"operator"); - } - if (stream.peek() == ":") { + }else if (stream.match(/\s*:/,false)) { if (w == "erlang") { return rval(state,stream,"builtin"); } else { return rval(state,stream,"function"); } + }else if (isMember(w,["true","false"])) { + return rval(state,stream,"boolean"); + }else{ + return rval(state,stream,"atom"); } - return rval(state,stream,"atom"); } // number + var digitRE = /[0-9]/; + var radixRE = /[0-9a-zA-Z]/; // 36#zZ style int if (digitRE.test(ch)) { stream.eatWhile(digitRE); if (stream.eat('#')) { - stream.eatWhile(digitRE); // 16#10 style integer + stream.eatWhile(radixRE); // 36#aZ style integer } else { if (stream.eat('.')) { // float stream.eatWhile(digitRE); @@ -279,7 +261,7 @@ CodeMirror.defineMode("erlang", function(cmCfg) { } // separators - if (greedy(stream,sepRE,separatorWords)) { + if (greedy(stream,separatorRE,separatorWords)) { // distinguish between "." as terminator and record field operator if (!state.in_record) { pushToken(state,stream); @@ -295,6 +277,17 @@ CodeMirror.defineMode("erlang", function(cmCfg) { return rval(state,stream,null); } + function isPrev(stream,string) { + var start = stream.start; + var len = string.length; + if (len <= start) { + var word = stream.string.slice(start-len,start); + return word == string; + }else{ + return false; + } + } + function nongreedy(stream,re,words) { if (stream.current().length == 1 && re.test(stream.current())) { stream.backUp(1); @@ -346,35 +339,37 @@ CodeMirror.defineMode("erlang", function(cmCfg) { return false; } - function Token(stream) { - this.token = stream ? stream.current() : ""; - this.column = stream ? stream.column() : 0; - this.indent = stream ? stream.indentation() : 0; + function isMember(element,list) { + return (-1 < list.indexOf(element)); } +///////////////////////////////////////////////////////////////////////////// function myIndent(state,textAfter) { var indent = cmCfg.indentUnit; - var outdentWords = ["after","catch"]; var token = (peekToken(state)).token; var wordAfter = takewhile(textAfter,/[^a-z]/); if (state.in_string || state.in_atom) { - return 0; - }else if (token == "." || token == "") { + return CodeMirror.Pass; + }else if (token == "") { return 0; }else if (isMember(token,openParenWords)) { return (peekToken(state)).column+token.length; + }else if (token == "when") { + return (peekToken(state)).column+token.length+1; + }else if (token == "fun" && wordAfter == "") { + return (peekToken(state)).column+token.length; }else if (token == "->") { - if (wordAfter == "end") { + if (isMember(wordAfter,["end","after","catch"])) { return peekToken(state,2).column; }else if (peekToken(state,2).token == "fun") { return peekToken(state,2).column+indent; - }else if (peekToken(state,2).token == ".") { + }else if (peekToken(state,2).token == "") { return indent; }else{ return (peekToken(state)).indent+indent; } - }else if (isMember(wordAfter,outdentWords)) { + }else if (isMember(wordAfter,["after","catch","of"])) { return (peekToken(state)).indent; }else{ return (peekToken(state)).column+indent; @@ -386,6 +381,12 @@ CodeMirror.defineMode("erlang", function(cmCfg) { return m ? str.slice(0,m.index) : str; } + function Token(stream) { + this.token = stream ? stream.current() : ""; + this.column = stream ? stream.column() : 0; + this.indent = stream ? stream.indentation() : 0; + } + function popToken(state) { return state.tokenStack.pop(); } @@ -403,7 +404,13 @@ CodeMirror.defineMode("erlang", function(cmCfg) { function pushToken(state,stream) { var token = stream.current(); var prev_token = peekToken(state).token; - if (isMember(token,ignoreWords)) { + + if (token == ".") { + state.tokenStack = []; + return false; + }else if(isMember(token,[",", ":", "of", "cond", "let", "query"])) { + return false; + }else if (drop_last(prev_token,token)) { return false; }else if (drop_both(prev_token,token)) { popToken(state); @@ -411,18 +418,25 @@ CodeMirror.defineMode("erlang", function(cmCfg) { }else if (drop_first(prev_token,token)) { popToken(state); return pushToken(state,stream); + }else if (isMember(token,["after","catch"])) { + return false; }else{ state.tokenStack.push(new Token(stream)); return true; } } + function drop_last(open, close) { + switch(open+" "+close) { + case "when ;": return true; + default: return false; + } + } + function drop_first(open, close) { switch (open+" "+close) { case "when ->": return true; case "-> end": return true; - case "-> .": return true; - case ". .": return true; default: return false; } } @@ -439,6 +453,8 @@ CodeMirror.defineMode("erlang", function(cmCfg) { case "if end": return true; case "receive end": return true; case "try end": return true; + case "-> catch": return true; + case "-> after": return true; case "-> ;": return true; default: return false; } diff --git a/theme/erlang-dark.css b/theme/erlang-dark.css index fce9f68664..a4a3682647 100644 --- a/theme/erlang-dark.css +++ b/theme/erlang-dark.css @@ -4,7 +4,7 @@ .cm-s-erlang-dark .CodeMirror-linenumber { color: #d0d0d0; } .cm-s-erlang-dark .CodeMirror-cursor { border-left: 1px solid white !important; } -.cm-s-erlang-dark span.cm-atom { color: #845dc4; } +.cm-s-erlang-dark span.cm-atom { color: #f133f1; } .cm-s-erlang-dark span.cm-attribute { color: #ff80e1; } .cm-s-erlang-dark span.cm-bracket { color: #ff9d00; } .cm-s-erlang-dark span.cm-builtin { color: #eaa; } @@ -14,11 +14,17 @@ .cm-s-erlang-dark span.cm-keyword { color: #ffee80; } .cm-s-erlang-dark span.cm-meta { color: #50fefe; } .cm-s-erlang-dark span.cm-number { color: #ffd0d0; } -.cm-s-erlang-dark span.cm-operator { color: #d11; } +.cm-s-erlang-dark span.cm-operator { color: #d55; } +.cm-s-erlang-dark span.cm-property { color: #ccc; } +.cm-s-erlang-dark span.cm-qualifier { color: #ccc; } +.cm-s-erlang-dark span.cm-quote { color: #ccc; } +.cm-s-erlang-dark span.cm-special { color: #ffbbbb; } .cm-s-erlang-dark span.cm-string { color: #3ad900; } +.cm-s-erlang-dark span.cm-string-2 { color: #ccc; } .cm-s-erlang-dark span.cm-tag { color: #9effff; } .cm-s-erlang-dark span.cm-variable { color: #50fe50; } .cm-s-erlang-dark span.cm-variable-2 { color: #e0e; } +.cm-s-erlang-dark span.cm-variable-3 { color: #ccc; } .cm-s-erlang-dark .CodeMirror-activeline-background {background: #013461 !important;} .cm-s-erlang-dark .CodeMirror-matchingbracket {outline:1px solid grey; color:white !important;} From e800079f2930bd670aa936740b26e462a5e4cfb4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 19 Aug 2013 16:26:45 +0200 Subject: [PATCH 0916/5273] Fix another problem caused by the hack for #1474 --- lib/codemirror.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 15a3daaaef..123014b4a3 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1600,7 +1600,7 @@ window.CodeMirror = (function() { on(d.scroller, "dragover", drag_); on(d.scroller, "drop", operation(cm, onDrop)); } - on(d.scroller, "paste", function(e){ + on(d.scroller, "paste", function(e) { if (eventInWidget(d, e)) return; focusInput(cm); fastPoll(cm); @@ -1609,7 +1609,7 @@ window.CodeMirror = (function() { // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206 // Add a char to the end of textarea before paste occur so that // selection doesn't span to the end of textarea. - if (webkit && !cm.state.fakedLastChar) { + if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) { var start = d.input.selectionStart, end = d.input.selectionEnd; d.input.value += "$"; d.input.selectionStart = start; @@ -1679,6 +1679,7 @@ window.CodeMirror = (function() { if (captureMiddleClick) onContextMenu.call(cm, cm, e); return; case 2: + if (webkit) cm.state.lastMiddleDown = +new Date; if (start) extendSelection(cm.doc, start); setTimeout(bind(focusInput, cm), 20); e_preventDefault(e); From fdc2de9de3e260c05a5e7b4d9cfbab0014cf8a48 Mon Sep 17 00:00:00 2001 From: Gabriel Nahmias Date: Sun, 18 Aug 2013 12:40:04 -0500 Subject: [PATCH 0917/5273] [the-matrix theme] Add --- theme/the-matrix.css | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 theme/the-matrix.css diff --git a/theme/the-matrix.css b/theme/the-matrix.css new file mode 100644 index 0000000000..e0e77ffb83 --- /dev/null +++ b/theme/the-matrix.css @@ -0,0 +1,24 @@ +.cm-s-the-matrix.CodeMirror { background: #000000; color: #00FF00; } +.cm-s-the-matrix span.CodeMirror-selected { background: #a8f !important; } +.cm-s-the-matrix .CodeMirror-gutters { background: #060; border-right: 2px solid #00FF00; } +.cm-s-the-matrix .CodeMirror-linenumber { color: #FFFFFF; } +.cm-s-the-matrix .CodeMirror-cursor { border-left: 1px solid #00FF00 !important; } + +.cm-s-the-matrix span.cm-keyword {color: #008803; font-weight: bold;} +.cm-s-the-matrix span.cm-atom {color: #3FF;} +.cm-s-the-matrix span.cm-number {color: #FFB94F;} +.cm-s-the-matrix span.cm-def {color: #99C;} +.cm-s-the-matrix span.cm-variable {color: #F6C;} +.cm-s-the-matrix span.cm-variable-2 {color: #C6F;} +.cm-s-the-matrix span.cm-variable-3 {color: #96F;} +.cm-s-the-matrix span.cm-property {color: #62FFA0;} +.cm-s-the-matrix span.cm-operator {color: #999} +.cm-s-the-matrix span.cm-comment {color: #CCCCCC;} +.cm-s-the-matrix span.cm-string {color: #39C;} +.cm-s-the-matrix span.cm-meta {color: #C9F;} +.cm-s-the-matrix span.cm-error {color: #FF0000;} +.cm-s-the-matrix span.cm-qualifier {color: #FFF700;} +.cm-s-the-matrix span.cm-builtin {color: #30a;} +.cm-s-the-matrix span.cm-bracket {color: #cc7;} +.cm-s-the-matrix span.cm-tag {color: #FFBD40;} +.cm-s-the-matrix span.cm-attribute {color: #FFF700;} From 3d3686d51600c4785a15d95018421ea108c7b9c5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 19 Aug 2013 16:37:29 +0200 Subject: [PATCH 0918/5273] [the-matrix theme] Integrate --- demo/theme.html | 2 ++ theme/the-matrix.css | 2 ++ 2 files changed, 4 insertions(+) diff --git a/demo/theme.html b/demo/theme.html index d6aba19870..504673d865 100644 --- a/demo/theme.html +++ b/demo/theme.html @@ -24,6 +24,7 @@ + @@ -88,6 +89,7 @@

    Theme Demo

    + diff --git a/theme/the-matrix.css b/theme/the-matrix.css index e0e77ffb83..1ea26a1016 100644 --- a/theme/the-matrix.css +++ b/theme/the-matrix.css @@ -22,3 +22,5 @@ .cm-s-the-matrix span.cm-bracket {color: #cc7;} .cm-s-the-matrix span.cm-tag {color: #FFBD40;} .cm-s-the-matrix span.cm-attribute {color: #FFF700;} + +.cm-s-the-matrix .CodeMirror-activeline-background {background: #040;} From 612c6c9b2de394c14eb95459a5e11549912b12cd Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Mon, 19 Aug 2013 18:23:33 +0200 Subject: [PATCH 0919/5273] Fix windows detection --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 123014b4a3..fed6830d29 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -24,7 +24,7 @@ window.CodeMirror = (function() { // This is woefully incomplete. Suggestions for alternative methods welcome. var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent); var mac = ios || /Mac/.test(navigator.platform); - var windows = /windows/i.test(navigator.platform); + var windows = /win/i.test(navigator.platform); var opera_version = opera && navigator.userAgent.match(/Version\/(\d*\.\d*)/); if (opera_version) opera_version = Number(opera_version[1]); From 569a636553a83c0bce7497314729a0a34f4add7d Mon Sep 17 00:00:00 2001 From: Ingo Richter Date: Mon, 19 Aug 2013 15:27:13 -0700 Subject: [PATCH 0920/5273] [css mode] Add flow-from and flow-into properties --- 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 8abfb315c2..2eaa96a4a8 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -366,8 +366,8 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { "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", "font", "font-feature-settings", "font-family", - "font-kerning", "font-language-override", "font-size", "font-size-adjust", + "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", From 35688322fac76223f0a2b840262b2ecff9b3502e Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Tue, 20 Aug 2013 13:08:15 +0200 Subject: [PATCH 0921/5273] Some small editing corrections in the manual --- doc/manual.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 3d0b70b6dd..c1cf9f9c64 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -930,7 +930,7 @@

    Cursor and selection methods

    Set the cursor position. You can either pass a single {line, ch} object, or the line and the character as two separate parameters.
    -
    doc.setSelection(anchor: {line, ch}, head: {line, ch})
    +
    doc.setSelection(anchor: {line, ch}, ?head: {line, ch})
    Set the selection range. anchor and head should be {line, ch} objects. head defaults to anchor when @@ -941,7 +941,7 @@

    Cursor and selection methods

    will, if shift is held or the extending flag is set, move the head of the selection while leaving the anchor at its current - place. pos2 is optional, and can be passed to + place. to is optional, and can be passed to ensure a region (for example a word or paragraph) will end up selected (in addition to whatever lies between that region and the current anchor).
    @@ -2326,7 +2326,7 @@

    Writing CodeMirror Modes

    state.

    In a nested mode, it is recommended to add an - extra methods, innerMode which, given a state object, + extra method, innerMode which, given a state object, returns a {state, mode} object with the inner mode and its state for the current position. These are used by utility scripts such as the tag closer to From 69c8610dce41eabad58ba5c20f094554c78785fe Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 20 Aug 2013 16:40:08 +0200 Subject: [PATCH 0922/5273] [fullscreen addon] Add --- addon/display/fullscreen.css | 6 +++++ addon/display/fullscreen.js | 26 ++++++++++++++++++++ demo/fullscreen.html | 46 ++++++++---------------------------- doc/compress.html | 1 + doc/manual.html | 7 ++++++ 5 files changed, 50 insertions(+), 36 deletions(-) create mode 100644 addon/display/fullscreen.css create mode 100644 addon/display/fullscreen.js diff --git a/addon/display/fullscreen.css b/addon/display/fullscreen.css new file mode 100644 index 0000000000..00ad677ff5 --- /dev/null +++ b/addon/display/fullscreen.css @@ -0,0 +1,6 @@ +.CodeMirror-fullscreen { + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + height: auto; + z-index: 9999; +} diff --git a/addon/display/fullscreen.js b/addon/display/fullscreen.js new file mode 100644 index 0000000000..1ceee327d5 --- /dev/null +++ b/addon/display/fullscreen.js @@ -0,0 +1,26 @@ +(function() { + "use strict"; + + CodeMirror.defineOption("fullScreen", false, function(cm, val, old) { + if (old == CodeMirror.Init) old = false; + if (!old == !val) return; + if (val) setFullscreen(cm); + else setNormal(cm); + }); + + function setFullscreen(cm) { + cm.state.restoreScreenScrollPos = {top: window.pageYOffset, left: window.pageXOffset}; + cm.getWrapperElement().className += " CodeMirror-fullscreen"; + document.documentElement.style.overflow = "hidden"; + cm.refresh(); + } + + function setNormal(cm) { + var wrap = cm.getWrapperElement(); + wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, ""); + document.documentElement.style.overflow = ""; + var scroll = cm.state.restoreScreenScrollPos; + window.scrollTo(scroll.left, scroll.top); + cm.refresh(); + } +})(); diff --git a/demo/fullscreen.html b/demo/fullscreen.html index 8cf8005bdb..827d55d0cd 100644 --- a/demo/fullscreen.html +++ b/demo/fullscreen.html @@ -5,18 +5,12 @@ + - + +

    -

    Match Highlighter Demo

    +

    Match Selection Demo

    + +

    The TOML Mode

    +

    Created by Forbes Lindesay.

    +

    MIME type defined: text/x-toml.

    +
    diff --git a/mode/toml/toml.js b/mode/toml/toml.js new file mode 100644 index 0000000000..1d163f13bf --- /dev/null +++ b/mode/toml/toml.js @@ -0,0 +1,71 @@ +CodeMirror.defineMode("toml", function () { + return { + startState: function () { + return { + inString: false, + stringType: "", + lhs: true, + inArray: 0 + }; + }, + token: function (stream, state) { + //check for state changes + if (!state.inString && ((stream.peek() == '"') || (stream.peek() == "'"))) { + state.stringType = stream.peek(); + stream.next(); // Skip quote + state.inString = true; // Update state + } + if (stream.sol() && state.inArray === 0) { + state.lhs = true; + } + //return state + if (state.inString) { + while (state.inString && !stream.eol()) { + if (stream.peek() === state.stringType) { + stream.next(); // Skip quote + state.inString = false; // Clear flag + } else if (stream.peek() === '\\') { + stream.next(); + stream.next(); + } else { + stream.match(/^.[^\\\"\']*/); + } + } + return state.lhs ? "property string" : "string"; // Token style + } else if (state.inArray && stream.peek() === ']') { + stream.next(); + state.inArray--; + return 'bracket'; + } else if (state.lhs && stream.peek() === '[' && stream.skipTo(']')) { + stream.next();//skip closing ] + return "atom"; + } else if (stream.peek() === "#") { + stream.skipToEnd(); + return "comment"; + } else if (stream.eatSpace()) { + return null; + } else if (state.lhs && stream.eatWhile(function (c) { return c != '=' && c != ' '; })) { + return "property"; + } else if (state.lhs && stream.peek() === "=") { + stream.next(); + state.lhs = false; + return null; + } else if (!state.lhs && stream.match(/^\d\d\d\d[\d\-\:\.T]*Z/)) { + return 'atom'; //date + } else if (!state.lhs && (stream.match('true') || stream.match('false'))) { + return 'atom'; + } else if (!state.lhs && stream.peek() === '[') { + state.inArray++; + stream.next(); + return 'bracket'; + } else if (!state.lhs && stream.match(/^\-?\d+(?:\.\d+)?/)) { + return 'number'; + } else if (!stream.eatSpace()) { + stream.next(); + } + return null; + } + }; +}); + +CodeMirror.defineMIME('text/x-toml', 'toml'); From df7ce151b4baf26ffbd0acb0d67ab9ac28b0e2eb Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 3 Sep 2013 18:01:44 +0200 Subject: [PATCH 0964/5273] [tern addon] Fix fetching of parser state Issue #1799 --- addon/tern/tern.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addon/tern/tern.js b/addon/tern/tern.js index 1be5ba7f5d..4348c8d8e8 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -233,7 +233,10 @@ closeArgHints(ts); if (cm.somethingSelected()) return; - var lex = cm.getTokenAt(cm.getCursor()).state.lexical; + var state = cm.getTokenAt(cm.getCursor()).state; + var inner = CodeMirror.innerMode(cm.getMode(), state); + if (inner.mode.name != "javascript") return; + var lex = inner.state.lexical; if (lex.info != "call") return; var ch = lex.column, pos = lex.pos || 0; From 4f081574b95c73bec7214f3707b03a76647d6060 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 5 Sep 2013 10:37:02 +0200 Subject: [PATCH 0965/5273] [sql mode] Add comment style properties --- mode/sql/sql.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mode/sql/sql.js b/mode/sql/sql.js index 9016cc7aae..e9dcb7fd75 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -180,7 +180,11 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { if (!cx) return CodeMirror.Pass; if (cx.align) return cx.col + (textAfter.charAt(0) == cx.type ? 0 : 1); else return cx.indent + config.indentUnit; - } + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : null }; }); From 36edc05b1d7386fa5d8cb6f67214896ed95123a1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 5 Sep 2013 11:22:45 +0200 Subject: [PATCH 0966/5273] In refresh, recompute line heights when no known text height Issue #1793 --- lib/codemirror.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index fcb6bc03dd..c9a8b9d580 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3188,9 +3188,11 @@ window.CodeMirror = (function() { operation: function(f){return runInOp(this, f);}, refresh: operation(null, function() { + var badHeight = this.display.cachedTextHeight == null; clearCaches(this); updateScrollPos(this, this.doc.scrollLeft, this.doc.scrollTop); regChange(this); + if (badHeight) estimateLineHeights(this); }), swapDoc: operation(null, function(doc) { From 22ea8d9dbc41c108d67675d7b3a8cbdde7e7133d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 5 Sep 2013 11:32:33 +0200 Subject: [PATCH 0967/5273] [matchtags addon] Don't match tags when there is a selection Closes #1802 --- addon/edit/matchtags.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/edit/matchtags.js b/addon/edit/matchtags.js index 52e8460245..f189c1f8ef 100644 --- a/addon/edit/matchtags.js +++ b/addon/edit/matchtags.js @@ -25,6 +25,7 @@ cm.state.failedTagMatch = false; cm.operation(function() { clear(cm); + if (cm.somethingSelected()) return; var cur = cm.getCursor(), range = cm.getViewport(); range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to); var match = CodeMirror.findMatchingTag(cm, cur, range); From b8e09e976015c065d7911e472bc1902d7f299940 Mon Sep 17 00:00:00 2001 From: AndersMad Date: Sat, 31 Aug 2013 09:57:19 +0200 Subject: [PATCH 0968/5273] [css-hint addon] Add I have created this simple css autocomplete/hint that uses data from the css mode. Autocomplete works for both properties and values - but it does not filter the values by property. Better than nothing for now. --- addon/hint/css-hint.js | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 addon/hint/css-hint.js diff --git a/addon/hint/css-hint.js b/addon/hint/css-hint.js new file mode 100644 index 0000000000..d8fe3ebaf0 --- /dev/null +++ b/addon/hint/css-hint.js @@ -0,0 +1,50 @@ +(function () { + "use strict"; + + function getHints(cm) { + var cur = cm.getCursor(), token = cm.getTokenAt(cur); + var inner = CodeMirror.innerMode(cm.getMode(), token.state); + if (inner.mode.name != "css-base") return; + + // If it's not a 'word-style' token, ignore the token. + if (!/^[\w$_-]*$/.test(token.string)) { + token = { + start: cur.ch, end: cur.ch, string: "", state: token.state, + type: null + }; + var stack = token.state.stack; + var lastToken = stack && stack.length > 0 ? stack[stack.length - 1] : ""; + if (token.string == ":" || lastToken.indexOf("property") == 0) + token.type = "variable"; + else if (token.string == "{" || lastToken.indexOf("rule") == 0) + token.type = "property"; + } + + if (!token.type) + return; + + var spec = CodeMirror.resolveMode("text/css"); + var keywords = null; + if (token.type.indexOf("property") == 0) + keywords = spec.propertyKeywords; + else if (token.type.indexOf("variable") == 0) + keywords = spec.valueKeywords; + + if (!keywords) + return; + + var result = []; + for (var name in keywords) { + if (name.indexOf(token.string) == 0 /* > -1 */) + result.push(name); + } + + return { + list: result, + from: CodeMirror.Pos(cur.line, token.start), + to: CodeMirror.Pos(cur.line, token.end) + }; + } + + CodeMirror.registerHelper("hint", "css", getHints); +})(); From 90d036d610e4ba58649ec325967b3b7ef5efd15f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 5 Sep 2013 12:34:43 +0200 Subject: [PATCH 0969/5273] [css-hint addon] Integrate --- addon/hint/css-hint.js | 2 +- doc/compress.html | 1 + doc/manual.html | 4 ++++ mode/css/css.js | 12 +++++------- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/addon/hint/css-hint.js b/addon/hint/css-hint.js index d8fe3ebaf0..2b15300d0c 100644 --- a/addon/hint/css-hint.js +++ b/addon/hint/css-hint.js @@ -4,7 +4,7 @@ function getHints(cm) { var cur = cm.getCursor(), token = cm.getTokenAt(cur); var inner = CodeMirror.innerMode(cm.getMode(), token.state); - if (inner.mode.name != "css-base") return; + if (inner.mode.name != "css") return; // If it's not a 'word-style' token, ignore the token. if (!/^[\w$_-]*$/.test(token.string)) { diff --git a/doc/compress.html b/doc/compress.html index 92c0987ba9..5ee78bb4c5 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -157,6 +157,7 @@

    Script compression helper

    + diff --git a/doc/manual.html b/doc/manual.html index 3f591492b6..9f516b7e05 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2049,6 +2049,10 @@

    Addons

    schema data. See the demo. +
    hint/css-hint.js
    +
    A minimal hinting function for CSS code. + Defines CodeMirror.hint.css.
    +
    hint/python-hint.js
    A very simple hinting function for Python code. Defines CodeMirror.hint.python.
    diff --git a/mode/css/css.js b/mode/css/css.js index 0caebe9fac..085b119de4 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -1,10 +1,8 @@ -CodeMirror.defineMode("css", function(config) { - return CodeMirror.getMode(config, "text/css"); -}); - -CodeMirror.defineMode("css-base", function(config, parserConfig) { +CodeMirror.defineMode("css", function(config, parserConfig) { "use strict"; + if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css"); + var indentUnit = config.indentUnit, hooks = parserConfig.hooks || {}, atMediaTypes = parserConfig.atMediaTypes || {}, @@ -580,7 +578,7 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { return false; } }, - name: "css-base" + name: "css" }); CodeMirror.defineMIME("text/x-scss", { @@ -624,6 +622,6 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { } } }, - name: "css-base" + name: "css" }); })(); From 47965d3bd07e347b18e1ee4ab40617c7f1e41b12 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 5 Sep 2013 12:47:49 +0200 Subject: [PATCH 0970/5273] [closetag addon] Restructure --- addon/edit/closetag.js | 55 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index 454dfea5e6..0bf8881d08 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -27,9 +27,9 @@ if (val && (old == CodeMirror.Init || !old)) { var map = {name: "autoCloseTags"}; if (typeof val != "object" || val.whenClosing) - map["'/'"] = function(cm) { return autoCloseTag(cm, '/'); }; + map["'/'"] = function(cm) { return autoCloseSlash(cm); }; if (typeof val != "object" || val.whenOpening) - map["'>'"] = function(cm) { return autoCloseTag(cm, '>'); }; + map["'>'"] = function(cm) { return autoCloseGT(cm); }; cm.addKeyMap(map); } else if (!val && (old != CodeMirror.Init && old)) { cm.removeKeyMap("autoCloseTags"); @@ -41,40 +41,41 @@ var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"]; - function autoCloseTag(cm, ch) { + function autoCloseGT(cm) { var pos = cm.getCursor(), tok = cm.getTokenAt(pos); var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; - if (inner.mode.name != "xml") return CodeMirror.Pass; + if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass; var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html"; var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); - if (ch == ">" && state.tagName) { - var tagName = state.tagName; - if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); - var lowerTagName = tagName.toLowerCase(); - // Don't process the '>' at the end of an end-tag or self-closing tag - if (tok.type == "tag" && state.type == "closeTag" || - tok.string.indexOf("/") == (tok.string.length - 1) || // match something like - dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1) - return CodeMirror.Pass; + var tagName = state.tagName; + if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); + var lowerTagName = tagName.toLowerCase(); + // Don't process the '>' at the end of an end-tag or self-closing tag + if (tok.type == "tag" && state.type == "closeTag" || + tok.string.indexOf("/") == (tok.string.length - 1) || // match something like + dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1) + return CodeMirror.Pass; - var doIndent = indentTags && indexOf(indentTags, lowerTagName) > -1; - var curPos = doIndent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1); - cm.replaceSelection(">" + (doIndent ? "\n\n" : "") + "", - {head: curPos, anchor: curPos}); - if (doIndent) { - cm.indentLine(pos.line + 1); - cm.indentLine(pos.line + 2); - } - return; - } else if (ch == "/" && tok.string == "<") { - var tagName = state.context && state.context.tagName; - if (tagName) cm.replaceSelection("/" + tagName + ">", "end"); - return; + var doIndent = indentTags && indexOf(indentTags, lowerTagName) > -1; + var curPos = doIndent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1); + cm.replaceSelection(">" + (doIndent ? "\n\n" : "") + "", + {head: curPos, anchor: curPos}); + if (doIndent) { + cm.indentLine(pos.line + 1); + cm.indentLine(pos.line + 2); } - return CodeMirror.Pass; + } + + function autoCloseSlash(cm) { + var pos = cm.getCursor(), tok = cm.getTokenAt(pos); + var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; + if (tok.string != "<" || inner.mode.name != "xml") return CodeMirror.Pass; + + var tagName = state.context && state.context.tagName; + if (tagName) cm.replaceSelection("/" + tagName + ">", "end"); } function indexOf(collection, elt) { From a55b506103247d6664ee2fe72e21a85cb86e164b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 5 Sep 2013 12:51:31 +0200 Subject: [PATCH 0971/5273] [closetag addon] Allow closing by typing / even when before a word Closes #1795 --- addon/edit/closetag.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index 0bf8881d08..0bc3e8be17 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -72,7 +72,7 @@ function autoCloseSlash(cm) { var pos = cm.getCursor(), tok = cm.getTokenAt(pos); var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; - if (tok.string != "<" || inner.mode.name != "xml") return CodeMirror.Pass; + if (tok.string.charAt(0) != "<" || inner.mode.name != "xml") return CodeMirror.Pass; var tagName = state.context && state.context.tagName; if (tagName) cm.replaceSelection("/" + tagName + ">", "end"); From f5b9d3ca9030117806a8822f48853b7ff4b8bdaa Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 5 Sep 2013 14:52:48 +0200 Subject: [PATCH 0972/5273] [haskell mode] Allow keyword sets to be overridden --- mode/haskell/haskell.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mode/haskell/haskell.js b/mode/haskell/haskell.js index b18d5ced1a..59ca7f0baa 100644 --- a/mode/haskell/haskell.js +++ b/mode/haskell/haskell.js @@ -1,4 +1,4 @@ -CodeMirror.defineMode("haskell", function() { +CodeMirror.defineMode("haskell", function(_config, modeConfig) { function switchState(source, setState, f) { setState(f); @@ -221,6 +221,10 @@ CodeMirror.defineMode("haskell", function() { "unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip", "zip3", "zipWith", "zipWith3"); + var override = modeConfig.overrideKeywords; + if (override) for (var word in override) if (override.hasOwnProperty(word)) + wkw[word] = override[word]; + return wkw; })(); From fab90b772626b054ba82a81f26b9caa35a356f93 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 5 Sep 2013 15:10:51 +0200 Subject: [PATCH 0973/5273] [continuecomment addon] Clean up, support line comment blocks --- addon/comment/continuecomment.js | 40 ++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/addon/comment/continuecomment.js b/addon/comment/continuecomment.js index 9dba156189..94e5a3760f 100644 --- a/addon/comment/continuecomment.js +++ b/addon/comment/continuecomment.js @@ -1,35 +1,43 @@ (function() { var modes = ["clike", "css", "javascript"]; for (var i = 0; i < modes.length; ++i) - CodeMirror.extendMode(modes[i], {blockCommentStart: "/*", - blockCommentEnd: "*/", - blockCommentContinue: " * "}); + CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "}); function continueComment(cm) { var pos = cm.getCursor(), token = cm.getTokenAt(pos); + if (token.type != "comment") return CodeMirror.Pass; var mode = CodeMirror.innerMode(cm.getMode(), token.state).mode; - var space; - if (token.type == "comment" && mode.blockCommentStart && mode.blockCommentContinue) { + var insert; + 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) { // Comment ended, don't continue it } else if (token.string.indexOf(mode.blockCommentStart) == 0) { - space = full.slice(0, token.start); - if (!/^\s*$/.test(space)) { - space = ""; - for (var i = 0; i < token.start; ++i) space += " "; + insert = full.slice(0, token.start); + if (!/^\s*$/.test(insert)) { + insert = ""; + for (var i = 0; i < token.start; ++i) insert += " "; } } else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 && found + mode.blockCommentContinue.length > token.start && /^\s*$/.test(full.slice(0, found))) { - space = full.slice(0, found); + insert = full.slice(0, found); + } + if (insert != null) insert += mode.blockCommentContinue; + } + if (insert == null && mode.lineComment) { + var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment); + if (found > -1) { + insert = line.slice(0, found); + if (/\S/.test(insert)) insert = null; + else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0]; } } - if (space != null) - cm.replaceSelection("\n" + space + mode.blockCommentContinue, "end"); + if (insert != null) + cm.replaceSelection("\n" + insert, "end"); else return CodeMirror.Pass; } @@ -37,8 +45,10 @@ CodeMirror.defineOption("continueComments", null, function(cm, val, prev) { if (prev && prev != CodeMirror.Init) cm.removeKeyMap("continueComment"); - var map = {name: "continueComment"}; - map[typeof val == "string" ? val : "Enter"] = continueComment; - cm.addKeyMap(map); + if (val) { + var map = {name: "continueComment"}; + map[typeof val == "string" ? val : "Enter"] = continueComment; + cm.addKeyMap(map); + } }); })(); From f8282ccd7a17c2f9b81aa90452fe04c89cc256e7 Mon Sep 17 00:00:00 2001 From: Peter Kroon Date: Thu, 5 Sep 2013 14:20:04 +0200 Subject: [PATCH 0974/5273] [less mode] Fix indentation of nested rules Issue #1801 --- mode/less/less.js | 98 +++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/mode/less/less.js b/mode/less/less.js index 09f510e032..d637f6db98 100644 --- a/mode/less/less.js +++ b/mode/less/less.js @@ -1,7 +1,8 @@ /* LESS mode - http://www.lesscss.org/ Ported to CodeMirror by Peter Kroon - Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues GitHub: @peterkroon + Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues + GitHub: @peterkroon */ CodeMirror.defineMode("less", function(config) { @@ -17,68 +18,60 @@ CodeMirror.defineMode("less", function(config) { else if (ch == "/" && stream.eat("*")) { state.tokenize = tokenCComment; return tokenCComment(stream, state); - } - else if (ch == "<" && stream.eat("!")) { + } else if (ch == "<" && stream.eat("!")) { state.tokenize = tokenSGMLComment; return tokenSGMLComment(stream, state); - } - else if (ch == "=") ret(null, "compare"); + } else if (ch == "=") ret(null, "compare"); else if (ch == "|" && stream.eat("=")) return ret(null, "compare"); else if (ch == "\"" || ch == "'") { state.tokenize = tokenString(ch); return state.tokenize(stream, state); - } - else if (ch == "/") { // e.g.: .png will not be parsed as a class + } else if (ch == "/") { // e.g.: .png will not be parsed as a class if(stream.eat("/")){ state.tokenize = tokenSComment; return tokenSComment(stream, state); - }else{ - if(type == "string" || type == "(")return ret("string", "string"); - if(state.stack[state.stack.length-1] != undefined)return ret(null, ch); + } else { + if(type == "string" || type == "(") return ret("string", "string"); + if(state.stack[state.stack.length-1] != undefined) return ret(null, ch); stream.eatWhile(/[\a-zA-Z0-9\-_.\s]/); if( /\/|\)|#/.test(stream.peek() || (stream.eatSpace() && stream.peek() == ")")) || stream.eol() )return ret("string", "string"); // let url(/images/logo.png) without quotes return as string } - } - else if (ch == "!") { + } else if (ch == "!") { stream.match(/^\s*\w*/); return ret("keyword", "important"); - } - else if (/\d/.test(ch)) { + } else if (/\d/.test(ch)) { stream.eatWhile(/[\w.%]/); return ret("number", "unit"); - } - else if (/[,+<>*\/]/.test(ch)) { + } else if (/[,+<>*\/]/.test(ch)) { if(stream.peek() == "=" || type == "a")return ret("string", "string"); + if(ch === ",")return ret(null, ch); return ret(null, "select-op"); - } - else if (/[;{}:\[\]()~\|]/.test(ch)) { + } else if (/[;{}:\[\]()~\|]/.test(ch)) { if(ch == ":"){ stream.eatWhile(/[a-z\\\-]/); if( selectors.test(stream.current()) ){ return ret("tag", "tag"); - }else if(stream.peek() == ":"){//::-webkit-search-decoration + } else if(stream.peek() == ":"){//::-webkit-search-decoration stream.next(); stream.eatWhile(/[a-z\\\-]/); if(stream.current().match(/\:\:\-(o|ms|moz|webkit)\-/))return ret("string", "string"); if( selectors.test(stream.current().substring(1)) )return ret("tag", "tag"); return ret(null, ch); - }else{ + } else { return ret(null, ch); } - }else if(ch == "~"){ + } else if(ch == "~"){ if(type == "r")return ret("string", "string"); - }else{ + } else { return ret(null, ch); } - } - else if (ch == ".") { + } else if (ch == ".") { if(type == "(" || type == "string")return ret("string", "string"); // allow url(../image.png) stream.eatWhile(/[\a-zA-Z0-9\-_]/); if(stream.peek() == " ")stream.eatSpace(); if(stream.peek() == ")")return ret("number", "unit");//rgba(0,0,0,.25); return ret("tag", "tag"); - } - else if (ch == "#") { + } else if (ch == "#") { //we don't eat white-space, we want the hex color and or id only stream.eatWhile(/[A-Za-z0-9]/); //check if there is a proper hex color length e.g. #eee || #eeeEEE @@ -93,43 +86,42 @@ CodeMirror.defineMode("less", function(config) { //#time { color: #aaa } else if(stream.peek() == "}" )return ret("number", "unit"); //we have a valid hex color value, parse as id whenever an element/class is defined after the hex(id) value e.g. #eee aaa || #eee .aaa - else if( /[a-zA-Z\\]/.test(stream.peek()) )return ret("atom", "tag"); + else if( /[a-zA-Z\\]/.test(stream.peek()) )return ret("atom", "tag"); //when a hex value is on the end of a line, parse as id - else if(stream.eol())return ret("atom", "tag"); + else if(stream.eol())return ret("atom", "tag"); //default - else return ret("number", "unit"); - }else{//when not a valid hexvalue in the current stream e.g. #footer + else return ret("number", "unit"); + } else {//when not a valid hexvalue in the current stream e.g. #footer stream.eatWhile(/[\w\\\-]/); return ret("atom", "tag"); } - }else{//when not a valid hexvalue length + } else {//when not a valid hexvalue length stream.eatWhile(/[\w\\\-]/); return ret("atom", "tag"); } - } - else if (ch == "&") { + } else if (ch == "&") { stream.eatWhile(/[\w\-]/); return ret(null, ch); - } - else { + } else { stream.eatWhile(/[\w\\\-_%.{]/); + //console.log(type); if(type == "string"){ return ret("string", "string"); - }else if(stream.current().match(/(^http$|^https$)/) != null){ + } else if(stream.current().match(/(^http$|^https$)/) != null){ stream.eatWhile(/[\w\\\-_%.{:\/]/); return ret("string", "string"); - }else if(stream.peek() == "<" || stream.peek() == ">"){ + } else if(stream.peek() == "<" || stream.peek() == ">" || stream.peek() == "+"){ return ret("tag", "tag"); - }else if( /\(/.test(stream.peek()) ){ + } else if( /\(/.test(stream.peek()) ){ return ret(null, ch); - }else if (stream.peek() == "/" && state.stack[state.stack.length-1] != undefined){ // url(dir/center/image.png) + } else if (stream.peek() == "/" && state.stack[state.stack.length-1] != undefined){ // url(dir/center/image.png) return ret("string", "string"); - }else if( stream.current().match(/\-\d|\-.\d/) ){ // match e.g.: -5px -0.4 etc... only colorize the minus sign + } else if( stream.current().match(/\-\d|\-.\d/) ){ // match e.g.: -5px -0.4 etc... only colorize the minus sign //commment out these 2 comment if you want the minus sign to be parsed as null -500px //stream.backUp(stream.current().length-1); - //return ret(null, ch); //console.log( stream.current() ); + //return ret(null, ch); return ret("number", "unit"); - }else if( /\/|[\s\)]/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == "/")) && stream.current().indexOf(".") !== -1){ + } else if( /\/|[\s\)]/.test(stream.peek() || stream.eol() || (stream.eatSpace() && stream.peek() == "/")) && stream.current().indexOf(".") !== -1){ if(stream.current().substring(stream.current().length-1,stream.current().length) == "{"){ stream.backUp(1); return ret("tag", "tag"); @@ -137,14 +129,15 @@ CodeMirror.defineMode("less", function(config) { stream.eatSpace(); if( /[{<>.a-zA-Z\/]/.test(stream.peek()) || stream.eol() )return ret("tag", "tag"); // e.g. button.icon-plus return ret("string", "string"); // let url(/images/logo.png) without quotes return as string - }else if( stream.eol() || stream.peek() == "[" || stream.peek() == "#" || type == "tag" ){ + } else if( stream.eol() || stream.peek() == "[" || stream.peek() == "#" || type == "tag" ){ if(stream.current().substring(stream.current().length-1,stream.current().length) == "{")stream.backUp(1); return ret("tag", "tag"); - }else if(type == "compare" || type == "a" || type == "("){ + } else if(type == "compare" || type == "a" || type == "("){ return ret("string", "string"); - }else if(type == "|" || stream.current() == "-" || type == "["){ + } else if(type == "|" || stream.current() == "-" || type == "["){ + if(type == "|" )return ret("tag", "tag"); return ret(null, ch); - }else if(stream.peek() == ":") { + } else if(stream.peek() == ":") { stream.next(); var t_v = stream.peek() == ":" ? true : false; if(!t_v){ @@ -156,11 +149,14 @@ CodeMirror.defineMode("less", function(config) { stream.backUp(new_pos-(old_pos-1)); return ret("tag", "tag"); } else stream.backUp(new_pos-(old_pos-1)); - }else{ + } else { stream.backUp(1); } if(t_v)return ret("tag", "tag"); else return ret("variable", "variable"); - }else{ + } else if(state.stack[state.stack.length-1] === "font-family"){ + return ret(null, null); + } else { + if(state.stack[state.stack.length-1] === "{" || type === "select-op" || (state.stack[state.stack.length-1] === "rule" && type === ",") )return ret("tag", "tag"); return ret("variable", "variable"); } } @@ -238,12 +234,16 @@ CodeMirror.defineMode("less", function(config) { } else if (type == "}") state.stack.pop(); else if (type == "@media") state.stack.push("@media"); - else if (context == "{" && type != "comment") state.stack.push("rule"); + else if (stream.current() === "font-family") state.stack[state.stack.length-1] = "font-family"; + else if (context == "{" && type != "comment" && type !== "tag") state.stack.push("rule"); + else if (stream.peek() === ":" && stream.current().match(/@|#/) === null) style = type; return style; }, indent: function(state, textAfter) { var n = state.stack.length; + console.log(n); + if (/^\}/.test(textAfter)) n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1; return state.baseIndent + n * indentUnit; From b3353e715e9ae03aa7810d5533bfcb613f81a5b3 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 6 Sep 2013 09:41:26 +0200 Subject: [PATCH 0975/5273] [less mode] Remove console.log --- mode/less/less.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/mode/less/less.js b/mode/less/less.js index d637f6db98..8384b3cd76 100644 --- a/mode/less/less.js +++ b/mode/less/less.js @@ -104,7 +104,6 @@ CodeMirror.defineMode("less", function(config) { return ret(null, ch); } else { stream.eatWhile(/[\w\\\-_%.{]/); - //console.log(type); if(type == "string"){ return ret("string", "string"); } else if(stream.current().match(/(^http$|^https$)/) != null){ @@ -242,7 +241,6 @@ CodeMirror.defineMode("less", function(config) { indent: function(state, textAfter) { var n = state.stack.length; - console.log(n); if (/^\}/.test(textAfter)) n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1; From c55df0d8666b55e1d2c195c1d98770005aeb058d Mon Sep 17 00:00:00 2001 From: Matt Pass Date: Thu, 5 Sep 2013 18:23:48 +0100 Subject: [PATCH 0976/5273] Better lint icons and in fewer bytes Original error & warning icons had jagged edges due to being GIFs This made them look quite poor/low quality on dark BG'd themes So, new, better looking icons added which have been run thru TinyPNG for compression Result is fewer bytes than original and they look good on dark BG's too --- addon/lint/lint.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon/lint/lint.css b/addon/lint/lint.css index a57694e00e..e592b3672a 100644 --- a/addon/lint/lint.css +++ b/addon/lint/lint.css @@ -57,15 +57,15 @@ } .CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { - background-image: url("data:image/gif;base64,R0lGODlhEAAQANUAAPVvcvWHiPVucvRuc+ttcfV6f91KVN5LU99PV/FZY/JhaM4oN84pONE4Rd1ATfJLWutVYPRgbdxpcsgWKMgZKs4lNfE/UvE/U+artcpdSc5uXveimslHPuBhW/eJhfV5efaCgO2CgP+/v+PExP///////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAQABAAAAZ+wJJwSCwaScgkySgkjTQZTkYzWhadnE5oE+pwqkSshwQqkzxfa4kkQXxEpA9J9EFI1KQGQQBAigYCBA14ExEWF0gXihETeA0QD3AkD5QQg0NsDnAJmwkOd5gYFSQKpXAFDBhqaxgLBwQBBAapq00YEg0UDRKqTGtKSL7Cw8JBADs="); + 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/gif;base64,R0lGODlhEAAQANUAAP7bc//egf/ij/7ijv/jl/7kl//mnv7lnv/uwf7CTP7DTf7DT/7IW//Na/7Na//NbP7QdP/dmbltAIJNAF03AMSAJMSCLKqASa2DS6uBSquCSrGHTq6ETbCHT7WKUrKIUcCVXL+UXMOYX8GWXsSZYMiib6+ETbOIUcOXX86uhd3Muf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACsALAAAAAAQABAAAAZowJVwSCwaj0ihikRSJYcoBEL0XKlGkcjImQQhJBREKFnyICoThKeE/AAW6AXgdPyUAgrLJBEo0YsbAQyDhAEdRRwDDw8OaA4NDQImRBgFEJdglxAEGEQZKQcHBqOkKRpFF6mqq1WtrUEAOw=="); + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); } .CodeMirror-lint-marker-multiple { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJEAQvB2JVdrAAAAAdaVRYdENvbW1lbnQAAAAAAENyZWF0ZWQgd2l0aCBHSU1QZC5lBwAAAD1JREFUCNdtjkESADAEAzemf69f66HMqGlOIhYiFRFRtSQBWAY7mzx+EDTL6sSgb1jTk7Q87rxyqe37fXsAa78gLyZnRgEAAAAASUVORK5CYII="); + background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); background-repeat: no-repeat; background-position: right bottom; width: 100%; height: 100%; From 30a9ee56fe988d54e3bdd435f7c37af68c5c4c21 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 6 Sep 2013 10:23:44 +0200 Subject: [PATCH 0977/5273] Don't mutate options.gutters in setGuttersForLineNumbers Closes #1807 Closes #1808 --- lib/codemirror.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index c9a8b9d580..740389fc03 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -304,15 +304,13 @@ window.CodeMirror = (function() { // Make sure the gutters options contains the element // "CodeMirror-linenumbers" when the lineNumbers option is true. function setGuttersForLineNumbers(options) { - var found = false; - for (var i = 0; i < options.gutters.length; ++i) { - if (options.gutters[i] == "CodeMirror-linenumbers") { - if (options.lineNumbers) found = true; - else options.gutters.splice(i--, 1); - } + var found = indexOf(options.gutters, "CodeMirror-linenumbers"); + if (found == -1 && options.lineNumbers) { + options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); + } else if (found > -1 && !options.lineNumbers) { + options.gutters = options.gutters.slice(0); + options.gutters.splice(i, 1); } - if (!found && options.lineNumbers) - options.gutters.push("CodeMirror-linenumbers"); } // SCROLLBARS From c8c7fc18af5f025733a930fea202d98e54e12a5e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 6 Sep 2013 11:56:51 +0200 Subject: [PATCH 0978/5273] Prevent corrupted measurements due to vanishing/appearing scrollbar Issue #1787 --- lib/codemirror.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 740389fc03..b4b5549ee0 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -355,6 +355,7 @@ window.CodeMirror = (function() { if (mac_geLion && scrollbarWidth(d.measure) === 0) d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountainLion ? "18px" : "12px"; + return needsV; } function visibleLines(display, doc, viewPort) { @@ -410,11 +411,13 @@ window.CodeMirror = (function() { var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; var visible = visibleLines(cm.display, cm.doc, viewPort); for (;;) { + var hadVScroll = cm.display.scroller.scrollHeight > cm.display.scroller.clientHeight + 1; if (!updateDisplayInner(cm, changes, visible, forced)) break; - forced = false; updated = true; + changes = []; updateSelection(cm); - updateScrollbars(cm); + if (updateScrollbars(cm) != hadVScroll) continue; + forced = false; // Clip forced viewport to actual scrollable area if (viewPort) @@ -423,7 +426,6 @@ window.CodeMirror = (function() { visible = visibleLines(cm.display, cm.doc, viewPort); if (visible.from >= cm.display.showingFrom && visible.to <= cm.display.showingTo) break; - changes = []; } if (updated) { From 7ea6f43856685f6d7ae71d3344cb2a1bdb1ab037 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 9 Sep 2013 10:32:32 +0200 Subject: [PATCH 0979/5273] Amend c8c7fc18af5f to handle window resize-tiggered updated Issue #1787 --- lib/codemirror.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index b4b5549ee0..8b6377dc50 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -355,7 +355,6 @@ window.CodeMirror = (function() { if (mac_geLion && scrollbarWidth(d.measure) === 0) d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountainLion ? "18px" : "12px"; - return needsV; } function visibleLines(display, doc, viewPort) { @@ -411,12 +410,16 @@ window.CodeMirror = (function() { var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; var visible = visibleLines(cm.display, cm.doc, viewPort); for (;;) { - var hadVScroll = cm.display.scroller.scrollHeight > cm.display.scroller.clientHeight + 1; + var oldWidth = cm.display.scroller.clientWidth; if (!updateDisplayInner(cm, changes, visible, forced)) break; updated = true; changes = []; updateSelection(cm); - if (updateScrollbars(cm) != hadVScroll) continue; + updateScrollbars(cm); + if (cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth) { + forced = true; + continue; + } forced = false; // Clip forced viewport to actual scrollable area From 007434607dbd4faf5c7d4c99a836e989fe8b20f5 Mon Sep 17 00:00:00 2001 From: Peter Kroon Date: Mon, 9 Sep 2013 10:38:16 +0200 Subject: [PATCH 0980/5273] [dtd mode] Add --- doc/compress.html | 1 + mode/dtd/dtd.js | 127 ++++++++++++++++++++++++++++++++++++++++++++ mode/dtd/index.html | 89 +++++++++++++++++++++++++++++++ mode/index.html | 1 + 4 files changed, 218 insertions(+) create mode 100644 mode/dtd/dtd.js create mode 100644 mode/dtd/index.html diff --git a/doc/compress.html b/doc/compress.html index 5ee78bb4c5..d49c193263 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -86,6 +86,7 @@

    Script compression helper

    + diff --git a/mode/dtd/dtd.js b/mode/dtd/dtd.js new file mode 100644 index 0000000000..7033bf0f8b --- /dev/null +++ b/mode/dtd/dtd.js @@ -0,0 +1,127 @@ +/* + DTD mode + Ported to CodeMirror by Peter Kroon + Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues + GitHub: @peterkroon +*/ + +CodeMirror.defineMode("dtd", function(config) { + var indentUnit = config.indentUnit, type; + function ret(style, tp) {type = tp; return style;} + + function tokenBase(stream, state) { + var ch = stream.next(); + + if (ch == "<" && stream.eat("!") ) { + if (stream.eatWhile(/[\-]/)) { + state.tokenize = tokenSGMLComment; + return tokenSGMLComment(stream, state); + } else if (stream.eatWhile(/[\w]/)) return ret("keyword", "doindent"); + } else if (ch == "<" && stream.eat("?")) { //xml declaration + 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.match(/[\(\)\[\]\-\.,\+\?>]/)) return ret(null, ch);//if(ch === ">") return ret(null, "endtag"); else + else if (ch.match(/[\[\]]/)) return ret("rule", ch); + else if (ch == "\"" || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } else if (stream.eatWhile(/[a-zA-Z\?\+\d]/)) { + var sc = stream.current(); + if( sc.substr(sc.length-1,sc.length).match(/\?|\+/) !== null )stream.backUp(1); + return ret("tag", "tag"); + } else if (ch == "%" || ch == "*" ) return ret("number", "number"); + else { + stream.eatWhile(/[\w\\\-_%.{,]/); + return ret(null, null); + } + } + + function tokenSGMLComment(stream, state) { + var dashes = 0, ch; + while ((ch = stream.next()) != null) { + if (dashes >= 2 && ch == ">") { + state.tokenize = tokenBase; + break; + } + dashes = (ch == "-") ? dashes + 1 : 0; + } + return ret("comment", "comment"); + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == quote && !escaped) { + state.tokenize = tokenBase; + break; + } + escaped = !escaped && ch == "\\"; + } + return ret("string", "tag"); + }; + } + + function inBlock(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = tokenBase; + break; + } + stream.next(); + } + return style; + }; + } + + return { + startState: function(base) { + return {tokenize: tokenBase, + baseIndent: base || 0, + stack: []}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + + var context = state.stack[state.stack.length-1]; + if (stream.current() == "[" || type === "doindent" || type == "[") state.stack.push("rule"); + else if (type === "endtag") state.stack[state.stack.length-1] = "endtag"; + else if (stream.current() == "]" || type == "]" || (type == ">" && context == "rule")) state.stack.pop(); + else if (type == "[") state.stack.push("["); + return style; + }, + + indent: function(state, textAfter) { + var n = state.stack.length; + + if( textAfter.match(/\]\s+|\]/) )n=n-1; + else if(textAfter.substr(textAfter.length-1, textAfter.length) === ">"){ + if(textAfter.substr(0,1) === "<")n; + else if( type == "doindent" && textAfter.length > 1 )n; + else if( type == "doindent")n--; + else if( type == ">" && textAfter.length > 1)n; + else if( type == "tag" && textAfter !== ">")n; + else if( type == "tag" && state.stack[state.stack.length-1] == "rule")n--; + else if( type == "tag")n++; + else if( textAfter === ">" && state.stack[state.stack.length-1] == "rule" && type === ">")n--; + else if( textAfter === ">" && state.stack[state.stack.length-1] == "rule")n; + else if( textAfter.substr(0,1) !== "<" && textAfter.substr(0,1) === ">" )n=n-1; + else if( textAfter === ">")n; + else n=n-1; + //over rule them all + if(type == null || type == "]")n--; + } + + return state.baseIndent + n * indentUnit; + }, + + electricChars: "]>" + }; +}); + +CodeMirror.defineMIME("application/xml-dtd", "dtd"); diff --git a/mode/dtd/index.html b/mode/dtd/index.html new file mode 100644 index 0000000000..076d827f7f --- /dev/null +++ b/mode/dtd/index.html @@ -0,0 +1,89 @@ + + +CodeMirror: DTD mode + + + + + + + + + +
    +

    DTD mode

    +
    + + +

    MIME types defined: application/xml-dtd.

    +
    diff --git a/mode/index.html b/mode/index.html index 5601a2c458..2b54d60689 100644 --- a/mode/index.html +++ b/mode/index.html @@ -41,6 +41,7 @@

    Language modes

  • Cython
  • D
  • diff
  • +
  • DTD
  • ECL
  • Erlang
  • Gas (AT&T-style assembly)
  • From 1564808cf8d9c3fc0a66c4e95a53962312f6e12c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 9 Sep 2013 10:46:14 +0200 Subject: [PATCH 0981/5273] Fix drag/drop on Chrome by setting an image src Work around a Chrome regression where it aborts the drag if the setDragImage image is src-less. Closes #1810 --- lib/codemirror.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 8b6377dc50..ce83709954 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1912,6 +1912,7 @@ window.CodeMirror = (function() { // 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=="; if (opera) { img.width = img.height = 1; cm.display.wrapper.appendChild(img); From 687026e00a0809dd8a836095c3d760ddc4cc1a08 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 9 Sep 2013 11:16:55 +0200 Subject: [PATCH 0982/5273] [tern addon] Compensate for fact that call start pos is a column, not char offset Closes #1811 --- addon/tern/tern.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/addon/tern/tern.js b/addon/tern/tern.js index 4348c8d8e8..8d35f0630b 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -239,9 +239,18 @@ var lex = inner.state.lexical; if (lex.info != "call") return; - var ch = lex.column, pos = lex.pos || 0; - for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) - if (cm.getLine(line).charAt(ch) == "(") {found = true; break;} + var ch, pos = lex.pos || 0, tabSize = cm.getOption("tabSize"); + for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) { + var str = cm.getLine(line), extra = 0; + for (var pos = 0;;) { + var tab = str.indexOf("\t", pos); + if (tab == -1) break; + extra += tabSize - (tab + extra) % tabSize - 1; + pos = tab + 1; + } + ch = lex.column - extra; + if (str.charAt(ch) == "(") {found = true; break;} + } if (!found) return; var start = Pos(line, ch); From e0b0e32ed97bdd9b4dcb559f0d383bbb197961e4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 9 Sep 2013 12:32:03 +0200 Subject: [PATCH 0983/5273] Allow styling of lines from mode tokenizers (experimental) --- lib/codemirror.js | 37 +++++++++++++++++++++++++------------ test/test.js | 19 +++++++++++++++++++ 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index ce83709954..a14ce5358f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -666,10 +666,11 @@ window.CodeMirror = (function() { } function buildLineElement(cm, line, lineNo, dims, reuse) { - var lineElement = lineContent(cm, line); + var built = buildLineContent(cm, line), lineElement = built.pre; var markers = line.gutterMarkers, display = cm.display, wrap; - if (!cm.options.lineNumbers && !markers && !line.bgClass && !line.wrapClass && !line.widgets) + var bgClass = built.bgClass ? built.bgClass + " " + (line.bgClass || "") : line.bgClass; + if (!cm.options.lineNumbers && !markers && !bgClass && !line.wrapClass && !line.widgets) return lineElement; // Lines with gutter elements, widgets or a background class need @@ -707,8 +708,8 @@ window.CodeMirror = (function() { wrap.appendChild(lineElement); } // Kludge to make sure the styled element lies behind the selection (by z-index) - if (line.bgClass) - wrap.insertBefore(elt("div", null, line.bgClass + " CodeMirror-linebackground"), wrap.firstChild); + if (bgClass) + wrap.insertBefore(elt("div", null, bgClass + " CodeMirror-linebackground"), wrap.firstChild); if (cm.options.lineNumbers || markers) { var gutterWrap = wrap.insertBefore(elt("div", null, null, "position: absolute; left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"), @@ -1031,7 +1032,7 @@ window.CodeMirror = (function() { return crudelyMeasureLine(cm, line); var display = cm.display, measure = emptyArray(line.text.length); - var pre = lineContent(cm, line, measure, true); + var pre = buildLineContent(cm, line, measure, true).pre; // IE does not cache element positions of inline elements between // calls to getBoundingClientRect. This makes the loop below, @@ -1135,7 +1136,7 @@ window.CodeMirror = (function() { if (cached || line.text.length >= cm.options.crudeMeasuringFrom) return measureChar(cm, line, line.text.length, cached && cached.measure, "right").right; - var pre = lineContent(cm, line, null, true); + var pre = buildLineContent(cm, line, null, true).pre; var end = pre.appendChild(zeroWidthElement(cm.display.measure)); removeChildrenAndAdd(cm.display.measure, pre); return getRect(end).right - getRect(cm.display.lineDiv).left; @@ -4314,13 +4315,23 @@ window.CodeMirror = (function() { } var styleToClassCache = {}; - function styleToClass(style) { + function interpretTokenStyle(style, builder) { if (!style) return null; + for (;;) { + var lineClass = style.match(/(?:^|\s)line-(background-)?(\S+)/); + if (!lineClass) break; + style = style.slice(0, lineClass.index) + style.slice(lineClass.index + lineClass[0].length); + var prop = lineClass[1] ? "bgClass" : "textClass"; + if (builder[prop] == null) + builder[prop] = lineClass[2]; + else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(builder[prop])) + builder[prop] += " " + lineClass[2]; + } return styleToClassCache[style] || (styleToClassCache[style] = "cm-" + style.replace(/ +/g, " cm-")); } - function lineContent(cm, realLine, measure, copyWidgets) { + function buildLineContent(cm, realLine, measure, copyWidgets) { var merged, line = realLine, empty = true; while (merged = collapsedSpanAtStart(line)) line = getLine(cm.doc, merged.find().from.line); @@ -4328,7 +4339,6 @@ window.CodeMirror = (function() { var builder = {pre: elt("pre"), col: 0, pos: 0, measure: null, measuredSomething: false, cm: cm, copyWidgets: copyWidgets}; - if (line.textClass) builder.pre.className = line.textClass; do { if (line.text) empty = false; @@ -4365,8 +4375,11 @@ window.CodeMirror = (function() { } } + var textClass = builder.textClass ? builder.textClass + " " + (realLine.textClass || "") : realLine.textClass; + if (textClass) builder.pre.className = textClass; + signal(cm, "renderLine", cm, realLine, builder.pre); - return builder.pre; + return builder; } var tokenSpecialChars = /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\uFEFF]/g; @@ -4477,7 +4490,7 @@ window.CodeMirror = (function() { 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]), styleToClass(styles[i+1])); + builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder)); return; } @@ -4527,7 +4540,7 @@ window.CodeMirror = (function() { spanStartStyle = ""; } text = allText.slice(at, at = styles[i++]); - style = styleToClass(styles[i++]); + style = interpretTokenStyle(styles[i++], builder); } } } diff --git a/test/test.js b/test/test.js index 21e09cb12e..a05b8afb42 100644 --- a/test/test.js +++ b/test/test.js @@ -1539,3 +1539,22 @@ testCM("change_removedText", function(cm) { eq(removedText[0].join("\n"), "abc\nd"); eq(removedText[1].join("\n"), ""); }); + +testCM("lineStyleFromMode", function(cm) { + CodeMirror.defineMode("test_mode", function() { + return {token: function(stream) { + if (stream.match(/^\[[^\]]*\]/)) return "line-brackets"; + if (stream.match(/^\([^\]]*\)/)) return "line-background-parens"; + stream.match(/^\s+|^\S+/); + }}; + }); + cm.setOption("mode", "test_mode"); + var bracketElts = byClassName(cm.getWrapperElement(), "brackets"); + eq(bracketElts.length, 1); + eq(bracketElts[0].nodeName, "PRE"); + is(!/brackets.*brackets/.test(bracketElts[0].className)); + var parenElts = byClassName(cm.getWrapperElement(), "parens"); + eq(parenElts.length, 1); + eq(parenElts[0].nodeName, "DIV"); + is(!/parens.*parens/.test(parenElts[0].className)); +}, {value: "line1: [br] [br]\nline2: (par) (par)\nline3: nothing"}); From 45d3cda933484698bfc0a8074cca717ffd2bc8eb Mon Sep 17 00:00:00 2001 From: stoskov Date: Mon, 9 Sep 2013 17:52:00 +0300 Subject: [PATCH 0984/5273] Add a hook to server response --- addon/tern/tern.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/addon/tern/tern.js b/addon/tern/tern.js index 8d35f0630b..5084539993 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -24,6 +24,9 @@ // no tip should be shown. By default the docstring is shown. // * typeTip: Like completionTip, but for the tooltips shown for type // queries. +// * responseFilter: A function(doc, query, request, error, data) that +// will be applied to the Tern responses before treating them +// // // It is possible to run the Tern server in a web worker by specifying // these additional options: @@ -102,8 +105,16 @@ rename: function(cm) { rename(this, cm); }, - request: function(cm, query, c) { - this.server.request(buildRequest(this, findDoc(this, cm.getDoc()), query), c); + request: function (cm, query, c) { + var self = this; + var doc = findDoc(this, cm.getDoc()); + var request = buildRequest(this, doc, query); + + this.server.request(request, function (error, data) { + if (!error && self.options.responseFilter) + data = self.options.responseFilter(doc, query, request, error, data); + c(error, data); + }); } }; From 1b3f9d090503ddb6727356224c42db3a2664e088 Mon Sep 17 00:00:00 2001 From: Peter Kroon Date: Tue, 10 Sep 2013 18:58:06 +0200 Subject: [PATCH 0985/5273] [lint demo] Remove duplicate script tag --- demo/lint.html | 1 - 1 file changed, 1 deletion(-) diff --git a/demo/lint.html b/demo/lint.html index 05236150ef..8372c52c47 100644 --- a/demo/lint.html +++ b/demo/lint.html @@ -13,7 +13,6 @@ - From 6dc51c9ab3d0ba68ad794ed4971a7efc46aebc3d Mon Sep 17 00:00:00 2001 From: Brett Zamir Date: Wed, 11 Sep 2013 13:50:04 +0800 Subject: [PATCH 0986/5273] [lint demo] missing semicolon --- demo/complete.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/complete.html b/demo/complete.html index 56999b9cc9..e256a908b4 100644 --- a/demo/complete.html +++ b/demo/complete.html @@ -71,7 +71,7 @@

    Autocomplete Demo

    + From 7579444498ba0db844f4921ee59a5dbaed9f93d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Gait=C3=A1n?= Date: Tue, 10 Sep 2013 16:20:42 -0300 Subject: [PATCH 0991/5273] [fortran mode] Add --- doc/compress.html | 1 + mode/fortran/fortran.js | 173 ++++++++++++++++++++++++++++++++++++++++ mode/fortran/index.html | 81 +++++++++++++++++++ mode/index.html | 1 + 4 files changed, 256 insertions(+) create mode 100644 mode/fortran/fortran.js create mode 100644 mode/fortran/index.html diff --git a/doc/compress.html b/doc/compress.html index d49c193263..8548991f90 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -89,6 +89,7 @@

    Script compression helper

    + diff --git a/mode/fortran/fortran.js b/mode/fortran/fortran.js new file mode 100644 index 0000000000..83fd8fde85 --- /dev/null +++ b/mode/fortran/fortran.js @@ -0,0 +1,173 @@ +CodeMirror.defineMode("fortran", function() { + function words(array) { + var keys = {}; + for (var i = 0; i < array.length; ++i) { + keys[array[i]] = true; + } + return keys; + } + + var keywords = words([ + "abstract", "accept", "allocatable", "allocate", + "array", "assign", "asynchronous", "backspace", + "bind", "block", "byte", "call", "case", + "class", "close", "common", "contains", + "continue", "cycle", "data", "deallocate", + "decode", "deferred", "dimension", "do", + "elemental", "else", "encode", "end", + "endif", "entry", "enumerator", "equivalence", + "exit", "external", "extrinsic", "final", + "forall", "format", "function", "generic", + "go", "goto", "if", "implicit", "import", "include", + "inquire", "intent", "interface", "intrinsic", + "module", "namelist", "non_intrinsic", + "non_overridable", "none", "nopass", + "nullify", "open", "optional", "options", + "parameter", "pass", "pause", "pointer", + "print", "private", "program", "protected", + "public", "pure", "read", "recursive", "result", + "return", "rewind", "save", "select", "sequence", + "stop", "subroutine", "target", "then", "to", "type", + "use", "value", "volatile", "where", "while", + "write"]); + var builtins = words(["abort", "abs", "access", "achar", "acos", + "adjustl", "adjustr", "aimag", "aint", "alarm", + "all", "allocated", "alog", "amax", "amin", + "amod", "and", "anint", "any", "asin", + "associated", "atan", "besj", "besjn", "besy", + "besyn", "bit_size", "btest", "cabs", "ccos", + "ceiling", "cexp", "char", "chdir", "chmod", + "clog", "cmplx", "command_argument_count", + "complex", "conjg", "cos", "cosh", "count", + "cpu_time", "cshift", "csin", "csqrt", "ctime", + "c_funloc", "c_loc", "c_associated", "c_null_ptr", + "c_null_funptr", "c_f_pointer", "c_null_char", + "c_alert", "c_backspace", "c_form_feed", + "c_new_line", "c_carriage_return", + "c_horizontal_tab", "c_vertical_tab", "dabs", + "dacos", "dasin", "datan", "date_and_time", + "dbesj", "dbesj", "dbesjn", "dbesy", "dbesy", + "dbesyn", "dble", "dcos", "dcosh", "ddim", "derf", + "derfc", "dexp", "digits", "dim", "dint", "dlog", + "dlog", "dmax", "dmin", "dmod", "dnint", + "dot_product", "dprod", "dsign", "dsinh", + "dsin", "dsqrt", "dtanh", "dtan", "dtime", + "eoshift", "epsilon", "erf", "erfc", "etime", + "exit", "exp", "exponent", "extends_type_of", + "fdate", "fget", "fgetc", "float", "floor", + "flush", "fnum", "fputc", "fput", "fraction", + "fseek", "fstat", "ftell", "gerror", "getarg", + "get_command", "get_command_argument", + "get_environment_variable", "getcwd", + "getenv", "getgid", "getlog", "getpid", + "getuid", "gmtime", "hostnm", "huge", "iabs", + "iachar", "iand", "iargc", "ibclr", "ibits", + "ibset", "ichar", "idate", "idim", "idint", + "idnint", "ieor", "ierrno", "ifix", "imag", + "imagpart", "index", "int", "ior", "irand", + "isatty", "ishft", "ishftc", "isign", + "iso_c_binding", "is_iostat_end", "is_iostat_eor", + "itime", "kill", "kind", "lbound", "len", "len_trim", + "lge", "lgt", "link", "lle", "llt", "lnblnk", "loc", + "log", "logical", "long", "lshift", "lstat", "ltime", + "matmul", "max", "maxexponent", "maxloc", "maxval", + "mclock", "merge", "move_alloc", "min", "minexponent", + "minloc", "minval", "mod", "modulo", "mvbits", + "nearest", "new_line", "nint", "not", "or", "pack", + "perror", "precision", "present", "product", "radix", + "rand", "random_number", "random_seed", "range", + "real", "realpart", "rename", "repeat", "reshape", + "rrspacing", "rshift", "same_type_as", "scale", + "scan", "second", "selected_int_kind", + "selected_real_kind", "set_exponent", "shape", + "short", "sign", "signal", "sinh", "sin", "sleep", + "sngl", "spacing", "spread", "sqrt", "srand", "stat", + "sum", "symlnk", "system", "system_clock", "tan", + "tanh", "time", "tiny", "transfer", "transpose", + "trim", "ttynam", "ubound", "umask", "unlink", + "unpack", "verify", "xor", "zabs", "zcos", "zexp", + "zlog", "zsin", "zsqrt"]); + + var dataTypes = words(["c_bool", "c_char", "c_double", "c_double_complex", + "c_float", "c_float_complex", "c_funptr", "c_int", + "c_int16_t", "c_int32_t", "c_int64_t", "c_int8_t", + "c_int_fast16_t", "c_int_fast32_t", "c_int_fast64_t", + "c_int_fast8_t", "c_int_least16_t", "c_int_least32_t", + "c_int_least64_t", "c_int_least8_t", "c_intmax_t", + "c_intptr_t", "c_long", "c_long_double", + "c_long_double_complex", "c_long_long", "c_ptr", + "c_short", "c_signed_char", "c_size_t", "character", + "complex", "double", "integer", "logical", "real"]); + var isOperatorChar = /[+\-*&=<>\/\:]/; + var litOperator = new RegExp("(\.and\.|\.or\.|\.eq\.|\.lt\.|\.le\.|\.gt\.|\.ge\.|\.ne\.|\.not\.|\.eqv\.|\.neqv\.)", "i"); + + function tokenBase(stream, state) { + + if (stream.match(litOperator)){ + return 'operator'; + } + + var ch = stream.next(); + if (ch == "!") { + stream.skipToEnd(); + return "comment"; + } + if (ch == '"' || ch == "'") { + state.tokenize = tokenString(ch); + return state.tokenize(stream, state); + } + if (/[\[\]\(\),]/.test(ch)) { + return null; + } + if (/\d/.test(ch)) { + stream.eatWhile(/[\w\.]/); + return "number"; + } + if (isOperatorChar.test(ch)) { + stream.eatWhile(isOperatorChar); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + var word = stream.current().toLowerCase(); + + if (keywords.hasOwnProperty(word)){ + return 'keyword'; + } + if (builtins.hasOwnProperty(word) || dataTypes.hasOwnProperty(word)) { + return 'builtin'; + } + return "variable"; + } + + function tokenString(quote) { + return function(stream, state) { + var escaped = false, next, end = false; + while ((next = stream.next()) != null) { + if (next == quote && !escaped) { + end = true; + break; + } + escaped = !escaped && next == "\\"; + } + if (end || !escaped) state.tokenize = null; + return "string"; + }; + } + + // Interface + + return { + startState: function() { + return {tokenize: null}; + }, + + token: function(stream, state) { + if (stream.eatSpace()) return null; + var style = (state.tokenize || tokenBase)(stream, state); + if (style == "comment" || style == "meta") return style; + return style; + } + }; +}); + +CodeMirror.defineMIME("text/x-fortran", "fortran"); diff --git a/mode/fortran/index.html b/mode/fortran/index.html new file mode 100644 index 0000000000..efa55ec89a --- /dev/null +++ b/mode/fortran/index.html @@ -0,0 +1,81 @@ + + +CodeMirror: Fortran mode + + + + + + + + + +
    +

    Fortran mode

    + + +
    + + + +

    MIME types defined: text/x-Fortran.

    +
    diff --git a/mode/index.html b/mode/index.html index 2b54d60689..f2bba985c2 100644 --- a/mode/index.html +++ b/mode/index.html @@ -44,6 +44,7 @@

    Language modes

  • DTD
  • ECL
  • Erlang
  • +
  • Fortran
  • Gas (AT&T-style assembly)
  • Go
  • Groovy
  • From afd9b56612b6326706631e363874c731da9debd7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 16 Sep 2013 14:56:23 +0200 Subject: [PATCH 0992/5273] Fix false positive in IE9/10 selection reset workaround hack Closes #1820 --- lib/codemirror.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index a14ce5358f..10545b9573 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1605,7 +1605,10 @@ window.CodeMirror = (function() { if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; if (e.keyCode == 16) cm.doc.sel.shift = false; })); - on(d.input, "input", bind(fastPoll, cm)); + on(d.input, "input", function() { + if (ie && !ie_lt9 && cm.display.inputHasSelection) cm.display.inputHasSelection = null; + fastPoll(cm); + }); on(d.input, "keydown", operation(cm, onKeyDown)); on(d.input, "keypress", operation(cm, onKeyPress)); on(d.input, "focus", bind(onFocus, cm)); From e470d7f4ad2e3bc60ece03e43319d3d70e15337e Mon Sep 17 00:00:00 2001 From: Tomas-A Date: Thu, 12 Sep 2013 16:53:15 +0100 Subject: [PATCH 0993/5273] [searchcursor addon] Fix multiple-line search There must be an error in line 73 because if the phrase starts at the same character position then conditional if will always become true (same number is equal to same number) therefore it must be changed to strict less than. --- addon/search/searchcursor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/search/searchcursor.js b/addon/search/searchcursor.js index 3da3f04e8f..c034d5865b 100644 --- a/addon/search/searchcursor.js +++ b/addon/search/searchcursor.js @@ -69,8 +69,8 @@ this.matches = function(reverse, pos) { var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(doc.getLine(ln)); var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match)); - if (reverse ? offsetA >= pos.ch || offsetA != match.length - : offsetA <= pos.ch || offsetA != line.length - match.length) + if (reverse ? offsetA > pos.ch || offsetA != match.length + : offsetA < pos.ch || offsetA != line.length - match.length) return; for (;;) { if (reverse ? !ln : ln == doc.lineCount() - 1) return; From 5cd7bdcaa1498c30e6dde4bd72674345ce8e3e12 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 16 Sep 2013 15:16:11 +0200 Subject: [PATCH 0994/5273] [sql mode] Merge functions and builtin list for plsql dialect Closes #1803 --- mode/sql/sql.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mode/sql/sql.js b/mode/sql/sql.js index e9dcb7fd75..63ce3fa843 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -266,7 +266,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { 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 + "accessible action add after algorithm all analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general global grant grants group groupby_concat handler hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), - builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), atoms: set("false true null unknown"), operatorChars: /^[*+\-%<>!=&|^]/, dateSQL: set("date time timestamp"), @@ -282,7 +282,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { 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 + "accessible action add after algorithm all always analyze asensitive at authors auto_increment autocommit avg avg_row_length before binary binlog both btree cache call cascade cascaded case catalog_name chain change changed character check checkpoint checksum class_origin client_statistics close coalesce code collate collation collations column columns comment commit committed completion concurrent condition connection consistent constraint contains continue contributors convert cross current_date current_time current_timestamp current_user cursor data database databases day_hour day_microsecond day_minute day_second deallocate dec declare default delay_key_write delayed delimiter des_key_file describe deterministic dev_pop dev_samp deviance directory disable discard distinctrow div dual dumpfile each elseif enable enclosed end ends engine engines enum errors escape escaped even event events every execute exists exit explain extended fast fetch field fields first flush for force foreign found_rows full fulltext function general generated global grant grants group groupby_concat handler hard hash help high_priority hosts hour_microsecond hour_minute hour_second if ignore ignore_server_ids import index index_statistics infile inner innodb inout insensitive insert_method install interval invoker isolation iterate key keys kill language last leading leave left level limit linear lines list load local localtime localtimestamp lock logs low_priority master master_heartbeat_period master_ssl_verify_server_cert masters match max max_rows maxvalue message_text middleint migrate min min_rows minute_microsecond minute_second mod mode modifies modify mutex mysql_errno natural next no no_write_to_binlog offline offset one online open optimize option optionally out outer outfile pack_keys parser partition partitions password persistent phase plugin plugins prepare preserve prev primary privileges procedure processlist profile profiles purge query quick range read read_write reads real rebuild recover references regexp relaylog release remove rename reorganize repair repeatable replace require resignal restrict resume return returns revoke right rlike rollback rollup row row_format rtree savepoint schedule schema schema_name schemas second_microsecond security sensitive separator serializable server session share show signal slave slow smallint snapshot soft soname spatial specific sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sqlexception sqlstate sqlwarning ssl start starting starts status std stddev stddev_pop stddev_samp storage straight_join subclass_origin sum suspend table_name table_statistics tables tablespace temporary terminated to trailing transaction trigger triggers truncate uncommitted undo uninstall unique unlock upgrade usage use use_frm user user_resources user_statistics using utc_date utc_time utc_timestamp value variables varying view views virtual warnings when while with work write xa xor year_month zerofill begin do then else loop repeat"), - builtin: set("bool boolean bit blob decimal double enum float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), + builtin: set("bool boolean bit blob decimal double float long longblob longtext medium mediumblob mediumint mediumtext time timestamp tinyblob tinyint tinytext text bigint int int1 int2 int3 int4 int8 integer float float4 float8 double char varbinary varchar varcharacter precision date datetime year unsigned signed numeric"), atoms: set("false true null unknown"), operatorChars: /^[*+\-%<>!=&|^]/, dateSQL: set("date time timestamp"), @@ -313,8 +313,7 @@ CodeMirror.defineMode("sql", function(config, parserConfig) { name: "sql", client: set("appinfo arraysize autocommit autoprint autorecovery autotrace blockterminator break btitle cmdsep colsep compatibility compute concat copycommit copytypecheck define describe echo editfile embedded escape exec execute feedback flagger flush heading headsep instance linesize lno loboffset logsource long longchunksize markup native newpage numformat numwidth pagesize pause pno recsep recsepchar release repfooter repheader serveroutput shiftinout show showmode size spool sqlblanklines sqlcase sqlcode sqlcontinue sqlnumber sqlpluscompatibility sqlprefix sqlprompt sqlterminator suffix tab term termout time timing trimout trimspool ttitle underline verify version wrap"), keywords: set("abort accept access add all alter and any array arraylen as asc assert assign at attributes audit authorization avg base_table begin between binary_integer body boolean by case cast char char_base check close cluster clusters colauth column comment commit compress connect connected constant constraint crash create current currval cursor data_base database date dba deallocate debugoff debugon decimal declare default definition delay delete desc digits dispose distinct do drop else elsif enable end entry escape exception exception_init exchange exclusive exists exit external fast fetch file for force form from function generic goto grant group having identified if immediate in increment index indexes indicator initial initrans insert interface intersect into is key level library like limited local lock log logging long loop master maxextents maxtrans member minextents minus mislabel mode modify multiset new next no noaudit nocompress nologging noparallel not nowait number_base object of off offline on online only open option or order out package parallel partition pctfree pctincrease pctused pls_integer positive positiven pragma primary prior private privileges procedure public raise range raw read rebuild record ref references refresh release rename replace resource restrict return returning reverse revoke rollback row rowid rowlabel rownum rows run savepoint schema segment select separate session set share snapshot some space split sql start statement storage subtype successful synonym tabauth table tables tablespace task terminate then to trigger truncate type union unique unlimited unrecoverable unusable update use using validate value values variable view views when whenever where while with work"), - functions: set("abs acos add_months ascii asin atan atan2 average bfilename ceil chartorowid chr concat convert cos cosh count decode deref dual dump dup_val_on_index empty error exp false floor found glb greatest hextoraw initcap instr instrb isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mod months_between new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null nvl others power rawtohex reftohex round rowcount rowidtochar rpad rtrim sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid upper user userenv variance vsize"), - builtin: set("bfile blob character clob dec float int integer mlslabel natural naturaln nchar nclob number numeric nvarchar2 real rowtype signtype smallint string varchar varchar2"), + builtin: set("bfile blob character clob dec float int integer mlslabel natural naturaln nchar nclob number numeric nvarchar2 real rowtype signtype smallint string varchar varchar2 abs acos add_months ascii asin atan atan2 average bfilename ceil chartorowid chr concat convert cos cosh count decode deref dual dump dup_val_on_index empty error exp false floor found glb greatest hextoraw initcap instr instrb isopen last_day least lenght lenghtb ln lower lpad ltrim lub make_ref max min mod months_between new_time next_day nextval nls_charset_decl_len nls_charset_id nls_charset_name nls_initcap nls_lower nls_sort nls_upper nlssort no_data_found notfound null nvl others power rawtohex reftohex round rowcount rowidtochar rpad rtrim sign sin sinh soundex sqlcode sqlerrm sqrt stddev substr substrb sum sysdate tan tanh to_char to_date to_label to_multi_byte to_number to_single_byte translate true trunc uid upper user userenv variance vsize"), operatorChars: /^[*+\-%<>!=~]/, dateSQL: set("date time timestamp"), support: set("doubleQuote nCharCast zerolessFloat binaryNumber hexNumber") From 1bdd4cb199082187c7f9251d10337eb413001ea8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 16 Sep 2013 15:43:40 +0200 Subject: [PATCH 0995/5273] Don't make changes to bgClass invalidate line measurement caches --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 10545b9573..f4ee4b1c17 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1001,7 +1001,7 @@ window.CodeMirror = (function() { var memo = cache[i]; if (memo.text == line.text && memo.markedSpans == line.markedSpans && cm.display.scroller.clientWidth == memo.width && - memo.classes == line.textClass + "|" + line.bgClass + "|" + line.wrapClass) + memo.classes == line.textClass + "|" + line.wrapClass) return memo; } } @@ -1021,7 +1021,7 @@ window.CodeMirror = (function() { var cache = cm.display.measureLineCache; var memo = {text: line.text, width: cm.display.scroller.clientWidth, markedSpans: line.markedSpans, measure: measure, - classes: line.textClass + "|" + line.bgClass + "|" + line.wrapClass}; + classes: line.textClass + "|" + line.wrapClass}; if (cache.length == 16) cache[++cm.display.measureLineCachePos % 16] = memo; else cache.push(memo); return measure; From a59d5767655792c8888f3e6a093f6f887908f8ae Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 16 Sep 2013 15:55:52 +0200 Subject: [PATCH 0996/5273] [merge addon] Signal updateDiff events --- addon/merge/merge.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index 391eb885fb..ceb48032b1 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -60,6 +60,7 @@ if (dv.diffOutOfDate) { dv.diff = getDiff(dv.orig.getValue(), dv.edit.getValue()); dv.diffOutOfDate = false; + CodeMirror.signal(dv.edit, "updateDiff", dv.diff); } if (dv.showDifferences) { updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes); From ecafd26e8c3cb6de5f36fde708368505f0e1ca08 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 16 Sep 2013 16:06:25 +0200 Subject: [PATCH 0997/5273] Fix spanAffectsWrapping regexp for Safari Issue #1825 --- demo/spanaffectswrapping_shim.html | 2 +- lib/codemirror.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/spanaffectswrapping_shim.html b/demo/spanaffectswrapping_shim.html index 00de3bdc2b..e598221c0c 100644 --- a/demo/spanaffectswrapping_shim.html +++ b/demo/spanaffectswrapping_shim.html @@ -32,7 +32,7 @@

    Automatically derive odd wrapping behavior for your browser

    + + + + +
    +

    Octave mode

    + +
    + + +

    MIME types defined: text/x-octave.

    +
    diff --git a/mode/octave/octave.js b/mode/octave/octave.js new file mode 100644 index 0000000000..23cd2fe222 --- /dev/null +++ b/mode/octave/octave.js @@ -0,0 +1,118 @@ +CodeMirror.defineMode("octave", function() { + function wordRegexp(words) { + return new RegExp("^((" + words.join(")|(") + "))\\b"); + } + + var singleOperators = new RegExp("^[\\+\\-\\*/&|\\^~<>!@'\\\\]"); + var singleDelimiters = new RegExp('^[\\(\\[\\{\\},:=;]'); + var doubleOperators = new RegExp("^((==)|(~=)|(<=)|(>=)|(<<)|(>>)|(\\.[\\+\\-\\*/\\^\\\\]))"); + var doubleDelimiters = new RegExp("^((!=)|(\\+=)|(\\-=)|(\\*=)|(/=)|(&=)|(\\|=)|(\\^=))"); + var tripleDelimiters = new RegExp("^((>>=)|(<<=))"); + var expressionEnd = new RegExp("^[\\]\\)]"); + var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*"); + + var builtins = wordRegexp([ + 'error', 'eval', 'function', 'abs', 'acos', 'atan', 'asin', 'cos', + 'cosh', 'exp', 'log', 'prod', 'log10', 'max', 'min', 'sign', 'sin', 'sinh', + 'sqrt', 'tan', 'reshape', 'break', 'zeros', 'default', 'margin', 'round', 'ones', + 'rand', 'syn', 'ceil', 'floor', 'size', 'clear', 'zeros', 'eye', 'mean', 'std', 'cov', + 'det', 'eig', 'inv', 'norm', 'rank', 'trace', 'expm', 'logm', 'sqrtm', 'linspace', 'plot', + 'title', 'xlabel', 'ylabel', 'legend', 'text', 'meshgrid', 'mesh', 'num2str' + ]); + + var keywords = wordRegexp([ + 'return', 'case', 'switch', 'else', 'elseif', 'end', 'endif', 'endfunction', + 'if', 'otherwise', 'do', 'for', 'while', 'try', 'catch', 'classdef', 'properties', 'events', + 'methods', 'global', 'persistent', 'endfor', 'endwhile', 'printf', 'disp', 'until', 'continue' + ]); + + + // tokenizers + function tokenTranspose(stream, state) { + if (!stream.sol() && stream.peek() === '\'') { + stream.next(); + state.tokenize = tokenBase; + return 'operator'; + } + state.tokenize = tokenBase; + return tokenBase(stream, state); + } + + + function tokenComment(stream, state) { + if (stream.match(/^.*%}/)) { + state.tokenize = tokenBase; + return 'comment'; + }; + stream.skipToEnd(); + return 'comment'; + } + + function tokenBase(stream, state) { + // whitespaces + if (stream.eatSpace()) return null; + + // Handle one line Comments + if (stream.match('%{')){ + state.tokenize = tokenComment; + stream.skipToEnd(); + return 'comment'; + } + + if (stream.match(/^(%)|(\.\.\.)/)){ + stream.skipToEnd(); + return 'comment'; + } + + // Handle Number Literals + if (stream.match(/^[0-9\.+-]/, false)) { + if (stream.match(/^[+-]?0x[0-9a-fA-F]+[ij]?/)) { + stream.tokenize = tokenBase; + return 'number'; }; + if (stream.match(/^[+-]?\d*\.\d+([EeDd][+-]?\d+)?[ij]?/)) { return 'number'; }; + if (stream.match(/^[+-]?\d+([EeDd][+-]?\d+)?[ij]?/)) { return 'number'; }; + } + if (stream.match(wordRegexp(['nan','NaN','inf','Inf']))) { return 'number'; }; + + // Handle Strings + if (stream.match(/^"([^"]|(""))*"/)) { return 'string'; } ; + if (stream.match(/^'([^']|(''))*'/)) { return 'string'; } ; + + // Handle words + if (stream.match(keywords)) { return 'keyword'; } ; + if (stream.match(builtins)) { return 'builtin'; } ; + if (stream.match(identifiers)) { return 'variable'; } ; + + if (stream.match(singleOperators) || stream.match(doubleOperators)) { return 'operator'; }; + if (stream.match(singleDelimiters) || stream.match(doubleDelimiters) || stream.match(tripleDelimiters)) { return null; }; + + if (stream.match(expressionEnd)) { + state.tokenize = tokenTranspose; + return null; + }; + + + // Handle non-detected items + stream.next(); + return 'error'; + }; + + + return { + startState: function() { + return { + tokenize: tokenBase + }; + }, + + token: function(stream, state) { + var style = state.tokenize(stream, state); + if (style === 'number' || style === 'variable'){ + state.tokenize = tokenTranspose; + } + return style; + } + }; +}); + +CodeMirror.defineMIME("text/x-octave", "octave"); From 51c8aee26fd4bb175f5640307dbc41295407697f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 17 Sep 2013 17:03:29 +0200 Subject: [PATCH 1001/5273] [mode/meta.js] Add missing modes --- mode/meta.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mode/meta.js b/mode/meta.js index 9c5d986f66..ce51c8ae19 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -13,12 +13,15 @@ CodeMirror.modeInfo = [ {name: 'CSS', mime: 'text/css', mode: 'css'}, {name: 'D', mime: 'text/x-d', mode: 'd'}, {name: 'diff', mime: 'text/x-diff', mode: 'diff'}, + {name: 'DTD', mime: 'application/xml-dtd', mode: 'dtd'}, {name: 'ECL', mime: 'text/x-ecl', mode: 'ecl'}, {name: 'Erlang', mime: 'text/x-erlang', mode: 'erlang'}, + {name: 'Fortran', mime: 'text/x-fortran', mode: 'fortran'}, {name: 'Gas', mime: 'text/x-gas', mode: 'gas'}, {name: 'GitHub Flavored Markdown', mime: 'text/x-gfm', mode: 'gfm'}, {name: 'GO', mime: 'text/x-go', mode: 'go'}, {name: 'Groovy', mime: 'text/x-groovy', mode: 'groovy'}, + {name: 'HAML', mime: 'text/x-haml', mode: 'haml'}, {name: 'Haskell', mime: 'text/x-haskell', mode: 'haskell'}, {name: 'Haxe', mime: 'text/x-haxe', mode: 'haxe'}, {name: 'ASP.NET', mime: 'application/x-aspx', mode: 'htmlembedded'}, @@ -40,6 +43,7 @@ CodeMirror.modeInfo = [ {name: 'Nginx', mime: 'text/x-nginx-conf', mode: 'nginx'}, {name: 'NTriples', mime: 'text/n-triples', mode: 'ntriples'}, {name: 'OCaml', mime: 'text/x-ocaml', mode: 'ocaml'}, + {name: 'Octave', mime: 'text/x-octave', mode: 'octave'}, {name: 'Pascal', mime: 'text/x-pascal', mode: 'pascal'}, {name: 'Perl', mime: 'text/x-perl', mode: 'perl'}, {name: 'PHP', mime: 'text/x-php', mode: 'php'}, @@ -69,6 +73,8 @@ CodeMirror.modeInfo = [ {name: 'Tcl', mime: 'text/x-tcl', mode: 'tcl'}, {name: 'TiddlyWiki ', mime: 'text/x-tiddlywiki', mode: 'tiddlywiki'}, {name: 'Tiki wiki', mime: 'text/tiki', mode: 'tiki'}, + {name: 'TOML', mime: 'text/x-toml', mode: 'toml'}, + {name: 'Turtle', mime: 'text/turtle', mode: 'turtle'}, {name: 'VB.NET', mime: 'text/x-vb', mode: 'vb'}, {name: 'VBScript', mime: 'text/vbscript', mode: 'vbscript'}, {name: 'Velocity', mime: 'text/velocity', mode: 'velocity'}, From e987409ef0c42435d8658c605f3ed2e517f475e8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 19 Sep 2013 22:18:54 +0200 Subject: [PATCH 1002/5273] [d mode] Remove executable flag from mode files Closes #1830 --- mode/d/d.js | 0 mode/d/index.html | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 mode/d/d.js mode change 100755 => 100644 mode/d/index.html diff --git a/mode/d/d.js b/mode/d/d.js old mode 100755 new mode 100644 diff --git a/mode/d/index.html b/mode/d/index.html old mode 100755 new mode 100644 From 344446ee7b1eb7747e52f6490bac1b407a0fb9a5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 23 Sep 2013 08:41:48 +0200 Subject: [PATCH 1003/5273] [real-world uses] Add nodeMirror --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 040da5910a..421250162c 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -85,6 +85,7 @@

    CodeMirror real-world uses

  • Mongo MapReduce WebBrowser
  • My2ndGeneration (social coding)
  • Navigate CMS
  • +
  • nodeMirror (IDE project)
  • NoTex (rST authoring)
  • Oak (online outliner)
  • ORG (z80 assembly IDE)
  • From d662cafbce9893e1232ccafaa9714a24388456ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Mass=C3=A9?= Date: Thu, 19 Sep 2013 17:15:38 -0400 Subject: [PATCH 1004/5273] solarized selection should match gutter --- theme/solarized.css | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/theme/solarized.css b/theme/solarized.css index f6b2a3f277..1a87d2d801 100644 --- a/theme/solarized.css +++ b/theme/solarized.css @@ -99,36 +99,14 @@ http://ethanschoonover.com/solarized/img/solarized-palette.png color: #586e75; } -.cm-s-solarized.cm-s-dark .CodeMirror-focused .CodeMirror-selected { - background: #386774; - color: inherit; -} - -.cm-s-solarized.cm-s-dark ::selection { - background: #386774; - color: inherit; -} - .cm-s-solarized.cm-s-dark .CodeMirror-selected { - background: #586e75; -} - -.cm-s-solarized.cm-s-light .CodeMirror-focused .CodeMirror-selected { - background: #eee8d5; - color: inherit; -} - -.cm-s-solarized.cm-s-light ::selection { - background: #eee8d5; - color: inherit; + background: #073642; } .cm-s-solarized.cm-s-light .CodeMirror-selected { - background: #93a1a1; + background: #eee8d5; } - - /* Editor styling */ From 9d67c932a266a9c5333f74bb61af5f587ae73cde Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 23 Sep 2013 12:07:31 +0200 Subject: [PATCH 1005/5273] [css mode] Recognize numbers with leading dot Closes #1833 Closes #1834 --- 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 085b119de4..4264bc606c 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -37,7 +37,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { stream.match(/^\s*\w*/); return ret("keyword", "important"); } - else if (/\d/.test(ch)) { + else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) { stream.eatWhile(/[\w.%]/); return ret("number", "unit"); } From d2b2ed74c55dcfe03eeaf467180041265f879009 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 23 Sep 2013 12:14:56 +0200 Subject: [PATCH 1006/5273] Ensure scrollbar/width instability doesn't cause infinite loop Issue #1787 --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 88f992d8af..cdf7652e72 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -409,14 +409,14 @@ window.CodeMirror = (function() { function updateDisplay(cm, changes, viewPort, forced) { var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; var visible = visibleLines(cm.display, cm.doc, viewPort); - for (;;) { + for (var first = true;; first = false) { var oldWidth = cm.display.scroller.clientWidth; if (!updateDisplayInner(cm, changes, visible, forced)) break; updated = true; changes = []; updateSelection(cm); updateScrollbars(cm); - if (cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth) { + if (first && cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth) { forced = true; continue; } From a3538de0decec580bc79fa0f9237973c83c8f5a9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 23 Sep 2013 12:30:12 +0200 Subject: [PATCH 1007/5273] Don't add null changes to history Issue #1836 --- lib/codemirror.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index cdf7652e72..41b4d759ed 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2329,6 +2329,7 @@ window.CodeMirror = (function() { } function makeChangeNoReadonly(doc, change, selUpdate) { + if (change.text.length == 1 && change.text[0] == "" && posEq(change.from, change.to)) return; var selAfter = computeSelAfterChange(doc, change, selUpdate); addToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); From c2f2f34b6cedebf0a1ade910e17c438e2ae49623 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 23 Sep 2013 13:02:14 +0200 Subject: [PATCH 1008/5273] [test suite] Fix windows/IE incompatibilities Closes #1826 --- test/test.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/test.js b/test/test.js index a05b8afb42..e5d9afdedd 100644 --- a/test/test.js +++ b/test/test.js @@ -1,5 +1,7 @@ var Pos = CodeMirror.Pos; +CodeMirror.defaults.rtlMoveVisually = true; + function forEach(arr, f) { for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); } @@ -529,10 +531,10 @@ testCM("multiBookmarkCursor", function(cm) { } var base1 = cm.cursorCoords(Pos(0, 1)).left, base4 = cm.cursorCoords(Pos(0, 4)).left; add(true); - eq(base1, cm.cursorCoords(Pos(0, 1)).left); + is(Math.abs(base1 - cm.cursorCoords(Pos(0, 1)).left) < .1); while (m = ms.pop()) m.clear(); add(false); - eq(base4, cm.cursorCoords(Pos(0, 1)).left); + is(Math.abs(base4 - cm.cursorCoords(Pos(0, 1)).left) < .1); }, {value: "abcdefg"}); testCM("getAllMarks", function(cm) { @@ -1159,7 +1161,7 @@ testCM("rtlMovement", function(cm) { prevX = cursor.offsetLeft; } }); -}, {rtlMoveVisually: true}); +}); // Verify that updating a line clears its bidi ordering testCM("bidiUpdate", function(cm) { From 46bab8eab13594efcb8f6752e44013ddb1502661 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 23 Sep 2013 13:50:16 +0200 Subject: [PATCH 1009/5273] Mark release 3.17 --- AUTHORS | 11 +++++++++++ bower.json | 2 +- doc/compress.html | 1 + doc/releases.html | 9 +++++++++ index.html | 2 +- lib/codemirror.js | 2 +- package.json | 2 +- 7 files changed, 25 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index bb6f8c8c64..ad2ec99576 100644 --- a/AUTHORS +++ b/AUTHORS @@ -17,6 +17,7 @@ alexey-k Alex Piggott Amy Ananya Sen +AndersMad Andre von Houck Andrey Lushnikov Andy Kimball @@ -36,6 +37,7 @@ Ben Keen boomyjee borawjm Brandon Frohs +Brett Zamir Brian Sletten Bruce Mitchener Chandra Sekhar Pydi @@ -44,6 +46,7 @@ Chris Coyier Chris Granger Chris Morgan Christopher Brown +ciaranj CodeAnimal ComFreek dagsta @@ -76,6 +79,7 @@ Felipe Lalanne Felix Raab Filip Noetzel flack +ForbesLindesay Ford_Lawnmower Gabriel Nahmias galambalazs @@ -85,6 +89,7 @@ Golevka Gordon Smith greengiant Guillaume Massé +Guillaume Massé Hans Engel Hardest Hasan Karahan @@ -137,6 +142,7 @@ komakino Konstantin Lopuhin koops ks-ifware +kubelsmieci Lanny leaf corcoran Leonya Khachaturov @@ -151,6 +157,8 @@ Marco Aurélio Marijn Haverbeke Mario Pietsch Mark Lentczner +Martin Balek +Martín Gaitán Mason Malone Mateusz Paprocki mats cronqvist @@ -219,6 +227,7 @@ Stas Kobzar Stefan Borsje Steffen Beyer Steve O'Hara +stoskov Tarmil tfjgeorge Thaddee Tyl @@ -228,6 +237,8 @@ Thomas Schmid Tim Baumann Timothy Farrell Timothy Hatcher +TobiasBg +Tomas-A Tomas Varaneckas Tom Erik Støwer Tom MacWright diff --git a/bower.json b/bower.json index 451d654c0c..2aeffb8990 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "CodeMirror", - "version": "3.16.0", + "version": "3.17.0", "main": ["lib/codemirror.js", "lib/codemirror.css"], "ignore": [ "**/.*", diff --git a/doc/compress.html b/doc/compress.html index d7f720fae1..30b148dd63 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -33,6 +33,7 @@

    Script compression helper

    Version:

    Version: + +

    Demonstration of +the hardwrap addon. +The above editor has its change event hooked up to +the wrapParagraphsInRange method, so that the paragraphs +are reflown as you are typing.

    + + + + diff --git a/doc/compress.html b/doc/compress.html index a3e3792a18..5ae53c4838 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -166,6 +166,7 @@

    Script compression helper

    + diff --git a/doc/manual.html b/doc/manual.html index 9f516b7e05..51ad9799bc 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -14,9 +14,10 @@ diff --git a/mode/julia/julia.js b/mode/julia/julia.js index edf9dc41b5..9ec2428cd4 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -11,7 +11,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif", "try", "finally", "catch"]; var blockClosers = ["end", "else", "elseif", "catch", "finally"]; var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote', 'typealias', 'abstract', 'bitstype', 'ccall']; - var builtinList = ['all', 'true', 'false', 'any', 'enumerate', 'open', 'close', 'linspace', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'error', 'warn', 'info']; + var builtinList = ['true', 'false', 'enumerate', 'open', 'close', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'UTF8String', 'ASCIIString', 'error', 'warn', 'info', '@printf']; //var stringPrefixes = new RegExp("^[br]?('|\")") var stringPrefixes = /^[br]?('|"{3}|")/; @@ -19,6 +19,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { var builtins = wordRegexp(builtinList); var openers = wordRegexp(blockOpeners); var closers = wordRegexp(blockClosers); + var macro = /@[_A-Za-z][_A-Za-z0-9]*!*/; var indentInfo = null; function in_array(state) { @@ -147,6 +148,7 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { if (stream.match(operators)) { return 'operator'; } + if (stream.match(delimiters)) { return null; } @@ -159,6 +161,9 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { return 'builtin'; } + if (stream.match(macro)) { + return 'meta'; + } if (stream.match(identifiers)) { state.leaving_expr=true; @@ -220,11 +225,6 @@ CodeMirror.defineMode("julia", function(_conf, parserConf) { return style; } - // Handle macro calls - if (current === '@') { - return stream.match(identifiers, false) ? 'meta' : ERRORCLASS; - } - return style; } From d64d8ba868dac600ba8572d3e4b51d612a9116fa Mon Sep 17 00:00:00 2001 From: Jason Johnston Date: Tue, 22 Oct 2013 13:41:45 -0600 Subject: [PATCH 1094/5273] [matchbrackets addon] add a maxScanLines configuration, defaulting to 100. --- addon/edit/matchbrackets.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js index 131fe831fd..9d9b3882f7 100644 --- a/addon/edit/matchbrackets.js +++ b/addon/edit/matchbrackets.js @@ -8,6 +8,7 @@ function findMatchingBracket(cm, where, strict) { var state = cm.state.matchBrackets; var maxScanLen = (state && state.maxScanLineLength) || 10000; + var maxScanLines = (state && state.maxScanLines) || 100; var cur = where || cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1; var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)]; @@ -32,7 +33,7 @@ } } } - for (var i = cur.line, found, e = forward ? Math.min(i + 100, cm.lineCount()) : Math.max(-1, i - 100); i != e; i+=d) { + for (var i = cur.line, found, e = forward ? Math.min(i + maxScanLines, cm.lineCount()) : Math.max(-1, i - maxScanLines); i != e; i+=d) { if (i == cur.line) found = scan(line, i, pos); else found = scan(cm.getLineHandle(i), i); if (found) break; From 02f49478ebbe133a1567832726589f05af0d4a3f Mon Sep 17 00:00:00 2001 From: angelozerr Date: Tue, 22 Oct 2013 17:03:01 +0200 Subject: [PATCH 1095/5273] [tern addon] Make it possible to pass in explicit positions Create Tern request with optionnal pos to manage for instance tern hover. See demo at http://codemirror-java.opensagres.eu.cloudbees.net/codemirror-javascript/demo/javascript-all.html --- addon/tern/tern.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/addon/tern/tern.js b/addon/tern/tern.js index fe93fa7335..1f18a657fb 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -96,7 +96,7 @@ getHint: function(cm, c) { return hint(this, cm, c); }, - showType: function(cm) { showType(this, cm); }, + showType: function(cm, pos) { showType(this, cm, pos); }, updateArgHints: function(cm) { updateArgHints(this, cm); }, @@ -106,10 +106,10 @@ rename: function(cm) { rename(this, cm); }, - request: function (cm, query, c) { + request: function (cm, query, c, pos) { var self = this; var doc = findDoc(this, cm.getDoc()); - var request = buildRequest(this, doc, query); + var request = buildRequest(this, doc, query, pos); this.server.request(request, function (error, data) { if (!error && self.options.responseFilter) @@ -221,7 +221,7 @@ // Type queries - function showType(ts, cm) { + function showType(ts, cm, pos) { ts.request(cm, "type", function(error, data) { if (error) return showError(ts, cm, error); if (ts.options.typeTip) { @@ -236,7 +236,7 @@ } } tempTooltip(cm, tip); - }); + }, pos); } // Maintaining argument hints @@ -450,13 +450,13 @@ // Generic request-building helper - function buildRequest(ts, doc, query) { + function buildRequest(ts, doc, query, pos) { var files = [], offsetLines = 0, allowFragments = !query.fullDocs; if (!allowFragments) delete query.fullDocs; if (typeof query == "string") query = {type: query}; query.lineCharPositions = true; if (query.end == null) { - query.end = doc.doc.getCursor("end"); + query.end = pos || doc.doc.getCursor("end"); if (doc.doc.somethingSelected()) query.start = doc.doc.getCursor("start"); } From ae0640c4befccf946cdbe12988d59bd3572ec00e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 24 Oct 2013 14:49:43 +0200 Subject: [PATCH 1096/5273] [javascript mode] Properly handle regexp at start of file --- mode/javascript/javascript.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index e8ace32d89..9fca783c44 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -103,7 +103,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { return ret("comment", "comment"); } else if (state.lastType == "operator" || state.lastType == "keyword c" || - /^[\[{}\(,;:]$/.test(state.lastType)) { + state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) { nextUntilUnescaped(stream, "/"); stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla return ret("regexp", "string-2"); @@ -410,7 +410,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { startState: function(basecolumn) { return { tokenize: jsTokenBase, - lastType: null, + lastType: "sof", cc: [], lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false), localVars: parserConfig.localVars, From 759b3a0e9ab1ce6486341651252d968e417ffe5e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 26 Oct 2013 22:06:59 +0200 Subject: [PATCH 1097/5273] Fix undesirable selection-mangling in indentLine Issue #1910 --- lib/codemirror.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index e52c883201..231b782971 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2759,9 +2759,7 @@ window.CodeMirror = (function() { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} if (pos < indentation) indentString += spaceStr(indentation - pos); - if (indentString == curSpaceString) - setSelection(cm.doc, Pos(n, curSpaceString.length), Pos(n, curSpaceString.length)); - else + if (indentString != curSpaceString || doc.sel.head.line == n && doc.sel.head.ch < curSpaceString.length) replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); line.stateAfter = null; } From 8d000ddae0935f73e32ef517841c4df21db175e2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 28 Oct 2013 19:40:54 +0100 Subject: [PATCH 1098/5273] [javascript mode] Fix bug in recognizing local variable in nested context --- mode/javascript/javascript.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 9fca783c44..05ae70bd2f 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -165,6 +165,10 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function inScope(state, varname) { for (var v = state.localVars; v; v = v.next) if (v.name == varname) return true; + for (var cx = state.context; cx; cx = cx.prev) { + for (var v = cx.vars; v; v = v.next) + if (v.name == varname) return true; + } } function parseJS(state, style, type, content, stream) { From bf55dac09202b4dbca190a8323ed698e0d2eff74 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 29 Oct 2013 08:46:21 +0100 Subject: [PATCH 1099/5273] Disable textarea when readOnly=nocursor Issue #1909 --- lib/codemirror.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 231b782971..9e7b720781 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3308,8 +3308,14 @@ window.CodeMirror = (function() { option("resetSelectionOnContextMenu", true); option("readOnly", false, function(cm, val) { - if (val == "nocursor") {onBlur(cm); cm.display.input.blur();} - else if (!val) resetInput(cm, true); + if (val == "nocursor") { + onBlur(cm); + cm.display.input.blur(); + cm.display.disabled = true; + } else { + cm.display.disabled = false; + if (!val) resetInput(cm, true); + } }); option("dragDrop", true); From 65c750e8f7b04c7b99a915d912c16f235430ca3e Mon Sep 17 00:00:00 2001 From: ilvalle Date: Mon, 28 Oct 2013 10:21:27 +0100 Subject: [PATCH 1100/5273] [indent-fold addon] Fix folding for empty files --- addon/fold/indent-fold.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addon/fold/indent-fold.js b/addon/fold/indent-fold.js index b54da34777..7ae005d904 100644 --- a/addon/fold/indent-fold.js +++ b/addon/fold/indent-fold.js @@ -1,8 +1,9 @@ CodeMirror.registerHelper("fold", "indent", function(cm, start) { var lastLine = cm.lastLine(), tabSize = cm.getOption("tabSize"), - firstLine = cm.getLine(start.line), - myIndent = CodeMirror.countColumn(firstLine, null, tabSize); + firstLine = cm.getLine(start.line); + if (!tabSize || !firstLine) return; + var myIndent = CodeMirror.countColumn(firstLine, null, tabSize); function foldEnded(curColumn, prevColumn) { return curColumn < myIndent || From 701b226107b3eded05cb10575c258647854c0352 Mon Sep 17 00:00:00 2001 From: Forbes Lindesay Date: Tue, 22 Oct 2013 17:17:16 +0100 Subject: [PATCH 1101/5273] Add the PEG.js language --- mode/peg/index.html | 66 ++++++++++++++++++++++++++++ mode/peg/peg.js | 103 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 mode/peg/index.html create mode 100644 mode/peg/peg.js diff --git a/mode/peg/index.html b/mode/peg/index.html new file mode 100644 index 0000000000..3e55a5e4b5 --- /dev/null +++ b/mode/peg/index.html @@ -0,0 +1,66 @@ + + + + CodeMirror: PEG Mode + + + + + + + + + + + + +
    +

    PEG.js Mode

    +
    + +

    The PEG.js Mode

    +

    Created by Forbes Lindesay.

    +
    + + \ No newline at end of file diff --git a/mode/peg/peg.js b/mode/peg/peg.js new file mode 100644 index 0000000000..6f8b480946 --- /dev/null +++ b/mode/peg/peg.js @@ -0,0 +1,103 @@ +CodeMirror.defineMode("peg", function (config) { + var jsMode = CodeMirror.getMode(config, "javascript"); + + function identifier(stream) { + return stream.match(/^[a-zA-Z_][a-zA-Z0-9_]*/); + } + + return { + startState: function () { + return { + inString: false, + stringType: null, + inComment: false, + inChracterClass: false, + braced: 0, + lhs: true, + localState: null + }; + }, + token: function (stream, state) { + if (stream) + + //check for state changes + if (!state.inString && !state.inComment && ((stream.peek() == '"') || (stream.peek() == "'"))) { + state.stringType = stream.peek(); + stream.next(); // Skip quote + state.inString = true; // Update state + } + if (!state.inString && !state.inComment && stream.match(/^\/\*/)) { + state.inComment = true; + } + + //return state + if (state.inString) { + while (state.inString && !stream.eol()) { + if (stream.peek() === state.stringType) { + stream.next(); // Skip quote + state.inString = false; // Clear flag + } else if (stream.peek() === '\\') { + stream.next(); + stream.next(); + } else { + stream.match(/^.[^\\\"\']*/); + } + } + return state.lhs ? "property string" : "string"; // Token style + } else if (state.inComment) { + while (state.inComment && !stream.eol()) { + if (stream.match(/\*\//)) { + state.inComment = false; // Clear flag + } else { + stream.match(/^.[^\*]*/); + } + } + return "comment"; + } else if (state.inChracterClass) { + if (stream.match(/^[^\]\\]+/)) { + return; + } else if (stream.match(/^\\./)) { + return; + } else { + stream.next(); + state.inChracterClass = false; + return 'bracket'; + } + } else if (stream.peek() === '[') { + stream.next(); + state.inChracterClass = true; + return 'bracket'; + } else if (stream.match(/^\/\//)) { + stream.skipToEnd(); + return "comment"; + } else if (state.braced || stream.peek() === '{') { + if (state.localState === null) { + state.localState = jsMode.startState(); + } + var token = jsMode.token(stream, state.localState); + var text = stream.current(); + if (!token) { + for (var i = 0; i < text.length; i++) { + if (text[i] === '{') { + state.braced++; + } else if (text[i] === '}') { + state.braced--; + } + }; + } + return token; + } else if (identifier(stream)) { + if (stream.peek() === ':') { + return 'variable'; + } + return 'variable-2'; + } else if (['[', ']', '(', ')'].indexOf(stream.peek()) != -1) { + stream.next(); + return 'bracket'; + } else if (!stream.eatSpace()) { + stream.next(); + } + return null; + } + }; +}); From acb16d4be0aba6edf51b97c413cd66a4e248c9e1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 29 Oct 2013 08:58:07 +0100 Subject: [PATCH 1102/5273] [pegjs mode] Integrate --- doc/compress.html | 1 + mode/index.html | 1 + mode/meta.js | 1 + mode/{peg => pegjs}/index.html | 10 +++++----- mode/{peg/peg.js => pegjs/pegjs.js} | 4 ++-- 5 files changed, 10 insertions(+), 7 deletions(-) rename mode/{peg => pegjs}/index.html (90%) rename mode/{peg/peg.js => pegjs/pegjs.js} (97%) diff --git a/doc/compress.html b/doc/compress.html index d1384a76ef..f49c978b2e 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -118,6 +118,7 @@

    Script compression helper

    + diff --git a/mode/index.html b/mode/index.html index 337f3336e4..81abc42d8c 100644 --- a/mode/index.html +++ b/mode/index.html @@ -71,6 +71,7 @@

    Language modes

  • OCaml
  • Octave (MATLAB)
  • Pascal
  • +
  • PEG.js
  • Perl
  • PHP
  • Pig Latin
  • diff --git a/mode/meta.js b/mode/meta.js index 47f042568d..226cff12e5 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -48,6 +48,7 @@ CodeMirror.modeInfo = [ {name: 'OCaml', mime: 'text/x-ocaml', mode: 'ocaml'}, {name: 'Octave', mime: 'text/x-octave', mode: 'octave'}, {name: 'Pascal', mime: 'text/x-pascal', mode: 'pascal'}, + {name: 'PEG.js', mime: null, mode: 'pegjs'}, {name: 'Perl', mime: 'text/x-perl', mode: 'perl'}, {name: 'PHP', mime: 'text/x-php', mode: 'php'}, {name: 'PHP(HTML)', mime: 'application/x-httpd-php', mode: 'php'}, diff --git a/mode/peg/index.html b/mode/pegjs/index.html similarity index 90% rename from mode/peg/index.html rename to mode/pegjs/index.html index 3e55a5e4b5..678b714d8e 100644 --- a/mode/peg/index.html +++ b/mode/pegjs/index.html @@ -1,14 +1,14 @@ - CodeMirror: PEG Mode + CodeMirror: PEG.js Mode - + @@ -22,7 +22,7 @@
    @@ -55,7 +55,7 @@

    PEG.js Mode

    letter = [a-z]+ @@ -63,4 +63,4 @@

    The PEG.js Mode

    Created by Forbes Lindesay.

    - \ No newline at end of file + diff --git a/mode/peg/peg.js b/mode/pegjs/pegjs.js similarity index 97% rename from mode/peg/peg.js rename to mode/pegjs/pegjs.js index 6f8b480946..6cdcc61f30 100644 --- a/mode/peg/peg.js +++ b/mode/pegjs/pegjs.js @@ -1,4 +1,4 @@ -CodeMirror.defineMode("peg", function (config) { +CodeMirror.defineMode("pegjs", function (config) { var jsMode = CodeMirror.getMode(config, "javascript"); function identifier(stream) { @@ -100,4 +100,4 @@ CodeMirror.defineMode("peg", function (config) { return null; } }; -}); +}, "javascript"); From 0d32c1e73bd30408e4d70503aebeefdaef8fecda Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 30 Oct 2013 20:03:31 +0100 Subject: [PATCH 1103/5273] [haskell mode] Fix unintended prototype property access bug Closes #1917 --- mode/haskell/haskell.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/haskell/haskell.js b/mode/haskell/haskell.js index 59ca7f0baa..68a6317e64 100644 --- a/mode/haskell/haskell.js +++ b/mode/haskell/haskell.js @@ -237,7 +237,7 @@ CodeMirror.defineMode("haskell", function(_config, modeConfig) { token: function(stream, state) { var t = state.f(stream, function(s) { state.f = s; }); var w = stream.current(); - return (w in wellKnownWords) ? wellKnownWords[w] : t; + return wellKnownWords.hasOwnProperty(w) ? wellKnownWords[w] : t; }, blockCommentStart: "{-", From de91f48272d060cfe83406280242ba469f5aba27 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 31 Oct 2013 08:23:15 +0100 Subject: [PATCH 1104/5273] [real-world uses] Add Crudzilla --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 8afe73aa0a..4e0896c377 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -51,6 +51,7 @@

    CodeMirror real-world uses

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

    Miscellaneous methods

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

    Addons

    dialog/dialog.js
    Provides a very simple way to query users for text input. - Adds an openDialog method to CodeMirror instances, - which can be called with an HTML fragment that provides the - prompt (should include an input tag), and a - callback function that is called when text has been entered. - Depends on addon/dialog/dialog.css.
    + Adds an openDialog method to + CodeMirror instances, which can be called with an HTML fragment + that provides the prompt (should include an input + tag), and a callback function that is called when text has been + entered. Also adds + an openNotification function that + simply shows an HTML fragment as a notification. Depends + on addon/dialog/dialog.css.
    search/searchcursor.js
    Adds the getSearchCursor(query, start, caseFold) → From 11c50cb69b406794eac7421b2997407a8d17528f Mon Sep 17 00:00:00 2001 From: Andy Joslin Date: Thu, 7 Nov 2013 13:49:19 -0500 Subject: [PATCH 1125/5273] [vim mode] use openNotification instead of openConfirm for errors --- keymap/vim.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index e67a46ed7f..dab10e21a4 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2726,10 +2726,9 @@ return regexp; } function showConfirm(cm, text) { - if (cm.openConfirm) { - cm.openConfirm('' + text + - ' ', function() {}, - {bottom: true}); + if (cm.openNotification) { + cm.openNotification('' + text + '', + {bottom: true, duration: 5000}); } else { alert(text); } From 74a3f2261d8f8646a282e089cf8d8c777e498274 Mon Sep 17 00:00:00 2001 From: Brandon Frohs Date: Thu, 7 Nov 2013 17:13:09 -0500 Subject: [PATCH 1126/5273] [markdown mode] `\n* ` should not toggle em state. Closes #1920. --- mode/markdown/markdown.js | 7 ++++++- mode/markdown/test.js | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index bf1750d5b6..0d60b3db8f 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -257,6 +257,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.taskOpen = false; state.taskClosed = false; + // Get sol() value now, before character is consumed + var sol = stream.sol(); + var ch = stream.next(); if (ch === '\\') { @@ -355,7 +358,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { } var t = getType(state); if (ch === '*' || (ch === '_' && !ignoreUnderscore)) { - if (state.strong === ch && stream.eat(ch)) { // Remove STRONG + if (sol && stream.peek() === ' ') { + // Do nothing, surrounded by newline and space + } else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG state.strong = false; return t; } else if (!state.strong && stream.eat(ch)) { // Add STRONG diff --git a/mode/markdown/test.js b/mode/markdown/test.js index f167917289..081be96be1 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -577,6 +577,10 @@ MT("emEscapedBySpaceOut", "foo _ bar[em _hello_]world"); + MT("emEscapedByNewline", + "foo", + "_ bar[em _hello_]world"); + // Unclosed emphasis characters // Instead of simply marking as EM / STRONG, it would be nice to have an // incomplete flag for EM and STRONG, that is styled slightly different. From a7120a79dc85e7caccc639e9192a63a6c209308f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 11 Nov 2013 08:55:07 +0100 Subject: [PATCH 1127/5273] [real-world uses] Add MVC Playground --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 4e0896c377..6e23106793 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -88,6 +88,7 @@

    CodeMirror real-world uses

  • Mergely (interactive diffing)
  • MIHTool (iOS web-app debugging tool)
  • Mongo MapReduce WebBrowser
  • +
  • MVC Playground
  • My2ndGeneration (social coding)
  • Navigate CMS
  • nodeMirror (IDE project)
  • From 8f491df2a175a942c4d3b51781998bb1ad868054 Mon Sep 17 00:00:00 2001 From: Michael Zhou Date: Sat, 9 Nov 2013 05:03:52 -0500 Subject: [PATCH 1128/5273] [clike demo] Fix duplicate variable names for C and C++ editors The C editor and the C++ editor have the same variable name, so the latter shadows the former. Fixed by renaming both. --- mode/clike/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/clike/index.html b/mode/clike/index.html index 45add4910b..93bd718a0a 100644 --- a/mode/clike/index.html +++ b/mode/clike/index.html @@ -165,12 +165,12 @@

    Java example

    ]", + "[link ]", + "[tag&bracket <][tag div][tag&bracket >]", + "[tag&bracket ]"); + })(); From 60ab165bfa2bfc81b97d3b2b2d16c9665002adf5 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 6 May 2014 11:04:27 +0200 Subject: [PATCH 1833/5273] [dylan mode] Add module loading shim Closes #2533 --- mode/dylan/dylan.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mode/dylan/dylan.js b/mode/dylan/dylan.js index d81ef0cbcb..ccf9679181 100644 --- a/mode/dylan/dylan.js +++ b/mode/dylan/dylan.js @@ -1,3 +1,13 @@ +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + CodeMirror.defineMode("dylan", function(_config) { // Words var words = { @@ -282,3 +292,5 @@ CodeMirror.defineMode("dylan", function(_config) { }); CodeMirror.defineMIME("text/x-dylan", "dylan"); + +}); From 6abb339705fd234de93b14c28f37a5a212b65629 Mon Sep 17 00:00:00 2001 From: binny Date: Mon, 5 May 2014 21:55:30 +0530 Subject: [PATCH 1834/5273] [vim] Visual paste operation with unit tests --- keymap/vim.js | 61 +++++++++++++++++++++++++++++------------------- test/vim_test.js | 25 ++++++++++++++++++++ 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index c78d76af94..1ea39c1ef0 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2051,7 +2051,7 @@ } this.enterInsertMode(cm, { repeat: actionArgs.repeat }, vim); }, - paste: function(cm, actionArgs) { + paste: function(cm, actionArgs, vim) { var cur = copyCursor(cm.getCursor()); var register = vimGlobalState.registerController.getRegister( actionArgs.registerName); @@ -2092,7 +2092,9 @@ } var linewise = register.linewise; if (linewise) { - if (actionArgs.after) { + if(vim.visualMode) { + text = vim.visualLine ? text.slice(0, -1) : '\n' + text.slice(0, text.length - 1) + '\n'; + } else if (actionArgs.after) { // Move the newline at the end to the start instead, and paste just // before the newline character of the line we are on right now. text = '\n' + text.slice(0, text.length - 1); @@ -2103,24 +2105,35 @@ } else { cur.ch += actionArgs.after ? 1 : 0; } - cm.replaceRange(text, cur); - // Now fine tune the cursor to where we want it. var curPosFinal; var idx; - if (linewise && actionArgs.after) { - curPosFinal = Pos( - cur.line + 1, - findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line + 1))); - } else if (linewise && !actionArgs.after) { - curPosFinal = Pos( - cur.line, - findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line))); - } else if (!linewise && actionArgs.after) { - idx = cm.indexFromPos(cur); - curPosFinal = cm.posFromIndex(idx + text.length - 1); + if (vim.visualMode) { + var selectedArea = getSelectedAreaRange(cm, vim); + var selectionStart = selectedArea[0]; + var selectionEnd = selectedArea[1]; + // push the previously selected text to unnamed register + vimGlobalState.registerController.unnamedRegister.setText(cm.getRange(selectionStart, selectionEnd)); + cm.replaceRange(text, selectionStart, selectionEnd); + curPosFinal = cm.posFromIndex(cm.indexFromPos(selectionStart) + text.length - 1); + if(linewise)curPosFinal.ch=0; } else { - idx = cm.indexFromPos(cur); - curPosFinal = cm.posFromIndex(idx + text.length); + cm.replaceRange(text, cur); + // Now fine tune the cursor to where we want it. + if (linewise && actionArgs.after) { + curPosFinal = Pos( + cur.line + 1, + findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line + 1))); + } else if (linewise && !actionArgs.after) { + curPosFinal = Pos( + cur.line, + findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line))); + } else if (!linewise && actionArgs.after) { + idx = cm.indexFromPos(cur); + curPosFinal = cm.posFromIndex(idx + text.length - 1); + } else { + idx = cm.indexFromPos(cur); + curPosFinal = cm.posFromIndex(idx + text.length); + } } cm.setCursor(curPosFinal); }, @@ -2220,13 +2233,6 @@ var selectionStart = selectedAreaRange[0]; var selectionEnd = selectedAreaRange[1]; var toLower = actionArgs.toLower; - if (cursorIsBefore(selectionEnd, selectionStart)) { - var tmp = selectionStart; - selectionStart = selectionEnd; - selectionEnd = tmp; - } else { - selectionEnd = cm.clipPos(Pos(selectionEnd.line, selectionEnd.ch+1)); - } var text = cm.getRange(selectionStart, selectionEnd); cm.replaceRange(toLower ? text.toLowerCase() : text.toUpperCase(), selectionStart, selectionEnd); cm.setCursor(selectionStart); @@ -2324,6 +2330,13 @@ return [{line: selectionStart.line, ch: 0}, {line: selectionEnd.line, ch: lineLength(cm, selectionEnd.line)}]; } } else { + if (cursorIsBefore(selectionEnd, selectionStart)) { + var tmp = selectionStart; + selectionStart = selectionEnd; + selectionEnd = tmp; + } else { + selectionEnd = cm.clipPos(Pos(selectionEnd.line, selectionEnd.ch+1)); + } exitVisualMode(cm); } return [selectionStart, selectionEnd]; diff --git a/test/vim_test.js b/test/vim_test.js index 71cd5ed941..a3f3fed3ad 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1639,6 +1639,31 @@ testVim('uppercase/lowercase_visual', function(cm, vim, helpers) { helpers.doKeys('V', 'U', 'j', '.'); eq('ABCDEF\nGHIJKL\nMnopq\nSHORT LINE\nLONG LINE OF TEXT', cm.getValue()); }, { value: 'abcdef\nghijkl\nmnopq\nshort line\nlong line of text'}); +testVim('visual_paste', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('v', 'l', 'l', 'y', 'j', 'v', 'l', 'p'); + helpers.assertCursorAt(1, 4); + eq('this is a\nunthi test for visual paste', cm.getValue()); + cm.setCursor(0, 0); + // in case of pasting whole line + helpers.doKeys('y', 'y'); + cm.setCursor(1, 6); + helpers.doKeys('v', 'l', 'l', 'l', 'p'); + helpers.assertCursorAt(2, 0); + eq('this is a\nunthi \nthis is a\n for visual paste', cm.getValue()); +}, { value: 'this is a\nunit test for visual paste'}); + +// This checks the contents of the register used to paste the text +testVim('v_paste_from_register', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('"', 'a', 'y', 'w'); + cm.setCursor(1, 0); + helpers.doKeys('v', 'p'); + cm.openDialog = helpers.fakeOpenDialog('registers'); + cm.openNotification = helpers.fakeOpenNotification(function(text) { + is(/a\s+register/.test(text)); + }); +}, { value: 'register contents\nare not erased'}); testVim('S_normal', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('j', 'S'); From 6db5ec2870fc78977c817e35440185e26bff9175 Mon Sep 17 00:00:00 2001 From: binny Date: Wed, 30 Apr 2014 06:01:39 +0530 Subject: [PATCH 1835/5273] [vim] support for append action command in visual mode added --- keymap/vim.js | 8 ++++++++ test/vim_test.js | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/keymap/vim.js b/keymap/vim.js index 1ea39c1ef0..c48506adaa 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -271,6 +271,7 @@ actionArgs: { insertAt: 'charAfter' }}, { keys: ['A'], type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'eol' }}, + { keys: ['A'], type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'endOfSelectedArea' }, context: 'visual' }, { keys: ['i'], type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'inplace' }}, { keys: ['I'], type: 'action', action: 'enterInsertMode', isEdit: true, @@ -1914,6 +1915,13 @@ cm.setCursor(offsetCursor(cm.getCursor(), 0, 1)); } else if (insertAt == 'firstNonBlank') { cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm)); + } else if (insertAt == 'endOfSelectedArea') { + var selectionEnd = cm.getCursor('head'); + var selectionStart = cm.getCursor('anchor'); + var cursor = cm.getCursor(); + cursor = cursorIsBefore(selectionStart, selectionEnd) ? Pos(cursor.line, selectionEnd.ch+1) : Pos(cursor.line, selectionEnd.ch); + cm.setCursor(cursor); + exitVisualMode(cm); } cm.setOption('keyMap', 'vim-insert'); cm.setOption('disableInput', false); diff --git a/test/vim_test.js b/test/vim_test.js index a3f3fed3ad..fecc52ba35 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1141,6 +1141,13 @@ testVim('a_eol', function(cm, vim, helpers) { helpers.assertCursorAt(0, lines[0].length); eq('vim-insert', cm.getOption('keyMap')); }); +testVim('a_endOfSelectedArea', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('v', 'j', 'l'); + helpers.doKeys('A'); + helpers.assertCursorAt(1, 2); + eq('vim-insert', cm.getOption('keyMap')); +}, {value: 'foo\nbar'}); testVim('i', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('i'); From 546eb6ce365d860d1649f0b6e22cd6b1f7879a21 Mon Sep 17 00:00:00 2001 From: binny Date: Fri, 2 May 2014 03:32:33 +0530 Subject: [PATCH 1836/5273] [vim] Resolve upward selection bug --- keymap/vim.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index c48506adaa..e33d269089 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1918,9 +1918,8 @@ } else if (insertAt == 'endOfSelectedArea') { var selectionEnd = cm.getCursor('head'); var selectionStart = cm.getCursor('anchor'); - var cursor = cm.getCursor(); - cursor = cursorIsBefore(selectionStart, selectionEnd) ? Pos(cursor.line, selectionEnd.ch+1) : Pos(cursor.line, selectionEnd.ch); - cm.setCursor(cursor); + selectionEnd = cursorIsBefore(selectionStart, selectionEnd) ? Pos(selectionEnd.line, selectionEnd.ch+1) : (selectionEnd.line < selectionStart.line ? Pos(selectionStart.line, 0) : selectionEnd); + cm.setCursor(selectionEnd); exitVisualMode(cm); } cm.setOption('keyMap', 'vim-insert'); From 41a29b0132445f8f10a5fc4b83f7c1e456171d03 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 8 May 2014 12:22:20 +0200 Subject: [PATCH 1837/5273] Abort wheel delta measurement when scrolling explicitly Issue #2537 --- lib/codemirror.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 4a843d3f63..0bf6f2d8e8 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1927,6 +1927,10 @@ if (!updated && op.selectionChanged) updateSelection(cm); if (!updated && op.startHeight != cm.doc.height) updateScrollbars(cm); + // 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; + // Propagate the scroll position to the actual DOM scroller if (op.scrollTop != null && display.scroller.scrollTop != op.scrollTop) { var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); From 0efe7a57115a252abf033e16ea1d1a375cd5a229 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 9 May 2014 14:48:38 +0200 Subject: [PATCH 1838/5273] [sublime keybindings] Don't include zero-char selection bottoms in swapLine* Issue #2542 --- keymap/sublime.js | 16 ++++++++-------- test/sublime_test.js | 6 ++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/keymap/sublime.js b/keymap/sublime.js index eea46347fd..9158e27944 100644 --- a/keymap/sublime.js +++ b/keymap/sublime.js @@ -184,9 +184,12 @@ }; cmds[map["Shift-" + ctrl + "Up"] = "swapLineUp"] = function(cm) { - var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1; + var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1, newSels = []; for (var i = 0; i < ranges.length; i++) { var range = ranges[i], from = range.from().line - 1, to = range.to().line; + newSels.push({anchor: Pos(range.anchor.line - 1, range.anchor.ch), + head: Pos(range.head.line - 1, range.head.ch)}); + if (range.to().ch == 0 && !range.empty()) --to; if (from > at) linesToMove.push(from, to); else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to; at = to; @@ -196,16 +199,12 @@ var from = linesToMove[i], to = linesToMove[i + 1]; var line = cm.getLine(from); cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine"); - if (to > cm.lastLine()) { + if (to > cm.lastLine()) cm.replaceRange("\n" + line, Pos(cm.lastLine()), null, "+swapLine"); - var sels = cm.listSelections(), last = sels[sels.length - 1]; - var head = last.head.line == to ? Pos(to - 1) : last.head; - var anchor = last.anchor.line == to ? Pos(to - 1) : last.anchor; - cm.setSelections(sels.slice(0, sels.length - 1).concat([{head: head, anchor: anchor}])); - } else { + else cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine"); - } } + cm.setSelections(newSels); cm.scrollIntoView(); }); }; @@ -214,6 +213,7 @@ var ranges = cm.listSelections(), linesToMove = [], at = cm.lastLine() + 1; for (var i = ranges.length - 1; i >= 0; i--) { var range = ranges[i], from = range.to().line + 1, to = range.from().line; + if (range.to().ch == 0 && !range.empty()) from--; if (from < at) linesToMove.push(from, to); else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to; at = to; diff --git a/test/sublime_test.js b/test/sublime_test.js index f09504c51a..c93e041b87 100644 --- a/test/sublime_test.js +++ b/test/sublime_test.js @@ -178,6 +178,12 @@ 1, 0, 2, 0, 2, 2, 2, 2)); + stTest("swapLineEmptyBottomSel", "1\n2\n3", + setSel(0, 1, 1, 0), + "swapLineDown", val("2\n1\n3"), hasSel(1, 1, 2, 0), + "swapLineUp", val("1\n2\n3"), hasSel(0, 1, 1, 0), + "swapLineUp", val("1\n2\n3"), hasSel(0, 0, 0, 0)); + stTest("swapLineUpFromEnd", "a\nb\nc", Pos(2, 1), "swapLineUp", hasSel(1, 1, 1, 1), val("a\nc\nb")); From fea31914767042d0d42800ab82dc29b3e76a6a2b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 9 May 2014 15:18:36 +0200 Subject: [PATCH 1839/5273] [javascript-hint addon] Support an option that disables use of the current global scope --- addon/hint/javascript-hint.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addon/hint/javascript-hint.js b/addon/hint/javascript-hint.js index 305bb85a29..baf20b45dc 100644 --- a/addon/hint/javascript-hint.js +++ b/addon/hint/javascript-hint.js @@ -108,7 +108,8 @@ if (obj.type && obj.type.indexOf("variable") === 0) { if (options && options.additionalContext) base = options.additionalContext[obj.string]; - base = base || window[obj.string]; + if (!options || options.useGlobalScope !== false) + base = base || window[obj.string]; } else if (obj.type == "string") { base = ""; } else if (obj.type == "atom") { @@ -128,7 +129,8 @@ // (reading into JS mode internals to get at the local and global variables) for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); - gatherCompletions(window); + if (!options || options.useGlobalScope !== false) + gatherCompletions(window); forEach(keywords, maybeAdd); } return found; From a6faf989152a86a22f6155a775f3c16d724d1a88 Mon Sep 17 00:00:00 2001 From: Bem Jones-Bey Date: Tue, 6 May 2014 15:00:32 -0700 Subject: [PATCH 1840/5273] [css mode] Add more CSS Shapes properties Add shape-image-threshold and shape-margin. --- 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 3fae9687fd..8828329fc4 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -433,8 +433,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "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-inside", "shape-outside", "size", - "speak", "speak-as", "speak-header", + "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", From 81aeea3757b2c9826af68fb21fd5a170684f0aac Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 9 May 2014 15:24:47 +0200 Subject: [PATCH 1841/5273] [real-world uses] Add Better Text Viewer and CrossUI --- doc/realworld.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/realworld.html b/doc/realworld.html index ccfbf4be41..e6649b1f02 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -28,6 +28,7 @@

    CodeMirror real-world uses

  • Adobe Brackets (code editor)
  • Amber (JavaScript-based Smalltalk system)
  • APEye (tool for testing & documenting APIs)
  • +
  • Better Text Viewer (plain text reader app for Chrome)
  • Bitbucket (code hosting)
  • Blogger's template editor
  • BlueGriffon (HTML editor)
  • @@ -35,6 +36,7 @@

    CodeMirror real-world uses

  • Chrome DevTools
  • ClickHelp (technical writing tool)
  • Complete.ly playground
  • +
  • CrossUI (cross-platform UI builder)
  • Cruncher (notepad with calculation features)
  • Code per Node (Drupal module)
  • Codebug (PHP Xdebug front-end)
  • From 01e844f09eb74ad55a987779ead1c1fb17d5aea9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 9 May 2014 15:52:39 +0200 Subject: [PATCH 1842/5273] Add license and version comment to all scripts --- addon/comment/comment.js | 3 +++ addon/comment/continuecomment.js | 3 +++ addon/dialog/dialog.js | 3 +++ addon/display/fullscreen.js | 3 +++ addon/display/placeholder.js | 3 +++ addon/display/rulers.js | 3 +++ addon/edit/closebrackets.js | 3 +++ addon/edit/closetag.js | 3 +++ addon/edit/continuelist.js | 3 +++ addon/edit/matchbrackets.js | 3 +++ addon/edit/matchtags.js | 3 +++ addon/edit/trailingspace.js | 3 +++ addon/fold/brace-fold.js | 3 +++ addon/fold/comment-fold.js | 3 +++ addon/fold/foldcode.js | 3 +++ addon/fold/foldgutter.js | 3 +++ addon/fold/indent-fold.js | 3 +++ addon/fold/markdown-fold.js | 3 +++ addon/fold/xml-fold.js | 3 +++ addon/hint/anyword-hint.js | 3 +++ addon/hint/css-hint.js | 3 +++ addon/hint/html-hint.js | 3 +++ addon/hint/javascript-hint.js | 3 +++ addon/hint/python-hint.js | 3 +++ addon/hint/show-hint.js | 3 +++ addon/hint/sql-hint.js | 3 +++ addon/hint/xml-hint.js | 3 +++ addon/lint/coffeescript-lint.js | 3 +++ addon/lint/css-lint.js | 3 +++ addon/lint/javascript-lint.js | 3 +++ addon/lint/json-lint.js | 3 +++ addon/lint/lint.js | 3 +++ addon/lint/yaml-lint.js | 3 +++ addon/merge/merge.js | 3 +++ addon/mode/loadmode.js | 3 +++ addon/mode/multiplex.js | 3 +++ addon/mode/multiplex_test.js | 3 +++ addon/mode/overlay.js | 3 +++ addon/runmode/colorize.js | 3 +++ addon/runmode/runmode-standalone.js | 3 +++ addon/runmode/runmode.js | 3 +++ addon/runmode/runmode.node.js | 3 +++ addon/scroll/scrollpastend.js | 3 +++ addon/search/match-highlighter.js | 3 +++ addon/search/search.js | 3 +++ addon/search/searchcursor.js | 3 +++ addon/selection/active-line.js | 3 +++ addon/selection/mark-selection.js | 3 +++ addon/tern/tern.js | 3 +++ addon/tern/worker.js | 3 +++ addon/wrap/hardwrap.js | 3 +++ bin/release | 15 +++++++++++++++ keymap/emacs.js | 3 +++ keymap/sublime.js | 3 +++ keymap/vim.js | 3 +++ lib/codemirror.js | 3 +++ mode/apl/apl.js | 3 +++ mode/asterisk/asterisk.js | 3 +++ mode/clike/clike.js | 3 +++ mode/clojure/clojure.js | 3 +++ mode/cobol/cobol.js | 3 +++ mode/coffeescript/coffeescript.js | 3 +++ mode/commonlisp/commonlisp.js | 3 +++ mode/css/css.js | 3 +++ mode/css/less_test.js | 3 +++ mode/css/scss_test.js | 3 +++ mode/css/test.js | 3 +++ mode/cypher/cypher.js | 3 +++ mode/d/d.js | 3 +++ mode/diff/diff.js | 3 +++ mode/django/django.js | 3 +++ mode/dtd/dtd.js | 3 +++ mode/dylan/dylan.js | 3 +++ mode/ecl/ecl.js | 3 +++ mode/eiffel/eiffel.js | 3 +++ mode/erlang/erlang.js | 3 +++ mode/fortran/fortran.js | 3 +++ mode/gas/gas.js | 3 +++ mode/gfm/gfm.js | 3 +++ mode/gfm/test.js | 3 +++ mode/gherkin/gherkin.js | 3 +++ mode/go/go.js | 3 +++ mode/groovy/groovy.js | 3 +++ mode/haml/haml.js | 3 +++ mode/haml/test.js | 3 +++ mode/haskell/haskell.js | 3 +++ mode/haxe/haxe.js | 3 +++ mode/htmlembedded/htmlembedded.js | 3 +++ mode/htmlmixed/htmlmixed.js | 3 +++ mode/http/http.js | 3 +++ mode/jade/jade.js | 3 +++ mode/javascript/javascript.js | 3 +++ mode/javascript/test.js | 3 +++ mode/jinja2/jinja2.js | 3 +++ mode/julia/julia.js | 3 +++ mode/livescript/livescript.js | 3 +++ mode/lua/lua.js | 3 +++ mode/markdown/markdown.js | 3 +++ mode/markdown/test.js | 3 +++ mode/meta.js | 3 +++ mode/mirc/mirc.js | 3 +++ mode/mllike/mllike.js | 3 +++ mode/nginx/nginx.js | 3 +++ mode/ntriples/ntriples.js | 3 +++ mode/octave/octave.js | 3 +++ mode/pascal/pascal.js | 3 +++ mode/pegjs/pegjs.js | 3 +++ mode/perl/perl.js | 3 +++ mode/php/php.js | 3 +++ mode/php/test.js | 3 +++ mode/pig/pig.js | 3 +++ mode/properties/properties.js | 3 +++ mode/puppet/puppet.js | 3 +++ mode/python/python.js | 3 +++ mode/q/q.js | 3 +++ mode/r/r.js | 3 +++ mode/rpm/rpm.js | 3 +++ mode/rst/rst.js | 3 +++ mode/ruby/ruby.js | 3 +++ mode/ruby/test.js | 3 +++ mode/rust/rust.js | 3 +++ mode/sass/sass.js | 3 +++ mode/scheme/scheme.js | 3 +++ mode/shell/shell.js | 3 +++ mode/shell/test.js | 3 +++ mode/sieve/sieve.js | 3 +++ mode/smalltalk/smalltalk.js | 3 +++ mode/smarty/smarty.js | 3 +++ mode/smartymixed/smartymixed.js | 3 +++ mode/solr/solr.js | 3 +++ mode/sparql/sparql.js | 3 +++ mode/sql/sql.js | 3 +++ mode/stex/stex.js | 3 +++ mode/stex/test.js | 3 +++ mode/tcl/tcl.js | 3 +++ mode/tiddlywiki/tiddlywiki.js | 3 +++ mode/tiki/tiki.js | 3 +++ mode/toml/toml.js | 3 +++ mode/turtle/turtle.js | 3 +++ mode/vb/vb.js | 3 +++ mode/vbscript/vbscript.js | 3 +++ mode/velocity/velocity.js | 3 +++ mode/verilog/test.js | 3 +++ mode/verilog/verilog.js | 3 +++ mode/xml/test.js | 3 +++ mode/xml/xml.js | 3 +++ mode/xquery/test.js | 3 +++ mode/xquery/xquery.js | 3 +++ mode/yaml/yaml.js | 3 +++ mode/z80/z80.js | 3 +++ test/lint/lint.js | 7 ++++++- 151 files changed, 468 insertions(+), 1 deletion(-) diff --git a/addon/comment/comment.js b/addon/comment/comment.js index 1eb9a05c5d..f56721206e 100644 --- a/addon/comment/comment.js +++ b/addon/comment/comment.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/comment/continuecomment.js b/addon/comment/continuecomment.js index 42277267f5..5247a845c4 100644 --- a/addon/comment/continuecomment.js +++ b/addon/comment/continuecomment.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/dialog/dialog.js b/addon/dialog/dialog.js index 586b7370dc..8fbdea168d 100644 --- a/addon/dialog/dialog.js +++ b/addon/dialog/dialog.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // Open simple dialogs on top of an editor. Relies on dialog.css. (function(mod) { diff --git a/addon/display/fullscreen.js b/addon/display/fullscreen.js index e39c6e162f..e7f22a7936 100644 --- a/addon/display/fullscreen.js +++ b/addon/display/fullscreen.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/display/placeholder.js b/addon/display/placeholder.js index 0fdc9b0d5b..fbc0a8bdf0 100644 --- a/addon/display/placeholder.js +++ b/addon/display/placeholder.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/display/rulers.js b/addon/display/rulers.js index 42cc2b9a90..e025415b51 100644 --- a/addon/display/rulers.js +++ b/addon/display/rulers.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 3cea887d1d..4caac60b98 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index c7c0701ba5..d64045ab1b 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /** * Tag-closer extension for CodeMirror. * diff --git a/addon/edit/continuelist.js b/addon/edit/continuelist.js index 2946aa6a24..3dcf757397 100644 --- a/addon/edit/continuelist.js +++ b/addon/edit/continuelist.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/edit/matchbrackets.js b/addon/edit/matchbrackets.js index dcdde81dfe..c1221ca4c0 100644 --- a/addon/edit/matchbrackets.js +++ b/addon/edit/matchbrackets.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/edit/matchtags.js b/addon/edit/matchtags.js index 76a7b87c9a..a91d578365 100644 --- a/addon/edit/matchtags.js +++ b/addon/edit/matchtags.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("../fold/xml-fold")); diff --git a/addon/edit/trailingspace.js b/addon/edit/trailingspace.js index ec07221e30..e12162d33c 100644 --- a/addon/edit/trailingspace.js +++ b/addon/edit/trailingspace.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/fold/brace-fold.js b/addon/fold/brace-fold.js index f0ee62029a..a0161e2c19 100644 --- a/addon/fold/brace-fold.js +++ b/addon/fold/brace-fold.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/fold/comment-fold.js b/addon/fold/comment-fold.js index d72c5479a7..593539affd 100644 --- a/addon/fold/comment-fold.js +++ b/addon/fold/comment-fold.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/fold/foldcode.js b/addon/fold/foldcode.js index 81094e2543..51cc3939b3 100644 --- a/addon/fold/foldcode.js +++ b/addon/fold/foldcode.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/fold/foldgutter.js b/addon/fold/foldgutter.js index 9caba59aad..04ce8493e8 100644 --- a/addon/fold/foldgutter.js +++ b/addon/fold/foldgutter.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("./foldcode")); diff --git a/addon/fold/indent-fold.js b/addon/fold/indent-fold.js index d0130836a2..126ed4953c 100644 --- a/addon/fold/indent-fold.js +++ b/addon/fold/indent-fold.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/fold/markdown-fold.js b/addon/fold/markdown-fold.js index 3bbf5b6077..ecee9e7e27 100644 --- a/addon/fold/markdown-fold.js +++ b/addon/fold/markdown-fold.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/fold/xml-fold.js b/addon/fold/xml-fold.js index d554e2fc42..e1fd5756d8 100644 --- a/addon/fold/xml-fold.js +++ b/addon/fold/xml-fold.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/hint/anyword-hint.js b/addon/hint/anyword-hint.js index 3ef979b524..0b6d872f3d 100644 --- a/addon/hint/anyword-hint.js +++ b/addon/hint/anyword-hint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/hint/css-hint.js b/addon/hint/css-hint.js index 96d9d52e1b..a93458819c 100644 --- a/addon/hint/css-hint.js +++ b/addon/hint/css-hint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("../../mode/css/css")); diff --git a/addon/hint/html-hint.js b/addon/hint/html-hint.js index cbe7c61ad4..cfdcff9de2 100755 --- a/addon/hint/html-hint.js +++ b/addon/hint/html-hint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/hint/javascript-hint.js b/addon/hint/javascript-hint.js index baf20b45dc..29f3960902 100644 --- a/addon/hint/javascript-hint.js +++ b/addon/hint/javascript-hint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/hint/python-hint.js b/addon/hint/python-hint.js index eebfcc76dc..49dfb08f3a 100644 --- a/addon/hint/python-hint.js +++ b/addon/hint/python-hint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/hint/show-hint.js b/addon/hint/show-hint.js index 46b55648cb..4bede1fb03 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/hint/sql-hint.js b/addon/hint/sql-hint.js index a48d2b3cea..e527a878b9 100644 --- a/addon/hint/sql-hint.js +++ b/addon/hint/sql-hint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("../../mode/sql/sql")); diff --git a/addon/hint/xml-hint.js b/addon/hint/xml-hint.js index 9cfd1e884f..de9f79eb3b 100644 --- a/addon/hint/xml-hint.js +++ b/addon/hint/xml-hint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/lint/coffeescript-lint.js b/addon/lint/coffeescript-lint.js index 6df17f8f84..2cc6314f06 100644 --- a/addon/lint/coffeescript-lint.js +++ b/addon/lint/coffeescript-lint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js // declare global: coffeelint diff --git a/addon/lint/css-lint.js b/addon/lint/css-lint.js index de9cd20d7a..93f2e5f5d8 100644 --- a/addon/lint/css-lint.js +++ b/addon/lint/css-lint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // Depends on csslint.js from https://github.com/stubbornella/csslint // declare global: CSSLint diff --git a/addon/lint/javascript-lint.js b/addon/lint/javascript-lint.js index 86c863a4a2..ed62dd989c 100644 --- a/addon/lint/javascript-lint.js +++ b/addon/lint/javascript-lint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/lint/json-lint.js b/addon/lint/json-lint.js index 1f5f82d0ca..b548a8e439 100644 --- a/addon/lint/json-lint.js +++ b/addon/lint/json-lint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // Depends on jsonlint.js from https://github.com/zaach/jsonlint // declare global: jsonlint diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 393a689036..1682acf6ea 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/lint/yaml-lint.js b/addon/lint/yaml-lint.js index b53673af4b..3ada0eaf9f 100644 --- a/addon/lint/yaml-lint.js +++ b/addon/lint/yaml-lint.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/merge/merge.js b/addon/merge/merge.js index fe3fcf4282..61e25e5d36 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/mode/loadmode.js b/addon/mode/loadmode.js index e08c281321..e49421b8fc 100644 --- a/addon/mode/loadmode.js +++ b/addon/mode/loadmode.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/mode/multiplex.js b/addon/mode/multiplex.js index 07385c35f2..40601f4dfa 100644 --- a/addon/mode/multiplex.js +++ b/addon/mode/multiplex.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/mode/multiplex_test.js b/addon/mode/multiplex_test.js index c0656357c7..a10012ce8c 100644 --- a/addon/mode/multiplex_test.js +++ b/addon/mode/multiplex_test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { CodeMirror.defineMode("markdown_with_stex", function(){ var inner = CodeMirror.getMode({}, "stex"); diff --git a/addon/mode/overlay.js b/addon/mode/overlay.js index e32fa830b3..82f754c461 100644 --- a/addon/mode/overlay.js +++ b/addon/mode/overlay.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // Utility function that allows modes to be combined. The mode given // as the base argument takes care of most of the normal mode // functionality, but a second (typically simple) mode is used, which diff --git a/addon/runmode/colorize.js b/addon/runmode/colorize.js index 0f9530b17b..eb99f29945 100644 --- a/addon/runmode/colorize.js +++ b/addon/runmode/colorize.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("./runmode")); diff --git a/addon/runmode/runmode-standalone.js b/addon/runmode/runmode-standalone.js index e36e00fbc6..3e1e746e95 100644 --- a/addon/runmode/runmode-standalone.js +++ b/addon/runmode/runmode-standalone.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + window.CodeMirror = {}; (function() { diff --git a/addon/runmode/runmode.js b/addon/runmode/runmode.js index 5592a99a60..5406ff72fd 100644 --- a/addon/runmode/runmode.js +++ b/addon/runmode/runmode.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/runmode/runmode.node.js b/addon/runmode/runmode.node.js index 15bf392313..f8c467f381 100644 --- a/addon/runmode/runmode.node.js +++ b/addon/runmode/runmode.node.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /* Just enough of CodeMirror to run runMode under node.js */ // declare global: StringStream diff --git a/addon/scroll/scrollpastend.js b/addon/scroll/scrollpastend.js index 467b7aa1cf..e9f4ecb68a 100644 --- a/addon/scroll/scrollpastend.js +++ b/addon/scroll/scrollpastend.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/search/match-highlighter.js b/addon/search/match-highlighter.js index 83ab8c33c7..0dc28c10ba 100644 --- a/addon/search/match-highlighter.js +++ b/addon/search/match-highlighter.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // Highlighting text that matches the selection // // Defines an option highlightSelectionMatches, which, when enabled, diff --git a/addon/search/search.js b/addon/search/search.js index 7a1db6ee09..7bc3414c7b 100644 --- a/addon/search/search.js +++ b/addon/search/search.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // Define search commands. Depends on dialog.js or another // implementation of the openDialog method. diff --git a/addon/search/searchcursor.js b/addon/search/searchcursor.js index 899f44c4ab..f6df00a94e 100644 --- a/addon/search/searchcursor.js +++ b/addon/search/searchcursor.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/addon/selection/active-line.js b/addon/selection/active-line.js index a818f109b6..bafcb6b8c3 100644 --- a/addon/selection/active-line.js +++ b/addon/selection/active-line.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, 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. // // Adds an option 'styleActiveLine' which, when enabled, gives the diff --git a/addon/selection/mark-selection.js b/addon/selection/mark-selection.js index ae0d393143..f621c0704a 100644 --- a/addon/selection/mark-selection.js +++ b/addon/selection/mark-selection.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // Because sometimes you need to mark the selected *text*. // // Adds an option 'styleSelectedText' which, when enabled, gives diff --git a/addon/tern/tern.js b/addon/tern/tern.js index 2f450ed024..318f1484d9 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // Glue code between CodeMirror and Tern. // // Create a CodeMirror.TernServer to wrap an actual Tern server, diff --git a/addon/tern/worker.js b/addon/tern/worker.js index 1ff63de411..615ce61e6a 100644 --- a/addon/tern/worker.js +++ b/addon/tern/worker.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // declare global: tern, server var server; diff --git a/addon/wrap/hardwrap.js b/addon/wrap/hardwrap.js index 87aab1b8f6..fb0b5f2fcf 100644 --- a/addon/wrap/hardwrap.js +++ b/addon/wrap/hardwrap.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/bin/release b/bin/release index 3c33290f3f..91451faae5 100755 --- a/bin/release +++ b/bin/release @@ -27,6 +27,21 @@ rewrite("doc/manual.html", function(manual) { return manual.replace(/>version \d+\.\d+\.\d+<\/span>/, ">version " + number + ""); }); +function walkDir(dir) { + fs.readdirSync(dir).forEach(function(file) { + var fname = dir + "/" + file; + if (/\.js$/.test(file)) rewrite(file, function(script) { + return script.replace(/^\/\/ CodeMirror \d+\.\d+\.\d+, copyright/, + "// CodeMirror " + number + ", copyright"); + }); + else if (fs.lstatSync(fname).isDirectory()) walkDir(fname); + }); +} +walkDir("mode"); +walkDir("lib"); +walkDir("addon"); +walkDir("keymap"); + if (bumpOnly) process.exit(0); child.exec("bash bin/authors.sh", function(){}); diff --git a/keymap/emacs.js b/keymap/emacs.js index 7cecf1f627..b1b70254d8 100644 --- a/keymap/emacs.js +++ b/keymap/emacs.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../lib/codemirror")); diff --git a/keymap/sublime.js b/keymap/sublime.js index 9158e27944..0681fa3e2b 100644 --- a/keymap/sublime.js +++ b/keymap/sublime.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // A rough approximation of Sublime Text's keybindings // Depends on addon/search/searchcursor.js and optionally addon/dialog/dialogs.js diff --git a/keymap/vim.js b/keymap/vim.js index e33d269089..9dce29e253 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /** * Supported keybindings: * diff --git a/lib/codemirror.js b/lib/codemirror.js index 0bf6f2d8e8..50bccb38a9 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, 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 // implemented in JavaScript on top of the browser's DOM. // diff --git a/mode/apl/apl.js b/mode/apl/apl.js index 2ba74c18c2..0a318dad61 100644 --- a/mode/apl/apl.js +++ b/mode/apl/apl.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/asterisk/asterisk.js b/mode/asterisk/asterisk.js index c56fc0b38a..f34471d4eb 100644 --- a/mode/asterisk/asterisk.js +++ b/mode/asterisk/asterisk.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /* * ===================================================================================== * diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 60b88bf1aa..a114344f87 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/clojure/clojure.js b/mode/clojure/clojure.js index 3b596ad607..f8e8879d42 100644 --- a/mode/clojure/clojure.js +++ b/mode/clojure/clojure.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /** * Author: Hans Engel * Branched from CodeMirror's Scheme mode (by Koh Zi Han, based on implementation by Koh Zi Chun) diff --git a/mode/cobol/cobol.js b/mode/cobol/cobol.js index e66e42a191..231218509a 100644 --- a/mode/cobol/cobol.js +++ b/mode/cobol/cobol.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /** * Author: Gautam Mehta * Branched from CodeMirror's Scheme mode diff --git a/mode/coffeescript/coffeescript.js b/mode/coffeescript/coffeescript.js index c6da8f2a29..5350f6099c 100644 --- a/mode/coffeescript/coffeescript.js +++ b/mode/coffeescript/coffeescript.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /** * Link to the project's GitHub page: * https://github.com/pickhardt/coffeescript-codemirror-mode diff --git a/mode/commonlisp/commonlisp.js b/mode/commonlisp/commonlisp.js index a0f0732bf6..ffb3c96493 100644 --- a/mode/commonlisp/commonlisp.js +++ b/mode/commonlisp/commonlisp.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/css/css.js b/mode/css/css.js index 8828329fc4..6b49e473f0 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/css/less_test.js b/mode/css/less_test.js index ea64f91d12..a569e107dd 100644 --- a/mode/css/less_test.js +++ b/mode/css/less_test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { "use strict"; diff --git a/mode/css/scss_test.js b/mode/css/scss_test.js index c51cb42bba..85077532dc 100644 --- a/mode/css/scss_test.js +++ b/mode/css/scss_test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-scss"); function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "scss"); } diff --git a/mode/css/test.js b/mode/css/test.js index f9f667295c..85f597b570 100644 --- a/mode/css/test.js +++ b/mode/css/test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { var mode = CodeMirror.getMode({indentUnit: 2}, "css"); function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } diff --git a/mode/cypher/cypher.js b/mode/cypher/cypher.js index f102c9ec1a..902430c2b0 100644 --- a/mode/cypher/cypher.js +++ b/mode/cypher/cypher.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // By the Neo4j Team and contributors. // https://github.com/neo4j-contrib/CodeMirror diff --git a/mode/d/d.js b/mode/d/d.js index 3ab8b42838..cb9a674cec 100644 --- a/mode/d/d.js +++ b/mode/d/d.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/diff/diff.js b/mode/diff/diff.js index d43f15d51a..ad62f2fcef 100644 --- a/mode/diff/diff.js +++ b/mode/diff/diff.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/django/django.js b/mode/django/django.js index 38de7d5ee3..3fe57cdea3 100644 --- a/mode/django/django.js +++ b/mode/django/django.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), diff --git a/mode/dtd/dtd.js b/mode/dtd/dtd.js index b4a6cb3155..7c3b6a1cab 100644 --- a/mode/dtd/dtd.js +++ b/mode/dtd/dtd.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /* DTD mode Ported to CodeMirror by Peter Kroon diff --git a/mode/dylan/dylan.js b/mode/dylan/dylan.js index ccf9679181..b4526f6fad 100644 --- a/mode/dylan/dylan.js +++ b/mode/dylan/dylan.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/ecl/ecl.js b/mode/ecl/ecl.js index 2b841ff5f1..18d60899e0 100644 --- a/mode/ecl/ecl.js +++ b/mode/ecl/ecl.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/eiffel/eiffel.js b/mode/eiffel/eiffel.js index c6c3c84600..52c54e7863 100644 --- a/mode/eiffel/eiffel.js +++ b/mode/eiffel/eiffel.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/erlang/erlang.js b/mode/erlang/erlang.js index 3d4b1ba92e..7e2a1d4ad3 100644 --- a/mode/erlang/erlang.js +++ b/mode/erlang/erlang.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /*jshint unused:true, eqnull:true, curly:true, bitwise:true */ /*jshint undef:true, latedef:true, trailing:true */ /*global CodeMirror:true */ diff --git a/mode/fortran/fortran.js b/mode/fortran/fortran.js index 58dac127c1..66b9c9ad70 100644 --- a/mode/fortran/fortran.js +++ b/mode/fortran/fortran.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/gas/gas.js b/mode/gas/gas.js index ba5f195a11..6bf66b6f49 100644 --- a/mode/gas/gas.js +++ b/mode/gas/gas.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/gfm/gfm.js b/mode/gfm/gfm.js index 5a028c48b4..5de044807d 100644 --- a/mode/gfm/gfm.js +++ b/mode/gfm/gfm.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("../markdown/markdown"), require("../../addon/mode/overlay")); diff --git a/mode/gfm/test.js b/mode/gfm/test.js index d06a219240..f3d72bfadf 100644 --- a/mode/gfm/test.js +++ b/mode/gfm/test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { var mode = CodeMirror.getMode({tabSize: 4}, "gfm"); function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } diff --git a/mode/gherkin/gherkin.js b/mode/gherkin/gherkin.js index 41003641ec..c94efcb6aa 100644 --- a/mode/gherkin/gherkin.js +++ b/mode/gherkin/gherkin.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /* Gherkin mode - http://www.cukes.info/ Report bugs/issues here: https://github.com/marijnh/CodeMirror/issues diff --git a/mode/go/go.js b/mode/go/go.js index 82463052f6..46e13b6c54 100644 --- a/mode/go/go.js +++ b/mode/go/go.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/groovy/groovy.js b/mode/groovy/groovy.js index 399452d536..4a867d8337 100644 --- a/mode/groovy/groovy.js +++ b/mode/groovy/groovy.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/haml/haml.js b/mode/haml/haml.js index 59a86e7cec..1ab5001fc2 100644 --- a/mode/haml/haml.js +++ b/mode/haml/haml.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../ruby/ruby")); diff --git a/mode/haml/test.js b/mode/haml/test.js index 75d0e7710f..0a8fc55696 100644 --- a/mode/haml/test.js +++ b/mode/haml/test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { var mode = CodeMirror.getMode({tabSize: 4, indentUnit: 2}, "haml"); function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } diff --git a/mode/haskell/haskell.js b/mode/haskell/haskell.js index 2876172a95..4d923568d0 100644 --- a/mode/haskell/haskell.js +++ b/mode/haskell/haskell.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/haxe/haxe.js b/mode/haxe/haxe.js index ffde5991ad..487a88ddf3 100644 --- a/mode/haxe/haxe.js +++ b/mode/haxe/haxe.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/htmlembedded/htmlembedded.js b/mode/htmlembedded/htmlembedded.js index 3a07c3432e..7b3b9be725 100644 --- a/mode/htmlembedded/htmlembedded.js +++ b/mode/htmlembedded/htmlembedded.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed")); diff --git a/mode/htmlmixed/htmlmixed.js b/mode/htmlmixed/htmlmixed.js index d80ef9c64c..1dacbe8098 100644 --- a/mode/htmlmixed/htmlmixed.js +++ b/mode/htmlmixed/htmlmixed.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css")); diff --git a/mode/http/http.js b/mode/http/http.js index d2ad5994b6..bd0cb574d3 100644 --- a/mode/http/http.js +++ b/mode/http/http.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/jade/jade.js b/mode/jade/jade.js index 64d4d2f4be..b7c99b083d 100644 --- a/mode/jade/jade.js +++ b/mode/jade/jade.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("../javascript/javascript"), require("../css/css"), require("../htmlmixed/htmlmixed")); diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index e719089349..71e8a09c6f 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // TODO actually recognize syntax of TypeScript constructs (function(mod) { diff --git a/mode/javascript/test.js b/mode/javascript/test.js index 782f0457f9..4411a98452 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { var mode = CodeMirror.getMode({indentUnit: 2}, "javascript"); function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } diff --git a/mode/jinja2/jinja2.js b/mode/jinja2/jinja2.js index 4b535e5322..e80c772929 100644 --- a/mode/jinja2/jinja2.js +++ b/mode/jinja2/jinja2.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/julia/julia.js b/mode/julia/julia.js index d37ab503ed..79b47fb3ef 100644 --- a/mode/julia/julia.js +++ b/mode/julia/julia.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/livescript/livescript.js b/mode/livescript/livescript.js index 1efc3ecf66..8e822bd6d3 100644 --- a/mode/livescript/livescript.js +++ b/mode/livescript/livescript.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /** * Link to the project's GitHub page: * https://github.com/duralog/CodeMirror diff --git a/mode/lua/lua.js b/mode/lua/lua.js index 3673557c27..6121b86b38 100644 --- a/mode/lua/lua.js +++ b/mode/lua/lua.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // LUA mode. Ported to CodeMirror 2 from Franciszek Wawrzak's // CodeMirror 1 mode. // highlights keywords, strings, comments (no leveling supported! ("[==[")), tokens, basic indenting diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 84ea4d46b9..81472f02f7 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror", require("../xml/xml"))); diff --git a/mode/markdown/test.js b/mode/markdown/test.js index 4d1d70ad14..ba1b15fc82 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { var mode = CodeMirror.getMode({tabSize: 4}, "markdown"); function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } diff --git a/mode/meta.js b/mode/meta.js index 5fc51ebeec..5cccf7e9ab 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../lib/codemirror")); diff --git a/mode/mirc/mirc.js b/mode/mirc/mirc.js index 6b2a23a16c..321830baf7 100644 --- a/mode/mirc/mirc.js +++ b/mode/mirc/mirc.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + //mIRC mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara (function(mod) { diff --git a/mode/mllike/mllike.js b/mode/mllike/mllike.js index d4d59fceb7..18771467a8 100644 --- a/mode/mllike/mllike.js +++ b/mode/mllike/mllike.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/nginx/nginx.js b/mode/nginx/nginx.js index 4e17cdb3c4..22c266384d 100644 --- a/mode/nginx/nginx.js +++ b/mode/nginx/nginx.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/ntriples/ntriples.js b/mode/ntriples/ntriples.js index cd5eb24f07..1f9ba451cb 100644 --- a/mode/ntriples/ntriples.js +++ b/mode/ntriples/ntriples.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /********************************************************** * This script provides syntax highlighting support for * the Ntriples format. diff --git a/mode/octave/octave.js b/mode/octave/octave.js index 16fe4dfd78..e5a50bce3b 100644 --- a/mode/octave/octave.js +++ b/mode/octave/octave.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/pascal/pascal.js b/mode/pascal/pascal.js index 642dd9bf79..652addd2c2 100644 --- a/mode/pascal/pascal.js +++ b/mode/pascal/pascal.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/pegjs/pegjs.js b/mode/pegjs/pegjs.js index f74f2a4f22..725579d5a0 100644 --- a/mode/pegjs/pegjs.js +++ b/mode/pegjs/pegjs.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("../javascript/javascript")); diff --git a/mode/perl/perl.js b/mode/perl/perl.js index 0126d3ea36..9b02783a1d 100644 --- a/mode/perl/perl.js +++ b/mode/perl/perl.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // CodeMirror2 mode/perl/perl.js (text/x-perl) beta 0.10 (2011-11-08) // This is a part of CodeMirror from https://github.com/sabaca/CodeMirror_mode_perl (mail@sabaca.com) diff --git a/mode/php/php.js b/mode/php/php.js index 81591e4d65..4185804791 100644 --- a/mode/php/php.js +++ b/mode/php/php.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../clike/clike")); diff --git a/mode/php/test.js b/mode/php/test.js index db68d75de3..2d901cf08d 100644 --- a/mode/php/test.js +++ b/mode/php/test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { var mode = CodeMirror.getMode({indentUnit: 2}, "php"); function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } diff --git a/mode/pig/pig.js b/mode/pig/pig.js index 64ac506a79..52ad349c41 100644 --- a/mode/pig/pig.js +++ b/mode/pig/pig.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /* * Pig Latin Mode for CodeMirror 2 * @author Prasanth Jayachandran diff --git a/mode/properties/properties.js b/mode/properties/properties.js index 6dfe06f128..b91191a7b5 100644 --- a/mode/properties/properties.js +++ b/mode/properties/properties.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/puppet/puppet.js b/mode/puppet/puppet.js index da8823e5ed..bba431eb3d 100644 --- a/mode/puppet/puppet.js +++ b/mode/puppet/puppet.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/python/python.js b/mode/python/python.js index 4fc4354ff7..1fb32a7c16 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/q/q.js b/mode/q/q.js index d6e3b66610..ff788d9d52 100644 --- a/mode/q/q.js +++ b/mode/q/q.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/r/r.js b/mode/r/r.js index 281d7fa40f..d04eca3899 100644 --- a/mode/r/r.js +++ b/mode/r/r.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/rpm/rpm.js b/mode/rpm/rpm.js index 497997c4ff..bad1b3e024 100644 --- a/mode/rpm/rpm.js +++ b/mode/rpm/rpm.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/rst/rst.js b/mode/rst/rst.js index 0763d4b999..11c3678428 100644 --- a/mode/rst/rst.js +++ b/mode/rst/rst.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror"), require("../python/python"), require("../stex/stex"), require("../../addon/mode/overlay")); diff --git a/mode/ruby/ruby.js b/mode/ruby/ruby.js index 4ef08b1552..8ffd2d7e8a 100644 --- a/mode/ruby/ruby.js +++ b/mode/ruby/ruby.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/ruby/test.js b/mode/ruby/test.js index c97d106686..1a6067d027 100644 --- a/mode/ruby/test.js +++ b/mode/ruby/test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { var mode = CodeMirror.getMode({indentUnit: 2}, "ruby"); function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } diff --git a/mode/rust/rust.js b/mode/rust/rust.js index 2e6e20b231..e7abed3520 100644 --- a/mode/rust/rust.js +++ b/mode/rust/rust.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/sass/sass.js b/mode/sass/sass.js index 74ae91db12..8cdb1365f9 100644 --- a/mode/sass/sass.js +++ b/mode/sass/sass.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/scheme/scheme.js b/mode/scheme/scheme.js index 7124f7283b..97979057ef 100644 --- a/mode/scheme/scheme.js +++ b/mode/scheme/scheme.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /** * Author: Koh Zi Han, based on implementation by Koh Zi Chun */ diff --git a/mode/shell/shell.js b/mode/shell/shell.js index 5abb44711f..c1893a4dd1 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/shell/test.js b/mode/shell/test.js index 3ab045c087..8bdb82103d 100644 --- a/mode/shell/test.js +++ b/mode/shell/test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { var mode = CodeMirror.getMode({}, "shell"); function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } diff --git a/mode/sieve/sieve.js b/mode/sieve/sieve.js index 8256dda0a4..d74c839e01 100644 --- a/mode/sieve/sieve.js +++ b/mode/sieve/sieve.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/smalltalk/smalltalk.js b/mode/smalltalk/smalltalk.js index deb78a4f7a..42fdc67830 100644 --- a/mode/smalltalk/smalltalk.js +++ b/mode/smalltalk/smalltalk.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/smarty/smarty.js b/mode/smarty/smarty.js index 2a78c6d394..8c4bd13b61 100644 --- a/mode/smarty/smarty.js +++ b/mode/smarty/smarty.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /** * Smarty 2 and 3 mode. */ diff --git a/mode/smartymixed/smartymixed.js b/mode/smartymixed/smartymixed.js index 7e5e12c0ec..3be014b872 100644 --- a/mode/smartymixed/smartymixed.js +++ b/mode/smartymixed/smartymixed.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /** * @file smartymixed.js * @brief Smarty Mixed Codemirror mode (Smarty + Mixed HTML) diff --git a/mode/solr/solr.js b/mode/solr/solr.js index 25d928ec1b..ed7eff6eb6 100644 --- a/mode/solr/solr.js +++ b/mode/solr/solr.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/sparql/sparql.js b/mode/sparql/sparql.js index f228b1dffe..f4453e6864 100644 --- a/mode/sparql/sparql.js +++ b/mode/sparql/sparql.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/sql/sql.js b/mode/sql/sql.js index 417db06282..59510ffa08 100644 --- a/mode/sql/sql.js +++ b/mode/sql/sql.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/stex/stex.js b/mode/stex/stex.js index 59a395a0fe..b5ef7898f3 100644 --- a/mode/stex/stex.js +++ b/mode/stex/stex.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /* * Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de) * Licence: MIT diff --git a/mode/stex/test.js b/mode/stex/test.js index ab629e81ea..6eaf0f6881 100644 --- a/mode/stex/test.js +++ b/mode/stex/test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { var mode = CodeMirror.getMode({tabSize: 4}, "stex"); function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } diff --git a/mode/tcl/tcl.js b/mode/tcl/tcl.js index 4c29ee7d98..49c555b108 100644 --- a/mode/tcl/tcl.js +++ b/mode/tcl/tcl.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + //tcl mode by Ford_Lawnmower :: Based on Velocity mode by Steve O'Hara (function(mod) { diff --git a/mode/tiddlywiki/tiddlywiki.js b/mode/tiddlywiki/tiddlywiki.js index ecd1d173c0..31dff8cb93 100644 --- a/mode/tiddlywiki/tiddlywiki.js +++ b/mode/tiddlywiki/tiddlywiki.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /*** |''Name''|tiddlywiki.js| |''Description''|Enables TiddlyWikiy syntax highlighting using CodeMirror| diff --git a/mode/tiki/tiki.js b/mode/tiki/tiki.js index eb9a893fde..02c2f1b74b 100644 --- a/mode/tiki/tiki.js +++ b/mode/tiki/tiki.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/toml/toml.js b/mode/toml/toml.js index 2c722b3752..593807a900 100644 --- a/mode/toml/toml.js +++ b/mode/toml/toml.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/turtle/turtle.js b/mode/turtle/turtle.js index de9fc2b6c7..b2c7023c16 100644 --- a/mode/turtle/turtle.js +++ b/mode/turtle/turtle.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/vb/vb.js b/mode/vb/vb.js index 4fd80210fb..6fa42d97eb 100644 --- a/mode/vb/vb.js +++ b/mode/vb/vb.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/vbscript/vbscript.js b/mode/vbscript/vbscript.js index 4be7c7f2bb..9293c0af34 100644 --- a/mode/vbscript/vbscript.js +++ b/mode/vbscript/vbscript.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + /* For extra ASP classic objects, initialize CodeMirror instance with this option: isASP: true diff --git a/mode/velocity/velocity.js b/mode/velocity/velocity.js index b64636bb43..fd0292920b 100644 --- a/mode/velocity/velocity.js +++ b/mode/velocity/velocity.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/verilog/test.js b/mode/verilog/test.js index 6f5770b848..42d4f618cf 100644 --- a/mode/verilog/test.js +++ b/mode/verilog/test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { var mode = CodeMirror.getMode({indentUnit: 4}, "verilog"); function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } diff --git a/mode/verilog/verilog.js b/mode/verilog/verilog.js index d52ecea2a3..c575ac5f51 100644 --- a/mode/verilog/verilog.js +++ b/mode/verilog/verilog.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/xml/test.js b/mode/xml/test.js index 1b9d9d1760..122e1675ce 100644 --- a/mode/xml/test.js +++ b/mode/xml/test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function() { var mode = CodeMirror.getMode({indentUnit: 2}, "xml"), mname = "xml"; function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), mname); } diff --git a/mode/xml/xml.js b/mode/xml/xml.js index 3248c454d1..946757fc57 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/xquery/test.js b/mode/xquery/test.js index 41719dd169..511a879d90 100644 --- a/mode/xquery/test.js +++ b/mode/xquery/test.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + // Don't take these too seriously -- the expected results appear to be // based on the results of actual runs without any serious manual // verification. If a change you made causes them to fail, the test is diff --git a/mode/xquery/xquery.js b/mode/xquery/xquery.js index 2c7faf425a..0426bf66a5 100644 --- a/mode/xquery/xquery.js +++ b/mode/xquery/xquery.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/yaml/yaml.js b/mode/yaml/yaml.js index f7b3a90c03..41679f1eea 100644 --- a/mode/yaml/yaml.js +++ b/mode/yaml/yaml.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/mode/z80/z80.js b/mode/z80/z80.js index c778803072..d441e383ac 100644 --- a/mode/z80/z80.js +++ b/mode/z80/z80.js @@ -1,3 +1,6 @@ +// CodeMirror 4.1.1, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS mod(require("../../lib/codemirror")); diff --git a/test/lint/lint.js b/test/lint/lint.js index a65deb60be..ba8900f7d7 100644 --- a/test/lint/lint.js +++ b/test/lint/lint.js @@ -31,6 +31,8 @@ var scopePasser = walk.make({ ScopeBody: function(node, prev, c) { c(node, node.scope); } }); +var cBlob = /^\/\/ CodeMirror \d+\.\d+\.\d+, copyright \(c\) by Marijn Haverbeke and others\n\/\/ Distributed under an MIT license: http:\/\/codemirror.net\/LICENSE\n\n/; + function checkFile(fileName) { var file = fs.readFileSync(fileName, "utf8"), notAllowed; if (notAllowed = file.match(/[\x00-\x08\x0b\x0c\x0e-\x19\uFEFF\t]|[ \t]\n/)) { @@ -41,6 +43,9 @@ function checkFile(fileName) { var info = acorn.getLineInfo(file, notAllowed.index); fail(msg + " at line " + info.line + ", column " + info.column, {source: fileName}); } + + if (!cBlob.test(file)) + fail("Missing license blob", {source: fileName}); var globalsSeen = Object.create(null); @@ -152,7 +157,7 @@ function checkDir(dir) { fs.readdirSync(dir).forEach(function(file) { var fname = dir + "/" + file; if (/\.js$/.test(file)) checkFile(fname); - else if (file != "dep" && fs.lstatSync(fname).isDirectory()) checkDir(fname); + else if (fs.lstatSync(fname).isDirectory()) checkDir(fname); }); } From 01fb28518dd76a7848606669020bc1b85a81c899 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 9 May 2014 15:56:59 +0200 Subject: [PATCH 1843/5273] Fix bug in release script --- bin/release | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/release b/bin/release index 91451faae5..c26d290f94 100755 --- a/bin/release +++ b/bin/release @@ -30,7 +30,7 @@ rewrite("doc/manual.html", function(manual) { function walkDir(dir) { fs.readdirSync(dir).forEach(function(file) { var fname = dir + "/" + file; - if (/\.js$/.test(file)) rewrite(file, function(script) { + if (/\.js$/.test(file)) rewrite(fname, function(script) { return script.replace(/^\/\/ CodeMirror \d+\.\d+\.\d+, copyright/, "// CodeMirror " + number + ", copyright"); }); From a5b79b5c30fd8694fcb1fdaafeb70ab0bd335ca9 Mon Sep 17 00:00:00 2001 From: as3boyan Date: Sat, 10 May 2014 22:00:23 +0300 Subject: [PATCH 1844/5273] [show-hint addon] Fix a typo --- 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 4bede1fb03..59322749ce 100644 --- a/addon/hint/show-hint.js +++ b/addon/hint/show-hint.js @@ -379,7 +379,7 @@ alignWithWord: true, closeCharacters: /[\s()\[\]{};:>,]/, closeOnUnfocus: true, - completeOnSignleClick: false, + completeOnSingleClick: false, container: null, customKeys: null, extraKeys: null From a0edb5ba6f5d6ccb289ab6ab2ef2b6b4ad98762b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 12 May 2014 09:20:28 +0200 Subject: [PATCH 1845/5273] Don't mess up the display when updateDisplay is given a negative top offset Issue #2554 --- lib/codemirror.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 50bccb38a9..ddb2514618 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -463,7 +463,7 @@ // the the current scroll position). viewPort may contain top, // height, and ensure (see op.scrollToPos) properties. function visibleLines(display, doc, viewPort) { - var top = viewPort && viewPort.top != null ? viewPort.top : display.scroller.scrollTop; + 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; @@ -667,7 +667,6 @@ cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + "px"; } - function checkForWebkitWidthBug(cm, measure) { // Work around Webkit bug where it sometimes reserves space for a // non-existing phantom scrollbar in the scroller (Issue #2420) From bb0725b52fd9a1bcf19c623e0fb19f43ace40522 Mon Sep 17 00:00:00 2001 From: Bem Jones-Bey Date: Fri, 9 May 2014 10:28:00 -0700 Subject: [PATCH 1846/5273] [css mode] Add object-fit and object-position properties --- mode/css/css.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mode/css/css.js b/mode/css/css.js index 6b49e473f0..e5ed6ad5f5 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -425,7 +425,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "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", "opacity", "order", "orphans", "outline", + "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", From 33eb40146574312f7de39c697af3b18c86d0d902 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 12 May 2014 10:07:27 +0200 Subject: [PATCH 1847/5273] [css mode] Better handling of parentheses in property values Issue #2551 --- mode/css/css.js | 15 +++++---------- mode/css/test.js | 10 ++++++++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index e5ed6ad5f5..00d3785bcf 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -167,7 +167,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { } else if (type == ":") { return "pseudo"; } else if (allowNested && type == "(") { - return pushContext(state, stream, "params"); + return pushContext(state, stream, "parens"); } return state.context.type; }; @@ -228,6 +228,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { states.parens = function(type, stream, state) { if (type == "{" || type == "}") return popAndPass(type, stream, state); if (type == ")") return popContext(state); + if (type == "(") return pushContext(state, stream, "parens"); + if (type == "word") wordAsValue(stream); return "parens"; }; @@ -303,13 +305,6 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return "interpolation"; }; - states.params = function(type, stream, state) { - if (type == ")") return popContext(state); - if (type == "{" || type == "}") return popAndPass(type, stream, state); - if (type == "word") wordAsValue(stream); - return "params"; - }; - return { startState: function(base) { return {tokenize: null, @@ -332,10 +327,10 @@ CodeMirror.defineMode("css", function(config, parserConfig) { indent: function(state, textAfter) { var cx = state.context, ch = textAfter && textAfter.charAt(0); var indent = cx.indent; - if (cx.type == "prop" && ch == "}") cx = cx.prev; + if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev; if (cx.prev && (ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") || - ch == ")" && (cx.type == "parens" || cx.type == "params" || cx.type == "media_parens") || + ch == ")" && (cx.type == "parens" || cx.type == "media_parens") || ch == "{" && (cx.type == "at" || cx.type == "media"))) { indent = cx.indent - indentUnit; cx = cx.prev; diff --git a/mode/css/test.js b/mode/css/test.js index 85f597b570..1a75e08ea4 100644 --- a/mode/css/test.js +++ b/mode/css/test.js @@ -122,4 +122,14 @@ MT("empty_url", "[def @import] [tag url]() [tag screen];"); + + MT("parens", + "[qualifier .foo] {", + " [property background-image]: [variable fade]([atom #000], [number 20%]);", + " [property border-image]: [variable linear-gradient](", + " [atom to] [atom bottom],", + " [variable fade]([atom #000], [number 20%]) [number 0%],", + " [variable fade]([atom #000], [number 20%]) [number 100%]", + " );", + "}"); })(); From 687fb51f4a6547942b08efee81e8b84393d99a5b Mon Sep 17 00:00:00 2001 From: daines Date: Mon, 12 May 2014 09:24:07 -0400 Subject: [PATCH 1848/5273] Fix typo in manual --- doc/manual.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/manual.html b/doc/manual.html index 59c81f3456..d78797dadd 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2328,7 +2328,7 @@

    Addons

    of the token that is being completed as {line, ch} objects.
    If no hinting function is given, the addon will - use CodeMirror.hint.auto, with + use CodeMirror.hint.auto, which calls getHelpers with the "hint" type to find applicable hinting functions, and tries them one by one. If that fails, it looks From 87df1c6e7f2a07c42689c6afba4b7192445196c8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 13 May 2014 11:20:30 +0200 Subject: [PATCH 1849/5273] [closetag addon] Improve heuristic for seeing if closing tag already exists Issue #2557 --- addon/edit/closetag.js | 28 +++++++++++++++++++++++++--- addon/fold/xml-fold.js | 2 +- mode/xml/xml.js | 2 +- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index d64045ab1b..db31b0eb02 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -58,6 +58,7 @@ 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 dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); @@ -71,8 +72,7 @@ tok.type == "tag" && state.type == "closeTag" || tok.string.indexOf("/") == (tok.string.length - 1) || // match something like dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 || - CodeMirror.scanForClosingTag && CodeMirror.scanForClosingTag(cm, pos, tagName, - Math.min(cm.lastLine() + 1, pos.line + 50))) + closingTagExists(cm, tagName, pos, state, true)) return CodeMirror.Pass; var indent = indentTags && indexOf(indentTags, lowerTagName) > -1; @@ -103,7 +103,8 @@ var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; if (tok.type == "string" || tok.string.charAt(0) != "<" || tok.start != pos.ch - 1 || inner.mode.name != "xml" || - !state.context || !state.context.tagName) + !state.context || !state.context.tagName || + closingTagExists(cm, state.context.tagName, pos, state)) return CodeMirror.Pass; replacements[i] = "/" + state.context.tagName + ">"; } @@ -116,4 +117,25 @@ if (collection[i] == elt) return i; return -1; } + + // If xml-fold is loaded, we use its functionality to try and verify + // whether a given tag is actually unclosed. + function closingTagExists(cm, tagName, pos, state, newTag) { + if (!CodeMirror.scanForClosingTag) return false; + var end = Math.min(cm.lastLine() + 1, pos.line + 500); + var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end); + if (!nextClose || nextClose.tag != tagName) return false; + var cx = state.context; + // If the immediate wrapping context contains onCx instances of + // the same tag, a closing tag only exists if there are at least + // that many closing tags of that type following. + for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx; + pos = nextClose.to; + for (var i = 1; i < onCx; i++) { + var next = CodeMirror.scanForClosingTag(cm, pos, null, end); + if (!next || next.tag != tagName) return false; + pos = next.to; + } + return true; + } }); diff --git a/addon/fold/xml-fold.js b/addon/fold/xml-fold.js index e1fd5756d8..33d6e07b53 100644 --- a/addon/fold/xml-fold.js +++ b/addon/fold/xml-fold.js @@ -176,6 +176,6 @@ // Used by addon/edit/closetag.js CodeMirror.scanForClosingTag = function(cm, pos, name, end) { var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null); - return !!findMatchingClose(iter, name); + return findMatchingClose(iter, name); }; }); diff --git a/mode/xml/xml.js b/mode/xml/xml.js index 946757fc57..9a84b632aa 100644 --- a/mode/xml/xml.js +++ b/mode/xml/xml.js @@ -124,7 +124,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { state.state = baseState; state.tagName = state.tagStart = null; var next = state.tokenize(stream, state); - return next ? next + " error" : "error"; + return next ? next + " tag error" : "tag error"; } else if (/[\'\"]/.test(ch)) { state.tokenize = inAttribute(ch); state.stringStartCol = stream.column(); From 5b5c813680f3f69affc472942e3000c1b714e0db Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 13 May 2014 11:32:21 +0200 Subject: [PATCH 1850/5273] Make ctrl-drag copy text Issue #2556 --- lib/codemirror.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index ddb2514618..ba39b4e9a3 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2574,17 +2574,17 @@ lastClick = {time: now, pos: start}; } - var sel = cm.doc.sel, addNew = mac ? e.metaKey : e.ctrlKey; - if (cm.options.dragDrop && dragAndDrop && !addNew && !isReadOnly(cm) && + var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey; + if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && type == "single" && sel.contains(start) > -1 && sel.somethingSelected()) - leftButtonStartDrag(cm, e, start); + leftButtonStartDrag(cm, e, start, modifier); else - leftButtonSelect(cm, e, start, type, addNew); + 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) { + function leftButtonStartDrag(cm, e, start, modifier) { var display = cm.display; var dragEnd = operation(cm, function(e2) { if (webkit) display.scroller.draggable = false; @@ -2593,7 +2593,8 @@ off(display.scroller, "drop", dragEnd); if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { e_preventDefault(e2); - extendSelection(cm.doc, start); + if (!modifier) + extendSelection(cm.doc, start); focusInput(cm); // Work around unexplainable focus problem in IE9 (#2127) if (ie_upto10 && !ie_upto8) @@ -2817,7 +2818,8 @@ try { var text = e.dataTransfer.getData("Text"); if (text) { - var selected = cm.state.draggingText && cm.listSelections(); + if (cm.state.draggingText && !(mac ? e.metaKey : e.ctrlKey)) + 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"); From e6eed2510342b43bdc869f860385a49f8e4061a0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 13 May 2014 11:53:02 +0200 Subject: [PATCH 1851/5273] Ensure a viewport always contains a single line --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index ba39b4e9a3..371c37651f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -479,7 +479,7 @@ return {from: lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight), to: ensureTo}; } - return {from: from, to: to}; + return {from: from, to: Math.max(to, from + 1)}; } // LINE NUMBERS From 02725ae5464565178884059639e791ca42aee266 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 13 May 2014 13:18:48 +0200 Subject: [PATCH 1852/5273] [tern addon] Improve alignment of completion docs --- addon/tern/tern.css | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/tern/tern.css b/addon/tern/tern.css index eacc2f053a..76fba33d4a 100644 --- a/addon/tern/tern.css +++ b/addon/tern/tern.css @@ -76,6 +76,7 @@ .CodeMirror-Tern-hint-doc { max-width: 25em; + margin-top: -3px; } .CodeMirror-Tern-fname { color: black; } From 9556bdd640d17ffccaa40d80939cfbce0e36b160 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 13 May 2014 13:34:43 +0200 Subject: [PATCH 1853/5273] [tern addon] Remove unnecessary error check --- addon/tern/tern.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addon/tern/tern.js b/addon/tern/tern.js index 318f1484d9..3508f18130 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -432,7 +432,7 @@ function rename(ts, cm) { var token = cm.getTokenAt(cm.getCursor()); - if (!/\w/.test(token.string)) showError(ts, cm, "Not at a variable"); + if (!/\w/.test(token.string)) return showError(ts, cm, "Not at a variable"); dialog(cm, "New name for " + token.string, function(newName) { ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) { if (error) return showError(ts, cm, error); @@ -443,7 +443,6 @@ function selectName(ts, cm) { var cur = cm.getCursor(), token = cm.getTokenAt(cur); - if (!/\w/.test(token.string)) showError(ts, cm, "Not at a variable"); var name = findDoc(ts, cm.doc).name; ts.request(cm, {type: "refs"}, function(error, data) { if (error) return showError(ts, cm, error); From 09c8a0b09afe6eab99ea297a2d2bc1c737546b80 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 13 May 2014 13:41:49 +0200 Subject: [PATCH 1854/5273] [tern addon] Lint fix --- addon/tern/tern.js | 1 - 1 file changed, 1 deletion(-) diff --git a/addon/tern/tern.js b/addon/tern/tern.js index 3508f18130..9bae94b27e 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -442,7 +442,6 @@ } function selectName(ts, cm) { - var cur = cm.getCursor(), token = cm.getTokenAt(cur); var name = findDoc(ts, cm.doc).name; ts.request(cm, {type: "refs"}, function(error, data) { if (error) return showError(ts, cm, error); From 714954d744e74626b38a87834c7e46a589133f01 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 15 May 2014 12:34:58 +0200 Subject: [PATCH 1855/5273] [tern addon] Allow hiding and deleting docs by identity, not just name --- addon/tern/tern.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/addon/tern/tern.js b/addon/tern/tern.js index 9bae94b27e..27d6421512 100644 --- a/addon/tern/tern.js +++ b/addon/tern/tern.js @@ -17,7 +17,7 @@ // indicate that a file is not available. // * fileFilter: A function(value, docName, doc) that will be applied // to documents before passing them on to Tern. -// * switchToDoc: A function(name) that should, when providing a +// * switchToDoc: A function(name, doc) that should, when providing a // multi-file view, switch the view or focus to the named file. // * showError: A function(editor, message) that can be used to // override the way errors are displayed. @@ -88,17 +88,17 @@ return this.docs[name] = data; }, - delDoc: function(name) { - var found = this.docs[name]; + delDoc: function(id) { + var found = resolveDoc(this, id); if (!found) return; CodeMirror.off(found.doc, "change", this.trackChange); - delete this.docs[name]; - this.server.delFile(name); + delete this.docs[found.name]; + this.server.delFile(found.name); }, - hideDoc: function(name) { + hideDoc: function(id) { closeArgHints(this); - var found = this.docs[name]; + var found = resolveDoc(this, id); if (found && found.changed) sendDoc(this, found); }, @@ -157,6 +157,12 @@ return ts.addDoc(name, doc); } + function resolveDoc(ts, id) { + if (typeof id == "string") return ts.docs[id]; + if (id instanceof CodeMirror) id = id.getDoc(); + if (id instanceof CodeMirror.Doc) return findDoc(ts, id); + } + function trackChange(ts, doc, change) { var data = findDoc(ts, doc); @@ -387,7 +393,7 @@ doc.doc.setSelection(end, start); if (curDoc != doc && ts.options.switchToDoc) { closeArgHints(ts); - ts.options.switchToDoc(doc.name); + ts.options.switchToDoc(doc.name, doc.doc); } } From c6e7cd1bd76cb42fe67199cd643d2b17cc3d0372 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Fri, 9 May 2014 20:42:08 +0200 Subject: [PATCH 1856/5273] [vim] Add vim keypress and command done events --- demo/vim.html | 11 +++++++++++ keymap/vim.js | 16 +++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/demo/vim.html b/demo/vim.html index ad34660892..f92ff9e6d8 100644 --- a/demo/vim.html +++ b/demo/vim.html @@ -45,6 +45,7 @@

    Vim bindings demo

    return (--n >= 0) ? (unsigned char) *bufp++ : EOF; } +
    + + +

    Mode for Kotlin (http://kotlin.jetbrains.org/)

    +

    Developed by Hadi Hariri (https://github.com/hhariri).

    +

    MIME type defined: text/x-kotlin.

    + diff --git a/mode/kotlin/kotlin.js b/mode/kotlin/kotlin.js new file mode 100644 index 0000000000..73c84f6c4f --- /dev/null +++ b/mode/kotlin/kotlin.js @@ -0,0 +1,280 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + +CodeMirror.defineMode("kotlin", function (config, parserConfig) { + function words(str) { + var obj = {}, words = str.split(" "); + for (var i = 0; i < words.length; ++i) obj[words[i]] = true; + return obj; + } + + var multiLineStrings = parserConfig.multiLineStrings; + + var keywords = words( + "package continue return object while break class data trait throw super" + + " when type this else This try val var fun for is in if do as true false null get set"); + var softKeywords = words("import" + + " where by get set abstract enum open annotation override private public internal" + + " protected catch out vararg inline finally final ref"); + var blockKeywords = words("catch class do else finally for if where try while enum"); + var atoms = words("null true false this"); + + var curPunc; + + function tokenBase(stream, state) { + var ch = stream.next(); + if (ch == '"' || ch == "'") { + return startString(ch, stream, state); + } + // Wildcard import w/o trailing semicolon (import smth.*) + if (ch == "." && stream.eat("*")) { + return "word"; + } + if (/[\[\]{}\(\),;\:\.]/.test(ch)) { + curPunc = ch; + return null; + } + if (/\d/.test(ch)) { + if (stream.eat(/eE/)) { + stream.eat(/\+\-/); + stream.eatWhile(/\d/); + } + return "number"; + } + if (ch == "/") { + if (stream.eat("*")) { + state.tokenize.push(tokenComment); + return tokenComment(stream, state); + } + if (stream.eat("/")) { + stream.skipToEnd(); + return "comment"; + } + if (expectExpression(state.lastToken)) { + return startString(ch, stream, state); + } + } + // Commented + if (ch == "-" && stream.eat(">")) { + curPunc = "->"; + return null; + } + if (/[\-+*&%=<>!?|\/~]/.test(ch)) { + stream.eatWhile(/[\-+*&%=<>|~]/); + return "operator"; + } + stream.eatWhile(/[\w\$_]/); + + var cur = stream.current(); + if (atoms.propertyIsEnumerable(cur)) { + return "atom"; + } + if (softKeywords.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "softKeyword"; + } + + if (keywords.propertyIsEnumerable(cur)) { + if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement"; + return "keyword"; + } + return "word"; + } + + tokenBase.isBase = true; + + function startString(quote, stream, state) { + var tripleQuoted = false; + if (quote != "/" && stream.eat(quote)) { + if (stream.eat(quote)) tripleQuoted = true; + else return "string"; + } + function t(stream, state) { + var escaped = false, next, end = !tripleQuoted; + + while ((next = stream.next()) != null) { + if (next == quote && !escaped) { + if (!tripleQuoted) { + break; + } + if (stream.match(quote + quote)) { + end = true; + break; + } + } + + if (quote == '"' && next == "$" && !escaped && stream.eat("{")) { + state.tokenize.push(tokenBaseUntilBrace()); + return "string"; + } + + if (next == "$" && !escaped && !stream.eat(" ")) { + state.tokenize.push(tokenBaseUntilSpace()); + return "string"; + } + escaped = !escaped && next == "\\"; + } + if (multiLineStrings) + state.tokenize.push(t); + if (end) state.tokenize.pop(); + return "string"; + } + + state.tokenize.push(t); + return t(stream, state); + } + + function tokenBaseUntilBrace() { + var depth = 1; + + function t(stream, state) { + if (stream.peek() == "}") { + depth--; + if (depth == 0) { + state.tokenize.pop(); + return state.tokenize[state.tokenize.length - 1](stream, state); + } + } else if (stream.peek() == "{") { + depth++; + } + return tokenBase(stream, state); + } + + t.isBase = true; + return t; + } + + function tokenBaseUntilSpace() { + function t(stream, state) { + if (stream.eat(/[\w]/)) { + var isWord = stream.eatWhile(/[\w]/); + if (isWord) { + state.tokenize.pop(); + return "word"; + } + } + state.tokenize.pop(); + return "string"; + } + + t.isBase = true; + return t; + } + + function tokenComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (ch == "/" && maybeEnd) { + state.tokenize.pop(); + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function expectExpression(last) { + return !last || last == "operator" || last == "->" || /[\.\[\{\(,;:]/.test(last) || + last == "newstatement" || last == "keyword" || last == "proplabel"; + } + + function Context(indented, column, type, align, prev) { + this.indented = indented; + this.column = column; + this.type = type; + this.align = align; + this.prev = prev; + } + + function pushContext(state, col, type) { + return state.context = new Context(state.indented, col, type, null, state.context); + } + + function popContext(state) { + var t = state.context.type; + if (t == ")" || t == "]" || t == "}") + state.indented = state.context.indented; + return state.context = state.context.prev; + } + + // Interface + + return { + startState: function (basecolumn) { + return { + tokenize: [tokenBase], + context: new Context((basecolumn || 0) - config.indentUnit, 0, "top", false), + indented: 0, + startOfLine: true, + lastToken: null + }; + }, + + token: function (stream, state) { + var ctx = state.context; + if (stream.sol()) { + if (ctx.align == null) ctx.align = false; + state.indented = stream.indentation(); + state.startOfLine = true; + // Automatic semicolon insertion + if (ctx.type == "statement" && !expectExpression(state.lastToken)) { + popContext(state); + ctx = state.context; + } + } + if (stream.eatSpace()) return null; + curPunc = null; + var style = state.tokenize[state.tokenize.length - 1](stream, state); + if (style == "comment") return style; + if (ctx.align == null) ctx.align = true; + if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state); + // Handle indentation for {x -> \n ... } + else if (curPunc == "->" && ctx.type == "statement" && ctx.prev.type == "}") { + popContext(state); + state.context.align = false; + } + else if (curPunc == "{") pushContext(state, stream.column(), "}"); + else if (curPunc == "[") pushContext(state, stream.column(), "]"); + else if (curPunc == "(") pushContext(state, stream.column(), ")"); + else if (curPunc == "}") { + while (ctx.type == "statement") ctx = popContext(state); + if (ctx.type == "}") ctx = popContext(state); + while (ctx.type == "statement") ctx = popContext(state); + } + else if (curPunc == ctx.type) popContext(state); + else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement")) + pushContext(state, stream.column(), "statement"); + state.startOfLine = false; + state.lastToken = curPunc || style; + return style; + }, + + indent: function (state, textAfter) { + if (!state.tokenize[state.tokenize.length - 1].isBase) return 0; + var firstChar = textAfter && textAfter.charAt(0), ctx = state.context; + if (ctx.type == "statement" && !expectExpression(state.lastToken)) ctx = ctx.prev; + var closing = firstChar == ctx.type; + if (ctx.type == "statement") { + return ctx.indented + (firstChar == "{" ? 0 : config.indentUnit); + } + else if (ctx.align) return ctx.column + (closing ? 0 : 1); + else return ctx.indented + (closing ? 0 : config.indentUnit); + }, + + electricChars: "{}" + }; +}); + +CodeMirror.defineMIME("text/x-kotlin", "kotlin"); + +}); From 4928d37fb9650ce76e1dcba8ad593f1a579b1f70 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 4 Jul 2014 11:54:03 +0200 Subject: [PATCH 1958/5273] [kotlin mode] Integrate Issue #2678 --- doc/compress.html | 1 + mode/index.html | 1 + mode/kotlin/index.html | 3 +- mode/meta.js | 193 +++++++++++++++++++++-------------------- 4 files changed, 101 insertions(+), 97 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 5762aa442b..ede45e1c6e 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -123,6 +123,7 @@

    Script compression helper

    + diff --git a/mode/index.html b/mode/index.html index 91fb92bff8..1aa0b8d821 100644 --- a/mode/index.html +++ b/mode/index.html @@ -65,6 +65,7 @@

    Language modes

  • JavaScript
  • Jinja2
  • Julia
  • +
  • Kotlin
  • LESS
  • LiveScript
  • Lua
  • diff --git a/mode/kotlin/index.html b/mode/kotlin/index.html index 24fb46706f..38700f3226 100644 --- a/mode/kotlin/index.html +++ b/mode/kotlin/index.html @@ -79,7 +79,8 @@

    Kotlin mode

    Mode for Kotlin (http://kotlin.jetbrains.org/)

    diff --git a/mode/meta.js b/mode/meta.js index 4e42cb32df..3627cd7470 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -12,102 +12,103 @@ "use strict"; CodeMirror.modeInfo = [ - {name: 'APL', mime: 'text/apl', mode: 'apl'}, - {name: 'Asterisk', mime: 'text/x-asterisk', mode: 'asterisk'}, - {name: 'C', mime: 'text/x-csrc', mode: 'clike'}, - {name: 'C++', mime: 'text/x-c++src', mode: 'clike'}, - {name: 'Cobol', mime: 'text/x-cobol', mode: 'cobol'}, - {name: 'Java', mime: 'text/x-java', mode: 'clike'}, - {name: 'C#', mime: 'text/x-csharp', mode: 'clike'}, - {name: 'Scala', mime: 'text/x-scala', mode: 'clike'}, - {name: 'Clojure', mime: 'text/x-clojure', mode: 'clojure'}, - {name: 'CoffeeScript', mime: 'text/x-coffeescript', mode: 'coffeescript'}, - {name: 'Common Lisp', mime: 'text/x-common-lisp', mode: 'commonlisp'}, - {name: 'Cypher', mime: 'application/x-cypher-query', mode: 'cypher'}, - {name: 'CSS', mime: 'text/css', mode: 'css'}, - {name: 'D', mime: 'text/x-d', mode: 'd'}, - {name: 'diff', mime: 'text/x-diff', mode: 'diff'}, - {name: 'DTD', mime: 'application/xml-dtd', mode: 'dtd'}, - {name: 'Dylan', mime: 'text/x-dylan', mode: 'dylan'}, - {name: 'ECL', mime: 'text/x-ecl', mode: 'ecl'}, - {name: 'Eiffel', mime: 'text/x-eiffel', mode: 'eiffel'}, - {name: 'Erlang', mime: 'text/x-erlang', mode: 'erlang'}, - {name: 'Fortran', mime: 'text/x-fortran', mode: 'fortran'}, - {name: 'F#', mime: 'text/x-fsharp', mode: 'mllike'}, - {name: 'Gas', mime: 'text/x-gas', mode: 'gas'}, - {name: 'Gherkin', mime: 'text/x-feature', mode: 'gherkin'}, - {name: 'GitHub Flavored Markdown', mime: 'text/x-gfm', mode: 'gfm'}, - {name: 'Go', mime: 'text/x-go', mode: 'go'}, - {name: 'Groovy', mime: 'text/x-groovy', mode: 'groovy'}, - {name: 'HAML', mime: 'text/x-haml', mode: 'haml'}, - {name: 'Haskell', mime: 'text/x-haskell', mode: 'haskell'}, - {name: 'Haxe', mime: 'text/x-haxe', mode: 'haxe'}, - {name: 'ASP.NET', mime: 'application/x-aspx', mode: 'htmlembedded'}, - {name: 'Embedded Javascript', mime: 'application/x-ejs', mode: 'htmlembedded'}, - {name: 'JavaServer Pages', mime: 'application/x-jsp', mode: 'htmlembedded'}, - {name: 'HTML', mime: 'text/html', mode: 'htmlmixed'}, - {name: 'HTTP', mime: 'message/http', mode: 'http'}, - {name: 'Jade', mime: 'text/x-jade', mode: 'jade'}, - {name: 'JavaScript', mime: 'text/javascript', mode: 'javascript'}, - {name: 'JavaScript', mime: 'application/javascript', mode: 'javascript'}, - {name: 'JSON', mime: 'application/x-json', mode: 'javascript'}, - {name: 'JSON', mime: 'application/json', mode: 'javascript'}, - {name: 'JSON-LD', mime: 'application/ld+json', mode: 'javascript'}, - {name: 'TypeScript', mime: 'application/typescript', mode: 'javascript'}, - {name: 'Jinja2', mime: null, mode: 'jinja2'}, - {name: 'Julia', mime: 'text/x-julia', mode: 'julia'}, - {name: 'LESS', mime: 'text/x-less', mode: 'css'}, - {name: 'LiveScript', mime: 'text/x-livescript', mode: 'livescript'}, - {name: 'Lua', mime: 'text/x-lua', mode: 'lua'}, - {name: 'Markdown (GitHub-flavour)', mime: 'text/x-markdown', mode: 'markdown'}, - {name: 'mIRC', mime: 'text/mirc', mode: 'mirc'}, - {name: 'Nginx', mime: 'text/x-nginx-conf', mode: 'nginx'}, - {name: 'NTriples', mime: 'text/n-triples', mode: 'ntriples'}, - {name: 'OCaml', mime: 'text/x-ocaml', mode: 'mllike'}, - {name: 'Octave', mime: 'text/x-octave', mode: 'octave'}, - {name: 'Pascal', mime: 'text/x-pascal', mode: 'pascal'}, - {name: 'PEG.js', mime: null, mode: 'pegjs'}, - {name: 'Perl', mime: 'text/x-perl', mode: 'perl'}, - {name: 'PHP', mime: 'text/x-php', mode: 'php'}, - {name: 'PHP(HTML)', mime: 'application/x-httpd-php', mode: 'php'}, - {name: 'Pig', mime: 'text/x-pig', mode: 'pig'}, - {name: 'Plain Text', mime: 'text/plain', mode: 'null'}, - {name: 'Properties files', mime: 'text/x-properties', mode: 'properties'}, - {name: 'Python', mime: 'text/x-python', mode: 'python'}, - {name: 'Puppet', mime: 'text/x-puppet', mode: 'puppet'}, - {name: 'Cython', mime: 'text/x-cython', mode: 'python'}, - {name: 'R', mime: 'text/x-rsrc', mode: 'r'}, - {name: 'reStructuredText', mime: 'text/x-rst', mode: 'rst'}, - {name: 'Ruby', mime: 'text/x-ruby', mode: 'ruby'}, - {name: 'Rust', mime: 'text/x-rustsrc', mode: 'rust'}, - {name: 'Sass', mime: 'text/x-sass', mode: 'sass'}, - {name: 'Scheme', mime: 'text/x-scheme', mode: 'scheme'}, - {name: 'SCSS', mime: 'text/x-scss', mode: 'css'}, - {name: 'Shell', mime: 'text/x-sh', mode: 'shell'}, - {name: 'Sieve', mime: 'application/sieve', mode: 'sieve'}, - {name: 'Smalltalk', mime: 'text/x-stsrc', mode: 'smalltalk'}, - {name: 'Smarty', mime: 'text/x-smarty', mode: 'smarty'}, - {name: 'SmartyMixed', mime: 'text/x-smarty', mode: 'smartymixed'}, - {name: 'Solr', mime: 'text/x-solr', mode: 'solr'}, - {name: 'SPARQL', mime: 'application/x-sparql-query', mode: 'sparql'}, - {name: 'SQL', mime: 'text/x-sql', mode: 'sql'}, - {name: 'MariaDB', mime: 'text/x-mariadb', mode: 'sql'}, - {name: 'sTeX', mime: 'text/x-stex', mode: 'stex'}, - {name: 'LaTeX', mime: 'text/x-latex', mode: 'stex'}, - {name: 'SystemVerilog', mime: 'text/x-systemverilog', mode: 'verilog'}, - {name: 'Tcl', mime: 'text/x-tcl', mode: 'tcl'}, - {name: 'TiddlyWiki ', mime: 'text/x-tiddlywiki', mode: 'tiddlywiki'}, - {name: 'Tiki wiki', mime: 'text/tiki', mode: 'tiki'}, - {name: 'TOML', mime: 'text/x-toml', mode: 'toml'}, - {name: 'Turtle', mime: 'text/turtle', mode: 'turtle'}, - {name: 'VB.NET', mime: 'text/x-vb', mode: 'vb'}, - {name: 'VBScript', mime: 'text/vbscript', mode: 'vbscript'}, - {name: 'Velocity', mime: 'text/velocity', mode: 'velocity'}, - {name: 'Verilog', mime: 'text/x-verilog', mode: 'verilog'}, - {name: 'XML', mime: 'application/xml', mode: 'xml'}, - {name: 'XQuery', mime: 'application/xquery', mode: 'xquery'}, - {name: 'YAML', mime: 'text/x-yaml', mode: 'yaml'}, - {name: 'Z80', mime: 'text/x-z80', mode: 'z80'} + {name: "APL", mime: "text/apl", mode: "apl"}, + {name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk"}, + {name: "C", mime: "text/x-csrc", mode: "clike"}, + {name: "C++", mime: "text/x-c++src", mode: "clike"}, + {name: "Cobol", mime: "text/x-cobol", mode: "cobol"}, + {name: "Java", mime: "text/x-java", mode: "clike"}, + {name: "C#", mime: "text/x-csharp", mode: "clike"}, + {name: "Scala", mime: "text/x-scala", mode: "clike"}, + {name: "Clojure", mime: "text/x-clojure", mode: "clojure"}, + {name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript"}, + {name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp"}, + {name: "Cypher", mime: "application/x-cypher-query", mode: "cypher"}, + {name: "CSS", mime: "text/css", mode: "css"}, + {name: "D", mime: "text/x-d", mode: "d"}, + {name: "diff", mime: "text/x-diff", mode: "diff"}, + {name: "DTD", mime: "application/xml-dtd", mode: "dtd"}, + {name: "Dylan", mime: "text/x-dylan", mode: "dylan"}, + {name: "ECL", mime: "text/x-ecl", mode: "ecl"}, + {name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel"}, + {name: "Erlang", mime: "text/x-erlang", mode: "erlang"}, + {name: "Fortran", mime: "text/x-fortran", mode: "fortran"}, + {name: "F#", mime: "text/x-fsharp", mode: "mllike"}, + {name: "Gas", mime: "text/x-gas", mode: "gas"}, + {name: "Gherkin", mime: "text/x-feature", mode: "gherkin"}, + {name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm"}, + {name: "Go", mime: "text/x-go", mode: "go"}, + {name: "Groovy", mime: "text/x-groovy", mode: "groovy"}, + {name: "HAML", mime: "text/x-haml", mode: "haml"}, + {name: "Haskell", mime: "text/x-haskell", mode: "haskell"}, + {name: "Haxe", mime: "text/x-haxe", mode: "haxe"}, + {name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded"}, + {name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded"}, + {name: "JavaServer Pages", mime: "application/x-jsp", mode: "htmlembedded"}, + {name: "HTML", mime: "text/html", mode: "htmlmixed"}, + {name: "HTTP", mime: "message/http", mode: "http"}, + {name: "Jade", mime: "text/x-jade", mode: "jade"}, + {name: "JavaScript", mime: "text/javascript", mode: "javascript"}, + {name: "JavaScript", mime: "application/javascript", mode: "javascript"}, + {name: "JSON", mime: "application/x-json", mode: "javascript"}, + {name: "JSON", mime: "application/json", mode: "javascript"}, + {name: "JSON-LD", mime: "application/ld+json", mode: "javascript"}, + {name: "TypeScript", mime: "application/typescript", mode: "javascript"}, + {name: "Jinja2", mime: null, mode: "jinja2"}, + {name: "Julia", mime: "text/x-julia", mode: "julia"}, + {name: "Kotlin", mime: "text/x-kotlin", mode: "kotlin"}, + {name: "LESS", mime: "text/x-less", mode: "css"}, + {name: "LiveScript", mime: "text/x-livescript", mode: "livescript"}, + {name: "Lua", mime: "text/x-lua", mode: "lua"}, + {name: "Markdown (GitHub-flavour)", mime: "text/x-markdown", mode: "markdown"}, + {name: "mIRC", mime: "text/mirc", mode: "mirc"}, + {name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx"}, + {name: "NTriples", mime: "text/n-triples", mode: "ntriples"}, + {name: "OCaml", mime: "text/x-ocaml", mode: "mllike"}, + {name: "Octave", mime: "text/x-octave", mode: "octave"}, + {name: "Pascal", mime: "text/x-pascal", mode: "pascal"}, + {name: "PEG.js", mime: null, mode: "pegjs"}, + {name: "Perl", mime: "text/x-perl", mode: "perl"}, + {name: "PHP", mime: "text/x-php", mode: "php"}, + {name: "PHP(HTML)", mime: "application/x-httpd-php", mode: "php"}, + {name: "Pig", mime: "text/x-pig", mode: "pig"}, + {name: "Plain Text", mime: "text/plain", mode: "null"}, + {name: "Properties files", mime: "text/x-properties", mode: "properties"}, + {name: "Python", mime: "text/x-python", mode: "python"}, + {name: "Puppet", mime: "text/x-puppet", mode: "puppet"}, + {name: "Cython", mime: "text/x-cython", mode: "python"}, + {name: "R", mime: "text/x-rsrc", mode: "r"}, + {name: "reStructuredText", mime: "text/x-rst", mode: "rst"}, + {name: "Ruby", mime: "text/x-ruby", mode: "ruby"}, + {name: "Rust", mime: "text/x-rustsrc", mode: "rust"}, + {name: "Sass", mime: "text/x-sass", mode: "sass"}, + {name: "Scheme", mime: "text/x-scheme", mode: "scheme"}, + {name: "SCSS", mime: "text/x-scss", mode: "css"}, + {name: "Shell", mime: "text/x-sh", mode: "shell"}, + {name: "Sieve", mime: "application/sieve", mode: "sieve"}, + {name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk"}, + {name: "Smarty", mime: "text/x-smarty", mode: "smarty"}, + {name: "SmartyMixed", mime: "text/x-smarty", mode: "smartymixed"}, + {name: "Solr", mime: "text/x-solr", mode: "solr"}, + {name: "SPARQL", mime: "application/x-sparql-query", mode: "sparql"}, + {name: "SQL", mime: "text/x-sql", mode: "sql"}, + {name: "MariaDB", mime: "text/x-mariadb", mode: "sql"}, + {name: "sTeX", mime: "text/x-stex", mode: "stex"}, + {name: "LaTeX", mime: "text/x-latex", mode: "stex"}, + {name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog"}, + {name: "Tcl", mime: "text/x-tcl", mode: "tcl"}, + {name: "TiddlyWiki ", mime: "text/x-tiddlywiki", mode: "tiddlywiki"}, + {name: "Tiki wiki", mime: "text/tiki", mode: "tiki"}, + {name: "TOML", mime: "text/x-toml", mode: "toml"}, + {name: "Turtle", mime: "text/turtle", mode: "turtle"}, + {name: "VB.NET", mime: "text/x-vb", mode: "vb"}, + {name: "VBScript", mime: "text/vbscript", mode: "vbscript"}, + {name: "Velocity", mime: "text/velocity", mode: "velocity"}, + {name: "Verilog", mime: "text/x-verilog", mode: "verilog"}, + {name: "XML", mime: "application/xml", mode: "xml"}, + {name: "XQuery", mime: "application/xquery", mode: "xquery"}, + {name: "YAML", mime: "text/x-yaml", mode: "yaml"}, + {name: "Z80", mime: "text/x-z80", mode: "z80"} ]; }); From b55cc7f5cd0b1128508dda51f525538dd1897f29 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 3 Jul 2014 15:05:42 +0200 Subject: [PATCH 1959/5273] [multi-editor operations] Set up operation grouping Now nested operations from different editors end at the same time --- lib/codemirror.js | 66 ++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 1aee422b42..85cfea9d7b 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1911,10 +1911,13 @@ // error-prone). Instead, display updates are batched and then all // combined and executed at once. + var operationGroup = null; + var nextOpId = 0; // Start a new operation. function startOperation(cm) { cm.curOp = { + cm: cm, viewChanged: false, // Flag that indicates that lines might need to be redrawn startHeight: cm.doc.height, // Used to detect need to update scrollbar forceUpdate: false, // Used to force a redraw @@ -1928,19 +1931,32 @@ scrollToPos: null, // Used to scroll to a specific position id: ++nextOpId // Unique ID }; - if (!delayedCallbackDepth++) delayedCallbacks = []; + if (operationGroup) { + operationGroup.ops.push(cm.curOp); + } else { + cm.curOp.ownsGroup = operationGroup = { + ops: [cm.curOp], + delayedCallbacks: [] + }; + } } // Finish an operation, updating the display and signalling delayed events function endOperation(cm) { - var op = cm.curOp, doc = cm.doc, display = cm.display; - cm.curOp = null; - var delayed; - if (!--delayedCallbackDepth) { - delayed = delayedCallbacks; - delayedCallbacks = null; - } + var op = cm.curOp, group = op.ownsGroup; + if (!group) return; + + cm.curOp = operationGroup = null; + for (var i = 0; i < group.ops.length; i++) + endOperationInner(group.ops[i]); + + for (var i = 0; i < group.delayedCallbacks.length; ++i) + group.delayedCallbacks[i](); + } + + function endOperationInner(op) { + var cm = op.cm, display = cm.display, doc = cm.doc; if (op.updateMaxLine) findMaxLine(cm); // If it looks like an update might be needed, call updateDisplay @@ -1949,11 +1965,11 @@ op.scrollToPos.to.line >= display.viewTo) || display.maxLineChanged && cm.options.lineWrapping) { var updated = updateDisplay(cm, {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); - if (cm.display.scroller.offsetHeight) cm.doc.scrollTop = cm.display.scroller.scrollTop; + if (cm.display.scroller.offsetHeight) doc.scrollTop = cm.display.scroller.scrollTop; } // If no update was run, but the selection changed, redraw that. if (!updated && op.selectionChanged) updateSelection(cm); - if (!updated && op.startHeight != cm.doc.height) updateScrollbars(cm); + if (!updated && op.startHeight != doc.height) updateScrollbars(cm); // Abort mouse wheel delta measurement, when scrolling explicitly if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) @@ -1971,8 +1987,8 @@ } // If we need to scroll a specific position into view, do so. if (op.scrollToPos) { - var coords = scrollPosIntoView(cm, clipPos(cm.doc, op.scrollToPos.from), - clipPos(cm.doc, op.scrollToPos.to), op.scrollToPos.margin); + 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); } @@ -1992,7 +2008,6 @@ // Fire change events, and delayed event handlers if (op.changeObjs) signal(cm, "changes", cm, op.changeObjs); - if (delayed) for (var i = 0; i < delayed.length; ++i) delayed[i](); if (op.cursorActivityHandlers) for (var i = 0; i < op.cursorActivityHandlers.length; i++) op.cursorActivityHandlers[i](cm); @@ -6960,6 +6975,8 @@ for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args); }; + 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 // other methods on the editor, which might be in an inconsistent @@ -6967,25 +6984,26 @@ // signalLater looks whether there are any handlers, and schedules // them to be executed when the last operation ends, or, if no // operation is active, when a timeout fires. - var delayedCallbacks, delayedCallbackDepth = 0; function signalLater(emitter, type /*, values...*/) { var arr = emitter._handlers && emitter._handlers[type]; if (!arr) return; - var args = Array.prototype.slice.call(arguments, 2); - if (!delayedCallbacks) { - ++delayedCallbackDepth; - delayedCallbacks = []; - setTimeout(fireDelayed, 0); + var args = Array.prototype.slice.call(arguments, 2), list; + if (operationGroup) { + list = operationGroup.delayedCallbacks; + } else if (orphanDelayedCallbacks) { + list = orphanDelayedCallbacks; + } else { + list = orphanDelayedCallbacks = []; + setTimeout(fireOrphanDelayed, 0); } function bnd(f) {return function(){f.apply(null, args);};}; for (var i = 0; i < arr.length; ++i) - delayedCallbacks.push(bnd(arr[i])); + list.push(bnd(arr[i])); } - function fireDelayed() { - --delayedCallbackDepth; - var delayed = delayedCallbacks; - delayedCallbacks = null; + function fireOrphanDelayed() { + var delayed = orphanDelayedCallbacks; + orphanDelayedCallbacks = null; for (var i = 0; i < delayed.length; ++i) delayed[i](); } From 0bdd5ea0b31aade11c0f2a385cdd720aab90eea4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 3 Jul 2014 15:32:10 +0200 Subject: [PATCH 1960/5273] [multi-editor operations] Fire delayed events before the operation ends --- lib/codemirror.js | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 85cfea9d7b..b9c63a226d 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1925,6 +1925,7 @@ typing: false, // Whether this reset should be careful to leave existing text (for compositing) changeObjs: null, // Accumulated changes, for firing change events cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on + cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already selectionChanged: false, // Whether the selection needs to be redrawn updateMaxLine: false, // Set when the widest line needs to be determined anew scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet @@ -1941,18 +1942,33 @@ } } + function fireCallbacksForOps(group) { + // Calls delayed callbacks and cursorActivity handlers until no + // new ones appear + var callbacks = group.delayedCallbacks, i = 0; + do { + for (; i < callbacks.length; i++) + callbacks[i](); + for (var j = 0; j < group.ops.length; j++) { + var op = group.ops[j]; + if (op.cursorActivityHandlers) + while (op.cursorActivityCalled < op.cursorActivityHandlers.length) + op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm); + } + } while (i < callbacks.length); + } + // Finish an operation, updating the display and signalling delayed events function endOperation(cm) { var op = cm.curOp, group = op.ownsGroup; if (!group) return; - cm.curOp = operationGroup = null; - - for (var i = 0; i < group.ops.length; i++) - endOperationInner(group.ops[i]); - - for (var i = 0; i < group.delayedCallbacks.length; ++i) - group.delayedCallbacks[i](); + try { fireCallbacksForOps(group); } + finally { + cm.curOp = operationGroup = null; + for (var i = 0; i < group.ops.length; i++) + endOperationInner(group.ops[i]); + } } function endOperationInner(op) { @@ -2008,9 +2024,6 @@ // Fire change events, and delayed event handlers if (op.changeObjs) signal(cm, "changes", cm, op.changeObjs); - if (op.cursorActivityHandlers) - for (var i = 0; i < op.cursorActivityHandlers.length; i++) - op.cursorActivityHandlers[i](cm); } // Run the given function in an operation From 55e1ed94dc83539dcecc4abb56935c3b411da557 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 3 Jul 2014 15:54:08 +0200 Subject: [PATCH 1961/5273] Run operations cautiously again in highlightWorker --- lib/codemirror.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index b9c63a226d..089a3e9f3b 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1408,8 +1408,8 @@ 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 = []; - runInOp(cm, function() { 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; @@ -1421,7 +1421,7 @@ 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) regLineChange(cm, doc.frontier, "text"); + if (ischange) changedLines.push(doc.frontier); line.stateAfter = copyState(doc.mode, state); } else { processLine(cm, line.text, state); @@ -1433,6 +1433,9 @@ return true; } }); + if (changedLines.length) runInOp(cm, function() { + for (var i = 0; i < changedLines.length; i++) + regLineChange(cm, changedLines[i], "text"); }); } From 24920fb8a247a6079bc41d92af08f64cfe82b4b9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 3 Jul 2014 15:55:22 +0200 Subject: [PATCH 1962/5273] Don't wrap onKeyUp in an operation It doesn't need it --- lib/codemirror.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 089a3e9f3b..b2e194273f 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2452,7 +2452,7 @@ // Prevent wrapper from ever scrolling on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); - on(d.input, "keyup", operation(cm, onKeyUp)); + on(d.input, "keyup", function(e) { onKeyUp.call(cm, e); }); on(d.input, "input", function() { if (ie && ie_version >= 9 && cm.display.inputHasSelection) cm.display.inputHasSelection = null; fastPoll(cm); @@ -3145,8 +3145,8 @@ } function onKeyUp(e) { - if (signalDOMEvent(this, e)) return; if (e.keyCode == 16) this.doc.sel.shift = false; + signalDOMEvent(this, e); } function onKeyPress(e) { @@ -4164,7 +4164,7 @@ triggerOnKeyDown: methodOp(onKeyDown), triggerOnKeyPress: methodOp(onKeyPress), - triggerOnKeyUp: methodOp(onKeyUp), + triggerOnKeyUp: onKeyUp, execCommand: function(cmd) { if (commands.hasOwnProperty(cmd)) From e72560be12964597656fdf05d775893c46b81b14 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 3 Jul 2014 18:03:27 +0200 Subject: [PATCH 1963/5273] [multi-editor operations] Split actions at op end into steps, call in order --- lib/codemirror.js | 295 ++++++++++++++++++++++++++++------------------ 1 file changed, 181 insertions(+), 114 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index b2e194273f..1bf02d2089 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -108,6 +108,7 @@ for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) optionHandlers[opt](cm, options[opt], Init); + maybeUpdateLineNumberWidth(cm); for (var i = 0; i < initHooks.length; ++i) initHooks[i](cm); }); } @@ -467,18 +468,18 @@ } // Compute the lines that are visible in a given viewport (defaults - // the the current scroll position). viewPort may contain top, + // the the current scroll position). viewport may contain top, // height, and ensure (see op.scrollToPos) properties. - function visibleLines(display, doc, viewPort) { - var top = viewPort && viewPort.top != null ? Math.max(0, viewPort.top) : display.scroller.scrollTop; + 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 bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; 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; + if (viewport && viewport.ensure) { + var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; if (ensureFrom < from) return {from: ensureFrom, to: lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)}; @@ -543,83 +544,46 @@ // DISPLAY DRAWING - // Updates the display, selection, and scrollbars, using the - // information in display.view to find out which nodes are no longer - // up-to-date. Tries to bail out early when no changes are needed, - // unless forced is true. - // Returns true if an actual update happened, false otherwise. - function updateDisplay(cm, viewPort, forced) { - var oldFrom = cm.display.viewFrom, oldTo = cm.display.viewTo, updated; - var visible = visibleLines(cm.display, cm.doc, viewPort); - for (var first = true;; first = false) { - var oldWidth = cm.display.scroller.clientWidth; - if (!updateDisplayInner(cm, visible, forced)) break; - updated = true; - - // If the max line changed since it was last measured, measure it, - // and ensure the document's width matches it. - if (cm.display.maxLineChanged && !cm.options.lineWrapping) - adjustContentWidth(cm); - - var barMeasure = measureForScrollbars(cm); - updateSelection(cm); - setDocumentHeight(cm, barMeasure); - updateScrollbars(cm, barMeasure); - if (webkit && cm.options.lineWrapping) - checkForWebkitWidthBug(cm, barMeasure); // (Issue #2420) - if (webkit && barMeasure.scrollWidth > barMeasure.clientWidth && - barMeasure.scrollWidth < barMeasure.clientWidth + 1 && - !hScrollbarTakesSpace(cm)) - updateScrollbars(cm); // (Issue #2562) - if (first && cm.options.lineWrapping && oldWidth != cm.display.scroller.clientWidth) { - forced = true; - continue; - } - forced = false; - - // Clip forced viewport to actual scrollable area. - if (viewPort && viewPort.top != null) - viewPort = {top: Math.min(barMeasure.docHeight - scrollerCutOff - barMeasure.clientHeight, viewPort.top)}; - // Updated line heights might result in the drawn area not - // actually covering the viewport. Keep looping until it does. - visible = visibleLines(cm.display, cm.doc, viewPort); - if (visible.from >= cm.display.viewFrom && visible.to <= cm.display.viewTo) - break; - } + function DisplayUpdate(cm, viewport, force) { + var display = cm.display; - cm.display.updateLineNumbers = null; - if (updated) { - signalLater(cm, "update", cm); - if (cm.display.viewFrom != oldFrom || cm.display.viewTo != oldTo) - signalLater(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); - } - return updated; + 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.oldViewFrom = display.viewFrom; this.oldViewTo = display.viewTo; + this.oldScrollerWidth = display.scroller.clientWidth; + this.force = force; + this.dims = getDimensions(cm); } // Does the actual updating of the line display. Bails out // (returning false) when there is nothing to be done and forced is // false. - function updateDisplayInner(cm, visible, forced) { + function updateDisplayIfNeeded(cm, update) { var display = cm.display, doc = cm.doc; - if (!display.wrapper.offsetWidth) { + if (update.editorIsHidden) { resetView(cm); - return; + return false; } // Bail out if the visible area is already rendered and nothing changed. - if (!forced && visible.from >= display.viewFrom && visible.to <= display.viewTo && + if (!update.force && + update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && countDirtyView(cm) == 0) - return; + return false; - if (maybeUpdateLineNumberWidth(cm)) + if (maybeUpdateLineNumberWidth(cm)) { resetView(cm); - var dims = getDimensions(cm); + update.dims = getDimensions(cm); + } // Compute a suitable new viewport (from & to) var end = doc.first + doc.size; - var from = Math.max(visible.from - cm.options.viewportMargin, doc.first); - var to = Math.min(end, visible.to + cm.options.viewportMargin); + 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) { @@ -628,7 +592,7 @@ } var different = from != display.viewFrom || to != display.viewTo || - display.lastSizeC != display.wrapper.clientHeight; + display.lastSizeC != update.wrapperHeight; adjustView(cm, from, to); display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); @@ -636,13 +600,15 @@ cm.display.mover.style.top = display.viewOffset + "px"; var toUpdate = countDirtyView(cm); - if (!different && toUpdate == 0 && !forced) return; + if (!different && toUpdate == 0 && !update.force && + (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(); if (toUpdate > 4) display.lineDiv.style.display = "none"; - patchDisplay(cm, display.updateLineNumbers, dims); + patchDisplay(cm, display.updateLineNumbers, update.dims); if (toUpdate > 4) display.lineDiv.style.display = ""; // There might have been a widget with a focused element that got // hidden or updated, if so re-focus it. @@ -654,24 +620,50 @@ removeChildren(display.selectionDiv); if (different) { - display.lastSizeC = display.wrapper.clientHeight; + display.lastSizeC = update.wrapperHeight; startWorker(cm, 400); } - updateHeightsInViewport(cm); + display.updateLineNumbers = null; return true; } - function adjustContentWidth(cm) { - var display = cm.display; - var width = measureChar(cm, display.maxLine, display.maxLine.text.length).left; - display.maxLineChanged = false; - var minWidth = Math.max(0, width + 3); - var maxScrollLeft = Math.max(0, display.sizer.offsetLeft + minWidth + scrollerCutOff - display.scroller.clientWidth); - display.sizer.style.minWidth = minWidth + "px"; - if (maxScrollLeft < cm.doc.scrollLeft) - setScrollLeft(cm, Math.min(display.scroller.scrollLeft, maxScrollLeft), true); + function postUpdateDisplay(cm, update) { + var force = update.force, viewport = update.viewport; + for (var first = true;; first = false) { + updateHeightsInViewport(cm); + if (first && cm.options.lineWrapping && update.oldScrollerWidth != cm.display.scroller.clientWidth) { + force = true; + } else { + force = false; + // Clip forced viewport to actual scrollable area. + if (viewport && viewport.top != null) + viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - scrollerCutOff - + cm.display.scroller.clientHeight, viewport.top)}; + // Updated line heights might result in the drawn area not + // actually covering the viewport. Keep looping until it does. + var visible = visibleLines(cm.display, cm.doc, viewport); + if (visible.from >= cm.display.viewFrom && visible.to <= cm.display.viewTo) + break; + } + if (!updateDisplayIfNeeded(cm, update)) break; + } + + signalLater(cm, "update", cm); + if (cm.display.viewFrom != update.oldViewFrom || cm.display.viewTo != update.oldViewTo) + signalLater(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); + } + + function updateDisplaySimple(cm, viewport) { + var update = new DisplayUpdate(cm, viewport); + if (updateDisplayIfNeeded(cm, update)) { + postUpdateDisplay(cm, update); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + setDocumentHeight(cm, barMeasure); + updateScrollbars(cm, barMeasure); + } } function setDocumentHeight(cm, measure) { @@ -1257,10 +1249,10 @@ // SELECTION DRAWING // Redraw the selection and/or cursor - function updateSelection(cm) { - var display = cm.display, doc = cm.doc; - var curFragment = document.createDocumentFragment(); - var selFragment = document.createDocumentFragment(); + function drawSelection(cm) { + var display = cm.display, 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++) { var range = doc.sel.ranges[i]; @@ -1275,16 +1267,23 @@ if (cm.options.moveInputWithCursor) { var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); - var top = Math.max(0, Math.min(display.wrapper.clientHeight - 10, - headPos.top + lineOff.top - wrapOff.top)); - var left = Math.max(0, Math.min(display.wrapper.clientWidth - 10, - headPos.left + lineOff.left - wrapOff.left)); - display.inputDiv.style.top = top + "px"; - display.inputDiv.style.left = left + "px"; + 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, + headPos.left + lineOff.left - wrapOff.left)); } - removeChildrenAndAdd(display.cursorDiv, curFragment); - removeChildrenAndAdd(display.selectionDiv, selFragment); + return result; + } + + function updateSelection(cm, drawn) { + if (!drawn) drawn = drawSelection(cm); + removeChildrenAndAdd(cm.display.cursorDiv, drawn.cursors); + removeChildrenAndAdd(cm.display.selectionDiv, drawn.selection); + if (drawn.teTop != null) { + cm.display.inputDiv.style.top = drawn.teTop + "px"; + cm.display.inputDiv.style.left = drawn.teLeft + "px"; + } } // Draws a cursor for the given range @@ -1967,28 +1966,88 @@ if (!group) return; try { fireCallbacksForOps(group); } - finally { - cm.curOp = operationGroup = null; + finally { + operationGroup = null; for (var i = 0; i < group.ops.length; i++) - endOperationInner(group.ops[i]); + group.ops[i].cm.curOp = null; + endOperations(group); } } - function endOperationInner(op) { - var cm = op.cm, display = cm.display, doc = cm.doc; + // 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 + endOperation_R1(ops[i]); + for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + endOperation_W1(ops[i]); + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_R2(ops[i]); + for (var i = 0; i < ops.length; i++) // Write DOM (maybe) + endOperation_W2(ops[i]); + for (var i = 0; i < ops.length; i++) // Read DOM + endOperation_finish(ops[i]); + } + + function endOperation_R1(op) { + var cm = op.cm, display = cm.display; if (op.updateMaxLine) findMaxLine(cm); - // If it looks like an update might be needed, call updateDisplay - if (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) { - var updated = updateDisplay(cm, {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); - if (cm.display.scroller.offsetHeight) doc.scrollTop = cm.display.scroller.scrollTop; + 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; + op.update = op.mustUpdate && + 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); + } + + function endOperation_R2(op) { + var cm = op.cm, display = cm.display; + if (op.updatedDisplay) postUpdateDisplay(cm, op.update); + + // If the max line changed since it was last measured, measure it, + // and ensure the document's width matches it. + // updateDisplayIfNeeded 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; + op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo + + scrollerCutOff - display.scroller.clientWidth); } - // If no update was run, but the selection changed, redraw that. - if (!updated && op.selectionChanged) updateSelection(cm); - if (!updated && op.startHeight != doc.height) updateScrollbars(cm); + + op.barMeasure = measureForScrollbars(cm); + if (op.updatedDisplay || op.selectionChanged) + op.newSelectionNodes = drawSelection(cm); + } + + function endOperation_W2(op) { + var cm = op.cm; + + if (op.adjustWidthTo != null) { + 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); + } + + if (op.newSelectionNodes) + updateSelection(cm, op.newSelectionNodes); + if (op.updatedDisplay) + setDocumentHeight(cm, op.barMeasure); + if (op.updatedDisplay || op.startHeight != cm.doc.height) + updateScrollbars(cm, op.barMeasure); + + if (op.selectionChanged) restartBlink(cm); + + if (cm.state.focused && op.updateInput) + resetInput(cm, op.typing); + } + + function endOperation_finish(op) { + var cm = op.cm, display = cm.display, doc = cm.doc; // Abort mouse wheel delta measurement, when scrolling explicitly if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) @@ -2011,11 +2070,6 @@ if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords); } - if (op.selectionChanged) restartBlink(cm); - - if (cm.state.focused && op.updateInput) - resetInput(cm, op.typing); - // Fire events for markers that are hidden/unidden by editing or // undoing var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; @@ -2024,6 +2078,19 @@ if (unhidden) for (var i = 0; i < unhidden.length; ++i) if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); + if (display.wrapper.offsetHeight) + doc.scrollTop = cm.display.scroller.scrollTop; + + // Apply workaround for two webkit bugs + if (op.updatedDisplay && webkit) { + if (cm.options.lineWrapping) + checkForWebkitWidthBug(cm, op.barMeasure); // (Issue #2420) + if (op.barMeasure.scrollWidth > op.barMeasure.clientWidth && + op.barMeasure.scrollWidth < op.barMeasure.clientWidth + 1 && + !hScrollbarTakesSpace(cm)) + updateScrollbars(cm); // (Issue #2562) + } + // Fire change events, and delayed event handlers if (op.changeObjs) signal(cm, "changes", cm, op.changeObjs); @@ -2916,10 +2983,10 @@ function setScrollTop(cm, val) { if (Math.abs(cm.doc.scrollTop - val) < 2) return; cm.doc.scrollTop = val; - if (!gecko) updateDisplay(cm, {top: val}); + if (!gecko) updateDisplaySimple(cm, {top: val}); if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val; - if (gecko) updateDisplay(cm); + if (gecko) updateDisplaySimple(cm); startWorker(cm, 100); } // Sync scroller and scrollbar, ensure the gutter elements are @@ -3002,7 +3069,7 @@ 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); - updateDisplay(cm, {top: top, bottom: bot}); + updateDisplaySimple(cm, {top: top, bottom: bot}); } if (wheelSamples < 20) { From c698ab758b4682c2aca55135c9948735dd75a05f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 4 Jul 2014 12:26:41 +0200 Subject: [PATCH 1964/5273] [multi-editor operations] Add a few tests --- test/test.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/test.js b/test/test.js index 4ef4ef547d..dcfffb7c07 100644 --- a/test/test.js +++ b/test/test.js @@ -1988,3 +1988,38 @@ testCM("resizeLineWidget", function(cm) { cm.setSize(40); is(widget.parentNode.offsetWidth < 42); }); + +testCM("combinedOperations", function(cm) { + var place = document.getElementById("testground"); + var other = CodeMirror(place, {value: "123"}); + try { + cm.operation(function() { + cm.addLineClass(0, "wrap", "foo"); + other.addLineClass(0, "wrap", "foo"); + }); + eq(byClassName(cm.getWrapperElement(), "foo").length, 1); + eq(byClassName(other.getWrapperElement(), "foo").length, 1); + cm.operation(function() { + cm.removeLineClass(0, "wrap", "foo"); + other.removeLineClass(0, "wrap", "foo"); + }); + eq(byClassName(cm.getWrapperElement(), "foo").length, 0); + eq(byClassName(other.getWrapperElement(), "foo").length, 0); + } finally { + place.removeChild(other.getWrapperElement()); + } +}, {value: "abc"}); + +testCM("eventOrder", function(cm) { + var seen = []; + cm.on("change", function() { + if (!seen.length) cm.replaceSelection("."); + seen.push("change"); + }); + cm.on("cursorActivity", function() { + cm.replaceSelection("!"); + seen.push("activity"); + }); + cm.replaceSelection("/"); + eq(seen.join(","), "change,change,activity,change"); +}); From 63591907b0dcd51c2f64dc967143e044ecac6923 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 7 Jul 2014 14:30:27 +0200 Subject: [PATCH 1965/5273] Work around IE10- client rect + zoom issue Issue #2665 --- lib/codemirror.js | 24 ++++++++++++++++++++++++ test/lint/lint.js | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 1bf02d2089..cc7caace19 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1667,6 +1667,8 @@ rect = nullRect; } + if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect); + var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; var mid = (rtop + rbot) / 2; var heights = prepared.view.measure.heights; @@ -1678,9 +1680,22 @@ top: top, bottom: bot}; if (!rect.left && !rect.right) result.bogus = true; if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } + return result; } + // Work around problem with bounding client rects on ranges being + // returned incorrectly when zoomed on IE10 and below. + 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 {left: rect.left * scaleX, right: rect.right * scaleX, + top: rect.top * scaleY, bottom: rect.bottom * scaleY}; + } + function clearLineMeasurementCacheFor(lineView) { if (lineView.measure) { lineView.measure.cache = {}; @@ -7432,6 +7447,15 @@ return typeof e.oncopy == "function"; })(); + var badZoomedRects = null; + 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; + } + // KEY NAMES var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", diff --git a/test/lint/lint.js b/test/lint/lint.js index ef4c13bd9a..c2c45262a6 100644 --- a/test/lint/lint.js +++ b/test/lint/lint.js @@ -19,7 +19,7 @@ var topAllowedGlobals = Object.create(null); ("Error RegExp Number String Array Function Object Math Date undefined " + "parseInt parseFloat Infinity NaN isNaN " + "window document navigator prompt alert confirm console " + - "FileReader Worker postMessage importScripts " + + "screen FileReader Worker postMessage importScripts " + "setInterval clearInterval setTimeout clearTimeout " + "CodeMirror " + "test exports require module define") From 57761d076413ad7e49f1e45d94b122dd8dfb2c55 Mon Sep 17 00:00:00 2001 From: Jaydeep Solanki Date: Sat, 5 Jul 2014 06:06:24 +0530 Subject: [PATCH 1966/5273] [ruby mode] Better heuristic for distinguishing division from regexps --- mode/ruby/ruby.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/mode/ruby/ruby.js b/mode/ruby/ruby.js index b68ee2912a..d6c9d8796e 100644 --- a/mode/ruby/ruby.js +++ b/mode/ruby/ruby.js @@ -46,9 +46,23 @@ CodeMirror.defineMode("ruby", function(config) { var ch = stream.next(), m; if (ch == "`" || ch == "'" || ch == '"') { return chain(readQuoted(ch, "string", ch == '"' || ch == "`"), stream, state); - } else if (ch == "/" && !stream.eol() && stream.peek() != " ") { - if (stream.eat("=")) return "operator"; - return chain(readQuoted(ch, "string-2", true), stream, state); + } else if (ch == "/") { + var currentIndex = stream.current().length; + if (stream.skipTo("/")) { + var search_till = stream.current().length; + stream.backUp(stream.current().length - currentIndex); + var balance = 0; // balance brackets + while (stream.current().length < search_till) { + var chchr = stream.next(); + if (chchr == "(") balance += 1; + else if (chchr == ")") balance -= 1; + if (balance < 0) break; + } + stream.backUp(stream.current().length - currentIndex); + if (balance == 0) + return chain(readQuoted(ch, "string-2", true), stream, state); + } + return "operator"; } else if (ch == "%") { var style = "string", embed = true; if (stream.eat("s")) style = "atom"; From 347affcf2784dc8ed6e13abba517f7bd4968e715 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 7 Jul 2014 23:22:38 +0200 Subject: [PATCH 1967/5273] Handle altGr in early return from onKeyPress Issue #2671 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index cc7caace19..dcbacc258b 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3233,7 +3233,7 @@ function onKeyPress(e) { var cm = this; - if (signalDOMEvent(cm, e) || e.ctrlKey || mac && e.metaKey) return; + if (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)) || khtml) && handleKeyBinding(cm, e)) return; From 93c846bd2b3190459aed37399a3b5583d578911a Mon Sep 17 00:00:00 2001 From: binny Date: Wed, 2 Jul 2014 00:09:42 +0530 Subject: [PATCH 1968/5273] [vim] reselectSelection for visualBlock --- keymap/vim.js | 78 ++++++++++++++++++++++++++++++++---------------- test/vim_test.js | 24 ++++++++++++--- 2 files changed, 73 insertions(+), 29 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 6ff5edce4c..ab61e17afb 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1858,6 +1858,8 @@ }, // delete is a javascript keyword. 'delete': function(cm, operatorArgs, vim, curStart, curEnd) { + // Save the '>' mark before cm.replaceRange clears it. + var selectionEnd = vim.visualMode ? vim.marks['>'].find() : null; // If the ending line is past the last line, inclusive, instead of // including the trailing \n, include the \n before the starting line if (operatorArgs.linewise && @@ -1876,6 +1878,10 @@ } else { cm.replaceRange('', curStart, curEnd); } + // restore the saved bookmark + if (selectionEnd) { + vim.marks['>'] = cm.setBookmark(selectionEnd); + } if (operatorArgs.linewise) { cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm)); } else { @@ -2085,7 +2091,6 @@ curStart = cm.getCursor('anchor'); curEnd = cm.getCursor('head'); if (vim.visualLine) { - vim.visualLine = false; if (actionArgs.blockwise) { // This means Ctrl-V pressed in linewise visual vim.visualBlock = true; @@ -2097,8 +2102,8 @@ } else { exitVisualMode(cm); } + vim.visualLine = false; } else if (vim.visualBlock) { - vim.visualBlock = false; if (actionArgs.linewise) { // Shift-V pressed in blockwise visual mode vim.visualLine = true; @@ -2118,6 +2123,7 @@ } else { exitVisualMode(cm); } + vim.visualBlock = false; } else if (actionArgs.linewise) { // Shift-V pressed in characterwise visual mode. Switch to linewise // visual mode instead of exiting visual mode. @@ -2142,27 +2148,40 @@ : curStart); }, reselectLastSelection: function(cm, _actionArgs, vim) { + var curStart = vim.marks['<'].find(); + var curEnd = vim.marks['>'].find(); var lastSelection = vim.lastSelection; if (lastSelection) { - var curStart = lastSelection.curStartMark.find(); - var curEnd = lastSelection.curEndMark.find(); - cm.setSelection(curStart, curEnd); + // Set the selections as per last selection + var selectionStart = lastSelection.curStartMark.find(); + var selectionEnd = lastSelection.curEndMark.find(); + var blockwise = lastSelection.visualBlock; + // update last selection + updateLastSelection(cm, vim, curStart, curEnd); + if (blockwise) { + cm.setCursor(selectionStart); + selectionStart = selectBlock(cm, selectionEnd); + } else { + cm.setSelection(selectionStart, selectionEnd); + selectionStart = cm.getCursor('anchor'); + selectionEnd = cm.getCursor('head'); + } if (vim.visualMode) { - updateLastSelection(cm, vim); - var selectionStart = cm.getCursor('anchor'); - var selectionEnd = cm.getCursor('head'); updateMark(cm, vim, '<', cursorIsBefore(selectionStart, selectionEnd) ? selectionStart - : selectionEnd); + : selectionEnd); updateMark(cm, vim, '>', cursorIsBefore(selectionStart, selectionEnd) ? selectionEnd - : selectionStart); + : selectionStart); } + // Last selection is updated now + vim.visualMode = true; if (lastSelection.visualLine) { - vim.visualMode = true; vim.visualLine = true; - } - else { - vim.visualMode = true; + vim.visualBlock = false; + } else if (lastSelection.visualBlock) { vim.visualLine = false; + vim.visualBlock = true; + } else { + vim.visualBlock = vim.visualLine = false; } CodeMirror.signal(cm, "vim-mode-change", {mode: "visual", subMode: vim.visualLine ? "linewise" : ""}); } @@ -2552,6 +2571,10 @@ } start++; } + // Update selectionEnd and selectionStart + // after selection crossing + selectionEnd.ch = selections[0].head.ch; + selectionStart.ch = selections[0].anchor.ch; cm.setSelections(selections, primIndex); return selectionStart; } @@ -2586,22 +2609,27 @@ } return [selectionStart, selectionEnd]; } - function updateLastSelection(cm, vim) { - // We need the vim mark '<' to get the selection in case of yank and put - var selectionStart = vim.marks['<'].find() || cm.getCursor('anchor'); - var selectionEnd = vim.marks['>'].find() ||cm.getCursor('head'); - // To accommodate the effect lastPastedText in the last selection + function updateLastSelection(cm, vim, selectionStart, selectionEnd) { + if (!selectionStart || !selectionEnd) { + selectionStart = vim.marks['<'].find() || cm.getCursor('anchor'); + selectionEnd = vim.marks['>'].find() || cm.getCursor('head'); + } + // To accommodate the effect of lastPastedText in the last selection if (vim.lastPastedText) { - selectionEnd = cm.posFromIndex(cm.indexFromPos(selectionStart) + vim.lastPastedText.length-1); + selectionEnd = cm.posFromIndex(cm.indexFromPos(selectionStart) + vim.lastPastedText.length); vim.lastPastedText = null; } + var ranges = cm.listSelections(); + // This check ensures to set the cursor + // position where we left off in previous selection + var swap = getIndex(ranges, selectionStart) > -1; // can't use selection state here because yank has already reset its cursor // Also, Bookmarks make the visual selections robust to edit operations - vim.lastSelection = {'curStartMark': cm.setBookmark(selectionStart), 'curEndMark': cm.setBookmark(selectionEnd), 'visualMode': vim.visualMode, 'visualLine': vim.visualLine}; - if (cursorIsBefore(selectionEnd, selectionStart)) { - vim.lastSelection.curStartMark = cm.setBookmark(selectionEnd); - vim.lastSelection.curEndMark = cm.setBookmark(selectionStart); - } + vim.lastSelection = {'curStartMark': cm.setBookmark(swap ? selectionEnd : selectionStart), + 'curEndMark': cm.setBookmark(swap ? selectionStart : selectionEnd), + 'visualMode': vim.visualMode, + 'visualLine': vim.visualLine, + 'visualBlock': vim.visualBlock}; } function exitVisualMode(cm) { diff --git a/test/vim_test.js b/test/vim_test.js index b09d730d50..1c9e8c3c9a 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1655,7 +1655,8 @@ testVim('reselect_visual', function(cm, vim, helpers) { eq('123456\n2345\nbar', cm.getValue()); cm.setCursor(0, 0); helpers.doKeys('g', 'v'); - helpers.assertCursorAt(1, 3); + // here the fake cursor is at (1, 3) + helpers.assertCursorAt(2, 0); eqPos(makeCursor(1, 0), cm.getCursor('anchor')); helpers.doKeys('v'); cm.setCursor(2, 0); @@ -1669,17 +1670,32 @@ testVim('reselect_visual', function(cm, vim, helpers) { }, { value: '123456\nfoo\nbar' }); testVim('reselect_visual_line', function(cm, vim, helpers) { helpers.doKeys('l', 'V', 'j', 'j', 'V', 'g', 'v', 'd'); - eq('\nfoo\nand\nbar', cm.getValue()); + eq('foo\nand\nbar', cm.getValue()); cm.setCursor(1, 0); helpers.doKeys('V', 'y', 'j'); helpers.doKeys('V', 'p' , 'g', 'v', 'd'); - eq('\nfoo\nbar', cm.getValue()); + eq('foo\nand', cm.getValue()); }, { value: 'hello\nthis\nis\nfoo\nand\nbar' }); +testVim('reselect_visual_block', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('', 'k', 'h', ''); + cm.setCursor(2, 1); + helpers.doKeys('v', 'l', 'g', 'v'); + helpers.assertCursorAt(0, 1); + // Ensure selection is done with visual block mode rather than one + // continuous range. + eq(cm.getSelections().join(''), '23oo') + helpers.doKeys('g', 'v'); + helpers.assertCursorAt(2, 3); + // Ensure selection of deleted range + cm.setCursor(1, 1); + helpers.doKeys('v', '', 'j', 'd', 'g', 'v'); + eq(cm.getSelections().join(''), 'or'); +}, { value: '123456\nfoo\nbar' }); testVim('s_normal', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('s'); helpers.doInsertModeKeys('Esc'); - helpers.assertCursorAt(0, 0); eq('ac', cm.getValue()); }, { value: 'abc'}); testVim('s_visual', function(cm, vim, helpers) { From 238b451301227eb8987a4204fc726e1f1207777f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 8 Jul 2014 23:44:59 +0200 Subject: [PATCH 1969/5273] Fix broken double-checking of display coverage Both a potential infinite loop, due to updateDisplayIfNeeded not using the updated set of visibile lines, and the fact that the current check wasn't really covering changing document size, due to it happening before the call to setDocumentHeight Issue #2683 --- lib/codemirror.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index dcbacc258b..19abaf50b7 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -632,7 +632,6 @@ function postUpdateDisplay(cm, update) { var force = update.force, viewport = update.viewport; for (var first = true;; first = false) { - updateHeightsInViewport(cm); if (first && cm.options.lineWrapping && update.oldScrollerWidth != cm.display.scroller.clientWidth) { force = true; } else { @@ -643,11 +642,16 @@ cm.display.scroller.clientHeight, viewport.top)}; // Updated line heights might result in the drawn area not // actually covering the viewport. Keep looping until it does. - var visible = visibleLines(cm.display, cm.doc, viewport); - if (visible.from >= cm.display.viewFrom && visible.to <= cm.display.viewTo) + update.visible = visibleLines(cm.display, cm.doc, viewport); + if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) break; } if (!updateDisplayIfNeeded(cm, update)) break; + updateHeightsInViewport(cm); + var barMeasure = measureForScrollbars(cm); + updateSelection(cm); + setDocumentHeight(cm, barMeasure); + updateScrollbars(cm, barMeasure); } signalLater(cm, "update", cm); @@ -2023,7 +2027,7 @@ function endOperation_R2(op) { var cm = op.cm, display = cm.display; - if (op.updatedDisplay) postUpdateDisplay(cm, op.update); + if (op.updatedDisplay) updateHeightsInViewport(cm); // If the max line changed since it was last measured, measure it, // and ensure the document's width matches it. @@ -2064,6 +2068,8 @@ function endOperation_finish(op) { var cm = op.cm, display = cm.display, doc = cm.doc; + 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; From 6c0cd2b56b50837a010bd27f322a57edfbe9fee9 Mon Sep 17 00:00:00 2001 From: Richard van der Meer Date: Tue, 8 Jul 2014 11:51:35 +0200 Subject: [PATCH 1970/5273] [vbscript mode] Fixed "Cannot read property 'substr' of null" Error occurs when entering multiple dots --- mode/vbscript/vbscript.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/vbscript/vbscript.js b/mode/vbscript/vbscript.js index bff2594477..b66df2239a 100644 --- a/mode/vbscript/vbscript.js +++ b/mode/vbscript/vbscript.js @@ -291,7 +291,7 @@ CodeMirror.defineMode("vbscript", function(conf, parserConf) { style = state.tokenize(stream, state); current = stream.current(); - if (style.substr(0, 8) === 'variable' || style==='builtin' || style==='keyword'){//|| knownWords.indexOf(current.substring(1)) > -1) { + if (style && (style.substr(0, 8) === 'variable' || style==='builtin' || style==='keyword')){//|| knownWords.indexOf(current.substring(1)) > -1) { if (style === 'builtin' || style === 'keyword') style='variable'; if (knownWords.indexOf(current.substr(1)) > -1) style='variable-2'; From e92998af5dd97c771821f03c223b88442974bc6b Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Tue, 8 Jul 2014 20:35:07 -0700 Subject: [PATCH 1971/5273] [vim] Add features list to demo page --- demo/vim.html | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/demo/vim.html b/demo/vim.html index f92ff9e6d8..cc616759f0 100644 --- a/demo/vim.html +++ b/demo/vim.html @@ -45,17 +45,32 @@

    Vim bindings demo

    return (--n >= 0) ? (unsigned char) *bufp++ : EOF; } -
    - -
    +
    Key buffer:

    The vim keybindings are enabled by including keymap/vim.js and setting the vimMode option to true. This will also automatically change the keyMap option to "vim".

    +

    Features

    + +
      +
    • All common motions and operators, including text objects
    • +
    • Operator motion orthogonality
    • +
    • Visual mode - characterwise, linewise, partial support for blockwise
    • +
    • Full macro support (q, @)
    • +
    • Incremental highlighted search (/, ?, #, *, g#, g*)
    • +
    • Search/replace with confirm (:substitute, :%s)
    • +
    • Search history
    • +
    • Jump lists (Ctrl-o, Ctrl-i)
    • +
    • Key/command mapping with API (:map, :nmap, :vmap)
    • +
    • Sort (:sort)
    • +
    • Marks (`, ')
    • +
    • :global
    • +
    • Insert mode behaves identical to base CodeMirror
    • +
    • Cross-buffer yank/paste
    • +
    +

    Note that while the vim mode tries to emulate the most useful features of vim as faithfully as possible, it does not strive to become a complete vim implementation

    @@ -69,13 +84,6 @@

    Vim bindings demo

    matchBrackets: true, showCursorWhenSelecting: true }); - var editor2 = CodeMirror.fromTextArea(document.getElementById("code2"), { - lineNumbers: true, - mode: "text/x-csrc", - vimMode: true, - matchBrackets: true, - showCursorWhenSelecting: true - }); var commandDisplay = document.getElementById('command-display'); var keys = ''; CodeMirror.on(editor, 'vim-keypress', function(key) { From 770c0970cf2e3541ad21ee6fa0c7d78b21b368e0 Mon Sep 17 00:00:00 2001 From: binny Date: Wed, 9 Jul 2014 19:15:58 +0530 Subject: [PATCH 1972/5273] [vim] change for blockwise visual --- keymap/vim.js | 51 ++++++++++++++++++++++++++++++++++++------------ test/vim_test.js | 14 +++++++++++++ 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index ab61e17afb..c1b0df4683 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1831,17 +1831,39 @@ }; var operators = { - change: function(cm, operatorArgs, _vim, curStart, curEnd) { + change: function(cm, operatorArgs, vim) { + var selections = cm.listSelections(); + var start = selections[0], end = selections[selections.length-1]; + var curStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head; + var curEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor; + var text = cm.getSelection(); + var replacement = new Array(selections.length).join('1').split('1'); vimGlobalState.registerController.pushText( - operatorArgs.registerName, 'change', cm.getRange(curStart, curEnd), + operatorArgs.registerName, 'change', text, operatorArgs.linewise); if (operatorArgs.linewise) { - // Push the next line back down, if there is a next line. - var replacement = curEnd.line > cm.lastLine() ? '' : '\n'; - cm.replaceRange(replacement, curStart, curEnd); - cm.indentLine(curStart.line, 'smart'); - // null ch so setCursor moves to end of line. - curStart.ch = null; + // 'C' in visual block extends the block till eol for all lines + if (vim.visualBlock){ + var startLine = curStart.line; + while (startLine <= curEnd.line) { + var endCh = lineLength(cm, startLine); + var head = Pos(startLine, endCh); + var anchor = Pos(startLine, curStart.ch); + startLine++; + cm.replaceRange('', anchor, head); + } + } else { + // Push the next line back down, if there is a next line. + replacement = '\n'; + if (curEnd.line == curStart.line && curEnd.line == cm.lastLine()) { + replacement = ''; + } + cm.replaceRange(replacement, curStart, curEnd); + cm.indentLine(curStart.line, 'smart'); + // null ch so setCursor moves to end of line. + curStart.ch = null; + cm.setCursor(curStart); + } } else { // Exclude trailing whitespace if the range is not all whitespace. var text = cm.getRange(curStart, curEnd); @@ -1851,15 +1873,20 @@ curEnd = offsetCursor(curEnd, 0, - match[0].length); } } - cm.replaceRange('', curStart, curEnd); + if (vim.visualBlock) { + cm.replaceSelections(replacement); + } else { + cm.setCursor(curStart); + cm.replaceRange('', curStart, curEnd); + } } actions.enterInsertMode(cm, {}, cm.state.vim); - cm.setCursor(curStart); }, // delete is a javascript keyword. 'delete': function(cm, operatorArgs, vim, curStart, curEnd) { // Save the '>' mark before cm.replaceRange clears it. var selectionEnd = vim.visualMode ? vim.marks['>'].find() : null; + var text = cm.getSelection(); // If the ending line is past the last line, inclusive, instead of // including the trailing \n, include the \n before the starting line if (operatorArgs.linewise && @@ -1868,7 +1895,7 @@ curStart.ch = lineLength(cm, curStart.line); } vimGlobalState.registerController.pushText( - operatorArgs.registerName, 'delete', cm.getRange(curStart, curEnd), + operatorArgs.registerName, 'delete', text, operatorArgs.linewise); if (vim.visualBlock) { var selections = cm.listSelections(); @@ -1926,8 +1953,6 @@ var curStart = ranges[0].anchor; var curEnd = ranges[0].head; if (!operatorArgs.shouldMoveCursor) { - // extendSelection swaps curStart and curEnd, so make sure - // curStart < curEnd cm.setCursor(cursorIsBefore(curStart, curEnd) ? curStart : curEnd); } }, diff --git a/test/vim_test.js b/test/vim_test.js index 1c9e8c3c9a..76a2699780 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -895,6 +895,20 @@ testVim('cc_append', function(cm, vim, helpers) { helpers.doKeys('c', 'c'); eq(expectedLineCount, cm.lineCount()); }); +testVim('c_visual_block', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('', '2', 'j', 'l', 'l', 'l', 'c'); + var replacement = new Array(cm.listSelections().length+1).join('hello ').split(' '); + replacement.pop(); + cm.replaceSelections(replacement); + eq('1hello\n5hello\nahellofg', cm.getValue()); + cm.setCursor(2, 3); + helpers.doKeys('', '2', 'k', 'h', 'C'); + replacement = new Array(cm.listSelections().length+1).join('world ').split(' '); + replacement.pop(); + cm.replaceSelections(replacement); + eq('1hworld\n5hworld\nahworld', cm.getValue()); +}, {value: '1234\n5678\nabcdefg'}); // Swapcase commands edit in place and do not modify registers. testVim('g~w_repeat', function(cm, vim, helpers) { // Assert that dw does delete newline if it should go to the next line, and From 5285494ab15ba444bc95f956c389502796b0bce1 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 11 Jul 2014 08:51:22 +0200 Subject: [PATCH 1973/5273] Ignore auto indentation beyond column 80 Issue #2688 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 19abaf50b7..49fd45a084 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3812,7 +3812,7 @@ how = "not"; } else if (how == "smart") { indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); - if (indentation == Pass) { + if (indentation == Pass || indentation > 80) { if (!aggressive) return; how = "prev"; } From ce7536377698f682eaf3959408c70df665f690cf Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 11 Jul 2014 08:56:12 +0200 Subject: [PATCH 1974/5273] Bump indentation-ignoring threshold to 150 You might actually want to align things on long lines Issue #2688 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 49fd45a084..ad77be2cb9 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3812,7 +3812,7 @@ how = "not"; } else if (how == "smart") { indentation = cm.doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); - if (indentation == Pass || indentation > 80) { + if (indentation == Pass || indentation > 150) { if (!aggressive) return; how = "prev"; } From ae978a7e9372f7bae489510c68740741dfe67e05 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 11 Jul 2014 11:20:31 +0200 Subject: [PATCH 1975/5273] Bind Cmd-Home to goDocStart on Mac Closes #2687 --- doc/manual.html | 2 +- lib/codemirror.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 2deb8422a5..490143e31b 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -815,7 +815,7 @@

    Commands

    Redo the last change to the selection, or the last text change if no selection changes remain.
    -
    goDocStartCtrl-Up (PC), Cmd-Up (Mac)
    +
    goDocStartCtrl-Up (PC), Cmd-Up (Mac), Cmd-Home (Mac)
    Move the cursor to the start of the document.
    goDocEndCtrl-Down (PC), Cmd-End (Mac), Cmd-Down (Mac)
    diff --git a/lib/codemirror.js b/lib/codemirror.js index ad77be2cb9..bf5d6baa2e 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4824,7 +4824,7 @@ }; keyMap.macDefault = { "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", - "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", + "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", "Alt-Right": "goGroupRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delGroupBefore", "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", From 0b3d49f4cfc458d481a21b38d7be44fb48c1b46f Mon Sep 17 00:00:00 2001 From: Tim Alby Date: Thu, 10 Jul 2014 17:31:43 +0100 Subject: [PATCH 1976/5273] Fix key-binding behaviour on Mac in wrap mode Bind Cmd-Left to goLineLeft and Cmd-right to goLineRight instead of goLineStart and goLineEnd Create and bind delVisualLeft and delVisualRight to Cmd-Backspace and Cmd-Delete --- doc/manual.html | 16 +++++++++++----- lib/codemirror.js | 18 ++++++++++++++++-- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 490143e31b..ed0d076a9f 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -797,9 +797,15 @@

    Commands

    deleteLineCtrl-D (PC), Cmd-D (Mac)
    Deletes the whole line under the cursor, including newline at the end.
    -
    delLineLeftCmd-Backspace (Mac)
    +
    delLineLeft
    Delete the part of the line before the cursor.
    +
    delWrappedLineLeftCmd-Backspace (Mac)
    +
    Delete the part of the line from the left side of the visual line the cursor is on to the cursor.
    + +
    delWrappedLineRightCmd-Delete (Mac)
    +
    Delete the part of the line from the cursor to the right side of the visual line the cursor is on.
    +
    undoCtrl-Z (PC), Cmd-Z (Mac)
    Undo the last change.
    @@ -821,7 +827,7 @@

    Commands

    goDocEndCtrl-Down (PC), Cmd-End (Mac), Cmd-Down (Mac)
    Move the cursor to the end of the document.
    -
    goLineStartAlt-Left (PC), Cmd-Left (Mac), Ctrl-A (Mac)
    +
    goLineStartAlt-Left (PC), Ctrl-A (Mac)
    Move the cursor to the start of the line.
    goLineStartSmartHome
    @@ -829,14 +835,14 @@

    Commands

    already there, to the actual start of the line (including whitespace). -
    goLineEndAlt-Right (PC), Cmd-Right (Mac), Ctrl-E (Mac)
    +
    goLineEndAlt-Right (PC), Ctrl-E (Mac)
    Move the cursor to the end of the line.
    -
    goLineLeft
    +
    goLineLeftCmd-Left (Mac)
    Move the cursor to the left side of the visual line it is on. If this line is wrapped, that may not be the start of the line.
    -
    goLineRight
    +
    goLineRightCmd-Right (Mac)
    Move the cursor to the right side of the visual line it is on.
    goLineUpUp, Ctrl-P (Mac)
    diff --git a/lib/codemirror.js b/lib/codemirror.js index bf5d6baa2e..3fef17d95e 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4687,6 +4687,20 @@ 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()}; + }); + }, + 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();}, @@ -4825,10 +4839,10 @@ 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", - "Alt-Right": "goGroupRight", "Cmd-Left": "goLineStart", "Cmd-Right": "goLineEnd", "Alt-Backspace": "delGroupBefore", + "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", - "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delLineLeft", + "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", fallthrough: ["basic", "emacsy"] }; From 0392fd3bb51fe8b2ac0f385ff12e18299900630d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 11 Jul 2014 11:55:55 +0200 Subject: [PATCH 1977/5273] Catch and suppress input of certain code point on Mac Ctrl-arrow key presses were, for some reason, inserting such characters into our textarea. Issue #2689 --- lib/codemirror.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 3fef17d95e..f52f7865c6 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2388,8 +2388,11 @@ var text = input.value; // If nothing changed, bail. if (text == prevInput && !cm.somethingSelected()) return false; - // Work around nonsensical selection resetting in IE9/10 - if (ie && ie_version >= 9 && cm.display.inputHasSelection === text) { + // 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 && cm.display.inputHasSelection === text || + mac && /[\uf700-\uf7ff]/.test(text)) { resetInput(cm); return false; } From f02df0b41300a1069ab5e0e3ebae3431b6b507b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Abdelkader=20Mart=C3=ADnez=20P=C3=A9rez?= Date: Sun, 6 Jul 2014 04:30:44 +0200 Subject: [PATCH 1978/5273] [lint addon] Do not constrain severity names Issue #2681 --- addon/lint/lint.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 604e2e6058..a87e70c09e 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -11,7 +11,6 @@ })(function(CodeMirror) { "use strict"; var GUTTER_ID = "CodeMirror-lint-markers"; - var SEVERITIES = /^(?:error|warning)$/; function showTooltip(e, content) { var tt = document.createElement("div"); @@ -110,7 +109,7 @@ function annotationTooltip(ann) { var severity = ann.severity; - if (!SEVERITIES.test(severity)) severity = "error"; + if (!severity) severity = "error"; var tip = document.createElement("div"); tip.className = "CodeMirror-lint-message-" + severity; tip.appendChild(document.createTextNode(ann.message)); @@ -141,7 +140,7 @@ for (var i = 0; i < anns.length; ++i) { var ann = anns[i]; var severity = ann.severity; - if (!SEVERITIES.test(severity)) severity = "error"; + if (!severity) severity = "error"; maxSeverity = getMaxSeverity(maxSeverity, severity); if (options.formatAnnotation) ann = options.formatAnnotation(ann); From 13acf661b6976badca64e69861f054111757084b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 14 Jul 2014 11:07:30 +0200 Subject: [PATCH 1979/5273] Don't treat %= as the start of a string Closes #2692 --- 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 d6c9d8796e..e7de7b57f1 100644 --- a/mode/ruby/ruby.js +++ b/mode/ruby/ruby.js @@ -69,7 +69,7 @@ CodeMirror.defineMode("ruby", function(config) { else if (stream.eat(/[WQ]/)) style = "string"; else if (stream.eat(/[r]/)) style = "string-2"; else if (stream.eat(/[wxq]/)) { style = "string"; embed = false; } - var delim = stream.eat(/[^\w\s]/); + var delim = stream.eat(/[^\w\s=]/); if (!delim) return "operator"; if (matching.propertyIsEnumerable(delim)) delim = matching[delim]; return chain(readQuoted(delim, style, embed, true), stream, state); From f4ae5b42c929edc78c2df0888ae1b0179098652a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 15 Jul 2014 11:13:36 +0200 Subject: [PATCH 1980/5273] Track last copied text, in order to find selection boundaries on paste Issue #2697 --- lib/codemirror.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index f52f7865c6..fcaaab28bd 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2366,6 +2366,11 @@ cm.display.poll.set(20, p); } + // This will be set to an array of strings when copying, so that, + // when pasting, we know what kind of selections the copied text + // was made out of. + var lastCopied = null; + // Read input from the textarea, and update the document to match. // When something is selected, it is present in the textarea, and // selected (unless it is huge, in which case a placeholder is @@ -2409,7 +2414,13 @@ var inserted = text.slice(same), textLines = splitLines(inserted); // When pasing N lines into N selections, insert one line per selection - var multiPaste = cm.state.pasteIncoming && textLines.length > 1 && doc.sel.ranges.length == textLines.length; + var multiPaste = null; + if (cm.state.pasteIncoming && doc.sel.ranges.length > 1) { + if (lastCopied && lastCopied.join("\n") == inserted) + multiPaste = lastCopied.length == doc.sel.ranges.length && map(lastCopied, splitLines); + else if (textLines.length == doc.sel.ranges.length) + multiPaste = map(textLines, function(l) { return [l]; }); + } // Normal behavior is to insert the new text into every selection for (var i = doc.sel.ranges.length - 1; i >= 0; i--) { @@ -2422,7 +2433,7 @@ else if (cm.state.overwrite && range.empty() && !cm.state.pasteIncoming) to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); var updateInput = cm.curOp.updateInput; - var changeEvent = {from: from, to: to, text: multiPaste ? [textLines[i]] : textLines, + var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i] : textLines, origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"}; makeChange(cm.doc, changeEvent); signalLater(cm, "inputRead", cm, changeEvent); @@ -2589,27 +2600,29 @@ function prepareCopyCut(e) { if (cm.somethingSelected()) { + lastCopied = cm.getSelections(); if (d.inaccurateSelection) { d.prevInput = ""; d.inaccurateSelection = false; - d.input.value = cm.getSelection(); + d.input.value = lastCopied.join("\n"); selectInput(d.input); } } else { - 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 += cm.getRange(lineRange.anchor, lineRange.head); + text.push(cm.getRange(lineRange.anchor, lineRange.head)); } if (e.type == "cut") { cm.setSelections(ranges, null, sel_dontScroll); } else { d.prevInput = ""; - d.input.value = text; + d.input.value = text.join("\n"); selectInput(d.input); } + lastCopied = text; } if (e.type == "cut") cm.state.cutIncoming = true; } From bc87689c02950857049470355f20e8a29eb19639 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 16 Jul 2014 10:04:41 +0200 Subject: [PATCH 1981/5273] Remove unused extra argument to computeSelAfterChange --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index fcaaab28bd..0aad3fda68 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3549,7 +3549,7 @@ antiChanges.push(historyChangeFromChange(doc, change)); - var after = i ? computeSelAfterChange(doc, change, null) : lst(source); + var after = i ? computeSelAfterChange(doc, change) : lst(source); makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); if (!i && doc.cm) doc.cm.scrollIntoView(change); var rebased = []; @@ -3608,7 +3608,7 @@ change.removed = getBetween(doc, change.from, change.to); - if (!selAfter) selAfter = computeSelAfterChange(doc, change, null); + if (!selAfter) selAfter = computeSelAfterChange(doc, change); if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans); else updateDoc(doc, change, spans); setSelectionNoUndo(doc, selAfter, sel_dontScroll); From 59138ec896618d730046fda7002d57eef02bd6a8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 16 Jul 2014 12:55:59 +0200 Subject: [PATCH 1982/5273] [javascript mode] Indent properly in case of function arg in wrapped arg list --- mode/javascript/javascript.js | 2 ++ mode/javascript/test.js | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 315674be74..fdb066eb1f 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -298,6 +298,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { var result = function() { var state = cx.state, indent = state.indented; if (state.lexical.type == "stat") indent = state.lexical.indented; + else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev) + indent = outer.indented; state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info); }; result.lex = true; diff --git a/mode/javascript/test.js b/mode/javascript/test.js index a9cc993d3d..77cc695fef 100644 --- a/mode/javascript/test.js +++ b/mode/javascript/test.js @@ -128,6 +128,12 @@ " [keyword else]", " [number 3];"); + MT("indent_funarg", + "[variable foo]([number 10000],", + " [keyword function]([def a]) {", + " [keyword debugger];", + "};"); + MT("indent_below_if", "[keyword for] (;;)", " [keyword if] ([variable foo])", From 2fa988d3b46d47a732bdbf6d5ac1f52f49b6a6e0 Mon Sep 17 00:00:00 2001 From: Sander AKA Redsandro Date: Thu, 17 Jul 2014 16:44:50 +0200 Subject: [PATCH 1983/5273] Disable replace for readOnly content Disable the `replace()` when the selected `CodeMirror` is `readOnly`. --- addon/search/search.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addon/search/search.js b/addon/search/search.js index 3ce7cc95d8..b177dce6ed 100644 --- a/addon/search/search.js +++ b/addon/search/search.js @@ -110,6 +110,7 @@ var replacementQueryDialog = 'With: '; var doReplaceConfirm = "Replace? "; function replace(cm, all) { + if (cm.getOption("readOnly")) return; dialog(cm, replaceQueryDialog, "Replace:", cm.getSelection(), function(query) { if (!query) return; query = parseQuery(query); From ddd36cb0b085358e797cd64ff08ed819005b9f60 Mon Sep 17 00:00:00 2001 From: binny Date: Sat, 5 Jul 2014 07:02:00 +0530 Subject: [PATCH 1984/5273] [vim] visual block replace --- keymap/vim.js | 33 ++++++++++++++++++++++----------- test/vim_test.js | 13 +++++++++++++ 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index c1b0df4683..b239929f07 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2370,10 +2370,11 @@ var curStart = cm.getCursor(); var replaceTo; var curEnd; - if (vim.visualMode){ - curStart=cm.getCursor('start'); - curEnd=cm.getCursor('end'); - }else{ + var selections = cm.listSelections(); + if (vim.visualMode) { + curStart = cm.getCursor('start'); + curEnd = cm.getCursor('end'); + } else { var line = cm.getLine(curStart.line); replaceTo = curStart.ch + actionArgs.repeat; if (replaceTo > line.length) { @@ -2381,19 +2382,29 @@ } curEnd = Pos(curStart.line, replaceTo); } - if (replaceWith=='\n'){ + if (replaceWith=='\n') { if (!vim.visualMode) cm.replaceRange('', curStart, curEnd); // special case, where vim help says to replace by just one line-break (CodeMirror.commands.newlineAndIndentContinueComment || CodeMirror.commands.newlineAndIndent)(cm); - }else { - var replaceWithStr=cm.getRange(curStart, curEnd); + } else { + var replaceWithStr = cm.getRange(curStart, curEnd); //replace all characters in range by selected, but keep linebreaks - replaceWithStr=replaceWithStr.replace(/[^\n]/g,replaceWith); - cm.replaceRange(replaceWithStr, curStart, curEnd); - if (vim.visualMode){ + replaceWithStr = replaceWithStr.replace(/[^\n]/g, replaceWith); + if (vim.visualBlock) { + // Tabs are split in visua block before replacing + var spaces = new Array(cm.options.tabSize+1).join(' '); + replaceWithStr = cm.getSelection(); + replaceWithStr = replaceWithStr.replace(/\t/g, spaces).replace(/[^\n]/g, replaceWith).split('\n'); + cm.replaceSelections(replaceWithStr); + } else { + cm.replaceRange(replaceWithStr, curStart, curEnd); + } + if (vim.visualMode) { + curStart = cursorIsBefore(selections[0].anchor, selections[0].head) ? + selections[0].anchor : selections[0].head; cm.setCursor(curStart); exitVisualMode(cm); - }else{ + } else { cm.setCursor(offsetCursor(curEnd, 0, -1)); } } diff --git a/test/vim_test.js b/test/vim_test.js index 76a2699780..342737de52 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1332,6 +1332,19 @@ testVim('r', function(cm, vim, helpers) { helpers.doKeys('v', 'j', 'h', 'r', ''); eq('wuuu \n her', cm.getValue(),'Replacing selection by space-characters failed'); }, { value: 'wordet\nanother' }); +testVim('r_visual_block', function(cm, vim, helpers) { + cm.setCursor(2, 3); + helpers.doKeys('', 'k', 'k', 'h', 'h', 'r', 'l'); + eq('1lll\n5lll\nalllefg', cm.getValue()); + helpers.doKeys('', 'l', 'j', 'r', ''); + eq('1 l\n5 l\nalllefg', cm.getValue()); + cm.setCursor(2, 0); + helpers.doKeys('o'); + helpers.doInsertModeKeys('Esc'); + cm.replaceRange('\t\t', cm.getCursor()); + helpers.doKeys('', 'h', 'h', 'r', 'r'); + eq('1 l\n5 l\nalllefg\nrrrrrrrr', cm.getValue()); +}, {value: '1234\n5678\nabcdefg'}); testVim('R', function(cm, vim, helpers) { cm.setCursor(0, 1); helpers.doKeys('R'); From bce69920dfdce2b5eeb910bf7a7cff147a3bd5ca Mon Sep 17 00:00:00 2001 From: binny Date: Tue, 15 Jul 2014 05:32:25 +0530 Subject: [PATCH 1985/5273] [vim] changeCase for blockwise visual --- keymap/vim.js | 89 +++++++++++++++++++++++++++++++++++------------- test/vim_test.js | 16 +++++++-- 2 files changed, 79 insertions(+), 26 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index b239929f07..e7bb885bf2 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2348,6 +2348,9 @@ } } cm.setCursor(curPosFinal); + if (vim.visualMode) { + exitVisualMode(cm); + } }, undo: function(cm, actionArgs) { cm.operation(function() { @@ -2449,17 +2452,26 @@ repeatLastEdit(cm, vim, repeat, false /** repeatForInsert */); }, changeCase: function(cm, actionArgs, vim) { - var selectedAreaRange = getSelectedAreaRange(cm, vim); - var selectionStart = selectedAreaRange[0]; - var selectionEnd = selectedAreaRange[1]; + var selectionStart = getSelectedAreaRange(cm, vim)[0]; + var text = cm.getSelection(); + var lastSelectionCurEnd; + var blockSelection; + if (vim.lastSelection) { // save the curEnd marker to avoid its removal due to cm.replaceRange - var lastSelectionCurEnd = vim.lastSelection.curEndMark.find(); + lastSelectionCurEnd = vim.lastSelection.curEndMark.find(); + blockSelection = vim.lastSelection.visualBlock; + } var toLower = actionArgs.toLower; - var text = cm.getRange(selectionStart, selectionEnd); - cm.replaceRange(toLower ? text.toLowerCase() : text.toUpperCase(), selectionStart, selectionEnd); + text = toLower ? text.toLowerCase() : text.toUpperCase(); + cm.replaceSelections(vim.visualBlock || blockSelection ? text.split('\n') : [text]); // restore the last selection curEnd marker - vim.lastSelection.curEndMark = cm.setBookmark(lastSelectionCurEnd); + if (lastSelectionCurEnd) { + vim.lastSelection.curEndMark = cm.setBookmark(lastSelectionCurEnd); + } cm.setCursor(selectionStart); + if (vim.visualMode) { + exitVisualMode(cm); + } } }; @@ -2623,27 +2635,56 @@ return -1; } function getSelectedAreaRange(cm, vim) { - var selectionStart = cm.getCursor('anchor'); - var selectionEnd = cm.getCursor('head'); var lastSelection = vim.lastSelection; - if (!vim.visualMode) { - var lastSelectionCurStart = vim.lastSelection.curStartMark.find(); - var lastSelectionCurEnd = vim.lastSelection.curEndMark.find(); - var line = lastSelectionCurEnd.line - lastSelectionCurStart.line; - var ch = line ? lastSelectionCurEnd.ch : lastSelectionCurEnd.ch - lastSelectionCurStart.ch; - selectionEnd = {line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch}; - if (lastSelection.visualLine) { - return [{line: selectionStart.line, ch: 0}, {line: selectionEnd.line, ch: lineLength(cm, selectionEnd.line)}]; + var getCurrentSelectedAreaRange = function() { + var selections = cm.listSelections(); + var start = selections[0]; + var end = selections[selections.length-1]; + var selectionStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head; + var selectionEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor; + return [selectionStart, selectionEnd]; + }; + var getLastSelectedAreaRange = function() { + var start = lastSelection.curStartMark.find(); + var end = lastSelection.curEndMark.find(); + var selectionStart = cm.getCursor(); + var selectionEnd = cm.getCursor(); + if (lastSelection.visualBlock) { + var anchor = Pos(Math.min(start.line, end.line), Math.min(start.ch, end.ch)); + var head = Pos(Math.max(start.line, end.line), Math.max(start.ch, end.ch)); + var width = head.ch - anchor.ch; + var height = head.line - anchor.line; + selectionEnd = Pos(selectionStart.line + height, selectionStart.ch + width); + var endCh = cm.clipPos(selectionEnd).ch; + // We do not want selection crossing while selecting here. + // So, we cut down the selection. + while (endCh != selectionEnd.ch) { + if (endCh-1 == selectionStart.ch) { + break; + } + selectionEnd.line--; + endCh = cm.clipPos(selectionEnd).ch; + } + cm.setCursor(selectionStart); + selectBlock(cm, selectionEnd); + } else { + var line = end.line - start.line; + var ch = end.ch - start.ch; + selectionEnd = {line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch}; + if (lastSelection.visualLine) { + selectionStart = Pos(selectionStart.line, 0); + selectionEnd = Pos(selectionEnd.line, lineLength(cm, selectionEnd.line)); + } + cm.setSelection(selectionStart, selectionEnd); } + return [selectionStart, selectionEnd]; + }; + if (!vim.visualMode) { + // In case of replaying the action. + return getLastSelectedAreaRange(); } else { - if (cursorIsBefore(selectionEnd, selectionStart)) { - var tmp = selectionStart; - selectionStart = selectionEnd; - selectionEnd = tmp; - } - exitVisualMode(cm); + return getCurrentSelectedAreaRange(); } - return [selectionStart, selectionEnd]; } function updateLastSelection(cm, vim, selectionStart, selectionEnd) { if (!selectionStart || !selectionEnd) { diff --git a/test/vim_test.js b/test/vim_test.js index 342737de52..2fb1843169 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1683,7 +1683,7 @@ testVim('reselect_visual', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('g', 'v'); // here the fake cursor is at (1, 3) - helpers.assertCursorAt(2, 0); + helpers.assertCursorAt(1, 4); eqPos(makeCursor(1, 0), cm.getCursor('anchor')); helpers.doKeys('v'); cm.setCursor(2, 0); @@ -1753,7 +1753,7 @@ testVim('o_visual_block', function(cm, vim, helpers) { helpers.doKeys('o'); helpers.assertCursorAt(3, 1); }, { value: 'abcd\nefgh\nijkl\nmnop'}); -testVim('uppercase/lowercase_visual', function(cm, vim, helpers) { +testVim('changeCase_visual', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('v', 'l', 'l'); helpers.doKeys('U'); @@ -1772,6 +1772,18 @@ testVim('uppercase/lowercase_visual', function(cm, vim, helpers) { helpers.doKeys('V', 'U', 'j', '.'); eq('ABCDEF\nGHIJKL\nMnopq\nSHORT LINE\nLONG LINE OF TEXT', cm.getValue()); }, { value: 'abcdef\nghijkl\nmnopq\nshort line\nlong line of text'}); +testVim('changeCase_visual_block', function(cm, vim, helpers) { + cm.setCursor(2, 1); + helpers.doKeys('', 'k', 'k', 'h', 'U'); + eq('ABcdef\nGHijkl\nMNopq\nfoo', cm.getValue()); + cm.setCursor(0, 2); + helpers.doKeys('.'); + eq('ABCDef\nGHIJkl\nMNOPq\nfoo', cm.getValue()); + // check when last line is shorter. + cm.setCursor(2, 2); + helpers.doKeys('.'); + eq('ABCDef\nGHIJkl\nMNOPq\nfoO', cm.getValue()); +}, { value: 'abcdef\nghijkl\nmnopq\nfoo'}); testVim('visual_paste', function(cm, vim, helpers) { cm.setCursor(0, 0); helpers.doKeys('v', 'l', 'l', 'y', 'j', 'v', 'l', 'p'); From 9312c712a80d665e569e29ea8448e6bb52c03b69 Mon Sep 17 00:00:00 2001 From: binny Date: Fri, 18 Jul 2014 05:30:15 +0530 Subject: [PATCH 1986/5273] [vim] using dot to replay actions and operators --- keymap/vim.js | 111 ++++++++++++++++++++++++++++++++--------------- test/vim_test.js | 17 +++++++- 2 files changed, 92 insertions(+), 36 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index e7bb885bf2..16f51b3bf1 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1411,6 +1411,7 @@ if (operator) { var inverted = false; vim.lastMotion = null; + var lastSelection = vim.lastSelection; operatorArgs.repeat = repeat; // Indent in visual mode needs this. if (vim.visualMode) { curStart = selectionStart; @@ -1437,6 +1438,24 @@ curEnd.line = curStart.line + operatorArgs.selOffset.line; if (operatorArgs.selOffset.line) {curEnd.ch = operatorArgs.selOffset.ch; } else { curEnd.ch = curStart.ch + operatorArgs.selOffset.ch; } + // In case of blockwise visual + if (lastSelection && lastSelection.visualBlock) { + var block = lastSelection.visualBlock; + var width = block.width; + var height = block.height; + curEnd = Pos(curStart.line + height, curStart.ch + width); + // selectBlock creates a 'proper' rectangular block. + // We do not want that in all cases, so we manually set selections. + var selections = []; + for (var i = curStart.line; i < curEnd.line; i++) { + var anchor = Pos(i, curStart.ch); + var head = Pos(i, curEnd.ch); + var range = {anchor: anchor, head: head}; + selections.push(range); + } + cm.setSelections(selections); + var blockSelected = true; + } } else if (vim.visualMode) { var selOffset = Pos(); selOffset.line = curEnd.line - curStart.line; @@ -1457,8 +1476,8 @@ operatorArgs.registerName = registerName; // Keep track of linewise as it affects how paste and change behave. operatorArgs.linewise = linewise; - if (!vim.visualBlock) { - cm.extendSelection(curStart, curEnd); + if (!vim.visualBlock && !blockSelected) { + cm.setSelection(curStart, curEnd); } operators[operator](cm, operatorArgs, vim, curStart, curEnd, curOriginal); @@ -1838,6 +1857,8 @@ var curEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor; var text = cm.getSelection(); var replacement = new Array(selections.length).join('1').split('1'); + // save the selectionEnd mark + var selectionEnd = vim.marks['>'] ? vim.marks['>'].find() : cm.getCursor('head'); vimGlobalState.registerController.pushText( operatorArgs.registerName, 'change', text, operatorArgs.linewise); @@ -1880,34 +1901,52 @@ cm.replaceRange('', curStart, curEnd); } } + vim.marks['>'] = cm.setBookmark(selectionEnd); actions.enterInsertMode(cm, {}, cm.state.vim); }, // delete is a javascript keyword. - 'delete': function(cm, operatorArgs, vim, curStart, curEnd) { + 'delete': function(cm, operatorArgs, vim) { + var selections = cm.listSelections(); + var start = selections[0], end = selections[selections.length-1]; + var curStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head; + var curEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor; // Save the '>' mark before cm.replaceRange clears it. - var selectionEnd = vim.visualMode ? vim.marks['>'].find() : null; + var selectionEnd, selectionStart; + if (vim.visualMode) { + selectionEnd = vim.marks['>'].find(); + selectionStart = vim.marks['<'].find(); + } else if (vim.lastSelection) { + selectionEnd = vim.lastSelection.curStartMark.find(); + selectionStart = vim.lastSelection.curEndMark.find(); + } var text = cm.getSelection(); + vimGlobalState.registerController.pushText( + operatorArgs.registerName, 'delete', text, + operatorArgs.linewise); + var replacement = new Array(selections.length).join('1').split('1'); // If the ending line is past the last line, inclusive, instead of // including the trailing \n, include the \n before the starting line if (operatorArgs.linewise && - curEnd.line > cm.lastLine() && curStart.line > cm.firstLine()) { + curEnd.line == cm.lastLine() && curStart.line == curEnd.line) { + var tmp = copyCursor(curEnd); curStart.line--; curStart.ch = lineLength(cm, curStart.line); - } - vimGlobalState.registerController.pushText( - operatorArgs.registerName, 'delete', text, - operatorArgs.linewise); - if (vim.visualBlock) { - var selections = cm.listSelections(); - curStart = selections[0].anchor; - var replacement = new Array(selections.length).join('1').split('1'); - cm.replaceSelections(replacement); - } else { + curEnd = tmp; cm.replaceRange('', curStart, curEnd); + } else { + cm.replaceSelections(replacement); } // restore the saved bookmark if (selectionEnd) { - vim.marks['>'] = cm.setBookmark(selectionEnd); + var curStartMark = cm.setBookmark(selectionStart); + var curEndMark = cm.setBookmark(selectionEnd); + if (vim.visualMode) { + vim.marks['<'] = curStartMark; + vim.marks['>'] = curEndMark; + } else { + vim.lastSelection.curStartMark = curStartMark; + vim.lastSelection.curEndMark = curEndMark; + } } if (operatorArgs.linewise) { cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm)); @@ -2645,29 +2684,26 @@ return [selectionStart, selectionEnd]; }; var getLastSelectedAreaRange = function() { - var start = lastSelection.curStartMark.find(); - var end = lastSelection.curEndMark.find(); var selectionStart = cm.getCursor(); var selectionEnd = cm.getCursor(); - if (lastSelection.visualBlock) { - var anchor = Pos(Math.min(start.line, end.line), Math.min(start.ch, end.ch)); - var head = Pos(Math.max(start.line, end.line), Math.max(start.ch, end.ch)); - var width = head.ch - anchor.ch; - var height = head.line - anchor.line; + var block = lastSelection.visualBlock; + if (block) { + var width = block.width; + var height = block.height; selectionEnd = Pos(selectionStart.line + height, selectionStart.ch + width); - var endCh = cm.clipPos(selectionEnd).ch; - // We do not want selection crossing while selecting here. - // So, we cut down the selection. - while (endCh != selectionEnd.ch) { - if (endCh-1 == selectionStart.ch) { - break; - } - selectionEnd.line--; - endCh = cm.clipPos(selectionEnd).ch; + var selections = []; + // selectBlock creates a 'proper' rectangular block. + // We do not want that in all cases, so we manually set selections. + for (var i = selectionStart.line; i < selectionEnd.line; i++) { + var anchor = Pos(i, selectionStart.ch); + var head = Pos(i, selectionEnd.ch); + var range = {anchor: anchor, head: head}; + selections.push(range); } - cm.setCursor(selectionStart); - selectBlock(cm, selectionEnd); + cm.setSelections(selections); } else { + var start = lastSelection.curStartMark.find(); + var end = lastSelection.curEndMark.find(); var line = end.line - start.line; var ch = end.ch - start.ch; selectionEnd = {line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch}; @@ -2700,13 +2736,18 @@ // This check ensures to set the cursor // position where we left off in previous selection var swap = getIndex(ranges, selectionStart) > -1; + if (vim.visualBlock) { + var height = Math.abs(selectionStart.line - selectionEnd.line)+1; + var width = Math.abs(selectionStart.ch - selectionEnd.ch); + var block = {height: height, width: width}; + } // can't use selection state here because yank has already reset its cursor // Also, Bookmarks make the visual selections robust to edit operations vim.lastSelection = {'curStartMark': cm.setBookmark(swap ? selectionEnd : selectionStart), 'curEndMark': cm.setBookmark(swap ? selectionStart : selectionEnd), 'visualMode': vim.visualMode, 'visualLine': vim.visualLine, - 'visualBlock': vim.visualBlock}; + 'visualBlock': block}; } function exitVisualMode(cm) { diff --git a/test/vim_test.js b/test/vim_test.js index 2fb1843169..7c24634a89 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -944,7 +944,22 @@ testVim('visual_block_~', function(cm, vim, helpers) { helpers.assertCursorAt(2, 0); eq('hello\nwoRLd\nAbcDe', cm.getValue()); },{value: 'hello\nwOrld\nabcde' }); - +testVim('._swapCase_visualBlock', function(cm, vim, helpers) { + helpers.doKeys('', 'j', 'j', 'l', '~'); + cm.setCursor(0, 3); + helpers.doKeys('.'); + eq('HelLO\nWorLd\nAbcdE', cm.getValue()); +},{value: 'hEllo\nwOrlD\naBcDe' }); +testVim('._delete_visualBlock', function(cm, vim, helpers) { + helpers.doKeys('', 'j', 'x'); + eq('ive\ne\nsome\nsugar', cm.getValue()); + helpers.doKeys('.'); + eq('ve\n\nsome\nsugar', cm.getValue()); + helpers.doKeys('j', 'j', '.'); + eq('ve\n\nome\nugar', cm.getValue()); + helpers.doKeys('u', '', '.'); + eq('ve\n\nme\ngar', cm.getValue()); +},{value: 'give\nme\nsome\nsugar' }); testVim('>{motion}', function(cm, vim, helpers) { cm.setCursor(1, 3); var expectedLineCount = cm.lineCount(); From 252a9d6cb8afd782762bf10c75760cbbd75a5c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20Mass=C3=A9?= Date: Sat, 12 Jul 2014 20:20:08 -0400 Subject: [PATCH 1987/5273] [clike mode] Enable multilineString for scala It is a good approximation --- mode/clike/clike.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 3e253624b4..2873e3629b 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -369,6 +369,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { ), + multiLineStrings: true, blockKeywords: words("catch class do else finally for forSome if match switch try while"), atoms: words("true false null"), hooks: { From 58d2a8a8b28e6f45ca98729952870de92184cf05 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 20 Jul 2014 09:34:51 +0200 Subject: [PATCH 1988/5273] [yaml mode] Be less restrictive about keys in front of colons Issue #2695 --- 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 4ebe5c81cf..15a5916df1 100644 --- a/mode/yaml/yaml.js +++ b/mode/yaml/yaml.js @@ -80,7 +80,7 @@ CodeMirror.defineMode("yaml", function() { } /* pairs (associative arrays) -> key */ - if (!state.pair && stream.match(/^\s*\S+(?=\s*:($|\s))/i)) { + if (!state.pair && stream.match(/^\s*[^\-:{}"\[\]][^:{}"\[\]]*(?=\s*:($|\s))/i)) { state.pair = true; state.keyCol = stream.indentation(); return "atom"; From dff9738301bedfc57e0a3f3a2168edb05fd5dcf9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 20 Jul 2014 09:41:56 +0200 Subject: [PATCH 1989/5273] [puppet mode] Make regexp for regexps non-greedy Issue #2696 --- mode/puppet/puppet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/puppet/puppet.js b/mode/puppet/puppet.js index 66698bb6ad..b407ded883 100644 --- a/mode/puppet/puppet.js +++ b/mode/puppet/puppet.js @@ -176,7 +176,7 @@ CodeMirror.defineMode("puppet", function () { // Match characters that we are going to assume // are trying to be regex if (ch == '/') { - stream.match(/.*\//); + stream.match(/.*?\//); return 'variable-3'; } // Match all the numbers From 4e7e863c0e34f9fc450351d408a3f585d3843549 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 20 Jul 2014 10:26:22 +0200 Subject: [PATCH 1990/5273] Remove a few unneccesary property accesses --- lib/codemirror.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 0aad3fda68..8b3feac507 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3815,7 +3815,7 @@ if (how == "smart") { // Fall back to "prev" when the mode doesn't have an indentation // method. - if (!cm.doc.mode.indent) how = "prev"; + if (!doc.mode.indent) how = "prev"; else state = getStateBefore(cm, n); } @@ -3827,7 +3827,7 @@ indentation = 0; how = "not"; } else if (how == "smart") { - indentation = cm.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"; @@ -3851,7 +3851,7 @@ if (pos < indentation) indentString += spaceStr(indentation - pos); if (indentString != curSpaceString) { - replaceRange(cm.doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); + replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); } 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. From 1ddba34bb6e467282eeda6a79bd16c9650668169 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sun, 20 Jul 2014 10:56:24 +0200 Subject: [PATCH 1991/5273] Force stable y scroll when focusing textarea in onContextMenu Closes #2712 --- lib/codemirror.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/codemirror.js b/lib/codemirror.js index 8b3feac507..09ea0a3134 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3319,7 +3319,9 @@ "px; left: " + (e.clientX - 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) focusInput(cm); + if (webkit) window.scrollTo(null, oldScrollY); resetInput(cm); // Adds "Select all" to context menu in FF if (!cm.somethingSelected()) display.input.value = display.prevInput = " "; From 1d35536ee0f23be031beba12309a38db9f49b4d5 Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Sun, 20 Jul 2014 14:01:11 -0700 Subject: [PATCH 1992/5273] [vim] Do not open prompt if no cm.openDialog --- keymap/vim.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 16f51b3bf1..a47b005d02 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -561,7 +561,9 @@ MacroModeState.prototype = { exitMacroRecordMode: function() { var macroModeState = vimGlobalState.macroModeState; - macroModeState.onRecordingDone(); // close dialog + if (macroModeState.onRecordingDone) { + macroModeState.onRecordingDone(); // close dialog + } macroModeState.onRecordingDone = undefined; macroModeState.isRecording = false; }, @@ -571,8 +573,10 @@ if (register) { register.clear(); this.latestRegister = registerName; - this.onRecordingDone = cm.openDialog( - '(recording)['+registerName+']', null, {bottom:true}); + if (cm.openDialog) { + this.onRecordingDone = cm.openDialog( + '(recording)['+registerName+']', null, {bottom:true}); + } this.isRecording = true; } } From 1d4b525f8127e79aaee811ff2b6972a3fa76a7bd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Jul 2014 08:28:07 +0200 Subject: [PATCH 1993/5273] [yaml mode] Tweak key regexp Issue #2695 --- 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 15a5916df1..332aef6a23 100644 --- a/mode/yaml/yaml.js +++ b/mode/yaml/yaml.js @@ -80,7 +80,7 @@ CodeMirror.defineMode("yaml", function() { } /* pairs (associative arrays) -> key */ - if (!state.pair && stream.match(/^\s*[^\-:{}"\[\]][^:{}"\[\]]*(?=\s*:($|\s))/i)) { + if (!state.pair && stream.match(/^\s*(?:[,\[\]{}&*!|>'"%@`][^\s'":]|[^,\[\]{}#&*!|>'"%@`])[^#]*?(?=\s*:($|\s))/)) { state.pair = true; state.keyCol = stream.indentation(); return "atom"; From e02b946bfdf68ac4c3933b99e119a8fa9898efb6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Jul 2014 08:33:42 +0200 Subject: [PATCH 1994/5273] Also split pasted content by selection when selection length is a multiple of clipboard length Issue #2697 --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 09ea0a3134..31c6d71be5 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2417,7 +2417,7 @@ var multiPaste = null; if (cm.state.pasteIncoming && doc.sel.ranges.length > 1) { if (lastCopied && lastCopied.join("\n") == inserted) - multiPaste = lastCopied.length == doc.sel.ranges.length && map(lastCopied, splitLines); + multiPaste = doc.sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines); else if (textLines.length == doc.sel.ranges.length) multiPaste = map(textLines, function(l) { return [l]; }); } @@ -2433,7 +2433,7 @@ else if (cm.state.overwrite && range.empty() && !cm.state.pasteIncoming) to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); var updateInput = cm.curOp.updateInput; - var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i] : textLines, + var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, origin: cm.state.pasteIncoming ? "paste" : cm.state.cutIncoming ? "cut" : "+input"}; makeChange(cm.doc, changeEvent); signalLater(cm, "inputRead", cm, changeEvent); From ee088bc36b3fca2771835cc42febcabeb19e791c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Haso=C5=88?= Date: Mon, 14 Jul 2014 08:32:17 +0200 Subject: [PATCH 1995/5273] [bower.json] Normalized a package name The package name on http://bower.io/search/ is lowercase. --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index b103179156..407b86d649 100644 --- a/bower.json +++ b/bower.json @@ -1,5 +1,5 @@ { - "name": "CodeMirror", + "name": "codemirror", "version":"4.3.1", "main": ["lib/codemirror.js", "lib/codemirror.css"], "ignore": [ From 485a7da897e378025268e686f4eb79377973219e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 21 Jul 2014 08:51:28 +0200 Subject: [PATCH 1996/5273] Mark release 4.4 --- AUTHORS | 9 +++++++++ bower.json | 2 +- doc/compress.html | 1 + doc/manual.html | 2 +- doc/releases.html | 14 ++++++++++++++ index.html | 2 +- lib/codemirror.js | 2 +- package.json | 2 +- 8 files changed, 29 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index f5f569721e..0c2f67c31a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -18,6 +18,7 @@ Alberto Pose Albert Xing Alexander Pavlov Alexander Schepanovski +Alexander Shvets Alexander Solovyov Alexandre Bique alexey-k @@ -168,6 +169,7 @@ Jason Grout Jason Johnston Jason San Jose Jason Siefken +Jaydeep Solanki Jean Boussier jeffkenton Jeff Pickhardt @@ -205,6 +207,7 @@ kubelsmieci Lanny Laszlo Vidacs leaf corcoran +Leonid Khachaturov Leonya Khachaturov Liam Newman LM @@ -269,6 +272,7 @@ Niels van Groningen Nikita Beloglazov Nikita Vasilyev Nikolay Kostov +nilp0inter nlwillia pablo Page @@ -291,7 +295,9 @@ Radek Piórkowski Rahul Randy Edmunds Rasmus Erik Voel Jensen +Richard van der Meer Richard Z.H. Wang +Roberto Abdelkader Martínez Pérez robertop23 Robert Plummer Ruslan Osmanov @@ -299,6 +305,7 @@ Ryan Prior sabaca Samuel Ainsworth sandeepshetty +Sander AKA Redsandro santec Sascha Peilicke satchmorun @@ -330,6 +337,7 @@ Thaddee Tyl think Thomas Dvornik Thomas Schmid +Tim Alby Tim Baumann Timothy Farrell Timothy Hatcher @@ -349,6 +357,7 @@ Volker Mische wenli Wesley Wiser William Jamieson +William Stein Wojtek Ptak Xavier Mendez YNH Webdev diff --git a/bower.json b/bower.json index 407b86d649..8c57fcdd4b 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "codemirror", - "version":"4.3.1", + "version":"4.4.0", "main": ["lib/codemirror.js", "lib/codemirror.css"], "ignore": [ "**/.*", diff --git a/doc/compress.html b/doc/compress.html index ede45e1c6e..859210c45c 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -36,6 +36,7 @@

    Script compression helper

    Version: + + +

    MIME types defined: application/x-slim.

    + +

    + Parsing/Highlighting Tests: + normal, + verbose. +

    + diff --git a/mode/slim/slim.js b/mode/slim/slim.js new file mode 100644 index 0000000000..5e737131aa --- /dev/null +++ b/mode/slim/slim.js @@ -0,0 +1,575 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Slim Highlighting for CodeMirror copyright (c) HicknHack Software Gmbh + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"), require("../ruby/ruby")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror", "../htmlmixed/htmlmixed", "../ruby/ruby"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { +"use strict"; + + CodeMirror.defineMode("slim", function(config) { + var htmlMode = CodeMirror.getMode(config, {name: "htmlmixed"}); + var rubyMode = CodeMirror.getMode(config, "ruby"); + var modes = { html: htmlMode, ruby: rubyMode }; + var embedded = { + ruby: "ruby", + javascript: "javascript", + css: "text/css", + sass: "text/x-sass", + scss: "text/x-scss", + less: "text/x-less", + styl: "text/x-styl", // no highlighting so far + coffee: "coffeescript", + asciidoc: "text/x-asciidoc", + markdown: "text/x-markdown", + textile: "text/x-textile", // no highlighting so far + creole: "text/x-creole", // no highlighting so far + wiki: "text/x-wiki", // no highlighting so far + mediawiki: "text/x-mediawiki", // no highlighting so far + rdoc: "text/x-rdoc", // no highlighting so far + builder: "text/x-builder", // no highlighting so far + nokogiri: "text/x-nokogiri", // no highlighting so far + erb: "application/x-erb" + }; + var embeddedRegexp = function(map){ + var arr = []; + for(var key in map) arr.push(key); + return new RegExp("^("+arr.join('|')+"):"); + }(embedded); + + var styleMap = { + "commentLine": "comment", + "slimSwitch": "operator special", + "slimTag": "tag", + "slimId": "attribute def", + "slimClass": "attribute qualifier", + "slimAttribute": "attribute", + "slimSubmode": "keyword special", + "closeAttributeTag": null, + "slimDoctype": null, + "lineContinuation": null + }; + var closing = { + "{": "}", + "[": "]", + "(": ")" + }; + + var nameStartChar = "_a-zA-Z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD"; + var nameChar = nameStartChar + "\\-0-9\xB7\u0300-\u036F\u203F-\u2040"; + var nameRegexp = new RegExp("^[:"+nameStartChar+"](?::["+nameChar+"]|["+nameChar+"]*)"); + var attributeNameRegexp = new RegExp("^[:"+nameStartChar+"][:\\."+nameChar+"]*(?=\\s*=)"); + var wrappedAttributeNameRegexp = new RegExp("^[:"+nameStartChar+"][:\\."+nameChar+"]*"); + var classNameRegexp = /^\.-?[_a-zA-Z]+[\w\-]*/; + var classIdRegexp = /^#[_a-zA-Z]+[\w\-]*/; + + function backup(pos, tokenize, style) { + var restore = function(stream, state) { + state.tokenize = tokenize; + if (stream.pos < pos) { + stream.pos = pos; + return style; + } + return state.tokenize(stream, state); + }; + return function(stream, state) { + state.tokenize = restore; + return tokenize(stream, state); + }; + } + + function maybeBackup(stream, state, pat, offset, style) { + var cur = stream.current(); + var idx = cur.search(pat); + if (idx > -1) { + state.tokenize = backup(stream.pos, state.tokenize, style); + stream.backUp(cur.length - idx - offset); + } + return style; + } + + function continueLine(state, column) { + state.stack = { + parent: state.stack, + style: "continuation", + indented: column, + tokenize: state.line + }; + state.line = state.tokenize; + } + function finishContinue(state) { + if (state.line == state.tokenize) { + state.line = state.stack.tokenize; + state.stack = state.stack.parent; + } + } + + function lineContinuable(column, tokenize) { + return function(stream, state) { + finishContinue(state); + if (stream.match(/^\\$/)) { + continueLine(state, column); + return "lineContinuation"; + } + var style = tokenize(stream, state); + if (stream.eol() && stream.current().match(/(?:^|[^\\])(?:\\\\)*\\$/)) { + stream.backUp(1); + } + return style; + }; + } + function commaContinuable(column, tokenize) { + return function(stream, state) { + finishContinue(state); + var style = tokenize(stream, state); + if (stream.eol() && stream.current().match(/,$/)) { + continueLine(state, column); + } + return style; + }; + } + + function rubyInQuote(endQuote, tokenize) { + // TODO: add multi line support + return function(stream, state) { + var ch = stream.peek(); + if (ch == endQuote && state.rubyState.tokenize.length == 1) { + // step out of ruby context as it seems to complete processing all the braces + stream.next(); + state.tokenize = tokenize; + return "closeAttributeTag"; + } else { + return ruby(stream, state); + } + }; + } + function startRubySplat(tokenize) { + var rubyState; + var runSplat = function(stream, state) { + if (state.rubyState.tokenize.length == 1 && !state.rubyState.context.prev) { + stream.backUp(1); + if (stream.eatSpace()) { + state.rubyState = rubyState; + state.tokenize = tokenize; + return tokenize(stream, state); + } + stream.next(); + } + return ruby(stream, state); + }; + return function(stream, state) { + rubyState = state.rubyState; + state.rubyState = rubyMode.startState(); + state.tokenize = runSplat; + return ruby(stream, state); + }; + } + + function ruby(stream, state) { + return rubyMode.token(stream, state.rubyState); + } + + function htmlLine(stream, state) { + if (stream.match(/^\\$/)) { + return "lineContinuation"; + } + return html(stream, state); + } + function html(stream, state) { + if (stream.match(/^#\{/)) { + state.tokenize = rubyInQuote("}", state.tokenize); + return null; + } + return maybeBackup(stream, state, /[^\\]#\{/, 1, htmlMode.token(stream, state.htmlState)); + } + + function startHtmlLine(lastTokenize) { + return function(stream, state) { + var style = htmlLine(stream, state); + if (stream.eol()) state.tokenize = lastTokenize; + return style; + }; + } + + function startHtmlMode(stream, state, offset) { + state.stack = { + parent: state.stack, + style: "html", + indented: stream.column() + offset, // pipe + space + tokenize: state.line + }; + state.line = state.tokenize = html; + return null; + } + + function comment(stream, state) { + stream.skipToEnd(); + return state.stack.style; + } + + function commentMode(stream, state) { + state.stack = { + parent: state.stack, + style: "comment", + indented: state.indented + 1, + tokenize: state.line + }; + state.line = comment; + return comment(stream, state); + } + + function attributeWrapper(stream, state) { + if (stream.eat(state.stack.endQuote)) { + state.line = state.stack.line; + state.tokenize = state.stack.tokenize; + state.stack = state.stack.parent; + return null; + } + if (stream.match(wrappedAttributeNameRegexp)) { + state.tokenize = attributeWrapperAssign; + return "slimAttribute"; + } + stream.next(); + return null; + } + function attributeWrapperAssign(stream, state) { + if (stream.match(/^==?/)) { + state.tokenize = attributeWrapperValue; + return null; + } + return attributeWrapper(stream, state); + } + function attributeWrapperValue(stream, state) { + var ch = stream.peek(); + if (ch == '"' || ch == "\'") { + state.tokenize = readQuoted(ch, "string", true, false, attributeWrapper); + stream.next(); + return state.tokenize(stream, state); + } + if (ch == '[') { + return startRubySplat(attributeWrapper)(stream, state); + } + if (stream.match(/^(true|false|nil)\b/)) { + state.tokenize = attributeWrapper; + return "keyword"; + } + return startRubySplat(attributeWrapper)(stream, state); + } + + function startAttributeWrapperMode(state, endQuote, tokenize) { + state.stack = { + parent: state.stack, + style: "wrapper", + indented: state.indented + 1, + tokenize: tokenize, + line: state.line, + endQuote: endQuote + }; + state.line = state.tokenize = attributeWrapper; + return null; + } + + function sub(stream, state) { + if (stream.match(/^#\{/)) { + state.tokenize = rubyInQuote("}", state.tokenize); + return null; + } + var subStream = new CodeMirror.StringStream(stream.string.slice(state.stack.indented), stream.tabSize); + subStream.pos = stream.pos - state.stack.indented; + subStream.start = stream.start - state.stack.indented; + subStream.lastColumnPos = stream.lastColumnPos - state.stack.indented; + subStream.lastColumnValue = stream.lastColumnValue - state.stack.indented; + var style = state.subMode.token(subStream, state.subState); + stream.pos = subStream.pos + state.stack.indented; + return style; + } + function firstSub(stream, state) { + state.stack.indented = stream.column(); + state.line = state.tokenize = sub; + return state.tokenize(stream, state); + } + + function createMode(mode) { + var query = embedded[mode]; + var spec = CodeMirror.mimeModes[query]; + if (spec) { + return CodeMirror.getMode(config, spec); + } + var factory = CodeMirror.modes[query]; + if (factory) { + return factory(config, {name: query}); + } + return CodeMirror.getMode(config, "null"); + } + + function getMode(mode) { + if (!modes.hasOwnProperty(mode)) { + return modes[mode] = createMode(mode); + } + return modes[mode]; + } + + function startSubMode(mode, state) { + var subMode = getMode(mode); + var subState = subMode.startState && subMode.startState(); + + state.subMode = subMode; + state.subState = subState; + + state.stack = { + parent: state.stack, + style: "sub", + indented: state.indented + 1, + tokenize: state.line + }; + state.line = state.tokenize = firstSub; + return "slimSubmode"; + } + + function doctypeLine(stream, _state) { + stream.skipToEnd(); + return "slimDoctype"; + } + + function startLine(stream, state) { + var ch = stream.peek(); + if (ch == '<') { + return (state.tokenize = startHtmlLine(state.tokenize))(stream, state); + } + if (stream.match(/^[|']/)) { + return startHtmlMode(stream, state, 1); + } + if (stream.match(/^\/(!|\[\w+])?/)) { + return commentMode(stream, state); + } + if (stream.match(/^(-|==?[<>]?)/)) { + state.tokenize = lineContinuable(stream.column(), commaContinuable(stream.column(), ruby)); + return "slimSwitch"; + } + if (stream.match(/^doctype\b/)) { + state.tokenize = doctypeLine; + return "keyword"; + } + + var m = stream.match(embeddedRegexp); + if (m) { + return startSubMode(m[1], state); + } + + return slimTag(stream, state); + } + + function slim(stream, state) { + if (state.startOfLine) { + return startLine(stream, state); + } + return slimTag(stream, state); + } + + function slimTag(stream, state) { + if (stream.eat('*')) { + state.tokenize = startRubySplat(slimTagExtras); + return null; + } + if (stream.match(nameRegexp)) { + state.tokenize = slimTagExtras; + return "slimTag"; + } + return slimClass(stream, state); + } + function slimTagExtras(stream, state) { + if (stream.match(/^(<>?|> state.indented && state.last != "slimSubmode") { + state.line = state.tokenize = state.stack.tokenize; + state.stack = state.stack.parent; + state.subMode = null; + state.subState = null; + } + } + if (stream.eatSpace()) return null; + var style = state.tokenize(stream, state); + state.startOfLine = false; + if (style) state.last = style; + return styleMap.hasOwnProperty(style) ? styleMap[style] : style; + }, + + blankLine: function(state) { + if (state.subMode && state.subMode.blankLine) { + return state.subMode.blankLine(state.subState); + } + }, + + innerMode: function(state) { + if (state.subMode) return {state: state.subState, mode: state.subMode}; + return {state: state, mode: mode}; + } + + //indent: function(state) { + // return state.indented; + //} + }; + return mode; + }, "htmlmixed", "ruby"); + + CodeMirror.defineMIME("text/x-slim", "slim"); + CodeMirror.defineMIME("application/x-slim", "slim"); +}); diff --git a/mode/slim/test.js b/mode/slim/test.js new file mode 100644 index 0000000000..be4ddacb62 --- /dev/null +++ b/mode/slim/test.js @@ -0,0 +1,96 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Slim Highlighting for CodeMirror copyright (c) HicknHack Software Gmbh + +(function() { + var mode = CodeMirror.getMode({tabSize: 4, indentUnit: 2}, "slim"); + function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } + + // Requires at least one media query + MT("elementName", + "[tag h1] Hey There"); + + MT("oneElementPerLine", + "[tag h1] Hey There .h2"); + + MT("idShortcut", + "[attribute&def #test] Hey There"); + + MT("tagWithIdShortcuts", + "[tag h1][attribute&def #test] Hey There"); + + MT("classShortcut", + "[attribute&qualifier .hello] Hey There"); + + MT("tagWithIdAndClassShortcuts", + "[tag h1][attribute&def #test][attribute&qualifier .hello] Hey There"); + + MT("docType", + "[keyword doctype] xml"); + + MT("comment", + "[comment / Hello WORLD]"); + + MT("notComment", + "[tag h1] This is not a / comment "); + + MT("attributes", + "[tag a]([attribute title]=[string \"test\"]) [attribute href]=[string \"link\"]}"); + + MT("multiLineAttributes", + "[tag a]([attribute title]=[string \"test\"]", + " ) [attribute href]=[string \"link\"]}"); + + MT("htmlCode", + "[tag&bracket <][tag h1][tag&bracket >]Title[tag&bracket ]"); + + MT("rubyBlock", + "[operator&special =][variable-2 @item]"); + + MT("selectorRubyBlock", + "[tag a][attribute&qualifier .test][operator&special =] [variable-2 @item]"); + + MT("nestedRubyBlock", + "[tag a]", + " [operator&special =][variable puts] [string \"test\"]"); + + MT("multilinePlaintext", + "[tag p]", + " | Hello,", + " World"); + + MT("multilineRuby", + "[tag p]", + " [comment /# this is a comment]", + " [comment and this is a comment too]", + " | Date/Time", + " [operator&special -] [variable now] [operator =] [tag DateTime][operator .][property now]", + " [tag strong][operator&special =] [variable now]", + " [operator&special -] [keyword if] [variable now] [operator >] [tag DateTime][operator .][property parse]([string \"December 31, 2006\"])", + " [operator&special =][string \"Happy\"]", + " [operator&special =][string \"Belated\"]", + " [operator&special =][string \"Birthday\"]"); + + MT("multilineComment", + "[comment /]", + " [comment Multiline]", + " [comment Comment]"); + + MT("hamlAfterRubyTag", + "[attribute&qualifier .block]", + " [tag strong][operator&special =] [variable now]", + " [attribute&qualifier .test]", + " [operator&special =][variable now]", + " [attribute&qualifier .right]"); + + MT("stretchedRuby", + "[operator&special =] [variable puts] [string \"Hello\"],", + " [string \"World\"]"); + + MT("interpolationInHashAttribute", + "[tag div]{[attribute id] = [string \"]#{[variable test]}[string _]#{[variable ting]}[string \"]} test"); + + MT("interpolationInHTMLAttribute", + "[tag div]([attribute title]=[string \"]#{[variable test]}[string _]#{[variable ting]()}[string \"]) Test"); +})(); diff --git a/test/index.html b/test/index.html index 9930301eb5..a10bd182d4 100644 --- a/test/index.html +++ b/test/index.html @@ -94,6 +94,8 @@

    Test Suite

    + + From b6e9eea8bb4daec6a0ff23f97104d251a0940414 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 14 Aug 2014 14:17:48 +0200 Subject: [PATCH 2038/5273] [slim mode] Integrate Issue #2755 --- doc/compress.html | 1 + mode/index.html | 1 + mode/meta.js | 1 + mode/slim/slim.js | 8 ++++---- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/compress.html b/doc/compress.html index 859210c45c..8d25e4b4e9 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -152,6 +152,7 @@

    Script compression helper

    + diff --git a/mode/index.html b/mode/index.html index 1aa0b8d821..1c106ae8e0 100644 --- a/mode/index.html +++ b/mode/index.html @@ -95,6 +95,7 @@

    Language modes

  • SCSS
  • Shell
  • Sieve
  • +
  • Slim
  • Smalltalk
  • Smarty
  • Smarty/HTML mixed
  • diff --git a/mode/meta.js b/mode/meta.js index 3627cd7470..e3c32b6f6c 100644 --- a/mode/meta.js +++ b/mode/meta.js @@ -86,6 +86,7 @@ CodeMirror.modeInfo = [ {name: "SCSS", mime: "text/x-scss", mode: "css"}, {name: "Shell", mime: "text/x-sh", mode: "shell"}, {name: "Sieve", mime: "application/sieve", mode: "sieve"}, + {name: "Slim", mime: "text/x-slim", mode: "slim"}, {name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk"}, {name: "Smarty", mime: "text/x-smarty", mode: "smarty"}, {name: "SmartyMixed", mime: "text/x-smarty", mode: "smartymixed"}, diff --git a/mode/slim/slim.js b/mode/slim/slim.js index 5e737131aa..164464d066 100644 --- a/mode/slim/slim.js +++ b/mode/slim/slim.js @@ -104,10 +104,10 @@ state.line = state.tokenize; } function finishContinue(state) { - if (state.line == state.tokenize) { - state.line = state.stack.tokenize; - state.stack = state.stack.parent; - } + if (state.line == state.tokenize) { + state.line = state.stack.tokenize; + state.stack = state.stack.parent; + } } function lineContinuable(column, tokenize) { From bbc53ebda20b9a0a5b889d10a3ca4a44a43b3c9a Mon Sep 17 00:00:00 2001 From: Hakan Tunc Date: Mon, 28 Jul 2014 14:36:45 -0500 Subject: [PATCH 2039/5273] Add mimetype text/x-nesc --- mode/clike/clike.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mode/clike/clike.js b/mode/clike/clike.js index 2873e3629b..ee2c77a025 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -437,4 +437,15 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { modeProps: {fold: ["brace", "include"]} }); + def("text/x-nesc", { + name: "clike", + keywords: words(cKeywords + "as atomic async call command component components configuration event generic " + + "implementation includes interface module new norace nx_struct nx_union post provides " + + "signal task uses abstract extends"), + blockKeywords: words("case do else for if switch while struct"), + atoms: words("null"), + hooks: {"#": cppHook}, + modeProps: {fold: ["brace", "include"]} + }); + }); From a46ad916a6f40a0208c3f04b9fb35dcb7153f691 Mon Sep 17 00:00:00 2001 From: amuntean Date: Mon, 28 Jul 2014 13:31:06 +0200 Subject: [PATCH 2040/5273] [merge] new allowEditingOriginals option to edit all compared files --- addon/merge/merge.css | 6 ++++++ addon/merge/merge.js | 27 ++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/addon/merge/merge.css b/addon/merge/merge.css index 63237fc8e9..5d24b9bb7f 100644 --- a/addon/merge/merge.css +++ b/addon/merge/merge.css @@ -62,6 +62,12 @@ color: #44c; } +.CodeMirror-merge-copy-reverse { + position: absolute; + cursor: pointer; + color: #44c; +} + .CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; } .CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; } diff --git a/addon/merge/merge.js b/addon/merge/merge.js index bde461fcea..d9b277664b 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -37,7 +37,7 @@ constructor: DiffView, init: function(pane, orig, options) { this.edit = this.mv.edit; - this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: true}, copyObj(options))); + this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options))); this.diff = getDiff(asString(orig), asString(options.value)); this.diffOutOfDate = false; @@ -282,16 +282,27 @@ if (dv.copyButtons) { var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc", "CodeMirror-merge-copy")); - copy.title = "Revert chunk"; + var editOriginals = dv.mv.options.allowEditingOriginals; + copy.title = editOriginals ? "Push to left" : "Revert chunk"; copy.chunk = {topEdit: topEdit, botEdit: botEdit, topOrig: topOrig, botOrig: botOrig}; copy.style.top = top + "px"; + + if (editOriginals) { + var topReverse = dv.orig.heightAtLine(topEdit, "local") - sTopEdit; + var copyReverse = dv.copyButtons.appendChild(elt("div", dv.type == "right" ? "\u21dd" : "\u21dc", + "CodeMirror-merge-copy-reverse")); + copyReverse.title = "Push to right"; + copyReverse.chunk = {topEdit: topOrig, botEdit: botOrig, topOrig: topEdit, botOrig: botEdit}; + copyReverse.style.top = topReverse + "px"; + dv.type == "right" ? copyReverse.style.left = "2px" : copyReverse.style.right = "2px"; + } } }); } - function copyChunk(dv, chunk) { + function copyChunk(dv, to, from, chunk) { if (dv.diffOutOfDate) return; - dv.edit.replaceRange(dv.orig.getRange(Pos(chunk.topOrig, 0), Pos(chunk.botOrig, 0)), + to.replaceRange(from.getRange(Pos(chunk.topOrig, 0), Pos(chunk.botOrig, 0)), Pos(chunk.topEdit, 0), Pos(chunk.botEdit, 0)); } @@ -326,6 +337,7 @@ (hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost"; wrap.push(elt("div", null, null, "height: 0; clear: both;")); + var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane")); this.edit = CodeMirror(editPane, copyObj(options)); @@ -353,7 +365,12 @@ dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type); CodeMirror.on(dv.copyButtons, "click", function(e) { var node = e.target || e.srcElement; - if (node.chunk) copyChunk(dv, node.chunk); + if (!node.chunk) return; + if (node.className == "CodeMirror-merge-copy-reverse") { + copyChunk(dv, dv.orig, dv.edit, node.chunk); + return; + } + copyChunk(dv, dv.edit, dv.orig, node.chunk); }); gapElts.unshift(dv.copyButtons); } From 162c6073e60fcc6635ba31e8ed7a0d35da68a5e0 Mon Sep 17 00:00:00 2001 From: Doug Wikle Date: Mon, 21 Jul 2014 08:29:29 -0400 Subject: [PATCH 2041/5273] [verilog mode] Addressed indentation issue Blocking indentation for import/export keywords --- mode/verilog/test.js | 144 +++++++++++++++++++++++++++++++++++++--- mode/verilog/verilog.js | 5 ++ 2 files changed, 138 insertions(+), 11 deletions(-) diff --git a/mode/verilog/test.js b/mode/verilog/test.js index e78860deb9..376d198685 100644 --- a/mode/verilog/test.js +++ b/mode/verilog/test.js @@ -5,7 +5,7 @@ var mode = CodeMirror.getMode({indentUnit: 4}, "verilog"); function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } - MT("Binary literals", + MT("binary_literals", "[number 1'b0]", "[number 1'b1]", "[number 1'bx]", @@ -30,14 +30,14 @@ "[number 'b0101]" ); - MT("Octal literals", + MT("octal_literals", "[number 3'o7]", "[number 3'O7]", "[number 3'so7]", "[number 3'SO7]" ); - MT("Decimal literals", + MT("decimal_literals", "[number 0]", "[number 1]", "[number 7]", @@ -52,7 +52,7 @@ "[number 32 'd 123]" ); - MT("Hex literals", + MT("hex_literals", "[number 4'h0]", "[number 4'ha]", "[number 4'hF]", @@ -69,7 +69,7 @@ "[number 32'hFFF?]" ); - MT("Real number literals", + MT("real_number_literals", "[number 1.2]", "[number 0.1]", "[number 2394.26331]", @@ -82,36 +82,158 @@ "[number 236.123_763_e-12]" ); - MT("Operators", + MT("operators", "[meta ^]" ); - MT("Keywords", + MT("keywords", "[keyword logic]", "[keyword logic] [variable foo]", "[keyword reg] [variable abc]" ); - MT("Variables", + MT("variables", "[variable _leading_underscore]", "[variable _if]", "[number 12] [variable foo]", "[variable foo] [number 14]" ); - MT("Tick defines", + MT("tick_defines", "[def `FOO]", "[def `foo]", "[def `FOO_bar]" ); - MT("System calls", + MT("system_calls", "[meta $display]", "[meta $vpi_printf]" ); - MT("Line comment", "[comment // Hello world]"); + MT("line_comment", "[comment // Hello world]"); + // Alignment tests + MT("align_port_map_style1", + /** + * mod mod(.a(a), + * .b(b) + * ); + */ + "[variable mod] [variable mod][bracket (].[variable a][bracket (][variable a][bracket )],", + " .[variable b][bracket (][variable b][bracket )]", + " [bracket )];", + "" + ); + + MT("align_port_map_style2", + /** + * mod mod( + * .a(a), + * .b(b) + * ); + */ + "[variable mod] [variable mod][bracket (]", + " .[variable a][bracket (][variable a][bracket )],", + " .[variable b][bracket (][variable b][bracket )]", + "[bracket )];", + "" + ); + + // Indentation tests + MT("indent_single_statement_if", + "[keyword if] [bracket (][variable foo][bracket )]", + " [keyword break];", + "" + ); + + MT("no_indent_after_single_line_if", + "[keyword if] [bracket (][variable foo][bracket )] [keyword break];", + "" + ); + + MT("indent_after_if_begin_same_line", + "[keyword if] [bracket (][variable foo][bracket )] [keyword begin]", + " [keyword break];", + " [keyword break];", + "[keyword end]", + "" + ); + + MT("indent_after_if_begin_next_line", + "[keyword if] [bracket (][variable foo][bracket )]", + " [keyword begin]", + " [keyword break];", + " [keyword break];", + " [keyword end]", + "" + ); + + MT("indent_single_statement_if_else", + "[keyword if] [bracket (][variable foo][bracket )]", + " [keyword break];", + "[keyword else]", + " [keyword break];", + "" + ); + + MT("indent_if_else_begin_same_line", + "[keyword if] [bracket (][variable foo][bracket )] [keyword begin]", + " [keyword break];", + " [keyword break];", + "[keyword end] [keyword else] [keyword begin]", + " [keyword break];", + " [keyword break];", + "[keyword end]", + "" + ); + + MT("indent_if_else_begin_next_line", + "[keyword if] [bracket (][variable foo][bracket )]", + " [keyword begin]", + " [keyword break];", + " [keyword break];", + " [keyword end]", + "[keyword else]", + " [keyword begin]", + " [keyword break];", + " [keyword break];", + " [keyword end]", + "" + ); + + MT("indent_if_nested_without_begin", + "[keyword if] [bracket (][variable foo][bracket )]", + " [keyword if] [bracket (][variable foo][bracket )]", + " [keyword if] [bracket (][variable foo][bracket )]", + " [keyword break];", + "" + ); + + MT("indent_case", + "[keyword case] [bracket (][variable state][bracket )]", + " [variable FOO]:", + " [keyword break];", + " [variable BAR]:", + " [keyword break];", + "[keyword endcase]", + "" + ); + + MT("unindent_after_end_with_preceding_text", + "[keyword begin]", + " [keyword break]; [keyword end]", + "" + ); + + MT("export_function_does_not_indent", + "[keyword export] [string \"DPI-C\"] [keyword function] [variable helloFromSV];", + "" + ); + + MT("export_task_does_not_indent", + "[keyword export] [string \"DPI-C\"] [keyword task] [variable helloFromSV];", + "" + ); })(); diff --git a/mode/verilog/verilog.js b/mode/verilog/verilog.js index 3414ec022e..46209b2492 100644 --- a/mode/verilog/verilog.js +++ b/mode/verilog/verilog.js @@ -95,6 +95,11 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) { openClose["do" ] = "while"; openClose["fork" ] = "join;join_any;join_none"; + // This is a bit of a hack but will work to not indent after import/epxort statements + // as long as the function/task name is on the same line + openClose["import"] = "function;task"; + openClose["export"] = "function;task"; + for (var i in noIndentKeywords) { var keyword = noIndentKeywords[i]; if (openClose[keyword]) { From d0916042da46ae396e3cba45de623f2a24c137f1 Mon Sep 17 00:00:00 2001 From: TheHowl Date: Sun, 25 May 2014 14:49:59 +0200 Subject: [PATCH 2042/5273] [php mode] Add json, curl, mysqli extensions --- mode/php/php.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/php/php.js b/mode/php/php.js index 75b003ff75..f8821ed651 100644 --- a/mode/php/php.js +++ b/mode/php/php.js @@ -95,7 +95,7 @@ "die echo empty exit eval include include_once isset list require require_once return " + "print unset __halt_compiler self static parent yield insteadof finally"; var phpAtoms = "true false null TRUE FALSE NULL __CLASS__ __DIR__ __FILE__ __LINE__ __METHOD__ __FUNCTION__ __NAMESPACE__ __TRAIT__"; - var phpBuiltin = "func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once"; + var phpBuiltin = "func_num_args func_get_arg func_get_args strlen strcmp strncmp strcasecmp strncasecmp each error_reporting define defined trigger_error user_error set_error_handler restore_error_handler get_declared_classes get_loaded_extensions extension_loaded get_extension_funcs debug_backtrace constant bin2hex hex2bin sleep usleep time mktime gmmktime strftime gmstrftime strtotime date gmdate getdate localtime checkdate flush wordwrap htmlspecialchars htmlentities html_entity_decode md5 md5_file crc32 getimagesize image_type_to_mime_type phpinfo phpversion phpcredits strnatcmp strnatcasecmp substr_count strspn strcspn strtok strtoupper strtolower strpos strrpos strrev hebrev hebrevc nl2br basename dirname pathinfo stripslashes stripcslashes strstr stristr strrchr str_shuffle str_word_count strcoll substr substr_replace quotemeta ucfirst ucwords strtr addslashes addcslashes rtrim str_replace str_repeat count_chars chunk_split trim ltrim strip_tags similar_text explode implode setlocale localeconv parse_str str_pad chop strchr sprintf printf vprintf vsprintf sscanf fscanf parse_url urlencode urldecode rawurlencode rawurldecode readlink linkinfo link unlink exec system escapeshellcmd escapeshellarg passthru shell_exec proc_open proc_close rand srand getrandmax mt_rand mt_srand mt_getrandmax base64_decode base64_encode abs ceil floor round is_finite is_nan is_infinite bindec hexdec octdec decbin decoct dechex base_convert number_format fmod ip2long long2ip getenv putenv getopt microtime gettimeofday getrusage uniqid quoted_printable_decode set_time_limit get_cfg_var magic_quotes_runtime set_magic_quotes_runtime get_magic_quotes_gpc get_magic_quotes_runtime import_request_variables error_log serialize unserialize memory_get_usage var_dump var_export debug_zval_dump print_r highlight_file show_source highlight_string ini_get ini_get_all ini_set ini_alter ini_restore get_include_path set_include_path restore_include_path setcookie header headers_sent connection_aborted connection_status ignore_user_abort parse_ini_file is_uploaded_file move_uploaded_file intval floatval doubleval strval gettype settype is_null is_resource is_bool is_long is_float is_int is_integer is_double is_real is_numeric is_string is_array is_object is_scalar ereg ereg_replace eregi eregi_replace split spliti join sql_regcase dl pclose popen readfile rewind rmdir umask fclose feof fgetc fgets fgetss fread fopen fpassthru ftruncate fstat fseek ftell fflush fwrite fputs mkdir rename copy tempnam tmpfile file file_get_contents stream_select stream_context_create stream_context_set_params stream_context_set_option stream_context_get_options stream_filter_prepend stream_filter_append fgetcsv flock get_meta_tags stream_set_write_buffer set_file_buffer set_socket_blocking stream_set_blocking socket_set_blocking stream_get_meta_data stream_register_wrapper stream_wrapper_register stream_set_timeout socket_set_timeout socket_get_status realpath fnmatch fsockopen pfsockopen pack unpack get_browser crypt opendir closedir chdir getcwd rewinddir readdir dir glob fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype file_exists is_writable is_writeable is_readable is_executable is_file is_dir is_link stat lstat chown touch clearstatcache mail ob_start ob_flush ob_clean ob_end_flush ob_end_clean ob_get_flush ob_get_clean ob_get_length ob_get_level ob_get_status ob_get_contents ob_implicit_flush ob_list_handlers ksort krsort natsort natcasesort asort arsort sort rsort usort uasort uksort shuffle array_walk count end prev next reset current key min max in_array array_search extract compact array_fill range array_multisort array_push array_pop array_shift array_unshift array_splice array_slice array_merge array_merge_recursive array_keys array_values array_count_values array_reverse array_reduce array_pad array_flip array_change_key_case array_rand array_unique array_intersect array_intersect_assoc array_diff array_diff_assoc array_sum array_filter array_map array_chunk array_key_exists pos sizeof key_exists assert assert_options version_compare ftok str_rot13 aggregate session_name session_module_name session_save_path session_id session_regenerate_id session_decode session_register session_unregister session_is_registered session_encode session_start session_destroy session_unset session_set_save_handler session_cache_limiter session_cache_expire session_set_cookie_params session_get_cookie_params session_write_close preg_match preg_match_all preg_replace preg_replace_callback preg_split preg_quote preg_grep overload ctype_alnum ctype_alpha ctype_cntrl ctype_digit ctype_lower ctype_graph ctype_print ctype_punct ctype_space ctype_upper ctype_xdigit virtual apache_request_headers apache_note apache_lookup_uri apache_child_terminate apache_setenv apache_response_headers apache_get_version getallheaders mysql_connect mysql_pconnect mysql_close mysql_select_db mysql_create_db mysql_drop_db mysql_query mysql_unbuffered_query mysql_db_query mysql_list_dbs mysql_list_tables mysql_list_fields mysql_list_processes mysql_error mysql_errno mysql_affected_rows mysql_insert_id mysql_result mysql_num_rows mysql_num_fields mysql_fetch_row mysql_fetch_array mysql_fetch_assoc mysql_fetch_object mysql_data_seek mysql_fetch_lengths mysql_fetch_field mysql_field_seek mysql_free_result mysql_field_name mysql_field_table mysql_field_len mysql_field_type mysql_field_flags mysql_escape_string mysql_real_escape_string mysql_stat mysql_thread_id mysql_client_encoding mysql_get_client_info mysql_get_host_info mysql_get_proto_info mysql_get_server_info mysql_info mysql mysql_fieldname mysql_fieldtable mysql_fieldlen mysql_fieldtype mysql_fieldflags mysql_selectdb mysql_createdb mysql_dropdb mysql_freeresult mysql_numfields mysql_numrows mysql_listdbs mysql_listtables mysql_listfields mysql_db_name mysql_dbname mysql_tablename mysql_table_name pg_connect pg_pconnect pg_close pg_connection_status pg_connection_busy pg_connection_reset pg_host pg_dbname pg_port pg_tty pg_options pg_ping pg_query pg_send_query pg_cancel_query pg_fetch_result pg_fetch_row pg_fetch_assoc pg_fetch_array pg_fetch_object pg_fetch_all pg_affected_rows pg_get_result pg_result_seek pg_result_status pg_free_result pg_last_oid pg_num_rows pg_num_fields pg_field_name pg_field_num pg_field_size pg_field_type pg_field_prtlen pg_field_is_null pg_get_notify pg_get_pid pg_result_error pg_last_error pg_last_notice pg_put_line pg_end_copy pg_copy_to pg_copy_from pg_trace pg_untrace pg_lo_create pg_lo_unlink pg_lo_open pg_lo_close pg_lo_read pg_lo_write pg_lo_read_all pg_lo_import pg_lo_export pg_lo_seek pg_lo_tell pg_escape_string pg_escape_bytea pg_unescape_bytea pg_client_encoding pg_set_client_encoding pg_meta_data pg_convert pg_insert pg_update pg_delete pg_select pg_exec pg_getlastoid pg_cmdtuples pg_errormessage pg_numrows pg_numfields pg_fieldname pg_fieldsize pg_fieldtype pg_fieldnum pg_fieldprtlen pg_fieldisnull pg_freeresult pg_result pg_loreadall pg_locreate pg_lounlink pg_loopen pg_loclose pg_loread pg_lowrite pg_loimport pg_loexport http_response_code get_declared_traits getimagesizefromstring socket_import_stream stream_set_chunk_size trait_exists header_register_callback class_uses session_status session_register_shutdown echo print global static exit array empty eval isset unset die include require include_once require_once json_decode json_encode json_last_error json_last_error_msg curl_close curl_copy_handle curl_errno curl_error curl_escape curl_exec curl_file_create curl_getinfo curl_init curl_multi_add_handle curl_multi_close curl_multi_exec curl_multi_getcontent curl_multi_info_read curl_multi_init curl_multi_remove_handle curl_multi_select curl_multi_setopt curl_multi_strerror curl_pause curl_reset curl_setopt_array curl_setopt curl_share_close curl_share_init curl_share_setopt curl_strerror curl_unescape curl_version mysqli_affected_rows mysqli_autocommit mysqli_change_user mysqli_character_set_name mysqli_close mysqli_commit mysqli_connect_errno mysqli_connect_error mysqli_connect mysqli_data_seek mysqli_debug mysqli_dump_debug_info mysqli_errno mysqli_error_list mysqli_error mysqli_fetch_all mysqli_fetch_array mysqli_fetch_assoc mysqli_fetch_field_direct mysqli_fetch_field mysqli_fetch_fields mysqli_fetch_lengths mysqli_fetch_object mysqli_fetch_row mysqli_field_count mysqli_field_seek mysqli_field_tell mysqli_free_result mysqli_get_charset mysqli_get_client_info mysqli_get_client_stats mysqli_get_client_version mysqli_get_connection_stats mysqli_get_host_info mysqli_get_proto_info mysqli_get_server_info mysqli_get_server_version mysqli_info mysqli_init mysqli_insert_id mysqli_kill mysqli_more_results mysqli_multi_query mysqli_next_result mysqli_num_fields mysqli_num_rows mysqli_options mysqli_ping mysqli_prepare mysqli_query mysqli_real_connect mysqli_real_escape_string mysqli_real_query mysqli_reap_async_query mysqli_refresh mysqli_rollback mysqli_select_db mysqli_set_charset mysqli_set_local_infile_default mysqli_set_local_infile_handler mysqli_sqlstate mysqli_ssl_set mysqli_stat mysqli_stmt_init mysqli_store_result mysqli_thread_id mysqli_thread_safe mysqli_use_result mysqli_warning_count"; CodeMirror.registerHelper("hintWords", "php", [phpKeywords, phpAtoms, phpBuiltin].join(" ").split(" ")); CodeMirror.registerHelper("wordChars", "php", /[\w$]/); From d46fd84445330c370d61c9cf38fc5e2c90236e08 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 14 Aug 2014 18:02:28 +0200 Subject: [PATCH 2043/5273] [sql-hint addon] Clean up, fix handling of whitespace Closes #2761 --- addon/hint/sql-hint.js | 110 ++++++++++++++++++++--------------------- mode/sql/index.html | 10 +++- 2 files changed, 62 insertions(+), 58 deletions(-) diff --git a/addon/hint/sql-hint.js b/addon/hint/sql-hint.js index fd58b8834e..cc756a2485 100644 --- a/addon/hint/sql-hint.js +++ b/addon/hint/sql-hint.js @@ -21,7 +21,7 @@ function getKeywords(editor) { var mode = editor.doc.modeOption; - if(mode === "sql") mode = "text/x-sql"; + if (mode === "sql") mode = "text/x-sql"; return CodeMirror.resolveMode(mode).keywords; } @@ -32,12 +32,12 @@ } function addMatches(result, search, wordlist, formatter) { - for(var word in wordlist) { - if(!wordlist.hasOwnProperty(word)) continue; - if(Array.isArray(wordlist)) { + for (var word in wordlist) { + if (!wordlist.hasOwnProperty(word)) continue; + if (Array.isArray(wordlist)) { word = wordlist[word]; } - if(match(search, word)) { + if (match(search, word)) { result.push(formatter(word)); } } @@ -49,33 +49,30 @@ var string = token.string.substr(1); var prevCur = Pos(cur.line, token.start); var table = editor.getTokenAt(prevCur).string; - if( !tables.hasOwnProperty( table ) ){ + if (!tables.hasOwnProperty(table)) table = findTableByAlias(table, editor); - } var columns = tables[table]; - if(!columns) { - return; - } - addMatches(result, string, columns, - function(w) {return "." + w;}); + if (!columns) return; + + addMatches(result, string, columns, function(w) {return "." + w;}); } function eachWord(lineText, f) { - if( !lineText ){return;} + if (!lineText) return; var excepted = /[,;]/g; - var words = lineText.split( " " ); - for( var i = 0; i < words.length; i++ ){ - f( words[i]?words[i].replace( excepted, '' ) : '' ); + var words = lineText.split(" "); + for (var i = 0; i < words.length; i++) { + f(words[i]?words[i].replace(excepted, '') : ''); } } - function convertCurToNumber( cur ){ + function convertCurToNumber(cur) { // max characters of a line is 999,999. - return cur.line + cur.ch / Math.pow( 10, 6 ); + return cur.line + cur.ch / Math.pow(10, 6); } - function convertNumberToCur( num ){ - return Pos(Math.floor( num ), +num.toString().split( '.' ).pop()); + function convertNumberToCur(num) { + return Pos(Math.floor(num), +num.toString().split('.').pop()); } function findTableByAlias(alias, editor) { @@ -86,26 +83,26 @@ var table = ""; var separator = []; var validRange = { - start: Pos( 0, 0 ), - end: Pos( editor.lastLine(), editor.getLineHandle( editor.lastLine() ).length ) + start: Pos(0, 0), + end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length) }; //add separator - var indexOfSeparator = fullQuery.indexOf( CONS.QUERY_DIV ); - while( indexOfSeparator != -1 ){ - separator.push( doc.posFromIndex(indexOfSeparator)); - indexOfSeparator = fullQuery.indexOf( CONS.QUERY_DIV, indexOfSeparator+1); + var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV); + while(indexOfSeparator != -1) { + separator.push(doc.posFromIndex(indexOfSeparator)); + indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1); } - separator.unshift( Pos( 0, 0 ) ); - separator.push( Pos( editor.lastLine(), editor.getLineHandle( editor.lastLine() ).text.length ) ); + separator.unshift(Pos(0, 0)); + separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length)); - //find valieRange + //find valid range var prevItem = 0; - var current = convertCurToNumber( editor.getCursor() ); - for( var i=0; i< separator.length; i++){ - var _v = convertCurToNumber( separator[i] ); - if( current > prevItem && current <= _v ){ - validRange = { start: convertNumberToCur( prevItem ), end: convertNumberToCur( _v ) }; + var current = convertCurToNumber(editor.getCursor()); + for (var i=0; i< separator.length; i++) { + var _v = convertCurToNumber(separator[i]); + if (current > prevItem && current <= _v) { + validRange = { start: convertNumberToCur(prevItem), end: convertNumberToCur(_v) }; break; } prevItem = _v; @@ -113,52 +110,51 @@ var query = doc.getRange(validRange.start, validRange.end, false); - for(var i=0; i < query.length; i++){ + for (var i = 0; i < query.length; i++) { var lineText = query[i]; - eachWord( lineText, function( word ){ + eachWord(lineText, function(word) { var wordUpperCase = word.toUpperCase(); - if( wordUpperCase === aliasUpperCase && tables.hasOwnProperty( previousWord ) ){ + if (wordUpperCase === aliasUpperCase && tables.hasOwnProperty(previousWord)) { table = previousWord; } - if( wordUpperCase !== CONS.ALIAS_KEYWORD ){ + if (wordUpperCase !== CONS.ALIAS_KEYWORD) { previousWord = word; } }); - if( table ){ break; } + if (table) break; } return table; } - function sqlHint(editor, options) { + CodeMirror.registerHelper("hint", "sql", function(editor, options) { tables = (options && options.tables) || {}; keywords = keywords || getKeywords(editor); var cur = editor.getCursor(); - var token = editor.getTokenAt(cur), end = token.end; var result = []; - var search = token.string.trim(); - + var token = editor.getTokenAt(cur), start, end, search; + if (token.string.match(/^\.?[\w@]+$/)) { + search = token.string; + start = token.start; + end = token.end; + } else { + start = end = cur.ch; + search = ""; + } if (search.charAt(0) == ".") { columnCompletion(result, editor); if (!result.length) { - while (token.start && search.charAt(0) == ".") { + while (start && search.charAt(0) == ".") { token = editor.getTokenAt(Pos(cur.line, token.start - 1)); + start = token.start; search = token.string + search; } - addMatches(result, search, tables, - function(w) {return w;}); + addMatches(result, search, tables, function(w) {return w;}); } } else { - addMatches(result, search, keywords, - function(w) {return w.toUpperCase();}); - addMatches(result, search, tables, - function(w) {return w;}); + addMatches(result, search, tables, function(w) {return w;}); + addMatches(result, search, keywords, function(w) {return w.toUpperCase();}); } - return { - list: result, - from: Pos(cur.line, token.start), - to: Pos(cur.line, end) - }; - } - CodeMirror.registerHelper("hint", "sql", sqlHint); + return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)}; + }); }); diff --git a/mode/sql/index.html b/mode/sql/index.html index 79a2e74e0f..7dd5f3075e 100644 --- a/mode/sql/index.html +++ b/mode/sql/index.html @@ -7,6 +7,9 @@ + + + + + +
    +

    Modelica mode

    + +
    + + + +

    Simple mode that tries to handle Modelica as well as it can.

    + +

    MIME types defined: text/x-modelica + (Modlica code).

    +
    diff --git a/mode/modelica/modelica.js b/mode/modelica/modelica.js new file mode 100644 index 0000000000..77ec7a3c18 --- /dev/null +++ b/mode/modelica/modelica.js @@ -0,0 +1,245 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +// Modelica support for CodeMirror, copyright (c) by Lennart Ochel + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +}) + +(function(CodeMirror) { + "use strict"; + + CodeMirror.defineMode("modelica", function(config, parserConfig) { + + var indentUnit = config.indentUnit; + var keywords = parserConfig.keywords || {}; + var builtin = parserConfig.builtin || {}; + var atoms = parserConfig.atoms || {}; + + var isSingleOperatorChar = /[;=\(:\),{}.*<>+\-\/^\[\]]/; + var isDoubleOperatorChar = /(:=|<=|>=|==|<>|\.\+|\.\-|\.\*|\.\/|\.\^)/; + var isDigit = /[0-9]/; + var isNonDigit = /[_a-zA-Z]/; + + function tokenLineComment(stream, state) { + stream.skipToEnd(); + state.tokenize = null; + return "comment"; + } + + function tokenBlockComment(stream, state) { + var maybeEnd = false, ch; + while (ch = stream.next()) { + if (maybeEnd && ch == "/") { + state.tokenize = null; + break; + } + maybeEnd = (ch == "*"); + } + return "comment"; + } + + function tokenString(stream, state) { + var escaped = false, ch; + while ((ch = stream.next()) != null) { + if (ch == '"' && !escaped) { + state.tokenize = null; + state.sol = false; + break; + } + escaped = !escaped && ch == "\\"; + } + + return "string"; + } + + function tokenIdent(stream, state) { + stream.eatWhile(isDigit); + while (stream.eat(isDigit) || stream.eat(isNonDigit)) { } + + + var cur = stream.current(); + + if(state.sol && (cur == "package" || cur == "model" || cur == "when" || cur == "connector")) state.level++; + else if(state.sol && cur == "end" && state.level > 0) state.level--; + + state.tokenize = null; + state.sol = false; + + if (keywords.propertyIsEnumerable(cur)) return "keyword"; + else if (builtin.propertyIsEnumerable(cur)) return "builtin"; + else if (atoms.propertyIsEnumerable(cur)) return "atom"; + else return "variable"; + } + + function tokenQIdent(stream, state) { + while (stream.eat(/[^']/)) { } + + state.tokenize = null; + state.sol = false; + + if(stream.eat("'")) + return "variable"; + else + return "error"; + } + + function tokenUnsignedNuber(stream, state) { + stream.eatWhile(isDigit); + if (stream.eat('.')) { + stream.eatWhile(isDigit); + } + if (stream.eat('e') || stream.eat('E')) { + if (!stream.eat('-')) + stream.eat('+'); + stream.eatWhile(isDigit); + } + + state.tokenize = null; + state.sol = false; + return "number"; + } + + // Interface + return { + startState: function() { + return { + tokenize: null, + level: 0, + sol: true + }; + }, + + token: function(stream, state) { + if(state.tokenize != null) { + return state.tokenize(stream, state); + } + + if(stream.sol()) { + state.sol = true; + } + + // WHITESPACE + if(stream.eatSpace()) { + state.tokenize = null; + return null; + } + + var ch = stream.next(); + + // LINECOMMENT + if(ch == '/' && stream.eat('/')) { + state.tokenize = tokenLineComment; + } + // BLOCKCOMMENT + else if(ch == '/' && stream.eat('*')) { + state.tokenize = tokenBlockComment; + } + // TWO SYMBOL TOKENS + else if(isDoubleOperatorChar.test(ch+stream.peek())) { + stream.next(); + state.tokenize = null; + return "operator"; + } + // SINGLE SYMBOL TOKENS + else if(isSingleOperatorChar.test(ch)) { + state.tokenize = null; + return "operator"; + } + // IDENT + else if(isNonDigit.test(ch)) { + state.tokenize = tokenIdent; + } + // Q-IDENT + else if(ch == "'" && stream.peek() && stream.peek() != "'") { + state.tokenize = tokenQIdent; + } + // STRING + else if(ch == '"') { + state.tokenize = tokenString; + } + // UNSIGNED_NUBER + else if(isDigit.test(ch)) { + state.tokenize = tokenUnsignedNuber; + } + // ERROR + else { + state.tokenize = null; + return "error"; + } + + return state.tokenize(stream, state); + }, + + indent: function(state, textAfter) { + if (state.tokenize != null) return CodeMirror.Pass; + + var level = state.level; + if(/(algorithm)/.test(textAfter)) level--; + if(/(equation)/.test(textAfter)) level--; + if(/(initial algorithm)/.test(textAfter)) level--; + if(/(initial equation)/.test(textAfter)) level--; + if(/(end)/.test(textAfter)) level--; + + if(level > 0) + return indentUnit*level; + else + return 0; + }, + + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" + }; + }); + + function words(str) { + var obj = {}, words = str.split(" "); + for (var i=0; i Date: Wed, 27 Aug 2014 00:39:53 -0700 Subject: [PATCH 2062/5273] [python mode] Make 'in' a keyword --- mode/python/python.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/python/python.js b/mode/python/python.js index 45dd63ba48..4e1f296ae1 100644 --- a/mode/python/python.js +++ b/mode/python/python.js @@ -15,12 +15,12 @@ return new RegExp("^((" + words.join(")|(") + "))\\b"); } - var wordOperators = wordRegexp(["and", "or", "not", "is", "in"]); + var wordOperators = wordRegexp(["and", "or", "not", "is"]); var commonKeywords = ["as", "assert", "break", "class", "continue", "def", "del", "elif", "else", "except", "finally", "for", "from", "global", "if", "import", "lambda", "pass", "raise", "return", - "try", "while", "with", "yield"]; + "try", "while", "with", "yield", "in"]; var commonBuiltins = ["abs", "all", "any", "bin", "bool", "bytearray", "callable", "chr", "classmethod", "compile", "complex", "delattr", "dict", "dir", "divmod", "enumerate", "eval", "filter", "float", "format", "frozenset", From 43379968f6a62b89e2b350acd9174971e3e50706 Mon Sep 17 00:00:00 2001 From: Hiroyuki Makino Date: Thu, 28 Aug 2014 23:03:04 +0900 Subject: [PATCH 2063/5273] [release notes] Fix section structure --- doc/releases.html | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/releases.html b/doc/releases.html index 4b6d384b9e..f88a0373a6 100644 --- a/doc/releases.html +++ b/doc/releases.html @@ -25,9 +25,9 @@

    Release notes and version history

    -
    +
    -

    Version 4.x

    +

    Version 4.x

    21-08-2014: Version 4.5:

    @@ -114,7 +114,11 @@

    Version 4.x

  • Full list of patches.
  • -

    Version 3.x

    +
    + +
    + +

    Version 3.x

    22-04-2014: Version 3.24:

    From 3d8c1e506fd80feeb28a873a6dc6d1087d82327a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 1 Sep 2014 13:32:06 +0200 Subject: [PATCH 2064/5273] Export findWordAt Closes #2790 --- doc/manual.html | 4 ++++ lib/codemirror.js | 42 +++++++++++++++++++++--------------------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 6069fa6aea..02f3a59aaf 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1312,6 +1312,10 @@

    Cursor and selection methods

    be "line" or "page". The other arguments and the returned value have the same interpretation as they have in findPosH. + +
    cm.findWordAt(pos: {line, ch}) → {anchor: {line, ch}, head: {line, ch}}
    +
    Returns the start and end of the 'word' (the stretch of + letters, whitespace, or punctuation) at the given position.

    Configuration methods

    diff --git a/lib/codemirror.js b/lib/codemirror.js index 2c3b17df67..4270b98a45 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2528,7 +2528,7 @@ var pos = posFromMouse(cm, e); if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; e_preventDefault(e); - var word = findWordAt(cm, pos); + var word = cm.findWordAt(pos); extendSelection(cm.doc, word.anchor, word.head); })); else @@ -2807,7 +2807,7 @@ start = posFromMouse(cm, e, true, true); ourIndex = -1; } else if (type == "double") { - var word = findWordAt(cm, start); + var word = cm.findWordAt(start); if (cm.display.shift || doc.extend) ourRange = extendRange(doc, ourRange, word.anchor, word.head); else @@ -2861,7 +2861,7 @@ var anchor = oldRange.anchor, head = pos; if (type != "single") { if (type == "double") - var range = findWordAt(cm, pos); + var range = cm.findWordAt(pos); else var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))); if (cmp(range.anchor, anchor) > 0) { @@ -3999,24 +3999,6 @@ return target; } - // Find the word at the given position (as returned by coordsChar). - function findWordAt(cm, pos) { - var doc = cm.doc, line = getLine(doc, pos.line).text; - var start = pos.ch, end = pos.ch; - if (line) { - var helper = cm.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; - } - return new Range(Pos(pos.line, start), Pos(pos.line, end)); - } - // EDITOR METHODS // The publicly visible API. Note that methodOp(f) means @@ -4358,6 +4340,24 @@ 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; + 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 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; + } + return new Range(Pos(pos.line, start), Pos(pos.line, end)); + }, + toggleOverwrite: function(value) { if (value != null && value == this.state.overwrite) return; if (this.state.overwrite = !this.state.overwrite) From 9b87ca9ca4f8c81f84ff755e921ddaf3aa7373fc Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 1 Sep 2014 13:34:35 +0200 Subject: [PATCH 2065/5273] [merge addon] Add diff_match_patch as explicit dependency Closes #2783 --- addon/merge/merge.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/addon/merge/merge.js b/addon/merge/merge.js index d9b277664b..da3ea47ccf 100644 --- a/addon/merge/merge.js +++ b/addon/merge/merge.js @@ -1,17 +1,17 @@ // CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE +// declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL + (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); + mod(require("../../lib/codemirror"), require("diff_match_patch")); else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); + define(["../../lib/codemirror", "diff_match_patch"], mod); else // Plain browser env - mod(CodeMirror); -})(function(CodeMirror) { + mod(CodeMirror, diff_match_patch); +})(function(CodeMirror, diff_match_patch) { "use strict"; - // declare global: diff_match_patch, DIFF_INSERT, DIFF_DELETE, DIFF_EQUAL - var Pos = CodeMirror.Pos; var svgNS = "http://www.w3.org/2000/svg"; From 59b7b9082be50d51e9b5589e6957668c5d3cb35a Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 1 Sep 2014 13:44:22 +0200 Subject: [PATCH 2066/5273] Add Hebrew code range to nonASCIISingleCaseWordChar regexp Fixes detection of Hebrew letters as word characters Closes #2789 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 4270b98a45..f06b99bd72 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -7295,7 +7295,7 @@ return function(){return f.apply(null, args);}; } - var nonASCIISingleCaseWordChar = /[\u00df\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; + var nonASCIISingleCaseWordChar = /[\u00df\u0590-\u05f4\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; var isWordCharBasic = CodeMirror.isWordChar = function(ch) { return /\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); From 623eb7badb58f5d7bc9bbd836f86f046180e2a1c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 1 Sep 2014 17:59:23 +0200 Subject: [PATCH 2067/5273] Force scroll update from swapDoc Issue #2714 --- lib/codemirror.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index f06b99bd72..c865bc560b 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2090,11 +2090,11 @@ display.wheelStartX = display.wheelStartY = null; // Propagate the scroll position to the actual DOM scroller - if (op.scrollTop != null && display.scroller.scrollTop != op.scrollTop) { + if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top; } - if (op.scrollLeft != null && display.scroller.scrollLeft != op.scrollLeft) { + if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft)); display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left; alignHorizontally(cm); @@ -4444,6 +4444,7 @@ clearCaches(this); resetInput(this); this.scrollTo(doc.scrollLeft, doc.scrollTop); + this.curOp.forceScroll = true; signalLater(this, "swapDoc", this, old); return old; }), From 376f3ec90d05272459bf0b79d4ff9005a284705e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 1 Sep 2014 18:04:52 +0200 Subject: [PATCH 2068/5273] [sass mode] Make sure indentCount is initialized propertly Issue #2786 --- mode/sass/sass.js | 1 + 1 file changed, 1 insertion(+) diff --git a/mode/sass/sass.js b/mode/sass/sass.js index 68df323e18..b792a02aa3 100644 --- a/mode/sass/sass.js +++ b/mode/sass/sass.js @@ -303,6 +303,7 @@ CodeMirror.defineMode("sass", function(config) { return { tokenizer: tokenBase, scopes: [{offset: 0, type: "sass"}], + indentCount: 0, definedVars: [], definedMixins: [] }; From cb5416f1229e2c8555784cb089916a5953c07b1b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Sep 2014 08:36:11 +0200 Subject: [PATCH 2069/5273] [markdown mode] Fix handling of escaped characters Issue #2792 --- mode/markdown/markdown.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 81ed24e8d3..90a9282f85 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -360,15 +360,9 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { var ch = stream.next(); - if (state.escape) { - state.escape = false; - return getType(state); - } - if (ch === '\\') { - if (modeCfg.highlightFormatting) state.formatting = "escape"; - state.escape = true; - return getType(state); + stream.next(); + if (modeCfg.highlightFormatting) return getType(state) + " escape"; } // Matches link titles present on next line @@ -650,7 +644,6 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { inline: inlineNormal, text: handleText, - escape: false, formatting: false, linkText: false, linkHref: false, @@ -683,7 +676,6 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { inline: s.inline, text: s.text, - escape: false, formatting: false, linkTitle: s.linkTitle, em: s.em, @@ -718,9 +710,6 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { state.thisLineHasContent = true; } - // Reset state.escape - state.escape = false; - // Reset state.taskList state.taskList = false; From 31319ee225a60dcc750ba01a40e70bdedaaaafc7 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Sep 2014 08:42:11 +0200 Subject: [PATCH 2070/5273] [markdown mode] Make test pass --- mode/markdown/markdown.js | 5 ++++- mode/markdown/test.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mode/markdown/markdown.js b/mode/markdown/markdown.js index 90a9282f85..1bad78d65e 100644 --- a/mode/markdown/markdown.js +++ b/mode/markdown/markdown.js @@ -362,7 +362,10 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) { if (ch === '\\') { stream.next(); - if (modeCfg.highlightFormatting) return getType(state) + " escape"; + if (modeCfg.highlightFormatting) { + var type = getType(state); + return type ? type + " formatting-escape" : "formatting-escape"; + } } // Matches link titles present on next line diff --git a/mode/markdown/test.js b/mode/markdown/test.js index 77a3b659c0..96ca1aefc7 100644 --- a/mode/markdown/test.js +++ b/mode/markdown/test.js @@ -54,7 +54,7 @@ "[link&formatting&formatting-link <][link user@example.com][link&formatting&formatting-link >]"); FT("formatting_escape", - "[formatting&formatting-escape \\]*"); + "[formatting-escape \\*]"); MT("plainText", "foo"); From f593e03a09a156f1a7824757beaa001369f11422 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 3 Sep 2014 22:23:25 +0200 Subject: [PATCH 2071/5273] Set a min height on the lines element to prevent collapsing of wrapper Issue #2765 --- lib/codemirror.css | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/codemirror.css b/lib/codemirror.css index c0897771aa..1ab8acb296 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -213,6 +213,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} .CodeMirror-lines { cursor: text; + min-height: 1px; /* prevents collapsing before first draw */ } .CodeMirror pre { /* Reset some styles that the rest of the page might have set */ From 17c992e979daf3a3aa75926d38144e3c9d4dc064 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 4 Sep 2014 08:44:24 +0200 Subject: [PATCH 2072/5273] Only apply IE<11 zooming compensation for client rects when getting rect from a range It does not happen when measuring a node Issue #2665 --- lib/codemirror.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index c865bc560b..151ee91a66 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1665,6 +1665,7 @@ start = start - 1; collapse = "right"; } + 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; @@ -1681,8 +1682,6 @@ rect = nullRect; } - if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect); - var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; var mid = (rtop + rbot) / 2; var heights = prepared.view.measure.heights; From 616339b47245b3a044057afa460a3768ffa0369c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 8 Sep 2014 12:52:49 +0200 Subject: [PATCH 2073/5273] [closetag addon] Work better with htmlmixed mode It now closes script and style tags when the slash is typed Closes #2797 --- addon/edit/closetag.js | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/addon/edit/closetag.js b/addon/edit/closetag.js index 69ea4446be..a0bec7dd43 100644 --- a/addon/edit/closetag.js +++ b/addon/edit/closetag.js @@ -102,11 +102,25 @@ var pos = ranges[i].head, tok = cm.getTokenAt(pos); var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; if (tok.type == "string" || tok.string.charAt(0) != "<" || - tok.start != pos.ch - 1 || inner.mode.name != "xml" || - !state.context || !state.context.tagName || - closingTagExists(cm, state.context.tagName, pos, state)) + tok.start != pos.ch - 1) return CodeMirror.Pass; - replacements[i] = "/" + state.context.tagName + ">"; + // Kludge to get around the fact that we are not in XML mode + // when completing in JS/CSS snippet in htmlmixed mode. Does not + // work for other XML embedded languages (there is no general + // way to go from a mixed mode to its current XML state). + if (inner.mode.name != "xml") { + if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript") + replacements[i] = "/script>"; + else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css") + replacements[i] = "/style>"; + else + return CodeMirror.Pass; + } else { + if (!state.context || !state.context.tagName || + closingTagExists(cm, state.context.tagName, pos, state)) + return CodeMirror.Pass; + replacements[i] = "/" + state.context.tagName + ">"; + } } cm.replaceSelections(replacements); ranges = cm.listSelections(); From 7817708c3165f1ca376bdc7181df6d036cb90ad8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 8 Sep 2014 13:03:54 +0200 Subject: [PATCH 2074/5273] [javascript mode] Fix parsing of argument-less fat arrow functions Closes #2794 --- mode/javascript/javascript.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mode/javascript/javascript.js b/mode/javascript/javascript.js index 46616bc021..2e24d3a55b 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -391,7 +391,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { function maybeoperatorNoComma(type, value, noComma) { var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma; var expr = noComma == false ? expression : expressionNoComma; - if (value == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); + if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext); if (type == "operator") { if (/\+\+|--/.test(value)) return cont(me); if (value == "?") return cont(expression, expect(":"), expr); @@ -417,13 +417,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function arrowBody(type) { findFatArrow(cx.stream, cx.state); - if (type == "{") return pass(statement); - return pass(expression); + return pass(type == "{" ? statement : expression); } function arrowBodyNoComma(type) { findFatArrow(cx.stream, cx.state); - if (type == "{") return pass(statement); - return pass(expressionNoComma); + return pass(type == "{" ? statement : expressionNoComma); } function maybelabel(type) { if (type == ":") return cont(poplex, statement); From 0a91c1427a2771a94731384f3537c78468be44f8 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 8 Sep 2014 13:22:02 +0200 Subject: [PATCH 2075/5273] [smalltalk mode] Use \s instead of space in regexps that denote whitespace Closes #2796 --- mode/smalltalk/smalltalk.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode/smalltalk/smalltalk.js b/mode/smalltalk/smalltalk.js index 50f41cc615..bb510ba2e1 100644 --- a/mode/smalltalk/smalltalk.js +++ b/mode/smalltalk/smalltalk.js @@ -53,7 +53,7 @@ CodeMirror.defineMode('smalltalk', function(config) { stream.next(); token = nextSymbol(stream, new Context(nextSymbol, context)); } else { - if (stream.eatWhile(/[^ .{}\[\]()]/)) + if (stream.eatWhile(/[^\s.{}\[\]()]/)) token.name = 'string-2'; else token.name = 'meta'; @@ -61,7 +61,7 @@ CodeMirror.defineMode('smalltalk', function(config) { } else if (aChar === '$') { if (stream.next() === '<') { - stream.eatWhile(/[^ >]/); + stream.eatWhile(/[^\s>]/); stream.next(); } token.name = 'string-2'; From 1adaa01dbf7fb030b61731314dd245d9dbf8014e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 9 Sep 2014 16:22:11 +0200 Subject: [PATCH 2076/5273] Add a requireJS demo --- addon/hint/html-hint.js | 4 ++-- demo/requirejs.html | 52 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 demo/requirejs.html diff --git a/addon/hint/html-hint.js b/addon/hint/html-hint.js index addd9b7bc0..992218f288 100755 --- a/addon/hint/html-hint.js +++ b/addon/hint/html-hint.js @@ -3,9 +3,9 @@ (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS - mod(require("../../lib/codemirror")); + mod(require("../../lib/codemirror", "./xml-hint")); else if (typeof define == "function" && define.amd) // AMD - define(["../../lib/codemirror"], mod); + define(["../../lib/codemirror", "./xml-hint"], mod); else // Plain browser env mod(CodeMirror); })(function(CodeMirror) { diff --git a/demo/requirejs.html b/demo/requirejs.html new file mode 100644 index 0000000000..6399f8d769 --- /dev/null +++ b/demo/requirejs.html @@ -0,0 +1,52 @@ + + + + CodeMirror: HTML completion demo + + + + + + + + + + + + +
    +

    RequireJS module loading demo

    + +

    This demo does the same thing as + the HTML5 completion demo, but + loads its dependencies + with Require.js, rather than + explicitly. Press ctrl-space to activate + completion.

    + +
    + + +
    + From c012f411ee01c9802d046c2d76dc3b4b0001d67b Mon Sep 17 00:00:00 2001 From: Marcel Gerber Date: Tue, 9 Sep 2014 12:23:51 +0200 Subject: [PATCH 2077/5273] Improve isWordChar() for Arabic language --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 151ee91a66..ea2caaff62 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -7295,7 +7295,7 @@ return function(){return f.apply(null, args);}; } - var nonASCIISingleCaseWordChar = /[\u00df\u0590-\u05f4\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; + var nonASCIISingleCaseWordChar = /[\u00df\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; var isWordCharBasic = CodeMirror.isWordChar = function(ch) { return /\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); From 8fac50ac265de832e08d428faffb36d464cb5bda Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 15 Sep 2014 11:32:38 +0200 Subject: [PATCH 2078/5273] Fix handling of electricChars in multi-line edits Closes #2804 --- lib/codemirror.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index ea2caaff62..246492a9fb 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -2456,16 +2456,16 @@ cm.options.smartIndent && range.head.ch < 100 && (!i || doc.sel.ranges[i - 1].head.line != range.head.line)) { var mode = cm.getModeAt(range.head); + var end = changeEnd(changeEvent); if (mode.electricChars) { for (var j = 0; j < mode.electricChars.length; j++) if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { - indentLine(cm, range.head.line, "smart"); + indentLine(cm, end.line, "smart"); break; } } else if (mode.electricInput) { - var end = changeEnd(changeEvent); if (mode.electricInput.test(getLine(doc, end.line).text.slice(0, end.ch))) - indentLine(cm, range.head.line, "smart"); + indentLine(cm, end.line, "smart"); } } } From c2ee5a6ec55f4542adc9838b467861019a3cad9b Mon Sep 17 00:00:00 2001 From: Marko Bonaci Date: Fri, 12 Sep 2014 19:14:38 +0200 Subject: [PATCH 2079/5273] Make parentheses visible while under `matchingbracket` rule Code: Brackets now become black when they are highlighted as "matching". JSON: key names are now in "white" (json was a bit saturated with orange - keys and string values). Cleanup: removed some unnecessary rules. Default face color normalized to #ffffec (was #ffffe9). --- theme/mbo.css | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/theme/mbo.css b/theme/mbo.css index 6cb2b18d9b..0ad6360b50 100644 --- a/theme/mbo.css +++ b/theme/mbo.css @@ -1,6 +1,10 @@ -/* Based on mbonaci's Brackets mbo theme */ +/****************************************************************/ +/* Based on mbonaci's Brackets mbo theme */ +/* https://github.com/mbonaci/global/blob/master/Mbo.tmTheme */ +/* Create your own: http://tmtheme-editor.herokuapp.com */ +/****************************************************************/ -.cm-s-mbo.CodeMirror {background: #2c2c2c; color: #ffffe9;} +.cm-s-mbo.CodeMirror {background: #2c2c2c; color: #ffffec;} .cm-s-mbo div.CodeMirror-selected {background: #716C62 !important;} .cm-s-mbo .CodeMirror-gutters {background: #4e4e4e; border-right: 0px;} .cm-s-mbo .CodeMirror-guttermarker { color: white; } @@ -15,6 +19,7 @@ .cm-s-mbo span.cm-property, .cm-s-mbo span.cm-attribute {color: #9ddfe9;} .cm-s-mbo span.cm-keyword {color: #ffb928;} .cm-s-mbo span.cm-string {color: #ffcf6c;} +.cm-s-mbo span.cm-string.cm-property {color: #ffffec;} .cm-s-mbo span.cm-variable {color: #ffffec;} .cm-s-mbo span.cm-variable-2 {color: #00a8c6;} @@ -23,17 +28,8 @@ .cm-s-mbo span.cm-tag {color: #9ddfe9;} .cm-s-mbo span.cm-link {color: #f54b07;} .cm-s-mbo span.cm-error {border-bottom: #636363; color: #ffffec;} +.cm-s-mbo span.cm-qualifier {color: #ffffec;} .cm-s-mbo .CodeMirror-activeline-background {background: #494b41 !important;} -.cm-s-mbo .CodeMirror-matchingbracket { - text-decoration: underline; - color: #f5e107 !important; - } - -.cm-s-mbo .CodeMirror-matchingtag { background: rgba(255, 255, 255, .37); } - -.cm-s-mbo span.cm-searching { - background-color: none; - background: none; - box-shadow: 0 0 0 1px #ffffec; -} +.cm-s-mbo .CodeMirror-matchingbracket {color: #222 !important;} +.cm-s-mbo .CodeMirror-matchingtag {background: rgba(255, 255, 255, .37);} From fcacef102486908b4331c8db9dc084daff7562bd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 15 Sep 2014 15:29:33 +0200 Subject: [PATCH 2080/5273] [show-hint addon] Give active hint color more precedence To make it easy for client code to color completions without clashing with the selected styling. --- addon/hint/show-hint.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/hint/show-hint.css b/addon/hint/show-hint.css index 8a4ff052e3..924e638f7f 100644 --- a/addon/hint/show-hint.css +++ b/addon/hint/show-hint.css @@ -32,7 +32,7 @@ cursor: pointer; } -.CodeMirror-hint-active { +li.CodeMirror-hint-active { background: #08f; color: white; } From 640fbb28abf7dc4014c8c5ee6efe9309c091a98a Mon Sep 17 00:00:00 2001 From: snasa Date: Mon, 15 Sep 2014 22:30:25 -0700 Subject: [PATCH 2081/5273] Update shell.js --- 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 77be75b97d..8e31f6f30b 100644 --- a/mode/shell/shell.js +++ b/mode/shell/shell.js @@ -128,7 +128,8 @@ CodeMirror.defineMode('shell', function() { startState: function() {return {tokens:[]};}, token: function(stream, state) { return tokenize(stream, state); - } + }, + lineComment: '#' }; }); From f09b6c5ec7bf2d7a7b2ee1ac8cc5c53b27f76f62 Mon Sep 17 00:00:00 2001 From: Daniele Di Sarli Date: Mon, 1 Sep 2014 21:53:17 +0200 Subject: [PATCH 2082/5273] Added wordsOnly option. Updated documentation. --- addon/search/match-highlighter.js | 32 +++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/addon/search/match-highlighter.js b/addon/search/match-highlighter.js index 14dd4d4184..e9a22721f7 100644 --- a/addon/search/match-highlighter.js +++ b/addon/search/match-highlighter.js @@ -8,12 +8,15 @@ // document. // // The option can be set to true to simply enable it, or to a -// {minChars, style, showToken} object to explicitly configure it. -// minChars is the minimum amount of characters that should be +// {minChars, style, wordsOnly, showToken, delay} object to explicitly +// configure it. minChars is the minimum amount of characters that should be // selected for the behavior to occur, and style is the token style to // apply to the matches. This will be prefixed by "cm-" to create an -// actual CSS class name. showToken, when enabled, will cause the -// current token to be highlighted when nothing is selected. +// actual CSS class name. If wordsOnly is enabled, the matches will be +// 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. (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS @@ -28,6 +31,7 @@ var DEFAULT_MIN_CHARS = 2; var DEFAULT_TOKEN_STYLE = "matchhighlight"; var DEFAULT_DELAY = 100; + var DEFAULT_WORDS_ONLY = false; function State(options) { if (typeof options == "object") { @@ -35,10 +39,12 @@ this.style = options.style; this.showToken = options.showToken; this.delay = options.delay; + this.wordsOnly = options.wordsOnly; } if (this.style == null) this.style = DEFAULT_TOKEN_STYLE; if (this.minChars == null) this.minChars = DEFAULT_MIN_CHARS; if (this.delay == null) this.delay = DEFAULT_DELAY; + if (this.wordsOnly == null) this.wordsOnly = DEFAULT_WORDS_ONLY; this.overlay = this.timeout = null; } @@ -81,12 +87,30 @@ } var from = cm.getCursor("from"), to = cm.getCursor("to"); if (from.line != to.line) return; + if (state.wordsOnly && !isWord(cm, from, to)) return; var selection = cm.getRange(from, to).replace(/^\s+|\s+$/g, ""); if (selection.length >= state.minChars) cm.addOverlay(state.overlay = makeOverlay(selection, false, state.style)); }); } + function isWord(cm, from, to) { + var str = cm.getRange(from, to); + if (str.match(/^\w+$/) !== null) { + if (from.ch > 0) { + var pos = {line: from.line, ch: from.ch - 1}; + var chr = cm.getRange(pos, from); + if (chr.match(/\W/) === null) return false; + } + if (to.ch < cm.getLine(from.line).length) { + var pos = {line: to.line, ch: to.ch + 1}; + var chr = cm.getRange(to, pos); + if (chr.match(/\W/) === null) return false; + } + return true; + } else return false; + } + function boundariesAround(stream, re) { return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) && (stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos))); From cf15c70108b65fda224510177c9ac18e6727f9c0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 18 Sep 2014 14:59:08 +0200 Subject: [PATCH 2083/5273] Add example of using markselection to style background to demo --- demo/markselection.html | 15 +++++++++++---- lib/codemirror.css | 9 ++++++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/demo/markselection.html b/demo/markselection.html index 93e38ec833..a182217fd5 100644 --- a/demo/markselection.html +++ b/demo/markselection.html @@ -12,6 +12,7 @@ .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;} .CodeMirror-selected { background-color: blue !important; } .CodeMirror-selectedtext { color: white; } + .styled-background { background-color: #ff7; }
    -

    Addons

    +

    Addons

    The addon directory in the distribution contains a number of reusable components that implement extra editor diff --git a/index.html b/index.html index 7a2bbdcfce..cf9f943ac5 100644 --- a/index.html +++ b/index.html @@ -40,7 +40,7 @@

    CodeMirror is a versatile text editor implemented in JavaScript for the browser. It is specialized for - editing code, and comes with a number of language modes and addons + editing code, and comes with a number of language modes and addons that implement more advanced editing functionality.

    A rich programming API and a From 137737779912ef2cb67416e5e91852753acfe6ae Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Tue, 14 Oct 2014 22:53:08 -0400 Subject: [PATCH 2146/5273] [vim] Fix uppercase key lookup --- keymap/vim.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keymap/vim.js b/keymap/vim.js index 9abb0f52bc..a0a01e06c6 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -230,7 +230,7 @@ function lookupKey(e) { var keyCode = e.keyCode; if (modifierCodes.indexOf(keyCode) != -1) { return; } - var hasModifier = e.ctrlKey || e.shiftKey || e.metaKey; + var hasModifier = e.ctrlKey || e.metaKey; var key = CodeMirror.keyNames[keyCode]; key = specialKey[key] || key; var name = ''; From 0caeb00baf3abf8e89d0358fbc3c5ee7eb2d75dd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 16 Oct 2014 09:45:57 +0200 Subject: [PATCH 2147/5273] Move ctrl-up/down bindings to mac keymap, bind them to goLineUp/Down on PC --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index dbfe56a503..df514190d2 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -4864,7 +4864,7 @@ // are simply ignored. keyMap.pcDefault = { "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", - "Ctrl-Home": "goDocStart", "Ctrl-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd", + "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", @@ -4879,7 +4879,7 @@ "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", - "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", + "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", fallthrough: ["basic", "emacsy"] }; // Very basic readline/emacs-style bindings, which are standard on Mac. From 10d9bf1100c1636aa8d9eb381b86bef23bc3ca3d Mon Sep 17 00:00:00 2001 From: Norman Rzepka Date: Tue, 14 Oct 2014 13:24:42 +0200 Subject: [PATCH 2148/5273] continuelist: hitting enter twice cancels the list --- addon/edit/continuelist.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/addon/edit/continuelist.js b/addon/edit/continuelist.js index 8cee761aee..56f54c9227 100644 --- a/addon/edit/continuelist.js +++ b/addon/edit/continuelist.js @@ -12,6 +12,7 @@ "use strict"; var listRE = /^(\s*)([*+-]|(\d+)\.)(\s+)/, + emptyListRE = /^(\s*)([*+-]|(\d+)\.)(\s*)$/, unorderedBullets = "*+-"; CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { @@ -25,12 +26,22 @@ cm.execCommand("newlineAndIndent"); return; } - var indent = match[1], after = match[4]; - var bullet = unorderedBullets.indexOf(match[2]) >= 0 - ? match[2] - : (parseInt(match[3], 10) + 1) + "."; + if (cm.getLine(pos.line).match(emptyListRE)) { + cm.replaceRange("", { + line: pos.line, ch: 0 + }, { + line: pos.line, ch: pos.ch + 1 + }); + replacements[i] = "\n"; - replacements[i] = "\n" + indent + bullet + after; + } else { + var indent = match[1], after = match[4]; + var bullet = unorderedBullets.indexOf(match[2]) >= 0 + ? match[2] + : (parseInt(match[3], 10) + 1) + "."; + + replacements[i] = "\n" + indent + bullet + after; + } } cm.replaceSelections(replacements); From d913da999746ef1bd1510ed9f4e275d023c5a785 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 16 Oct 2014 09:54:20 +0200 Subject: [PATCH 2149/5273] [perl mode] Remove electric chars Issue #2870 --- 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 c12677d249..2a64c2ed41 100644 --- a/mode/perl/perl.js +++ b/mode/perl/perl.js @@ -789,7 +789,7 @@ CodeMirror.defineMode("perl",function(){ tail:null};}, token:function(stream,state){ return (state.tokenize||tokenPerl)(stream,state);}, - electricChars:"{}"};}); + };}); CodeMirror.registerHelper("wordChars", "perl", /[\w$]/); From 0462939fa2e8e2699aabcfbb9c86802cbdb6c828 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 16 Oct 2014 10:02:50 +0200 Subject: [PATCH 2150/5273] Fix superfluous comma --- 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 2a64c2ed41..311574e74a 100644 --- a/mode/perl/perl.js +++ b/mode/perl/perl.js @@ -788,7 +788,7 @@ CodeMirror.defineMode("perl",function(){ style:null, tail:null};}, token:function(stream,state){ - return (state.tokenize||tokenPerl)(stream,state);}, + return (state.tokenize||tokenPerl)(stream,state);} };}); CodeMirror.registerHelper("wordChars", "perl", /[\w$]/); From c576c4cb4a9923b4acd172e7daa48fe67ef3c74f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 16 Oct 2014 17:45:14 +0200 Subject: [PATCH 2151/5273] Don't use finally in the operation that initializes the editor Trying to call endOperation on a half-constructed editor will never end well, and the resulting errors will mask the actual error that happened. --- lib/codemirror.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index df514190d2..7277b8bd0d 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -96,21 +96,20 @@ registerEventHandlers(this); ensureGlobalHandlers(); - var cm = this; - runInOp(this, function() { - cm.curOp.forceUpdate = true; - attachDoc(cm, doc); + startOperation(this); + this.curOp.forceUpdate = true; + attachDoc(this, doc); - if ((options.autofocus && !mobile) || activeElt() == display.input) - setTimeout(bind(onFocus, cm), 20); - else - onBlur(cm); + if ((options.autofocus && !mobile) || activeElt() == display.input) + setTimeout(bind(onFocus, this), 20); + else + onBlur(this); - for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) - optionHandlers[opt](cm, options[opt], Init); - maybeUpdateLineNumberWidth(cm); - for (var i = 0; i < initHooks.length; ++i) initHooks[i](cm); - }); + for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) + optionHandlers[opt](this, options[opt], Init); + maybeUpdateLineNumberWidth(this); + for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); + endOperation(this); } // DISPLAY CONSTRUCTOR From 833ccba1d5d0b8d226ccc100b9b9eb6e854f3836 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 16 Oct 2014 17:51:41 +0200 Subject: [PATCH 2152/5273] Add simple mode addon --- addon/mode/simple.js | 200 +++++++++++++++++++++++++++++++++++++++++++ demo/simplemode.html | 172 +++++++++++++++++++++++++++++++++++++ doc/compress.html | 1 + doc/manual.html | 5 ++ 4 files changed, 378 insertions(+) create mode 100644 addon/mode/simple.js create mode 100644 demo/simplemode.html diff --git a/addon/mode/simple.js b/addon/mode/simple.js new file mode 100644 index 0000000000..7299eaeb34 --- /dev/null +++ b/addon/mode/simple.js @@ -0,0 +1,200 @@ +// CodeMirror, copyright (c) by Marijn Haverbeke and others +// Distributed under an MIT license: http://codemirror.net/LICENSE + +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../../lib/codemirror")); + else if (typeof define == "function" && define.amd) // AMD + define(["../../lib/codemirror"], mod); + else // Plain browser env + mod(CodeMirror); +})(function(CodeMirror) { + "use strict"; + + CodeMirror.defineSimpleMode = function(name, states, props) { + CodeMirror.defineMode(name, function(config) { + return CodeMirror.simpleMode(config, states, props); + }); + }; + + CodeMirror.simpleMode = function(config, states) { + ensureState(states, "start"); + var states_ = {}, meta = states.meta || {}, hasIndentation = false; + for (var state in states) if (state != meta && states.hasOwnProperty(state)) { + var list = states_[state] = [], orig = states[state]; + for (var i = 0; i < orig.length; i++) { + var data = orig[i]; + list.push(new Rule(data, states)); + if (data.indent || data.dedent) hasIndentation = true; + } + } + var mode = { + startState: function() { + return {state: "start", pending: null, + local: null, localState: null, + indent: hasIndentation ? [] : null}; + }, + copyState: function(state) { + var s = {state: state.state, pending: state.pending, + local: state.local, localState: null, + indent: state.indent && state.indent.slice(0)}; + if (state.localState) + s.localState = CodeMirror.copyState(state.local.mode, state.localState); + for (var pers = state.persistentStates; pers; pers = pers.next) + s.persistentStates = {mode: pers.mode, + spec: pers.spec, + state: pers.state == state.localState ? s.localState : CodeMirror.copyState(pers.mode, pers.state), + next: s.persistentStates}; + return s; + }, + token: tokenFunction(states_, config), + innerMode: function(state) { return state.local && {mode: state.local.mode, state: state.localState}; }, + indent: indentFunction(states_, meta) + }; + if (meta) for (var prop in meta) if (meta.hasOwnProperty(prop)) + mode[prop] = meta[prop]; + return mode; + }; + + function ensureState(states, name) { + if (!states.hasOwnProperty(name)) + throw new Error("Undefined state " + name + "in simple mode"); + } + + function toRegex(val, caret) { + if (!val) return /(?:)/; + var flags = ""; + if (val instanceof RegExp) { + if (val.ignoreCase) flags = "i"; + val = val.source; + } else { + val = String(val); + } + return new RegExp((caret === false ? "" : "^") + "(?:" + val + ")", flags); + } + + function asToken(val) { + if (!val) return null; + if (typeof val == "string") return val.replace(/\./g, " "); + var result = []; + for (var i = 0; i < val.length; i++) + result.push(val[i] && val[i].replace(/\./g, " ")); + return result; + } + + function Rule(data, states) { + if (data.next) ensureState(states, data.next); + this.regex = toRegex(data.regex); + this.token = asToken(data.token); + this.data = data; + } + + function tokenFunction(states, config) { + return function(stream, state) { + if (state.pending) { + var pend = state.pending.shift(); + if (state.pending.length == 0) state.pending = null; + stream.pos += pend.text.length; + return pend.token; + } + + if (state.local) { + if (state.local.end && stream.match(state.local.end)) { + var tok = state.local.endToken || null; + state.local = state.localState = null; + return tok; + } else { + var tok = state.local.mode.token(stream, state.localState), m; + if (state.local.endScan && (m = state.local.endScan.exec(stream.current()))) + stream.pos = stream.start + m.index; + return tok; + } + } + + var curState = states[state.state]; + for (var i = 0; i < curState.length; i++) { + var rule = curState[i]; + var matches = stream.match(rule.regex); + if (matches) { + if (rule.data.next) + state.state = rule.data.next; + if (rule.data.mode) + enterLocalMode(config, state, rule.data.mode, rule.token); + if (rule.data.indent) + state.indent.push(stream.indentation() + config.indentUnit); + if (rule.data.dedent) + state.indent.pop(); + if (matches.length > 2) { + state.pending = []; + for (var j = 2; j < matches.length; j++) + state.pending.push({text: matches[j], token: rule.token[j - 1]}); + stream.backUp(matches[0].length - matches[1].length); + return rule.token[0]; + } else if (rule.token && rule.token.join) { + return rule.token[0]; + } else { + return rule.token; + } + } + } + stream.next(); + return null; + }; + } + + function cmp(a, b) { + if (a === b) return true; + if (!a || typeof a != "object" || !b || typeof b != "object") return false; + var props = 0; + for (var prop in a) if (a.hasOwnProperty(prop)) { + if (!b.hasOwnProperty(prop) || !cmp(a[prop], b[prop])) return false; + props++; + } + for (var prop in b) if (b.hasOwnProperty(prop)) props--; + return props == 0; + } + + function enterLocalMode(config, state, spec, token) { + var pers; + if (spec.persistent) for (var p = state.persistentStates; p && !pers; p = p.next) + if (spec.spec ? cmp(spec.spec, p.spec) : spec.mode == p.mode) pers = p; + var mode = pers ? pers.mode : spec.mode || CodeMirror.getMode(config, spec.spec); + var lState = pers ? pers.state : CodeMirror.startState(mode); + if (spec.persistent && !pers) + state.persistentStates = {mode: mode, spec: spec.spec, state: lState, next: state.persistentStates}; + + state.localState = lState; + state.local = {mode: mode, + end: spec.end && toRegex(spec.end), + endScan: spec.end && spec.forceEnd !== false && toRegex(spec.end, false), + endToken: token && token.join ? token[token.length - 1] : token}; + } + + function indexOf(val, arr) { + for (var i = 0; i < arr.length; i++) if (arr[i] === val) return true; + } + + function indentFunction(states, meta) { + return function(state, textAfter, line) { + if (state.local && state.local.mode.indent) + return state.local.mode.indent(state.localState, textAfter, line); + if (state.indent == null || state.local || meta.dontIndentStates && indexOf(state.state, meta.dontIndentStates) > -1) + return CodeMirror.Pass; + + var pos = state.indent.length - 1, rules = states[state.state]; + scan: for (;;) { + for (var i = 0; i < rules.length; i++) { + var rule = rules[i], m = rule.regex.exec(textAfter); + if (m) { + if (rule.data.dedent && rule.data.dedentIfLineStart !== false) pos--; + if (rule.next) rules = states[rule.next]; + textAfter = textAfter.slice(m[0].length); + continue scan; + } + } + break; + } + return pos < 0 ? 0 : state.indent[pos]; + }; + } +}); diff --git a/demo/simplemode.html b/demo/simplemode.html new file mode 100644 index 0000000000..4b8de8cded --- /dev/null +++ b/demo/simplemode.html @@ -0,0 +1,172 @@ + + +CodeMirror: Simple Mode Demo + + + + + + + + + +

    + +
    +

    Simple Mode Demo

    + +

    The mode/simple +addon allows CodeMirror modes to be specified with a relatively simple +declarative format. This format is not as powerful as writing code +directly against the mode +interface, but is a lot easier to get started with, and +sufficiently expressive for many simple language modes.

    + +

    This interface is still in flux. It is unlikely to be scrapped or +overhauled completely, so do start writing code against it, but +details might change as it stabilizes, and you might have to tweak +your code when upgrading.

    + +

    Simple modes (loosely based on +the Common +JavaScript Syntax Highlighting Specification, which never took +off), are state machines, where each state has a number of rules that +match tokens. A rule describes a type of token that may occur in the +current state, and possibly a transition to another state caused by +that token.

    + +

    The CodeMirror.defineSimpleMode(name, states) method +takes a mode name and an object that describes the mode's states. The +editor below shows an example of such a mode (and is itself +highlighted by the mode shown in it).

    + +
    + +

    Each state is an array of rules. A rule may have the following properties:

    + +
    +
    regex
    +
    The regular expression that matches the token. May be a string + or a regex object. When a regex, the ignoreCase flag + will be taken into account when matching the token. This regex + should only capture groups when the token property is + an array.
    +
    token
    +
    An optional token style. Multiple styles can be specified by + separating them with dots or spaces. When the regex for + this rule captures groups, it must capture all of the + string (since JS provides no way to find out where a group matched), + and this property must hold an array of token styles that has one + style for each matched group.
    +
    next
    +
    When a next property is present, the mode will + transfer to another state when the token is encountered.
    +
    mode
    +
    Can be used to embed another mode inside a mode. When present, + must hold an object with a spec property that describes + the embedded mode, and an optional end end property + that specifies the regexp that will end the extent of the mode. When + a persistent property is set (and true), the nested + mode's state will be preserved between occurrences of the mode.
    +
    indent
    +
    When true, this token changes the indentation to be one unit + more than the current line's indentation.
    +
    dedent
    +
    When true, this token will pop one scope off the indentation + stack.
    +
    dedentIfLineStart
    +
    If a token has its dedent property set, it will, by + default, cause lines where it appears at the start to be dedented. + Set this property to false to prevent that behavior.
    +
    + +

    The meta property of the states object is special, and +will not be interpreted as a state. Instead, properties set on it will +be set on the mode, which is useful for properties +like lineComment, +which sets the comment style for a mode. The simple mode addon also +recognizes a few such properties:

    + +
    +
    dontIndentStates
    +
    An array of states in which the mode's auto-indentation should + not take effect. Usually used for multi-line comment and string + states.
    +
    + + + + + +
    diff --git a/doc/compress.html b/doc/compress.html index 19639903a3..940465259d 100644 --- a/doc/compress.html +++ b/doc/compress.html @@ -219,6 +219,7 @@

    Script compression helper

    + diff --git a/doc/manual.html b/doc/manual.html index fccf7d6416..f89cc4b3fd 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -2715,6 +2715,11 @@

    Writing CodeMirror Modes

    advances it past a token, and returns a style for that token. More advanced modes can also handle indentation for the language.

    +

    This section describes the low-level mode interface. Many modes + are written directly against this, since it offers a lot of + control, but for a quick mode definition, you might want to use + the simple mode addon.

    +

    The mode script should call CodeMirror.defineMode to register itself with CodeMirror. This function takes two From eee65eef5a258fef405d6880566213f5acf9924c Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 16 Oct 2014 17:53:19 +0200 Subject: [PATCH 2153/5273] [simple mode demo] Slight rewording --- demo/simplemode.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/simplemode.html b/demo/simplemode.html index 4b8de8cded..9218b04247 100644 --- a/demo/simplemode.html +++ b/demo/simplemode.html @@ -32,7 +32,7 @@

    Simple Mode Demo

    The mode/simple -addon allows CodeMirror modes to be specified with a relatively simple +addon allows CodeMirror modes to be specified using a relatively simple declarative format. This format is not as powerful as writing code directly against the mode interface, but is a lot easier to get started with, and From a9acabd88b1930b2e5d4470cb3a6ce2a20ffa5db Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 17 Oct 2014 00:27:53 +0200 Subject: [PATCH 2154/5273] Switch to new logo --- demo/activeline.html | 2 +- demo/anywordhint.html | 2 +- demo/bidi.html | 2 +- demo/btree.html | 2 +- demo/buffers.html | 2 +- demo/changemode.html | 2 +- demo/closebrackets.html | 2 +- demo/closetag.html | 2 +- demo/complete.html | 2 +- demo/emacs.html | 2 +- demo/folding.html | 2 +- demo/fullscreen.html | 2 +- demo/hardwrap.html | 2 +- demo/html5complete.html | 2 +- demo/indentwrap.html | 2 +- demo/lint.html | 2 +- demo/loadmode.html | 2 +- demo/marker.html | 2 +- demo/markselection.html | 2 +- demo/matchhighlighter.html | 2 +- demo/matchtags.html | 2 +- demo/merge.html | 2 +- demo/multiplex.html | 2 +- demo/mustache.html | 2 +- demo/placeholder.html | 2 +- demo/preview.html | 2 +- demo/requirejs.html | 2 +- demo/resize.html | 2 +- demo/rulers.html | 2 +- demo/runmode.html | 2 +- demo/search.html | 2 +- demo/simplemode.html | 2 +- demo/spanaffectswrapping_shim.html | 2 +- demo/sublime.html | 2 +- demo/tern.html | 2 +- demo/theme.html | 2 +- demo/trailingspace.html | 2 +- demo/variableheight.html | 2 +- demo/vim.html | 2 +- demo/visibletabs.html | 2 +- demo/widget.html | 2 +- demo/xmlcomplete.html | 2 +- doc/compress.html | 2 +- doc/docs.css | 13 +- doc/internals.html | 2 +- doc/logo.png | Bin 12003 -> 9730 bytes doc/logo.svg | 279 ++++++++++++++++------------- doc/manual.html | 2 +- doc/realworld.html | 2 +- doc/releases.html | 2 +- doc/reporting.html | 2 +- doc/upgrade_v2.2.html | 2 +- doc/upgrade_v3.html | 2 +- doc/upgrade_v4.html | 2 +- index.html | 2 +- mode/apl/index.html | 2 +- mode/asterisk/index.html | 2 +- mode/clike/index.html | 2 +- mode/clike/scala.html | 2 +- mode/clojure/index.html | 2 +- mode/cobol/index.html | 2 +- mode/coffeescript/index.html | 2 +- mode/commonlisp/index.html | 2 +- mode/css/index.html | 2 +- mode/css/less.html | 2 +- mode/css/scss.html | 2 +- mode/cypher/index.html | 2 +- mode/d/index.html | 2 +- mode/diff/index.html | 2 +- mode/django/index.html | 2 +- mode/dtd/index.html | 2 +- mode/dylan/index.html | 2 +- mode/ecl/index.html | 2 +- mode/eiffel/index.html | 2 +- mode/erlang/index.html | 2 +- mode/fortran/index.html | 2 +- mode/gas/index.html | 2 +- mode/gfm/index.html | 2 +- mode/gherkin/index.html | 2 +- mode/go/index.html | 2 +- mode/groovy/index.html | 2 +- mode/haml/index.html | 2 +- mode/haskell/index.html | 2 +- mode/haxe/index.html | 2 +- mode/htmlembedded/index.html | 2 +- mode/htmlmixed/index.html | 2 +- mode/http/index.html | 2 +- mode/index.html | 2 +- mode/jade/index.html | 2 +- mode/javascript/index.html | 2 +- mode/javascript/json-ld.html | 2 +- mode/javascript/typescript.html | 2 +- mode/jinja2/index.html | 2 +- mode/julia/index.html | 2 +- mode/kotlin/index.html | 2 +- mode/livescript/index.html | 2 +- mode/lua/index.html | 2 +- mode/markdown/index.html | 2 +- mode/mirc/index.html | 2 +- mode/mllike/index.html | 2 +- mode/modelica/index.html | 2 +- mode/nginx/index.html | 2 +- mode/ntriples/index.html | 2 +- mode/octave/index.html | 2 +- mode/pascal/index.html | 2 +- mode/pegjs/index.html | 2 +- mode/perl/index.html | 2 +- mode/php/index.html | 2 +- mode/pig/index.html | 2 +- mode/properties/index.html | 2 +- mode/puppet/index.html | 2 +- mode/python/index.html | 2 +- mode/q/index.html | 2 +- mode/r/index.html | 2 +- mode/rpm/changes/index.html | 2 +- mode/rpm/index.html | 2 +- mode/rst/index.html | 2 +- mode/ruby/index.html | 2 +- mode/rust/index.html | 2 +- mode/sass/index.html | 2 +- mode/scheme/index.html | 2 +- mode/shell/index.html | 2 +- mode/sieve/index.html | 2 +- mode/slim/index.html | 2 +- mode/smalltalk/index.html | 2 +- mode/smarty/index.html | 2 +- mode/smartymixed/index.html | 2 +- mode/solr/index.html | 2 +- mode/sparql/index.html | 2 +- mode/sql/index.html | 2 +- mode/stex/index.html | 2 +- mode/tcl/index.html | 2 +- mode/textile/index.html | 2 +- mode/tiddlywiki/index.html | 2 +- mode/tiki/index.html | 2 +- mode/toml/index.html | 2 +- mode/tornado/index.html | 2 +- mode/turtle/index.html | 2 +- mode/vb/index.html | 2 +- mode/vbscript/index.html | 2 +- mode/velocity/index.html | 2 +- mode/verilog/index.html | 2 +- mode/xml/index.html | 2 +- mode/xquery/index.html | 2 +- mode/yaml/index.html | 2 +- mode/z80/index.html | 2 +- test/index.html | 2 +- 147 files changed, 311 insertions(+), 269 deletions(-) diff --git a/demo/activeline.html b/demo/activeline.html index c1391ef27e..741f6c45a4 100644 --- a/demo/activeline.html +++ b/demo/activeline.html @@ -12,7 +12,7 @@ .CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}