From 20d01284c2b4d0af466454effe622d0bf41d5c38 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 4 May 2013 12:47:52 +0200 Subject: [PATCH 0001/4742] Give the line wrapper a CSS class CodeMirror-code Issue #1492 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 4f0823b73a..507f3731ab 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -106,7 +106,7 @@ window.CodeMirror = (function() { d.scrollbarV = elt("div", [elt("div", null, null, "width: 1px")], "CodeMirror-vscrollbar"); d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); // DIVs containing the selection and the actual code - d.lineDiv = elt("div"); + d.lineDiv = elt("div", null, "CodeMirror-code"); 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("div", "\u00a0", "CodeMirror-cursor"); From 5dbe952bb3cabf64c92f4e80ffde7e9c7fc2d213 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 4 May 2013 12:56:47 +0200 Subject: [PATCH 0002/4742] [css mode] Properly make keywords case-insensitive Also prevent Object.prototype properties like toString from being interpreted as keywords. Closes #1495 --- mode/css/css.js | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/mode/css/css.js b/mode/css/css.js index 8b1aca280e..f0fae602d1 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -165,26 +165,27 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { if (type == "variable-definition") state.stack.push("propertyValue"); return "variable-2"; } else if (style == "property") { - if (context == "propertyValue"){ - if (valueKeywords[stream.current()]) { + var word = stream.current().toLowerCase(); + if (context == "propertyValue") { + if (valueKeywords.hasOwnProperty(word)) { style = "string-2"; - } else if (colorKeywords[stream.current()]) { + } else if (colorKeywords.hasOwnProperty(word)) { style = "keyword"; } else { style = "variable-2"; } } else if (context == "rule") { - if (!propertyKeywords[stream.current()]) { + if (!propertyKeywords.hasOwnProperty(word)) { 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()]) { + if (propertyKeywords.hasOwnProperty(word)) { style = "property"; - } else if (colorKeywords[stream.current()]) { + } else if (colorKeywords.hasOwnProperty(word)) { style = "keyword"; - } else if (valueKeywords[stream.current()]) { + } else if (valueKeywords.hasOwnProperty(word)) { style = "string-2"; } else { style = "tag"; @@ -194,38 +195,36 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { } else if (context == "@media") { if (atMediaTypes[stream.current()]) { style = "attribute"; // Known attribute - } else if (/^(only|not)$/i.test(stream.current())) { + } else if (/^(only|not)$/.test(word)) { style = "keyword"; - } else if (stream.current().toLowerCase() == "and") { + } else if (word == "and") { style = "error"; // "and" is only allowed in @mediaType - } else if (atMediaFeatures[stream.current()]) { + } else if (atMediaFeatures.hasOwnProperty(word)) { style = "error"; // Known property, should be in @mediaType( } else { // Unknown, expecting keyword or attribute, assuming attribute style = "attribute error"; } } else if (context == "@mediaType") { - if (atMediaTypes[stream.current()]) { + if (atMediaTypes.hasOwnProperty(word)) { style = "attribute"; - } else if (stream.current().toLowerCase() == "and") { + } else if (word == "and") { style = "operator"; - } else if (/^(only|not)$/i.test(stream.current())) { + } else if (/^(only|not)$/.test(word)) { style = "error"; // Only allowed in @media - } else if (atMediaFeatures[stream.current()]) { - style = "error"; // Known property, should be in parentheses } else { // Unknown attribute or property, but expecting property (preceded // by "and"). Should be in parentheses style = "error"; } } else if (context == "@mediaType(") { - if (propertyKeywords[stream.current()]) { + if (propertyKeywords.hasOwnProperty(word)) { // do nothing, remains "property" - } else if (atMediaTypes[stream.current()]) { + } else if (atMediaTypes.hasOwnProperty(word)) { style = "error"; // Known property, should be in parentheses - } else if (stream.current().toLowerCase() == "and") { + } else if (word == "and") { style = "operator"; - } else if (/^(only|not)$/i.test(stream.current())) { + } else if (/^(only|not)$/.test(word)) { style = "error"; // Only allowed in @media } else { style += " error"; From 798a05182b1996fdd9d96b1e7eb9fa4478afc292 Mon Sep 17 00:00:00 2001 From: Randy Edmunds Date: Fri, 3 May 2013 11:52:40 -0700 Subject: [PATCH 0003/4742] add gutter filler --- lib/codemirror.css | 8 +++++--- lib/codemirror.js | 16 +++++++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index 71e0d0e52b..5512380116 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -19,7 +19,7 @@ padding: 0 4px; /* Horizontal padding of content */ } -.CodeMirror-scrollbar-filler { +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { background-color: white; /* The little square between H and V scrollbars */ } @@ -125,7 +125,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} /* The fake, visible scrollbars. Used to force redraw during scrolling before actuall scrolling happens, thus preventing shaking and flickering artifacts. */ -.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler { +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { position: absolute; z-index: 6; display: none; @@ -142,7 +142,9 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} } .CodeMirror-scrollbar-filler { right: 0; bottom: 0; - z-index: 6; +} +.CodeMirror-gutter-filler { + left: 0; bottom: 0; } .CodeMirror-gutters { diff --git a/lib/codemirror.js b/lib/codemirror.js index 507f3731ab..051852f0c2 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -105,6 +105,7 @@ window.CodeMirror = (function() { d.scrollbarH = elt("div", [elt("div", null, null, "height: 1px")], "CodeMirror-hscrollbar"); d.scrollbarV = elt("div", [elt("div", null, null, "width: 1px")], "CodeMirror-vscrollbar"); d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); + d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); // DIVs containing the selection and the actual code d.lineDiv = elt("div", null, "CodeMirror-code"); d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); @@ -133,7 +134,7 @@ window.CodeMirror = (function() { d.scroller.setAttribute("tabIndex", "-1"); // The element in which the editor lives. d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV, - d.scrollbarFiller, d.scroller], "CodeMirror"); + d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); // Work around IE7 z-index bug if (ie_lt8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } if (place.appendChild) place.appendChild(d.wrapper); else place(d.wrapper); @@ -212,7 +213,7 @@ window.CodeMirror = (function() { estimateLineHeights(cm); regChange(cm); clearCaches(cm); - setTimeout(function(){updateScrollbars(cm.display, cm.doc.height);}, 100); + setTimeout(function(){updateScrollbars(cm.display, cm.doc.height, cm.options.fixedGutter);}, 100); } function estimateHeight(cm) { @@ -317,7 +318,7 @@ window.CodeMirror = (function() { // Re-synchronize the fake scrollbars with the actual size of the // content. Optionally force a scrollTop. - function updateScrollbars(d /* display */, docHeight) { + function updateScrollbars(d /* display */, docHeight, fixedGutter) { var totalHeight = docHeight + paddingVert(d); d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px"; var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight); @@ -339,6 +340,11 @@ window.CodeMirror = (function() { d.scrollbarFiller.style.display = "block"; d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbarWidth(d.measure) + "px"; } else d.scrollbarFiller.style.display = ""; + if (needsH && fixedGutter) { + d.gutterFiller.style.display = "block"; + d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px"; + d.gutterFiller.style.width = d.gutters.offsetWidth + "px"; + } else d.gutterFiller.style.display = ""; if (mac_geLion && scrollbarWidth(d.measure) === 0) d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountainLion ? "18px" : "12px"; @@ -404,7 +410,7 @@ window.CodeMirror = (function() { signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display.showingTo); } else break; updateSelection(cm); - updateScrollbars(cm.display, cm.doc.height); + updateScrollbars(cm.display, cm.doc.height, cm.options.fixedGutter); // Clip forced viewport to actual scrollable area if (viewPort) @@ -1590,7 +1596,7 @@ window.CodeMirror = (function() { var target = e_target(e); if (target == display.scrollbarH || target == display.scrollbarH.firstChild || target == display.scrollbarV || target == display.scrollbarV.firstChild || - target == display.scrollbarFiller) return null; + target == display.scrollbarFiller || target == display.gutterFiller) return null; } var x, y, space = getRect(display.lineSpace); // Fails unpredictably on IE[67] when mouse is dragged around quickly. From 9d92920b4fbb2d50f0246ebae3eeacef50bd56f4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 4 May 2013 13:08:38 +0200 Subject: [PATCH 0004/4742] Add coverGutterNextToScrollbar option Issue #1493 --- doc/manual.html | 7 +++++++ lib/codemirror.js | 11 +++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 6f47472050..a2a129d047 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -232,6 +232,13 @@

Configuration

horizontally (false) or whether it stays fixed during horizontal scrolling (true, the default). +
coverGutterNextToScrollbar: boolean
+
When fixedGutter + is on, and there is a horizontal scrollbar, by default the + gutter will be visible to the left of this scrollbar. If this + option is set to true, it will be covered by an element with + class CodeMirror-gutter-filler.
+
readOnly: boolean|string
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 051852f0c2..4becd1a0b6 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -213,7 +213,7 @@ window.CodeMirror = (function() { estimateLineHeights(cm); regChange(cm); clearCaches(cm); - setTimeout(function(){updateScrollbars(cm.display, cm.doc.height, cm.options.fixedGutter);}, 100); + setTimeout(function(){updateScrollbars(cm);}, 100); } function estimateHeight(cm) { @@ -251,6 +251,7 @@ window.CodeMirror = (function() { function guttersChanged(cm) { updateGutters(cm); + alignHorizontally(cm); regChange(cm); } @@ -318,7 +319,8 @@ window.CodeMirror = (function() { // Re-synchronize the fake scrollbars with the actual size of the // content. Optionally force a scrollTop. - function updateScrollbars(d /* display */, docHeight, fixedGutter) { + function updateScrollbars(cm) { + var d = cm.display, docHeight = cm.doc.height; var totalHeight = docHeight + paddingVert(d); d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px"; var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight); @@ -340,7 +342,7 @@ window.CodeMirror = (function() { d.scrollbarFiller.style.display = "block"; d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = scrollbarWidth(d.measure) + "px"; } else d.scrollbarFiller.style.display = ""; - if (needsH && fixedGutter) { + if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { d.gutterFiller.style.display = "block"; d.gutterFiller.style.height = scrollbarWidth(d.measure) + "px"; d.gutterFiller.style.width = d.gutters.offsetWidth + "px"; @@ -410,7 +412,7 @@ window.CodeMirror = (function() { signalLater(cm, "viewportChange", cm, cm.display.showingFrom, cm.display.showingTo); } else break; updateSelection(cm); - updateScrollbars(cm.display, cm.doc.height, cm.options.fixedGutter); + updateScrollbars(cm); // Clip forced viewport to actual scrollable area if (viewPort) @@ -3123,6 +3125,7 @@ window.CodeMirror = (function() { cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; cm.refresh(); }, true); + option("coverGutterNextToScrollbar", false, updateScrollbars); option("lineNumbers", false, function(cm) { setGuttersForLineNumbers(cm.options); guttersChanged(cm); From 53bc4b1f54670c827662d5210a37b35e63a07c39 Mon Sep 17 00:00:00 2001 From: Andy Kimball Date: Fri, 3 May 2013 11:42:48 +0100 Subject: [PATCH 0005/4742] Fix copy/paste in IE --- addon/runmode/runmode.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/addon/runmode/runmode.js b/addon/runmode/runmode.js index 3e1bed7361..a25e96c170 100644 --- a/addon/runmode/runmode.js +++ b/addon/runmode/runmode.js @@ -1,5 +1,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) { var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); + var isIe8OrEarlier = /\bMSIE\s(\d+)/.exec(navigator.userAgent); + isIe8OrEarlier = isIe8OrEarlier && +isIe8OrEarlier[1] <= 8; if (callback.nodeType == 1) { var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; @@ -7,7 +9,11 @@ CodeMirror.runMode = function(string, modespec, callback, options) { node.innerHTML = ""; callback = function(text, style) { if (text == "\n") { - node.appendChild(document.createElement("br")); + // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. + // Emitting a carriage return makes everything ok. + var newLine = isIe8OrEarlier ? '\r' : text; + var newLineSpan = node.appendChild(document.createElement("span")); + newLineSpan.appendChild( document.createTextNode(newLine)); col = 0; return; } From 64113ec97bb73c2a740d42d56021acb01ce05a92 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 4 May 2013 13:20:08 +0200 Subject: [PATCH 0006/4742] Simplify 53bc4b1f54670c827662d5210a37b35e63a07c39 --- addon/runmode/runmode.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/addon/runmode/runmode.js b/addon/runmode/runmode.js index a25e96c170..a7da6d718f 100644 --- a/addon/runmode/runmode.js +++ b/addon/runmode/runmode.js @@ -1,7 +1,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) { var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); - var isIe8OrEarlier = /\bMSIE\s(\d+)/.exec(navigator.userAgent); - isIe8OrEarlier = isIe8OrEarlier && +isIe8OrEarlier[1] <= 8; + var ie = /MSIE \d/.test(navigator.userAgent); + var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); if (callback.nodeType == 1) { var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; @@ -11,9 +11,7 @@ CodeMirror.runMode = function(string, modespec, callback, options) { if (text == "\n") { // Emitting LF or CRLF on IE8 or earlier results in an incorrect display. // Emitting a carriage return makes everything ok. - var newLine = isIe8OrEarlier ? '\r' : text; - var newLineSpan = node.appendChild(document.createElement("span")); - newLineSpan.appendChild( document.createTextNode(newLine)); + node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); col = 0; return; } From a3402da8e342d6925f5a431b7ccf3ff4bfd2966c Mon Sep 17 00:00:00 2001 From: Steffen Beyer Date: Sat, 4 May 2013 05:20:31 +0200 Subject: [PATCH 0007/4742] add overwrite mode ("R") to vim keymap --- keymap/vim.js | 19 +++++++++++++++++++ test/vim_test.js | 7 +++++++ 2 files changed, 26 insertions(+) diff --git a/keymap/vim.js b/keymap/vim.js index 499601b5b0..cbb9760360 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -255,6 +255,7 @@ { keys: ['P'], type: 'action', action: 'paste', actionArgs: { after: false }}, { 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: ['m', 'character'], type: 'action', action: 'setMark' }, @@ -1605,6 +1606,10 @@ } } }, + enterReplaceMode: function(cm, actionArgs) { + cm.setOption('keyMap', 'vim-replace'); + cm.toggleOverwrite(); + }, incrementNumberToken: function(cm, actionArgs, vim) { var cur = cm.getCursor(); var lineStr = cm.getLine(cur.line); @@ -3035,6 +3040,20 @@ fallthrough: ['default'] }; + function exitReplaceMode(cm) { + cm.toggleOverwrite(); + cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1, true); + cm.setOption('keyMap', 'vim'); + } + + CodeMirror.keyMap['vim-replace'] = { + 'Esc': exitReplaceMode, + 'Ctrl-[': exitReplaceMode, + 'Ctrl-C': exitReplaceMode, + 'Backspace': 'goCharLeft', + fallthrough: ['default'] + }; + return vimApi; }; // Initialize Vim and make it available as an API. diff --git a/test/vim_test.js b/test/vim_test.js index f958c5fd1a..17cf753ae2 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -860,6 +860,13 @@ testVim('r', function(cm, vim, helpers) { helpers.doKeys('v', 'j', 'h', 'r', 'Space'); eq('wuuu \n her', cm.getValue(),'Replacing selection by space-characters failed'); }, { value: 'wordet\nanother' }); +testVim('R', function(cm, vim, helpers) { + cm.setCursor(0, 1); + helpers.doKeys('R'); + helpers.assertCursorAt(0, 1); + eq('vim-replace', cm.getOption('keyMap')); + is(cm.state.overwrite, 'Setting overwrite state failed'); +}); testVim('mark', function(cm, vim, helpers) { cm.setCursor(2, 2); helpers.doKeys('m', 't'); From 1aae9a9453cdbe5e549ec8c11495098ccdf20810 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 4 May 2013 13:27:17 +0200 Subject: [PATCH 0008/4742] Document toggleOverwrite method --- doc/manual.html | 8 +++++--- lib/codemirror.js | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index a2a129d047..361a0e4273 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1360,9 +1360,6 @@

Mode, state, and token-related methods

Miscellaneous methods

-
CodeMirror(elt: Element|function(elt: Element), ?config: object)
-
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. @@ -1389,6 +1386,11 @@

Miscellaneous methods

Reduce the indentation of the line.
+
cm.toggleOverwrite(?value: bool)
+
Switches between overwrite and normal insert mode (when not + given an argument), or sets the overwrite mode to a specific + state (when given an argument).
+
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 diff --git a/lib/codemirror.js b/lib/codemirror.js index 4becd1a0b6..c1b95555fa 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -3002,7 +3002,8 @@ window.CodeMirror = (function() { sel.goalColumn = pos.left; }), - toggleOverwrite: function() { + toggleOverwrite: function(value) { + if (value != null && value == this.state.overwrite) return; if (this.state.overwrite = !this.state.overwrite) this.display.cursor.className += " CodeMirror-overwrite"; else From dc3ca9661bd9902f672f417ddfa1f839ab889a9e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Sat, 4 May 2013 13:33:09 +0200 Subject: [PATCH 0009/4742] [lint addon] Don't use -span- in css classes Apparently Bootstrap messes with those. Closes #1497 --- addon/lint/lint.css | 6 +++--- addon/lint/lint.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/addon/lint/lint.css b/addon/lint/lint.css index 4fd72e774a..eb15381f02 100644 --- a/addon/lint/lint.css +++ b/addon/lint/lint.css @@ -24,18 +24,18 @@ -ms-transition: opacity .4s; } -.CodeMirror-lint-span-error, .CodeMirror-lint-span-warning { +.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { background-position: left bottom; background-repeat: repeat-x; } -.CodeMirror-lint-span-error { +.CodeMirror-lint-mark-error { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg==") ; } -.CodeMirror-lint-span-warning { +.CodeMirror-lint-mark-warning { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); } diff --git a/addon/lint/lint.js b/addon/lint/lint.js index 231eb2f567..ca05da76ef 100644 --- a/addon/lint/lint.js +++ b/addon/lint/lint.js @@ -135,7 +135,7 @@ CodeMirror.validate = (function() { if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { - className: "CodeMirror-lint-span-" + severity, + className: "CodeMirror-lint-mark-" + severity, __annotation: ann })); } @@ -164,7 +164,7 @@ CodeMirror.validate = (function() { 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; + if (!/\bCodeMirror-lint-mark-/.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]})); From 3ff32994e81ef4c8dc7baac61aac71dbf4822726 Mon Sep 17 00:00:00 2001 From: Aaron Brooks Date: Sun, 5 May 2013 21:27:04 -0400 Subject: [PATCH 0010/4742] vim mode: Add tests covering word selection behavior. --- test/vim_test.js | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/vim_test.js b/test/vim_test.js index 17cf753ae2..567633c65d 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -688,6 +688,48 @@ testVim('<<', function(cm, vim, helpers) { helpers.assertCursorAt(0, 1); }, { value: ' word1\n word2\nword3 ', indentUnit: 2 }); +// Edit tests +function testEdit(name, before, pos, edit, after) { + return testVim(name, function(cm, vim, helpers) { + cm.setCursor(0, before.search(pos)); + helpers.doKeys.apply(this, edit.split('')); + eq(after, cm.getValue()); + }, {value: before}); +} + +// These Delete tests effectively cover word-wise Change, Visual & Yank. +// Tabs are used as differentiated whitespace to catch edge cases. +// Normal word: +testEdit('diw_mid_spc', 'foo \tbAr\t baz', /A/, 'diw', 'foo \t\t baz'); +testEdit('daw_mid_spc', 'foo \tbAr\t baz', /A/, 'daw', 'foo \tbaz'); +testEdit('diw_mid_punct', 'foo \tbAr.\t baz', /A/, 'diw', 'foo \t.\t baz'); +testEdit('daw_mid_punct', 'foo \tbAr.\t baz', /A/, 'daw', 'foo.\t baz'); +testEdit('diw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diw', 'foo \t,.\t baz'); +testEdit('daw_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daw', 'foo \t,.\t baz'); +testEdit('diw_start_spc', 'bAr \tbaz', /A/, 'diw', ' \tbaz'); +testEdit('daw_start_spc', 'bAr \tbaz', /A/, 'daw', 'baz'); +testEdit('diw_start_punct', 'bAr. \tbaz', /A/, 'diw', '. \tbaz'); +testEdit('daw_start_punct', 'bAr. \tbaz', /A/, 'daw', '. \tbaz'); +testEdit('diw_end_spc', 'foo \tbAr', /A/, 'diw', 'foo \t'); +testEdit('daw_end_spc', 'foo \tbAr', /A/, 'daw', 'foo'); +testEdit('diw_end_punct', 'foo \tbAr.', /A/, 'diw', 'foo \t.'); +testEdit('daw_end_punct', 'foo \tbAr.', /A/, 'daw', 'foo.'); +// Big word: +testEdit('diW_mid_spc', 'foo \tbAr\t baz', /A/, 'diW', 'foo \t\t baz'); +testEdit('daW_mid_spc', 'foo \tbAr\t baz', /A/, 'daW', 'foo \tbaz'); +testEdit('diW_mid_punct', 'foo \tbAr.\t baz', /A/, 'diW', 'foo \t\t baz'); +testEdit('daW_mid_punct', 'foo \tbAr.\t baz', /A/, 'daW', 'foo \tbaz'); +testEdit('diW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'diW', 'foo \t\t baz'); +testEdit('daW_mid_punct2', 'foo \t,bAr.\t baz', /A/, 'daW', 'foo \tbaz'); +testEdit('diW_start_spc', 'bAr\t baz', /A/, 'diW', '\t baz'); +testEdit('daW_start_spc', 'bAr\t baz', /A/, 'daW', 'baz'); +testEdit('diW_start_punct', 'bAr.\t baz', /A/, 'diW', '\t baz'); +testEdit('daW_start_punct', 'bAr.\t baz', /A/, 'daW', 'baz'); +testEdit('diW_end_spc', 'foo \tbAr', /A/, 'diW', 'foo \t'); +testEdit('daW_end_spc', 'foo \tbAr', /A/, 'daW', 'foo'); +testEdit('diW_end_punct', 'foo \tbAr.', /A/, 'diW', 'foo \t'); +testEdit('daW_end_punct', 'foo \tbAr.', /A/, 'daW', 'foo'); + // Operator-motion tests testVim('D', function(cm, vim, helpers) { var curStart = makeCursor(0, 3); From 0f394dc8c30ba2092bfcb40d83e70923d10841fd Mon Sep 17 00:00:00 2001 From: Aaron Brooks Date: Sun, 5 May 2013 21:30:02 -0400 Subject: [PATCH 0011/4742] vim mode: Fix off-by-one errors in word selection. The below conforms to Vim's behavior regarding whitespace trimming. --- keymap/vim.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index cbb9760360..52052c3ffd 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -835,7 +835,7 @@ return; } var query = cm.getLine(word.start.line).substring(word.start.ch, - word.end.ch + 1); + word.end.ch); if (isKeyword) { query = '\\b' + query + '\\b'; } else { @@ -1866,15 +1866,27 @@ var wordAfterRegex = matchRegex.exec(textAfterIdx); var wordStart = idx; - var wordEnd = idx + wordAfterRegex[0].length - 1; + var wordEnd = idx + wordAfterRegex[0].length; // TODO: Find a better way to do this. It will be slow on very long lines. - var wordBeforeRegex = matchRegex.exec(reverse(textBeforeIdx)); + var revTextBeforeIdx = reverse(textBeforeIdx); + var wordBeforeRegex = matchRegex.exec(revTextBeforeIdx); if (wordBeforeRegex) { wordStart -= wordBeforeRegex[0].length; } if (inclusive) { - wordEnd++; + // If present, trim all whitespace after word. + // Otherwise, trim all whitespace before word. + var textAfterWordEnd = line.substring(wordEnd); + var whitespacesAfterWord = textAfterWordEnd.match(/^\s*/)[0].length; + if (whitespacesAfterWord > 0) { + wordEnd += whitespacesAfterWord; + } else { + var revTrim = revTextBeforeIdx.length - wordStart; + var textBeforeWordStart = revTextBeforeIdx.substring(revTrim); + var whitespacesBeforeWord = textBeforeWordStart.match(/^\s*/)[0].length; + wordStart -= whitespacesBeforeWord; + } } return { start: { line: cur.line, ch: wordStart }, From b56c4ae750fc12ae5a250a4d574c1cb30f7cc8f0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 6 May 2013 08:17:32 +0200 Subject: [PATCH 0012/4742] Add CodeMirror Eclipse to real-world uses --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index fb78e9de3a..5b8106c169 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -31,6 +31,7 @@

{ } CodeMi
  • ClickHelp (technical writing tool)
  • Code per Node (Drupal module)
  • Codebug (PHP Xdebug front-end)
  • +
  • CodeMirror Eclipse (embed CM in Eclipse)
  • CodeMirror movie (scripted editing demos)
  • CodeMirror2-GWT (Google Web Toolkit wrapper)
  • Code Monster & Code Maven (learning environment)
  • From 66dac5ff0b84a5961ded9a65bf21582cb80a58de Mon Sep 17 00:00:00 2001 From: Timothy Hatcher Date: Tue, 30 Apr 2013 15:38:58 -0700 Subject: [PATCH 0013/4742] CodeMirror should set spellcheck=false on the input textarea WebKit does not honor autocorrect=off, but it does honor spellcheck=false. --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index c1b95555fa..4c9f04945e 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -97,7 +97,7 @@ window.CodeMirror = (function() { 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"); + input.setAttribute("autocorrect", "off"); input.setAttribute("autocapitalize", "off"); input.setAttribute("spellcheck", "false"); // Wraps and hides input textarea d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); From 2745e4e24341987c7c8aa9eebed32640c40a89b4 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 6 May 2013 08:27:29 +0200 Subject: [PATCH 0014/4742] [javascript mode] Fix bug in handling of expressions without commas Closes #1501 --- 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 2c2801dda6..87856a89f3 100644 --- a/mode/javascript/javascript.js +++ b/mode/javascript/javascript.js @@ -291,7 +291,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } function maybeoperatorComma(type, value) { - if (type == ",") return cont(expression); + if (type == ",") return pass(); return maybeoperatorNoComma(type, value, maybeoperatorComma); } function maybeoperatorNoComma(type, value, me) { From a48b5d71cd30c58808f359a9c604dac89d9b2ba6 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 6 May 2013 09:55:14 +0200 Subject: [PATCH 0015/4742] Don't call alignHorizontally before display update Closes #1498 --- lib/codemirror.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 4c9f04945e..5698a3cbcf 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -251,8 +251,8 @@ window.CodeMirror = (function() { function guttersChanged(cm) { updateGutters(cm); - alignHorizontally(cm); regChange(cm); + setTimeout(function(){alignHorizontally(cm);}, 20); } function updateGutters(cm) { @@ -3126,7 +3126,7 @@ window.CodeMirror = (function() { cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; cm.refresh(); }, true); - option("coverGutterNextToScrollbar", false, updateScrollbars); + option("coverGutterNextToScrollbar", false, updateScrollbars, true); option("lineNumbers", false, function(cm) { setGuttersForLineNumbers(cm.options); guttersChanged(cm); From 8411bcff5cdbcb60b6d1a579add1871e123a719f Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 6 May 2013 10:59:41 +0200 Subject: [PATCH 0016/4742] [sass mode] Support double-colon pseudo elements Closes #1461 --- mode/sass/sass.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/sass/sass.js b/mode/sass/sass.js index 8758b25189..9c9a0dae07 100644 --- a/mode/sass/sass.js +++ b/mode/sass/sass.js @@ -9,7 +9,7 @@ CodeMirror.defineMode("sass", function(config) { var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-", "\\!=", "/", "\\*", "%", "and", "or", "not"]; var opRegexp = tokenRegexp(operators); - var pseudoElementsRegexp = /^:[\w\-]+/; + var pseudoElementsRegexp = /^::?[\w\-]+/; var urlTokens = function(stream, state){ var ch = stream.peek(); From fdb46a21d48fbd36f0901d7bc1055572cf0fc4a4 Mon Sep 17 00:00:00 2001 From: LM Date: Mon, 6 May 2013 10:14:17 +0200 Subject: [PATCH 0017/4742] [smalltalk mode] add support for '$<...>' character syntax --- mode/smalltalk/smalltalk.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mode/smalltalk/smalltalk.js b/mode/smalltalk/smalltalk.js index f8c9026bb3..7730669149 100644 --- a/mode/smalltalk/smalltalk.js +++ b/mode/smalltalk/smalltalk.js @@ -40,7 +40,10 @@ CodeMirror.defineMode('smalltalk', function(config) { token.name = 'string-2'; } else if (aChar === '$') { - stream.eatWhile(/[^ ]/); + if (stream.next() === '<') { + stream.eatWhile(/[^ >]/); + stream.next(); + } token.name = 'string-2'; } else if (aChar === '|' && state.expectVariable) { From b4809cde9732dd76331a4a827e2245058cd3140e Mon Sep 17 00:00:00 2001 From: LM Date: Mon, 6 May 2013 10:15:13 +0200 Subject: [PATCH 0018/4742] [smalltalk mode] remove unused variable --- mode/smalltalk/smalltalk.js | 1 - 1 file changed, 1 deletion(-) diff --git a/mode/smalltalk/smalltalk.js b/mode/smalltalk/smalltalk.js index 7730669149..8a7290132c 100644 --- a/mode/smalltalk/smalltalk.js +++ b/mode/smalltalk/smalltalk.js @@ -121,7 +121,6 @@ CodeMirror.defineMode('smalltalk', function(config) { state.context = token.context; state.expectVariable = token.eos; - state.lastToken = token; return token.name; }, From 36f68ca85a48692c6246fb1a2f3a0dd8d3887e0a Mon Sep 17 00:00:00 2001 From: LM Date: Mon, 6 May 2013 10:16:29 +0200 Subject: [PATCH 0019/4742] [smalltalk mode] comma is special character --- mode/smalltalk/smalltalk.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/smalltalk/smalltalk.js b/mode/smalltalk/smalltalk.js index 8a7290132c..e7de666228 100644 --- a/mode/smalltalk/smalltalk.js +++ b/mode/smalltalk/smalltalk.js @@ -1,6 +1,6 @@ CodeMirror.defineMode('smalltalk', function(config) { - var specialChars = /[+\-\/\\*~<>=@%|&?!.:;^]/; + var specialChars = /[+\-\/\\*~<>=@%|&?!.,:;^]/; var keywords = /true|false|nil|self|super|thisContext/; var Context = function(tokenizer, parent) { From fca338be9dd62db07f154277c7b3bd0ade6788c7 Mon Sep 17 00:00:00 2001 From: LM Date: Mon, 6 May 2013 10:19:14 +0200 Subject: [PATCH 0020/4742] [smalltalk mode] disallow brackets in symbol literal --- mode/smalltalk/smalltalk.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mode/smalltalk/smalltalk.js b/mode/smalltalk/smalltalk.js index e7de666228..eb32417514 100644 --- a/mode/smalltalk/smalltalk.js +++ b/mode/smalltalk/smalltalk.js @@ -36,7 +36,7 @@ CodeMirror.defineMode('smalltalk', function(config) { token = nextString(stream, new Context(nextString, context)); } else if (aChar === '#') { - stream.eatWhile(/[^ .]/); + stream.eatWhile(/[^ .\[\]()]/); token.name = 'string-2'; } else if (aChar === '$') { From 949c5eb99e25c823a7154d1c4095a67b5b288d1b Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 7 May 2013 22:07:23 +0200 Subject: [PATCH 0021/4742] [closebrackets addon] Remove ECMA5-ism Closes #1508 --- addon/edit/closebrackets.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addon/edit/closebrackets.js b/addon/edit/closebrackets.js index 43902aee68..2abc8c5fe6 100644 --- a/addon/edit/closebrackets.js +++ b/addon/edit/closebrackets.js @@ -23,9 +23,9 @@ return CodeMirror.Pass; } }; - var closingBrackets = []; + var closingBrackets = ""; for (var i = 0; i < pairs.length; i += 2) (function(left, right) { - if (left != right) closingBrackets.push(right); + if (left != right) closingBrackets += right; function surround(cm) { var selection = cm.getSelection(); cm.replaceSelection(left + selection + right); From 4251e74998313a3dc9cab46496a3e39b0ea1c2d2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 8 May 2013 09:41:49 +0200 Subject: [PATCH 0022/4742] Add Janvas and Oak links to real-world uses --- doc/realworld.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/realworld.html b/doc/realworld.html index 5b8106c169..85d0360335 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -60,6 +60,7 @@

    { } CodeMi
  • HaxPad (editor for Win RT)
  • Histone template engine playground
  • ICEcoder (web IDE)
  • +
  • Janvas (vector graphics editor)
  • Joomla plugin
  • jQuery fundamentals (interactive tutorial)
  • jsbin.com (JS playground)
  • @@ -73,6 +74,7 @@

    { } CodeMi
  • My2ndGeneration (social coding)
  • Navigate CMS
  • NoTex (rST authoring)
  • +
  • Oak (online outliner)
  • ORG (z80 assembly IDE)
  • Orion-CodeMirror integration (running CodeMirror modes in Orion)
  • Paper.js (graphics scripting)
  • From 13ab1f1f14a2685428343cfadd0befaf93db9dfb Mon Sep 17 00:00:00 2001 From: John Lees-Miller Date: Sat, 4 May 2013 21:08:18 +0100 Subject: [PATCH 0023/4742] fix stex mode handling of line break with optional argument --- mode/stex/stex.js | 2 +- mode/stex/test.js | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mode/stex/stex.js b/mode/stex/stex.js index 318b63acd4..ca04c24f22 100644 --- a/mode/stex/stex.js +++ b/mode/stex/stex.js @@ -95,7 +95,7 @@ CodeMirror.defineMode("stex", function() { } // white space control characters - if (source.match(/^\\[,;!\/]/)) { + if (source.match(/^\\[,;!\/\\]/)) { return "tag"; } diff --git a/mode/stex/test.js b/mode/stex/test.js index 727a7db07e..ab629e81ea 100644 --- a/mode/stex/test.js +++ b/mode/stex/test.js @@ -114,4 +114,7 @@ MT("mathWithComment", "[keyword $][variable-2 x] [comment % $]", "[variable-2 y][keyword $] other text"); + + MT("lineBreakArgument", + "[tag \\\\][bracket [[][atom 1cm][bracket ]]]"); })(); From de3f7934304af3b7977b23816b09fde3f45ea928 Mon Sep 17 00:00:00 2001 From: Narciso Jaramillo Date: Tue, 7 May 2013 16:12:04 -0700 Subject: [PATCH 0024/4742] Make vim dialog work correctly --- keymap/vim.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/keymap/vim.js b/keymap/vim.js index 52052c3ffd..41f74ba7b3 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -2369,7 +2369,7 @@ onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp }); } else { - callback(prompt(shortText, "")); + onClose(prompt(shortText, "")); } } function findUnescapedSlashes(str) { From 240a326280005259928c1c0ef049963697efd0dd Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 8 May 2013 12:32:50 +0200 Subject: [PATCH 0025/4742] [compress script] Fix passing of arguments to UglifyJS, pass -c -m by default Closes #1510 --- bin/compress | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/compress b/bin/compress index d059b618ba..809fbe83d4 100755 --- a/bin/compress +++ b/bin/compress @@ -29,14 +29,15 @@ function help(ok) { process.exit(ok ? 0 : 1); } -var local = null, args = null, files = [], blob = ""; +var local = null, args = [], extraArgs = null, files = [], blob = ""; for (var i = 2; i < process.argv.length; ++i) { var arg = process.argv[i]; if (arg == "--local" && i + 1 < process.argv.length) { var parts = process.argv[++i].split(/\s+/); local = parts[0]; - args = parts.slice(1); + extraArgs = parts.slice(1); + if (!extraArgs.length) extraArgs = ["-c", "-m"]; } else if (arg == "--help") { help(true); } else if (arg[0] != "-") { @@ -73,7 +74,7 @@ if (files.length) { } if (local) { - require("child_process").spawn(local, args, {stdio: ["ignore", process.stdout, process.stderr]}); + require("child_process").spawn(local, args.concat(extraArgs), {stdio: ["ignore", process.stdout, process.stderr]}); } else { var data = new Buffer("js_code=" + require("querystring").escape(blob), "utf8"); var req = require("http").request({ From 7fcb11276e50601eb35a1c0a32bf810047e49988 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 8 May 2013 12:00:23 +0200 Subject: [PATCH 0026/4742] [bidi support] Overhaul algorithm to deal with corner case When a level 2 section intersected with a level 0 one, an assumption in the visual motion code was violated, resulting in bogus motion and thus infinite loops in the charCoords code. --- lib/codemirror.js | 119 ++++++++++++++++++++++++++-------------------- test/test.js | 3 +- 2 files changed, 69 insertions(+), 53 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 5698a3cbcf..97a8d14007 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -1149,32 +1149,26 @@ window.CodeMirror = (function() { if (right) m.left = m.right; else m.right = m.left; return intoCoordSystem(cm, lineObj, m, context); } - var order = getOrder(lineObj), ch = pos.ch; - if (!order) return get(ch); - var main, other, linedir = order[0].level; - for (var i = 0; i < order.length; ++i) { - var part = order[i], rtl = part.level % 2, nb, here; - 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) { - // 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; - } else if (right == ch) { - var nb = i < order.length - 1 && order[i+1]; - if (!rtl && nb && nb.from == nb.to) continue; - if (nb && part.level < nb.level) here = get(nb.level % 2 ? nb.to - 1 : nb.from); - else here = get(rtl ? ch : ch - 1, true); - if (rtl == linedir) main = here; else other = here; + function getBidi(ch, partPos) { + var part = order[partPos], right = part.level % 2; + if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { + part = order[--partPos]; + ch = bidiRight(part) - (part.level % 2 ? 0 : 1); + right = true; + } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { + part = order[++partPos]; + ch = bidiLeft(part) - part.level % 2; + right = false; } + if (right && ch == part.to && ch > part.from) return get(ch - 1); + return get(ch, right); } - if (linedir && !ch) other = get(order[0].to - 1); - if (!main) return other; - if (other) main.other = other; - return main; + var order = getOrder(lineObj), ch = pos.ch; + if (!order) return get(ch); + var partPos = getBidiPartAt(order, ch); + var val = getBidi(ch, partPos); + if (bidiOther != null) val.other = getBidi(ch, bidiOther); + return val; } function PosMaybeOutside(line, ch, outside) { @@ -5382,6 +5376,40 @@ window.CodeMirror = (function() { return Pos(lineN, ch); } + function compareBidiLevel(order, a, b) { + var linedir = order[0].level; + if (a == linedir) return true; + if (b == linedir) return false; + return a < b; + } + var bidiOther; + function getBidiPartAt(order, pos) { + for (var i = 0, found; i < order.length; ++i) { + var cur = order[i]; + if (cur.from < pos && cur.to > pos) { bidiOther = null; return i; } + if (cur.from == pos || cur.to == pos) { + if (found == null) { + found = i; + } else if (compareBidiLevel(order, cur.level, order[found].level)) { + bidiOther = found; + return i; + } else { + bidiOther = i; + return found; + } + } + } + bidiOther = null; + return found; + } + + function moveInLine(line, pos, dir, byUnit) { + if (!byUnit) return pos + dir; + do pos += dir; + while (pos > 0 && isExtendingChar.test(line.text.charAt(pos))); + return pos; + } + // This is somewhat involved. It is needed in order to move // 'visually' through bi-directional text -- i.e., pressing left // should make the cursor go left, even when in RTL text. The @@ -5391,37 +5419,24 @@ window.CodeMirror = (function() { function moveVisually(line, start, dir, byUnit) { var bidi = getOrder(line); if (!bidi) return moveLogically(line, start, dir, byUnit); - var moveOneUnit = byUnit ? function(pos, dir) { - do pos += dir; - while (pos > 0 && isExtendingChar.test(line.text.charAt(pos))); - return pos; - } : function(pos, dir) { return pos + dir; }; - var linedir = bidi[0].level; - for (var i = 0; i < bidi.length; ++i) { - var part = bidi[i], sticky = part.level % 2 == linedir; - if ((part.from < start && part.to > start) || - (sticky && (part.from == start || part.to == start))) break; - } - var target = moveOneUnit(start, part.level % 2 ? -dir : dir); - - while (target != null) { - if (part.level % 2 == linedir) { - if (target < part.from || target > part.to) { - part = bidi[i += dir]; - target = part && (dir > 0 == part.level % 2 ? moveOneUnit(part.to, -1) : moveOneUnit(part.from, 1)); - } else break; + var pos = getBidiPartAt(bidi, start), part = bidi[pos]; + var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); + + for (;;) { + if (target > part.from && target < part.to) return target; + if (target == part.from || target == part.to) { + if (getBidiPartAt(bidi, target) == pos) return target; + part = bidi[pos += dir]; + return (dir > 0) == part.level % 2 ? part.to : part.from; } else { - if (target == bidiLeft(part)) { - part = bidi[--i]; - target = part && bidiRight(part); - } else if (target == bidiRight(part)) { - part = bidi[++i]; - target = part && bidiLeft(part); - } else break; + part = bidi[pos += dir]; + if (!part) return null; + if ((dir > 0) == part.level % 2) + target = moveInLine(line, part.to, -1, byUnit); + else + target = moveInLine(line, part.from, 1, byUnit); } } - - return target < 0 || target > line.text.length ? null : target; } function moveLogically(line, start, dir, byUnit) { diff --git a/test/test.js b/test/test.js index a334c5a59c..93d899a66e 100644 --- a/test/test.js +++ b/test/test.js @@ -1013,7 +1013,8 @@ 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ج", "خمرحبها مها!", "foobarر"], 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 32050bbb0a9aa4d7e4ff995c4ecd06abf5c926b6 Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Mon, 6 May 2013 17:01:20 +0200 Subject: [PATCH 0027/4742] [vim keymap] Add Ctrl-o/Ctrl-i jumplist motions --- keymap/vim.js | 124 +++++++++++++++++++++++++++++++++++++++-------- test/vim_test.js | 41 ++++++++++++++++ 2 files changed, 145 insertions(+), 20 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 41f74ba7b3..e333dc9c25 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -81,13 +81,13 @@ // Motions { keys: ['H'], type: 'motion', motion: 'moveToTopLine', - motionArgs: { linewise: true }}, + motionArgs: { linewise: true, toJumplist: true }}, { keys: ['M'], type: 'motion', motion: 'moveToMiddleLine', - motionArgs: { linewise: true }}, + motionArgs: { linewise: true, toJumplist: true }}, { keys: ['L'], type: 'motion', motion: 'moveToBottomLine', - motionArgs: { linewise: true }}, + motionArgs: { linewise: true, toJumplist: true }}, { keys: ['h'], type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: false }}, @@ -133,9 +133,9 @@ motionArgs: { forward: false, wordEnd: true, bigWord: true, inclusive: true }}, { keys: ['{'], type: 'motion', motion: 'moveByParagraph', - motionArgs: { forward: false }}, + motionArgs: { forward: false, toJumplist: true }}, { keys: ['}'], type: 'motion', motion: 'moveByParagraph', - motionArgs: { forward: true }}, + motionArgs: { forward: true, toJumplist: true }}, { keys: ['Ctrl-f'], type: 'motion', motion: 'moveByPage', motionArgs: { forward: true }}, { keys: ['Ctrl-b'], type: 'motion', @@ -148,10 +148,10 @@ motionArgs: { forward: false, explicitRepeat: true }}, { keys: ['g', 'g'], type: 'motion', motion: 'moveToLineOrEdgeOfDocument', - motionArgs: { forward: false, explicitRepeat: true, linewise: true }}, + motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true }}, { keys: ['G'], type: 'motion', motion: 'moveToLineOrEdgeOfDocument', - motionArgs: { forward: true, explicitRepeat: true, linewise: true }}, + motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true }}, { keys: ['0'], type: 'motion', motion: 'moveToStartOfLine' }, { keys: ['^'], type: 'motion', motion: 'moveToFirstNonWhiteSpaceCharacter' }, @@ -169,7 +169,7 @@ motionArgs: { inclusive: true }}, { keys: ['%'], type: 'motion', motion: 'moveToMatchedSymbol', - motionArgs: { inclusive: true }}, + motionArgs: { inclusive: true, toJumplist: true }}, { keys: ['f', 'character'], type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: true , inclusive: true }}, @@ -186,18 +186,20 @@ motionArgs: { forward: true }}, { keys: [','], type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: false }}, - { keys: ['\'', 'character'], type: 'motion', motion: 'goToMark' }, - { keys: ['`', 'character'], type: 'motion', motion: 'goToMark' }, + { keys: ['\'', 'character'], type: 'motion', motion: 'goToMark', + motionArgs: {toJumplist: true}}, + { keys: ['`', 'character'], type: 'motion', motion: 'goToMark', + motionArgs: {toJumplist: true}}, { 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: [']', 'character'], type: 'motion', motion: 'moveToSymbol', - motionArgs: { forward: true}}, + motionArgs: { forward: true, toJumplist: true}}, { keys: ['[', 'character'], type: 'motion', motion: 'moveToSymbol', - motionArgs: { forward: false}}, + motionArgs: { forward: false, toJumplist: true}}, { keys: ['|'], type: 'motion', motion: 'moveToColumn', motionArgs: { }}, @@ -212,9 +214,9 @@ operatorArgs: { indentRight: false }}, { keys: ['g', '~'], type: 'operator', operator: 'swapcase' }, { keys: ['n'], type: 'motion', motion: 'findNext', - motionArgs: { forward: true }}, + motionArgs: { forward: true, toJumplist: true }}, { keys: ['N'], type: 'motion', motion: 'findNext', - motionArgs: { forward: false }}, + motionArgs: { forward: false, toJumplist: true }}, // Operator-Motion dual commands { keys: ['x'], type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: true }, @@ -235,6 +237,10 @@ { keys: ['~'], type: 'operatorMotion', operator: 'swapcase', motion: 'moveByCharacters', motionArgs: { forward: true }}, // Actions + { keys: ['Ctrl-i'], type: 'action', action: 'jumpListWalk', + actionArgs: { forward: true }}, + { keys: ['Ctrl-o'], type: 'action', action: 'jumpListWalk', + actionArgs: { forward: false }}, { keys: ['a'], type: 'action', action: 'enterInsertMode', actionArgs: { insertAt: 'charAfter' }}, { keys: ['A'], type: 'action', action: 'enterInsertMode', @@ -288,13 +294,13 @@ motionArgs: { textObjectInner: true }}, // Search { keys: ['/'], type: 'search', - searchArgs: { forward: true, querySrc: 'prompt' }}, + searchArgs: { forward: true, querySrc: 'prompt', toJumplist: true }}, { keys: ['?'], type: 'search', - searchArgs: { forward: false, querySrc: 'prompt' }}, + searchArgs: { forward: false, querySrc: 'prompt', toJumplist: true }}, { keys: ['*'], type: 'search', - searchArgs: { forward: true, querySrc: 'wordUnderCursor' }}, + searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }}, { keys: ['#'], type: 'search', - searchArgs: { forward: false, querySrc: 'wordUnderCursor' }}, + searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }}, // Ex command { keys: [':'], type: 'ex' } ]; @@ -362,6 +368,48 @@ return false; } + var circularJumpList = (function(){ + var size = 100; + var pointer = -1; + var head = 0; + var tail = 0; + var buffer = new Array(size); + function add(cm, oldCur, newCur) { + var current = pointer % size; + var curMark = buffer[current]; + function useNextSlot(cursor) { + var next = ++pointer % size; + var trashMark = buffer[next]; + if (trashMark) { + trashMark.clear(); + } + buffer[next] = cm.setBookmark(cursor); + } + if (!curMark || !cursorEqual(curMark.find(), oldCur)) { + useNextSlot(oldCur); + } + useNextSlot(newCur); + head = pointer; + tail = pointer - size + 1; + if (tail < 0) { + tail = 0; + } + } + function move(offset) { + pointer += offset; + if (pointer > head) { + pointer = head; + } else if (pointer < tail) { + pointer = tail; + } + return buffer[(size + pointer) % size]; + } + return { + cachedCursor: undefined, //used for # and * jumps + add: add, + move: move + }; + })(); // Global Vim state. Call getVimGlobalState to get and initialize. var vimGlobalState; function getVimGlobalState() { @@ -371,6 +419,7 @@ searchQuery: null, // Whether we are searching backwards. searchIsReversed: false, + jumpList: circularJumpList, // Recording latest f, t, F or T motion command. lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''}, registerController: new RegisterController({}) @@ -776,7 +825,7 @@ commandDispatcher.processMotion(cm, vim, { type: 'motion', motion: 'findNext', - motionArgs: { forward: true } + motionArgs: { forward: true, toJumplist: command.searchArgs.toJumplist } }); } function onPromptClose(query) { @@ -841,7 +890,13 @@ } else { query = escapeRegex(query); } + + // 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(); cm.setCursor(word.start); + handleQuery(query, true /** ignoreCase */, false /** smartCase */); break; } @@ -918,6 +973,17 @@ if (!motionResult) { return; } + if (motionArgs.toJumplist) { + var jumpList = getVimGlobalState().jumpList; + // if the current motion is # or *, use cachedCursor + var cachedCursor = jumpList.cachedCursor; + if (cachedCursor) { + recordJumpPosition(cm, cachedCursor, motionResult); + delete jumpList.cachedCursor; + } else { + recordJumpPosition(cm, curOriginal, motionResult); + } + } if (motionResult instanceof Array) { curStart = motionResult[0]; curEnd = motionResult[1]; @@ -1078,7 +1144,7 @@ } var equal = cursorEqual(cursor, best); - var between = (motionArgs.forward) ? + var between = (motionArgs.forward) ? cusrorIsBetween(cursor, mark, best) : cusrorIsBetween(best, mark, cursor); @@ -1384,6 +1450,18 @@ }; var actions = { + jumpListWalk: function(cm, actionArgs, vim) { + if (vim.visualMode) { + return; + } + var repeat = actionArgs.repeat; + var forward = actionArgs.forward; + var jumpList = getVimGlobalState().jumpList; + + var mark = jumpList.move(forward ? repeat : -repeat); + var markPos = mark ? mark.find() : cm.getCursor(); + cm.setCursor(markPos); + }, scrollToCursor: function(cm, actionArgs) { var lineNum = cm.getCursor().line; var heightProp = window.getComputedStyle(cm.getScrollerElement()). @@ -1893,6 +1971,12 @@ end: { line: cur.line, ch: wordEnd }}; } + function recordJumpPosition(cm, oldCur, newCur) { + if(!cursorEqual(oldCur, newCur)) { + getVimGlobalState().jumpList.add(cm, oldCur, newCur); + } + } + function recordLastCharacterSearch(increment, args) { var vimGlobalState = getVimGlobalState(); vimGlobalState.lastChararacterSearch.increment = increment; diff --git a/test/vim_test.js b/test/vim_test.js index 567633c65d..b2104d4186 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -158,6 +158,47 @@ function testVim(name, run, opts, expectedFail) { } }, expectedFail); }; +var jumplistScene = ''+ + 'word\n'+ + '(word)\n'+ + '{word\n'+ + 'word.\n'+ + '\n'+ + 'word search\n'+ + '}word\n'+ + 'word\n'+ + 'word\n'; +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) { + if(dialog)cm.openDialog = helpers.fakeOpenDialog('word'); + cm.setCursor(startPos); + helpers.doKeys.apply(null, keys); + 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'); /** * @param name Name of the test From c10c1597b64eeb4259274b1fb90b966d525c8f3e Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Thu, 9 May 2013 09:19:14 +0200 Subject: [PATCH 0028/4742] [real-world uses] Add Handcraft 2 --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 85d0360335..7268e4482c 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -56,6 +56,7 @@

    { } CodeMi
  • GitHub's Android app
  • Google Apps Script
  • Graphit (function graphing)
  • +
  • Handcraft 2 (HTML prototyping)
  • Haxe (Haxe Playground)
  • HaxPad (editor for Win RT)
  • Histone template engine playground
  • From 66edc4afabb9968f40a1e2272a57802f871988b7 Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Thu, 9 May 2013 23:47:47 +0200 Subject: [PATCH 0029/4742] [vim keymap] Fix deleted jumplist marks --- keymap/vim.js | 40 ++++++++++++++++++++++++++++++++-------- test/vim_test.js | 8 +++++++- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index e333dc9c25..2c4724eb6d 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -368,7 +368,7 @@ return false; } - var circularJumpList = (function(){ + var circularJumpList = function() { var size = 100; var pointer = -1; var head = 0; @@ -385,7 +385,13 @@ } buffer[next] = cm.setBookmark(cursor); } - if (!curMark || !cursorEqual(curMark.find(), oldCur)) { + if (curMark) { + var markPos = curMark.find(); + // avoid recording redundant cursor position + if (markPos && !cursorEqual(markPos, oldCur)) { + useNextSlot(oldCur); + } + } else { useNextSlot(oldCur); } useNextSlot(newCur); @@ -395,21 +401,38 @@ tail = 0; } } - function move(offset) { + function move(cm, offset) { pointer += offset; if (pointer > head) { pointer = head; } else if (pointer < tail) { pointer = tail; } - return buffer[(size + pointer) % size]; + var mark = buffer[(size + pointer) % size]; + // skip marks that are temporarily removed from text buffer + if (!mark.find()) { + var inc = offset > 0 ? 1 : -1; + var newCur; + var oldCur = cm.getCursor(); + do { + pointer += inc; + mark = buffer[(size + pointer) % size]; + // skip marks that are the same as current position + if (mark && + (newCur = mark.find()) && + !cursorEqual(oldCur, newCur)) { + break; + } + } while (pointer < head && pointer > tail); + } + return mark; } return { cachedCursor: undefined, //used for # and * jumps add: add, move: move }; - })(); + }; // Global Vim state. Call getVimGlobalState to get and initialize. var vimGlobalState; function getVimGlobalState() { @@ -419,7 +442,7 @@ searchQuery: null, // Whether we are searching backwards. searchIsReversed: false, - jumpList: circularJumpList, + jumpList: circularJumpList(), // Recording latest f, t, F or T motion command. lastChararacterSearch: {increment:0, forward:true, selectedCharacter:''}, registerController: new RegisterController({}) @@ -1458,8 +1481,9 @@ var forward = actionArgs.forward; var jumpList = getVimGlobalState().jumpList; - var mark = jumpList.move(forward ? repeat : -repeat); - var markPos = mark ? mark.find() : cm.getCursor(); + var mark = jumpList.move(cm, forward ? repeat : -repeat); + var markPos = mark ? mark.find() : undefined; + markPos = markPos ? markPos : cm.getCursor(); cm.setCursor(markPos); }, scrollToCursor: function(cm, actionArgs) { diff --git a/test/vim_test.js b/test/vim_test.js index b2104d4186..93596148be 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -172,6 +172,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_(); if(dialog)cm.openDialog = helpers.fakeOpenDialog('word'); cm.setCursor(startPos); helpers.doKeys.apply(null, keys); @@ -199,7 +200,12 @@ testJumplist('jumplist_repeat_', ['*', '*', '*', '3', 'Ctrl-o', '2', 'Ctrl- 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_skip_delted_mark', + ['*', 'n', 'n', 'k', 'd', 'k', 'Ctrl-o', 'Ctrl-o', 'Ctrl-o'], + [0,2], [0,2]); +testJumplist('jumplist_skip_delted_mark', + ['*', 'n', 'n', 'k', 'd', 'k', 'Ctrl-o', 'Ctrl-i', 'Ctrl-i'], + [1,0], [0,2]); /** * @param name Name of the test * @param keys An array of keys or a string with a single key to simulate. From 0c68e2095ae139ad573f401f61e7129d685a0fae Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 10 May 2013 09:19:26 +0200 Subject: [PATCH 0030/4742] [real-world uses] Add Code together --- doc/realworld.html | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/realworld.html b/doc/realworld.html index 7268e4482c..c3f2c814fc 100644 --- a/doc/realworld.html +++ b/doc/realworld.html @@ -38,6 +38,7 @@

    { } CodeMi
  • Codepen (gallery of animations)
  • Code School (online tech learning environment)
  • Code Snippets (WordPress snippet management plugin)
  • +
  • Code together (collaborative editing)
  • Codev (collaborative IDE)
  • Collaborative CodeMirror demo (CodeMirror + operational transforms)
  • Community Code Camp (code snippet sharing)
  • From 345114a579c8d207c871bf8e02d3cd9582c85049 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Fri, 10 May 2013 09:26:08 +0200 Subject: [PATCH 0031/4742] Add word char unicode range for Korean characters Closes #1512 --- lib/codemirror.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 97a8d14007..745caba277 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -5190,7 +5190,7 @@ window.CodeMirror = (function() { return function(){return f.apply(null, args);}; } - var nonASCIISingleCaseWordChar = /[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc]/; + var nonASCIISingleCaseWordChar = /[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; function isWordChar(ch) { return /\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); From 1bcd6e13971bf241d9743fa89a1e780315da586b Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Sun, 5 May 2013 15:40:58 -0400 Subject: [PATCH 0032/4742] [vim] Rewrite of moveToWord, much cleaner logic. Plus extra test cases. --- keymap/vim.js | 135 ++++++++++++++++++++++++++++------------------- test/vim_test.js | 127 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 206 insertions(+), 56 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 2c4724eb6d..3b857e58b1 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1082,7 +1082,7 @@ // Expand selection to entire line. expandSelectionToLine(cm, curStart, curEnd); } else if (motionArgs.forward) { - // Clip to trailing newlines only if we the motion goes forward. + // Clip to trailing newlines only if the motion goes forward. clipToLine(cm, curStart, curEnd); } operatorArgs.registerName = registerName; @@ -1911,10 +1911,30 @@ // caret to the first character of the next line. function clipToLine(cm, curStart, curEnd) { var selection = cm.getRange(curStart, curEnd); - var lines = selection.split('\n'); - if (lines.length > 1 && isWhiteSpaceString(lines.pop())) { - curEnd.line--; - curEnd.ch = lineLength(cm, curEnd.line); + // Only clip if the selection ends with trailing newline + whitespace + if (/\n\s*$/.test(selection)) { + var lines = selection.split('\n'); + // We know this is all whitepsace. + lines.pop(); + + // Cases: + // 1. Last word is an empty line - do not clip the trailing '\n' + // 2. Last word is not an empty line - clip the trailing '\n' + var line; + // Find the line containing the last word, and clip all whitespace up + // to it. + for (var line = lines.pop(); lines.length > 0 && line && isWhiteSpaceString(line); line = lines.pop()) { + var clipped = false; + curEnd.line--; + curEnd.ch = 0; + } + // If the last word is not an empty line, clip an additional newline + if (line) { + curEnd.line--; + curEnd.ch = lineLength(cm, curEnd.line); + } else { + curEnd.ch = 0; + } } } @@ -2141,18 +2161,31 @@ * backward. * @param {boolean} bigWord True if punctuation count as part of the word. * False if only [a-zA-Z0-9] characters count as part of the word. + * @param {boolean} emptyLineIsWord True if empty lines should be treated + * as words. * @return {Object{from:number, to:number, line: number}} The boundaries of * the word, or null if there are no more words. */ - // TODO: Treat empty lines (with no whitespace) as words. - function findWord(cm, cur, forward, bigWord) { + function findWord(cm, cur, forward, bigWord, emptyLineIsWord) { var lineNum = cur.line; var pos = cur.ch; var line = cm.getLine(lineNum); var dir = forward ? 1 : -1; var regexps = bigWord ? bigWordRegexp : wordRegexp; + if (emptyLineIsWord && line == '') { + lineNum += dir; + line = cm.getLine(lineNum); + if (!isLine(cm, lineNum)) { + return null; + } + pos = (forward) ? 0 : line.length; + } + while (true) { + if (emptyLineIsWord && line == '') { + return { from: 0, to: 0, line: lineNum }; + } var stop = (dir > 0) ? line.length : -1; var wordStart = stop, wordEnd = stop; // Find bounds of next word. @@ -2208,56 +2241,48 @@ */ function moveToWord(cm, repeat, forward, wordEnd, bigWord) { var cur = cm.getCursor(); + var curStart = copyCursor(cur); + var words = []; + if (forward && !wordEnd || !forward && wordEnd) { + repeat++; + } + // For 'e', empty lines are not considered words, go figure. + var emptyLineIsWord = !(forward && wordEnd); for (var i = 0; i < repeat; i++) { - var startCh = cur.ch, startLine = cur.line, word; - var movedToNextWord = false; - while (!movedToNextWord) { - // Search and advance. - word = findWord(cm, cur, forward, bigWord); - movedToNextWord = true; - if (word) { - // Move to the word we just found. If by moving to the word we end - // up in the same spot, then move an extra character and search - // again. - cur.line = word.line; - if (forward && wordEnd) { - // 'e' - cur.ch = word.to - 1; - } else if (forward && !wordEnd) { - // 'w' - if (inRangeInclusive(cur.ch, word.from, word.to) && - word.line == startLine) { - // Still on the same word. Go to the next one. - movedToNextWord = false; - cur.ch = word.to - 1; - } else { - cur.ch = word.from; - } - } else if (!forward && wordEnd) { - // 'ge' - if (inRangeInclusive(cur.ch, word.from, word.to) && - word.line == startLine) { - // still on the same word. Go to the next one. - movedToNextWord = false; - cur.ch = word.from; - } else { - cur.ch = word.to; - } - } else if (!forward && !wordEnd) { - // 'b' - cur.ch = word.from; - } - } else { - // No more words to be found. Move to the end. - if (forward) { - return { line: cur.line, ch: lineLength(cm, cur.line) }; - } else { - return { line: cur.line, ch: 0 }; - } - } - } + var word = findWord(cm, cur, forward, bigWord, emptyLineIsWord); + if (!word) { + var eodCh = lineLength(cm, cm.lastLine()); + words.push(forward + ? {line: cm.lastLine(), from: eodCh, to: eodCh} + : {line: 0, from: 0, to: 0}); + break; + } + words.push(word); + cur = {line: word.line, ch: forward ? (word.to - 1) : word.from}; + } + var shortCircuit = words.length != repeat; + var firstWord = words[0]; + var lastWord = words.pop(); + if (forward && !wordEnd) { + // w + if (!shortCircuit && (firstWord.from != curStart.ch || firstWord.line != curStart.line)) { + // We did not start in the middle of a word. Discard the extra word at the end. + lastWord = words.pop(); + } + return {line: lastWord.line, ch: lastWord.from}; + } else if (forward && wordEnd) { + return {line: lastWord.line, ch: lastWord.to - 1}; + } else if (!forward && wordEnd) { + // ge + if (!shortCircuit && (firstWord.to != curStart.ch || firstWord.line != curStart.line)) { + // We did not start in the middle of a word. Discard the extra word at the end. + lastWord = words.pop(); + } + return {line: lastWord.line, ch: lastWord.to}; + } else { + // b + return {line: lastWord.line, ch: lastWord.from}; } - return cur; } function moveToCharacter(cm, repeat, forward, character) { diff --git a/test/vim_test.js b/test/vim_test.js index 93596148be..4979e404b3 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -10,7 +10,9 @@ var code = '' + ' n = read(0, buf, sizeof buf);\n' + ' bufp = buf;\n' + ' }\n' + -' return (--n >= 0) ? (unsigned char) *bufp++ : EOF;\n' + +'\n' + +' return (--n >= 0) ? (unsigned char) *bufp++ : EOF;\n' + +' \n' + '}\n'; var lines = (function() { @@ -243,24 +245,30 @@ testMotion('j_repeat', ['2', 'j'], offsetCursor(word1.end, 2, 0), word1.end); testMotion('k', 'k', offsetCursor(word3.end, -1, 0), word3.end); testMotion('k_repeat', ['2', '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)); testMotion('w_repeat', ['2', 'w'], word2.start); testMotion('w_wrap', ['w'], word3.start, word2.start); testMotion('w_endOfDocument', 'w', endOfDocument, endOfDocument); +testMotion('w_start_to_end', ['1000', 'w'], endOfDocument, makeCursor(0, 0)); testMotion('W', 'W', bigWord1.start); testMotion('W_repeat', ['2', 'W'], bigWord3.start, bigWord1.start); testMotion('e', 'e', word1.end); testMotion('e_repeat', ['2', 'e'], word2.end); testMotion('e_wrap', 'e', word3.end, word2.end); testMotion('e_endOfDocument', 'e', endOfDocument, endOfDocument); +testMotion('e_start_to_end', ['1000', 'e'], endOfDocument, makeCursor(0, 0)); testMotion('b', 'b', word3.start, word3.end); testMotion('b_repeat', ['2', 'b'], word2.start, word3.end); testMotion('b_wrap', 'b', word2.start, word3.start); testMotion('b_startOfDocument', 'b', makeCursor(0, 0), makeCursor(0, 0)); +testMotion('b_end_to_start', ['1000', 'b'], makeCursor(0, 0), endOfDocument); testMotion('ge', ['g', 'e'], word2.end, word3.end); testMotion('ge_repeat', ['2', 'g', 'e'], word1.end, word3.start); testMotion('ge_wrap', ['g', 'e'], word2.end, word3.start); testMotion('ge_startOfDocument', ['g', 'e'], makeCursor(0, 0), makeCursor(0, 0)); +testMotion('ge_end_to_start', ['1000', 'g', 'e'], makeCursor(0, 0), endOfDocument); testMotion('gg', ['g', 'g'], makeCursor(lines[0].line, lines[0].textStart), makeCursor(3, 1)); testMotion('gg_repeat', ['3', 'g', 'g'], @@ -414,6 +422,7 @@ 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); helpers.doKeys('d', 'l'); @@ -527,6 +536,53 @@ testVim('dw_eol', function(cm, vim, helpers) { is(!register.linewise); eqPos(curStart, cm.getCursor()); }, { 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); + 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()); +}, { value: ' word1\n\nword2' }); +testVim('dw_empty_line_followed_by_whitespace', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'w'); + eq(' \nword', cm.getValue()); +}, { value: '\n \nword' }); +testVim('dw_empty_line_followed_by_word', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'w'); + eq('word', cm.getValue()); +}, { value: '\nword' }); +testVim('dw_empty_line_followed_by_empty_line', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'w'); + eq('\n', cm.getValue()); +}, { value: '\n\n' }); +testVim('dw_whitespace_followed_by_whitespace', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'w'); + eq('\n \n', cm.getValue()); +}, { value: ' \n \n' }); +testVim('dw_whitespace_followed_by_empty_line', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'w'); + eq('\n\n', cm.getValue()); +}, { value: ' \n\n' }); +testVim('dw_word_whitespace_word', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'w'); + eq('\n \nword2', cm.getValue()); +}, { value: 'word1\n \nword2'}) +testVim('dw_end_of_document', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('d', 'w'); + eq('\nab', cm.getValue()); +}, { value: '\nabc' }); 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. @@ -539,6 +595,75 @@ testVim('dw_repeat', function(cm, vim, helpers) { is(!register.linewise); eqPos(curStart, cm.getCursor()); }, { value: ' word1\nword2' }); +testVim('de_word_start_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'e'); + eq('\n\n', cm.getValue()); +}, { value: 'word\n\n' }); +testVim('de_word_end_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(0, 3); + helpers.doKeys('d', 'e'); + eq('wor', cm.getValue()); +}, { value: 'word\n\n\n' }); +testVim('de_whitespace_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'e'); + eq('', cm.getValue()); +}, { value: ' \n\n\n' }); +testVim('de_end_of_document', function(cm, vim, helpers) { + cm.setCursor(1, 2); + helpers.doKeys('d', 'e'); + eq('\nab', cm.getValue()); +}, { value: '\nabc' }); +testVim('db_empty_lines', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('d', 'b'); + eq('\n\n', cm.getValue()); +}, { value: '\n\n\n' }); +testVim('db_word_start_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('d', 'b'); + eq('\nword', cm.getValue()); +}, { value: '\n\nword' }); +testVim('db_word_end_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(2, 3); + helpers.doKeys('d', 'b'); + eq('\n\nd', cm.getValue()); +}, { value: '\n\nword' }); +testVim('db_whitespace_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('d', 'b'); + eq('', cm.getValue()); +}, { value: '\n \n' }); +testVim('db_start_of_document', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'b'); + eq('abc\n', cm.getValue()); +}, { value: 'abc\n' }); +testVim('dge_empty_lines', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doKeys('d', 'g', 'e'); + // Note: In real VIM the result should be '', but it's not quite consistent, + // since 2 newlines are deleted. But in the similar case of word\n\n, only + // 1 newline is deleted. We'll diverge from VIM's behavior since it's much + // easier this way. + eq('\n', cm.getValue()); +}, { value: '\n\n' }); +testVim('dge_word_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(1, 0); + helpers.doKeys('d', 'g', 'e'); + eq('wor\n', cm.getValue()); +}, { value: 'word\n\n'}); +testVim('dge_whitespace_and_empty_lines', function(cm, vim, helpers) { + cm.setCursor(2, 0); + helpers.doKeys('d', 'g', 'e'); + eq('', cm.getValue()); +}, { value: '\n \n' }); +testVim('dge_start_of_document', function(cm, vim, helpers) { + cm.setCursor(0, 0); + helpers.doKeys('d', 'g', 'e'); + eq('bc\n', cm.getValue()); +}, { value: 'abc\n' }); testVim('d_inclusive', function(cm, vim, helpers) { // Assert that when inclusive is set, the character the cursor is on gets // deleted too. From b50aef35d68a28b758ea18fe6d9856c41bff1948 Mon Sep 17 00:00:00 2001 From: lynschinzer Date: Wed, 8 May 2013 16:03:14 +0200 Subject: [PATCH 0033/4742] [vim keymap] Fix % seek forward behavior, add %seek skip comments/quotes --- keymap/vim.js | 45 ++++++++++++++++++++++++++++++++++++--------- test/vim_test.js | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 11 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index 3b857e58b1..fcdff6f74b 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -1345,9 +1345,24 @@ }, moveToMatchedSymbol: function(cm, motionArgs) { var cursor = cm.getCursor(); - var symbol = cm.getLine(cursor.line).charAt(cursor.ch); - if (isMatchableSymbol(symbol)) { - return findMatchedSymbol(cm, cm.getCursor(), motionArgs.symbol); + var line = cursor.line; + var ch = cursor.ch; + var lineText = cm.getLine(line); + var symbol; + var startContext = cm.getTokenAt(cursor).type; + var startCtxLevel = getContextLevel(startContext); + do { + symbol = lineText.charAt(ch++); + if (symbol && isMatchableSymbol(symbol)) { + var endContext = cm.getTokenAt({line:line, ch:ch}).type; + var endCtxLevel = getContextLevel(endContext); + if (startCtxLevel >= endCtxLevel) { + break; + } + } + } while (symbol); + if (symbol) { + return findMatchedSymbol(cm, {line:line, ch:ch-1}, symbol); } else { return cursor; } @@ -2338,9 +2353,17 @@ return idx; } + function getContextLevel(ctx) { + return (ctx === 'string' || ctx === 'comment') ? 1 : 0; + } + function findMatchedSymbol(cm, cur, symb) { var line = cur.line; - symb = symb ? symb : cm.getLine(line).charAt(cur.ch); + var ch = cur.ch; + symb = symb ? symb : cm.getLine(line).charAt(ch); + + var symbContext = cm.getTokenAt({line:line, ch:ch+1}).type; + var symbCtxLevel = getContextLevel(symbContext); var reverseSymb = ({ '(': ')', ')': '(', @@ -2356,7 +2379,7 @@ // 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); + var depth = 1, nextCh = symb, index = 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 @@ -2375,10 +2398,14 @@ } nextCh = lineText.charAt(index); } - if (nextCh === symb) { - depth++; - } else if (nextCh === reverseSymb) { - depth--; + var revSymbContext = cm.getTokenAt({line:line, ch:index+1}).type; + var revSymbCtxLevel = getContextLevel(revSymbContext); + if (symbCtxLevel >= revSymbCtxLevel) { + if (nextCh === symb) { + depth++; + } else if (nextCh === reverseSymb) { + depth--; + } } } diff --git a/test/vim_test.js b/test/vim_test.js index 4979e404b3..63d3197734 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -34,6 +34,7 @@ var wordLine = lines[0]; var bigWordLine = lines[1]; var charLine = lines[2]; var bracesLine = lines[3]; +var seekBraceLine = lines[4]; var word1 = { start: { line: wordLine.line, ch: 1 }, @@ -82,6 +83,14 @@ var curlys1 = { start: { line: bracesLine.line, ch: 9 }, end: { line: bracesLine.line, ch: 11 } }; +var seekOutside = { + start: { line: seekBraceLine.line, ch: 1 }, + end: { line: seekBraceLine.line, ch: 16 } +}; +var seekInside = { + start: { line: seekBraceLine.line, ch: 14 }, + end: { line: seekBraceLine.line, ch: 11 } +}; function copyCursor(cur) { return { ch: cur.ch, line: cur.line }; @@ -301,11 +310,34 @@ testMotion('T_repeat', ['2', 'T', 'p'], offsetCursor(pChars[0], 0, 1), pChars[2] testMotion('%_parens', ['%'], parens1.end, parens1.start); testMotion('%_squares', ['%'], squares1.end, squares1.start); testMotion('%_braces', ['%'], curlys1.end, curlys1.start); +testMotion('%_seek_outside', ['%'], seekOutside.end, seekOutside.start); +testMotion('%_seek_inside', ['%'], seekInside.end, seekInside.start); +testVim('%_seek_skip', function(cm, vim, helpers) { + cm.setCursor(0,0); + helpers.doKeys(['%']); + helpers.assertCursorAt(0,9); +}, {value:'01234"("()'}); +testVim('%_skip_string', function(cm, vim, helpers) { + cm.setCursor(0,0); + helpers.doKeys(['%']); + helpers.assertCursorAt(0,4); + cm.setCursor(0,2); + helpers.doKeys(['%']); + helpers.assertCursorAt(0,0); +}, {value:'(")")'}); +(')') +testVim('%_skip_comment', function(cm, vim, helpers) { + cm.setCursor(0,0); + helpers.doKeys(['%']); + helpers.assertCursorAt(0,6); + cm.setCursor(0,3); + helpers.doKeys(['%']); + helpers.assertCursorAt(0,0); +}, {value:'(/*)*/)'}); // Make sure that moving down after going to the end of a line always leaves you // at the end of a line, but preserves the offset in other cases testVim('Changing lines after Eol operation', function(cm, vim, helpers) { - var startPos = { line: 0, ch: 0 }; - cm.setCursor(startPos); + cm.setCursor(0,0); helpers.doKeys(['$']); helpers.doKeys(['j']); // After moving to Eol and then down, we should be at Eol of line 2 From 2f156c70610d98564a313ce0f89a14683195b36c Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Sun, 12 May 2013 15:07:22 -0400 Subject: [PATCH 0034/4742] [searchcursor] Small fixes to greedy regex search. Makes "backtracking" matches match the forward search matches. Fixes "0 or more" '\w*' type searches --- addon/search/searchcursor.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/addon/search/searchcursor.js b/addon/search/searchcursor.js index a590e84443..3da3f04e8f 100644 --- a/addon/search/searchcursor.js +++ b/addon/search/searchcursor.js @@ -24,16 +24,26 @@ if (!newMatch) break; match = newMatch; start = match.index; - cutOff = match.index + 1; + cutOff = match.index + (match[0].length || 1); + if (cutOff == line.length) break; + } + var matchLen = (match && match[0].length) || 0; + if (!matchLen) { + if (start == 0 && line.length == 0) {match = undefined;} + else if (start != doc.getLine(pos.line).length) { + matchLen++; + } } } else { query.lastIndex = pos.ch; - var line = doc.getLine(pos.line), match = query.exec(line), - start = match && match.index; + var line = doc.getLine(pos.line), match = query.exec(line); + var matchLen = (match && match[0].length) || 0; + var start = match && match.index; + if (start + matchLen != line.length && !matchLen) matchLen = 1; } - if (match && match[0]) + if (match && matchLen) return {from: Pos(pos.line, start), - to: Pos(pos.line, start + match[0].length), + to: Pos(pos.line, start + matchLen), match: match}; }; } else { // String query From d641e0d8c9254c0b5229cb961e028c930ee528ec Mon Sep 17 00:00:00 2001 From: Yunchi Luo Date: Fri, 15 Mar 2013 22:26:29 -0400 Subject: [PATCH 0035/4742] [vim] Fix greedy regex search --- keymap/vim.js | 11 ++++---- test/vim_test.js | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/keymap/vim.js b/keymap/vim.js index fcdff6f74b..48276836ca 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -842,7 +842,7 @@ try { updateSearchQuery(cm, query, ignoreCase, smartCase); } catch (e) { - showConfirm(cm, 'Invalid regex: ' + regexPart); + showConfirm(cm, 'Invalid regex: ' + query); return; } commandDispatcher.processMotion(cm, vim, { @@ -2656,7 +2656,7 @@ if (match[0].length == 0) { // Matched empty string, skip to next. stream.next(); - return; + return "searching"; } if (!stream.sol()) { // Backtrack 1 to match \b @@ -2692,12 +2692,11 @@ if (repeat === undefined) { repeat = 1; } return cm.operation(function() { var pos = cm.getCursor(); - if (!prev) { - pos.ch += 1; - } var cursor = cm.getSearchCursor(query, pos); for (var i = 0; i < repeat; i++) { - if (!cursor.find(prev)) { + var found = cursor.find(prev); + if (i == 0 && found && cursorEqual(cursor.from(), pos)) { found = cursor.find(prev); } + if (!found) { // SearchCursor may have returned null because it hit EOF, wrap // around and try again. cursor = cm.getSearchCursor(query, diff --git a/test/vim_test.js b/test/vim_test.js index 63d3197734..f2304b99cf 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -1401,6 +1401,76 @@ testVim('/_case', function(cm, vim, helpers) { helpers.doKeys('/'); helpers.assertCursorAt(1, 6); }, { value: 'match nope match \n nope Match' }); +testVim('/_nongreedy', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('aa'); + helpers.doKeys('/'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 3); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 0); +}, { value: 'aaa aa \n a aa'}); +testVim('?_nongreedy', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('aa'); + helpers.doKeys('?'); + helpers.assertCursorAt(1, 3); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 0); +}, { value: 'aaa aa \n a aa'}); +testVim('/_greedy', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('a+'); + helpers.doKeys('/'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 1); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 3); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 0); +}, { value: 'aaa aa \n a aa'}); +testVim('?_greedy', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('a+'); + helpers.doKeys('?'); + helpers.assertCursorAt(1, 3); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 1); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 0); +}, { value: 'aaa aa \n a aa'}); +testVim('/_greedy_0_or_more', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('a*'); + helpers.doKeys('/'); + helpers.assertCursorAt(0, 3); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 5); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 0); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 1); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 0); +}, { value: 'aaa aa\n aa'}); +testVim('?_greedy_0_or_more', function(cm, vim, helpers) { + cm.openDialog = helpers.fakeOpenDialog('a*'); + helpers.doKeys('?'); + helpers.assertCursorAt(1, 1); + helpers.doKeys('n'); + helpers.assertCursorAt(1, 0); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 5); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 4); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 3); + helpers.doKeys('n'); + helpers.assertCursorAt(0, 0); +}, { value: 'aaa aa\n aa'}); testVim('? and n/N', function(cm, vim, helpers) { cm.openDialog = helpers.fakeOpenDialog('match'); helpers.doKeys('?'); From db76ceeaffd461fb5e3d0559624e14701a53eaa9 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 13 May 2013 10:16:07 +0200 Subject: [PATCH 0036/4742] Prevent update and viewportChange events from being fired too often Previously, they'd fire multiple times when an update didn't immediately become stable. --- lib/codemirror.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/codemirror.js b/lib/codemirror.js index 745caba277..934fcd4f99 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -405,12 +405,8 @@ window.CodeMirror = (function() { var oldFrom = cm.display.showingFrom, oldTo = cm.display.showingTo, updated; var visible = visibleLines(cm.display, cm.doc, viewPort); for (;;) { - 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; + if (!updateDisplayInner(cm, changes, visible)) break; + updated = true; updateSelection(cm); updateScrollbars(cm); @@ -424,6 +420,11 @@ window.CodeMirror = (function() { changes = []; } + 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); + } return updated; } From b2c1d962d836efe08a39cabee7c1a46e6bc2551d Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 13 May 2013 10:22:53 +0200 Subject: [PATCH 0037/4742] Explicitly set gutter height This prevents it from being repainted whenever the height of the inner editor briefly changes during a repaint. (At least, it does on Webkit). Issue #1514 --- lib/codemirror.css | 1 - lib/codemirror.js | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/codemirror.css b/lib/codemirror.css index 5512380116..f5379d967c 100644 --- a/lib/codemirror.css +++ b/lib/codemirror.css @@ -149,7 +149,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} .CodeMirror-gutters { position: absolute; left: 0; top: 0; - height: 100%; padding-bottom: 30px; z-index: 3; } diff --git a/lib/codemirror.js b/lib/codemirror.js index 934fcd4f99..699f55a4c5 100644 --- a/lib/codemirror.js +++ b/lib/codemirror.js @@ -127,10 +127,8 @@ window.CodeMirror = (function() { // Will contain the gutters, if any d.gutters = elt("div", null, "CodeMirror-gutters"); d.lineGutter = null; - // Helper element to properly size the gutter backgrounds - var scrollerInner = elt("div", [d.sizer, d.heightForcer, d.gutters], null, "position: relative; min-height: 100%"); // Provides scrolling - d.scroller = elt("div", [scrollerInner], "CodeMirror-scroll"); + d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); d.scroller.setAttribute("tabIndex", "-1"); // The element in which the editor lives. d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV, @@ -323,6 +321,7 @@ window.CodeMirror = (function() { var d = cm.display, docHeight = cm.doc.height; var totalHeight = docHeight + paddingVert(d); 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; From ffebe6da853ac5825ae4b2dc7173dcbfa7d51e39 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 13 May 2013 10:30:09 +0200 Subject: [PATCH 0038/4742] [yaml mode] Comments must be preceded by whitespace Closes #1516 --- mode/yaml/yaml.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mode/yaml/yaml.js b/mode/yaml/yaml.js index bdd303dfed..7a095b31db 100644 --- a/mode/yaml/yaml.js +++ b/mode/yaml/yaml.js @@ -9,7 +9,9 @@ CodeMirror.defineMode("yaml", function() { var esc = state.escaped; state.escaped = false; /* comments */ - if (ch == "#") { stream.skipToEnd(); return "comment"; } + if (ch == "#" && (stream.pos == 0 || /\s/.test(stream.string.charAt(stream.pos - 1)))) { + stream.skipToEnd(); return "comment"; + } if (state.literal && stream.indentation() > state.keyCol) { stream.skipToEnd(); return "string"; } else if (state.literal) { state.literal = false; } From d4f05936c278ea12ff41eb766a1cd9935e37c965 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Mon, 13 May 2013 13:47:28 +0200 Subject: [PATCH 0039/4742] [comment addon] Implement automatic commenting/uncommenting --- addon/comment/comment.js | 145 ++++++++++++++++++++++++++++++ doc/manual.html | 68 ++++++++++++++ mode/clike/clike.js | 5 +- mode/clojure/clojure.js | 4 +- mode/coffeescript/coffeescript.js | 3 +- mode/commonlisp/commonlisp.js | 6 +- mode/css/css.js | 4 +- mode/erlang/erlang.js | 5 +- mode/gas/gas.js | 6 +- mode/go/go.js | 5 +- mode/haskell/haskell.js | 6 +- mode/javascript/index.html | 4 +- mode/javascript/javascript.js | 3 + mode/lua/lua.js | 6 +- mode/ocaml/ocaml.js | 5 +- mode/php/php.js | 3 + mode/python/python.js | 3 +- mode/ruby/ruby.js | 3 +- mode/rust/rust.js | 5 +- mode/scheme/scheme.js | 4 +- mode/xml/xml.js | 2 + test/comment_test.js | 46 ++++++++++ test/driver.js | 3 +- test/index.html | 2 + test/test.js | 2 + 25 files changed, 330 insertions(+), 18 deletions(-) create mode 100644 addon/comment/comment.js create mode 100644 test/comment_test.js diff --git a/addon/comment/comment.js b/addon/comment/comment.js new file mode 100644 index 0000000000..2963268a72 --- /dev/null +++ b/addon/comment/comment.js @@ -0,0 +1,145 @@ +(function() { + "use strict"; + + var noOptions = {}; + var nonWS = /[^\s\u00a0]/; + var Pos = CodeMirror.Pos; + + function firstNonWS(str) { + var found = str.search(nonWS); + return found == -1 ? 0 : found; + } + + CodeMirror.commands.toggleComment = function(cm) { + var from = cm.getCursor("start"), to = cm.getCursor("end"); + cm.uncomment(from, to) || cm.lineComment(from, to); + }; + + 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 commentString = options.lineComment || mode.lineComment; + if (!commentString) { + if (options.blockCommentStart || mode.blockCommentStart) { + options.fullLines = true; + self.blockComment(from, to, options); + } + return; + } + var tabSize = self.getOption("tabSize"), 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; + var blankLines = options.commentBlankLines; + + 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; + if (!blankLines && !nonWS.test(line)) continue; + if (line.slice(0, cut) != baseString) cut = firstNonWS(line); + self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut)); + } + } else { + for (var i = from.line; i < end; ++i) { + if (blankLines || nonWS.test(self.getLine(i))) + self.replaceRange(commentString + pad, Pos(i, 0)); + } + } + }); + }); + + 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 startString = options.blockCommentStart || mode.blockCommentStart; + var endString = options.blockCommentEnd || mode.blockCommentEnd; + if (!startString || !endString) { + if ((options.lineComment || mode.lineComment) && options.fullLines != false) + self.lineComment(from, to, options); + return; + } + + var end = Math.min(to.line, self.lastLine()); + if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end; + + var pad = options.padding == null ? " " : options.padding; + if (from.line > end) return; + + self.operation(function() { + if (options.fullLines != false) { + var lastLineHasText = nonWS.test(self.getLine(end)); + self.replaceRange(pad + endString, Pos(end)); + self.replaceRange(startString + pad, Pos(from.line, 0)); + var lead = options.blockCommentLead || mode.blockCommentLead; + if (lead != null) for (var i = from.line + 1; i <= end; ++i) + if (i != end || lastLineHasText) + self.replaceRange(lead + pad, Pos(i, 0)); + } else { + self.replaceRange(endString, to); + self.replaceRange(startString, from); + } + }); + }); + + 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 end = Math.min(to.line, self.lastLine()), start = Math.min(from.line, end); + + // Try finding line comments + var lineString = options.lineComment || mode.lineComment, lines = []; + var pad = options.padding == null ? " " : options.padding; + lineComment: for(;;) { + if (!lineString) break; + for (var i = start; i <= end; ++i) { + 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; + lines.push(line); + } + self.operation(function() { + for (var i = start; i <= end; ++i) { + var line = lines[i - start]; + var pos = line.indexOf(lineString), endPos = pos + lineString.length; + if (pos < 0) continue; + if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length; + self.replaceRange("", Pos(i, pos), Pos(i, endPos)); + } + }); + return true; + } + + // Try block comments + var startString = options.blockCommentStart || mode.blockCommentStart; + var endString = options.blockCommentEnd || mode.blockCommentEnd; + if (!startString || !endString) return false; + var lead = options.blockCommentLead || mode.blockCommentLead; + var startLine = self.getLine(start), endLine = end == start ? startLine : self.getLine(end); + var open = startLine.indexOf(startString), close = endLine.lastIndexOf(endString); + if (close == -1 && start != end) { + endLine = self.getLine(--end); + close = endLine.lastIndexOf(endString); + } + if (open == -1 || close == -1) return false; + + self.operation(function() { + self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)), + Pos(end, close + endString.length)); + var openEnd = open + startString.length; + if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length; + self.replaceRange("", Pos(start, open), Pos(start, openEnd)); + if (lead) for (var i = start + 1; i <= end; ++i) { + var line = self.getLine(i), found = line.indexOf(lead); + if (found == -1 || nonWS.test(line.slice(0, found))) continue; + var foundEnd = found + lead.length; + if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length; + self.replaceRange("", Pos(i, found), Pos(i, foundEnd)); + } + }); + return true; + }); +})(); diff --git a/doc/manual.html b/doc/manual.html index 361a0e4273..a7d6a67948 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1501,6 +1501,7 @@

    Add-ons

    prompt (should include an input tag), and a callback function that is called when text has been entered. Depends on addon/dialog/dialog.css.

    +
    search/searchcursor.js
    Adds the getSearchCursor(query, start, caseFold) → cursor method to CodeMirror instances, which can be used @@ -1539,6 +1540,7 @@

    Add-ons

    on searchcursor.js, and will make use of openDialog when available to make prompting for search queries less ugly.
    +
    edit/matchbrackets.js
    Defines an option matchBrackets which, when set to true, causes matching brackets to be highlighted whenever the @@ -1547,6 +1549,7 @@

    Add-ons

    once, and a method findMatchingBracket that can be used to run the bracket-finding algorithm that this uses internally.
    +
    edit/closebrackets.js
    Defines an option autoCloseBrackets that will auto-close brackets and quotes when typed. By default, it'll @@ -1554,6 +1557,50 @@

    Add-ons

    string similar to that (containing pairs of matching characters) to customize it. Demo here.
    + +
    comment/comment.js
    +
    Addon for commenting and uncommenting code. Adds three + methods to CodeMirror instances: +
    +
    lineComment(from: {line, ch}, to: {line, ch}, ?options: object)
    +
    Set the lines in the given range to be line comments. Will + fall back to blockComment when no line comment + style is defined for the mode.
    +
    blockComment(from: {line, ch}, to: {line, ch}, ?options: object)
    +
    Wrap the code in the given range in a block comment. Will + fall back to lineComment when no block comment + style is defined for the mode.
    +
    uncomment(from: {line, ch}, to: {line, ch}, ?options: object) → boolean
    +
    Try to uncomment the given range. + Returns true if a comment range was found and + removed, false otherwise.
    +
    + The options object accepted by these methods may + have the following properties: +
    +
    blockCommentStart, blockCommentEnd, blockCommentLead, lineComment: string
    +
    Override the comment string + properties of the mode with custom comment strings.
    +
    padding
    +
    A string that will be inserted after opening and before + closing comment markers. Defaults to a single space.
    +
    commentBlankLines
    +
    Whether, when adding line comments, to also comment lines + that contain only whitespace.
    +
    indent
    +
    When adding line comments and this is turned on, it will + align the comment block to the current indentation of the + first line of the block.
    +
    fullLines
    +
    When block commenting, this controls whether the whole + lines are indented, or only the precise range that is given. + Defaults to true.
    +
    + The addon also defines + a toggleComment command, + which will try to uncomment the current selection, and if that + fails, line-comments it.
    +
    fold/foldcode.js
    Helps with code folding. See the demo for an example. @@ -1571,6 +1618,7 @@

    Add-ons

    where indentation determines block structure (Python, Haskell), and CodeMirror.tagRangeFinder, for XML-style languages.
    +
    runmode/runmode.js
    Can be used to run a CodeMirror mode over text without actually opening an editor instance. @@ -1580,6 +1628,7 @@

    Add-ons

    (without including all of CodeMirror) and for running under node.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 @@ -1588,6 +1637,7 @@

    Add-ons

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

    Add-ons

    see the content between the delimiters. See this demo for an example.
    +
    hint/show-hint.js
    Provides a framework for showing autocompletion hints. Defines CodeMirror.showHint, which takes a @@ -1622,11 +1673,13 @@

    Add-ons

    hint sources for various languages. Check out the demo for an example.
    +
    match-highlighter.js
    Adds a highlightSelectionMatches option that can be enabled to highlight all instances of a currently selected word. Demo here.
    +
    lint/lint.js
    Defines an interface component for showing linting warnings, with pluggable warning sources @@ -1637,20 +1690,24 @@

    Add-ons

    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.
    +
    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.
    +
    edit/closetag.js
    Provides utility functions for adding automatic tag closing to XML modes. See the demo.
    +
    mode/loadmode.js
    Defines a CodeMirror.requireMode(modename, callback) function that will try to load a given mode and @@ -1663,12 +1720,14 @@

    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.
    +
    edit/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 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. @@ -1833,6 +1892,15 @@

    Writing CodeMirror Modes

    return CodeMirror.Pass to indicate that it could not come up with a precise indentation.

    +

    To work well with + the commenting addon, a mode may + define lineComment (string that starts a line + comment), blockCommentStart, blockCommentEnd + (strings that start and end block comments), + and blockCommentLead (a string to put at the start of + continued lines in a block comment). All of these are + optional.

    +

    Finally, a mode may define an electricChars property, which should hold a string containing all the characters that should trigger the behaviour diff --git a/mode/clike/clike.js b/mode/clike/clike.js index c14d7b4006..83bf8019f2 100644 --- a/mode/clike/clike.js +++ b/mode/clike/clike.js @@ -155,7 +155,10 @@ CodeMirror.defineMode("clike", function(config, parserConfig) { else return ctx.indented + (closing ? 0 : indentUnit); }, - electricChars: "{}" + electricChars: "{}", + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" }; }); diff --git a/mode/clojure/clojure.js b/mode/clojure/clojure.js index fae675477d..ee22a12fed 100644 --- a/mode/clojure/clojure.js +++ b/mode/clojure/clojure.js @@ -215,7 +215,9 @@ CodeMirror.defineMode("clojure", function () { indent: function (state) { if (state.indentStack == null) return state.indentation; return state.indentStack.indent; - } + }, + + lineComment: ";;" }; }); diff --git a/mode/coffeescript/coffeescript.js b/mode/coffeescript/coffeescript.js index cf1cf4f246..509d9207bb 100644 --- a/mode/coffeescript/coffeescript.js +++ b/mode/coffeescript/coffeescript.js @@ -337,8 +337,9 @@ CodeMirror.defineMode('coffeescript', function(conf) { } return state.scopes[0].offset; - } + }, + lineComment: "#" }; return external; }); diff --git a/mode/commonlisp/commonlisp.js b/mode/commonlisp/commonlisp.js index eeba759668..8fa08c8ac2 100644 --- a/mode/commonlisp/commonlisp.js +++ b/mode/commonlisp/commonlisp.js @@ -94,7 +94,11 @@ CodeMirror.defineMode("commonlisp", function (config) { indent: function (state, _textAfter) { var i = state.ctx.indentTo; return typeof i == "number" ? i : state.ctx.start + 1; - } + }, + + lineComment: ";;", + blockCommentStart: "#|", + blockCommentEnd: "|#" }; }); diff --git a/mode/css/css.js b/mode/css/css.js index f0fae602d1..f4ee021ed4 100644 --- a/mode/css/css.js +++ b/mode/css/css.js @@ -286,7 +286,9 @@ CodeMirror.defineMode("css-base", function(config, parserConfig) { return state.baseIndent + n * indentUnit; }, - electricChars: "}" + electricChars: "}", + blockCommentStart: "/*", + blockCommentEnd: "*/" }; }); diff --git a/mode/erlang/erlang.js b/mode/erlang/erlang.js index 029b8e5561..79e0434d1f 100644 --- a/mode/erlang/erlang.js +++ b/mode/erlang/erlang.js @@ -456,8 +456,9 @@ CodeMirror.defineMode("erlang", function(cmCfg) { indent: function(state, textAfter) { -// console.log(state.tokenStack); return myIndent(state,textAfter); - } + }, + + lineComment: "%" }; }); diff --git a/mode/gas/gas.js b/mode/gas/gas.js index 6604f01820..a6e6892908 100644 --- a/mode/gas/gas.js +++ b/mode/gas/gas.js @@ -321,6 +321,10 @@ CodeMirror.defineMode("gas", function(_config, parserConfig) { return style; } } - } + }, + + lineComment: lineCommentStartSymbol, + blockCommentStart: "/*", + blockCommentEnd: "*/" }; }); diff --git a/mode/go/go.js b/mode/go/go.js index 8b84a5ca42..6a458a6fe9 100644 --- a/mode/go/go.js +++ b/mode/go/go.js @@ -158,7 +158,10 @@ CodeMirror.defineMode("go", function(config) { else return ctx.indented + (closing ? 0 : indentUnit); }, - electricChars: "{}:" + electricChars: "{}:", + blockCommentStart: "/*", + blockCommentEnd: "*/", + lineComment: "//" }; }); diff --git a/mode/haskell/haskell.js b/mode/haskell/haskell.js index faec08dc33..b18d5ced1a 100644 --- a/mode/haskell/haskell.js +++ b/mode/haskell/haskell.js @@ -234,7 +234,11 @@ CodeMirror.defineMode("haskell", function() { var t = state.f(stream, function(s) { state.f = s; }); var w = stream.current(); return (w in wellKnownWords) ? wellKnownWords[w] : t; - } + }, + + blockCommentStart: "{-", + blockCommentEnd: "-}", + lineComment: "--" }; }); diff --git a/mode/javascript/index.html b/mode/javascript/index.html index dd0ca220d8..db063b772d 100644 --- a/mode/javascript/index.html +++ b/mode/javascript/index.html @@ -7,6 +7,7 @@ + @@ -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 0040/4742] [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 0041/4742] [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 0042/4742] 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 0043/4742] [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 0044/4742] [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 0045/4742] [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 0046/4742] 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 0047/4742] [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 0048/4742] 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 0049/4742] 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 0050/4742] [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 0051/4742] [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 0052/4742] 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 0053/4742] [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 0054/4742] 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 0055/4742] [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 0056/4742] [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 0057/4742] [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 0058/4742] [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 0059/4742] [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 0060/4742] [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 0061/4742] [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 0062/4742] 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 0076/4742] [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 0077/4742] [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 0078/4742] 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 0079/4742] 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 0080/4742] 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 0081/4742] [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 0082/4742] [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 0083/4742] 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 0084/4742] [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 0085/4742] [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 0086/4742] [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 0087/4742] [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 0088/4742] 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 0089/4742] [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 0090/4742] [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 0094/4742] 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 0095/4742] 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 0096/4742] 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 0097/4742] 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 0098/4742] 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 0099/4742] 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 0100/4742] [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 0101/4742] [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 0102/4742] [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 0103/4742] [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 0104/4742] 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 0105/4742] 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 0106/4742] 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 0107/4742] 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 0108/4742] 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 0109/4742] 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 0110/4742] 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 0111/4742] 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 0112/4742] [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 0113/4742] [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 0114/4742] [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 0115/4742] 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 0116/4742] 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 0117/4742] 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 0118/4742] 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 0119/4742] [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 0205/4742] [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 0206/4742] [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 0207/4742] [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 0208/4742] 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 0209/4742] 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 0213/4742] [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 0214/4742] 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 0215/4742] [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 0216/4742] 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 0217/4742] [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 0218/4742] [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 0219/4742] [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 0220/4742] [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 0221/4742] [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 0241/4742] 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 0242/4742] [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 0243/4742] [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 0244/4742] [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 0245/4742] [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 0246/4742] [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 0247/4742] [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 0248/4742] 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 0249/4742] 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 0250/4742] 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 0251/4742] [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 0252/4742] 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 0254/4742] [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 0255/4742] [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 0256/4742] [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 0257/4742] [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 0258/4742] 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 0259/4742] [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 0260/4742] [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 0261/4742] [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 0262/4742] 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 0263/4742] [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 0264/4742] [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 0265/4742] [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 0266/4742] 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 0267/4742] 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 0268/4742] [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 0269/4742] 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 0270/4742] 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 0271/4742] 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 0272/4742] 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 0273/4742] 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 0274/4742] 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 0275/4742] [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 0276/4742] [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 0277/4742] [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 0278/4742] [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 0279/4742] 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 0280/4742] [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 0281/4742] [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 0282/4742] [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 0283/4742] 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 0284/4742] [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 0285/4742] [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 0312/4742] [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 0333/4742] [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 0334/4742] [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 0335/4742] 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 0336/4742] [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 0337/4742] [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 0338/4742] 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 0339/4742] [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 0340/4742] [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 0341/4742] [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 0342/4742] 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 0343/4742] [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 0344/4742] 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 0345/4742] [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 0346/4742] [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 0347/4742] (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 0348/4742] 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 0349/4742] 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 0350/4742] [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 0351/4742] 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 0352/4742] [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 0353/4742] "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 0354/4742] 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 0355/4742] 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 0356/4742] 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 0357/4742] 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 0358/4742] 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 0359/4742] [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 0360/4742] 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 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

    #6335mO-CwW+nmUD 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 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 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 + + + + + + + + + + + + + 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 0373/4742] [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 0374/4742] 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 0375/4742] [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 0376/4742] [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 0377/4742] [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,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"); 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 0378/4742] [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 0379/4742] [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 0380/4742] [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 0381/4742] [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 0382/4742] [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 0383/4742] [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 0384/4742] [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 0385/4742] 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 0386/4742] [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 0387/4742] [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 0388/4742] 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 0389/4742] [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 0390/4742] 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 0391/4742] [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 0433/4742] [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 0434/4742] [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 0435/4742] 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 0436/4742] [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 0437/4742] [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 0438/4742] [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 0439/4742] [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 0440/4742] [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 0441/4742] [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 0442/4742] [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 0443/4742] [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 0444/4742] [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 0445/4742] 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 0446/4742] 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 0447/4742] 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 0448/4742] 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 0449/4742] [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 0450/4742] 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 0451/4742] [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 0452/4742] 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 0453/4742] 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 0454/4742] [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 0455/4742] [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 0460/4742] [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 0461/4742] 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 0462/4742] [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 0463/4742] [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 0464/4742] 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 0465/4742] [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 0466/4742] 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 0470/4742] [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 0471/4742] [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 0472/4742] [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 0473/4742] 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 0474/4742] [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 0475/4742] 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 0476/4742] 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 0477/4742] [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 0478/4742] 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 0563/4742] [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 0564/4742] [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 0565/4742] [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 0566/4742] 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 0567/4742] [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 0568/4742] 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 0569/4742] [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 0570/4742] 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 0571/4742] [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 0572/4742] [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 0573/4742] [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 0574/4742] [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 0575/4742] [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 0576/4742] 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 0577/4742] [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 0578/4742] [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 0579/4742] [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 0580/4742] [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 0581/4742] [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 0582/4742] [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 0583/4742] 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 0584/4742] [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 0585/4742] [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 0586/4742] [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 0587/4742] [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 0588/4742] [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 0589/4742] 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 0590/4742] 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 0591/4742] 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 0592/4742] [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 0593/4742] [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 0594/4742] [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 0595/4742] [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 0596/4742] [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 0597/4742] [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 1302/4742] [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 1303/4742] [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 1304/4742] [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 1305/4742] [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 1306/4742] 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 1307/4742] [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 1308/4742] [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 1309/4742] [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 1310/4742] [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 1311/4742] 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 1312/4742] 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 1313/4742] [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 1314/4742] 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 1315/4742] [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 1316/4742] [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 1317/4742] 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 1318/4742] [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 1319/4742] 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 1320/4742] 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 1321/4742] [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 1322/4742] [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 1323/4742] [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 1324/4742] [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 1325/4742] [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 1427/4742] [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 1428/4742] [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 1429/4742] [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 1430/4742] 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 1431/4742] 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 1432/4742] [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 1433/4742] [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 1434/4742] 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 1435/4742] [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 1436/4742] 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 1437/4742] [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 1438/4742] 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 1439/4742] [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 1440/4742] [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 1441/4742] [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 1442/4742] 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 1443/4742] 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 1444/4742] 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 1445/4742] 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 1446/4742] 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 1447/4742] [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 1448/4742] 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 1449/4742] 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 1450/4742] 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 1451/4742] [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 1452/4742] 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 1453/4742] [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 1454/4742] [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 1455/4742] [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 1456/4742] [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 1457/4742] [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 1458/4742] [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 1459/4742] 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 1460/4742] 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 1461/4742] [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 1462/4742] [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 1463/4742] 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 1464/4742] [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 1465/4742] 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 1507/4742] [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 1508/4742] 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 1509/4742] [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 1510/4742] [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 1511/4742] [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 1512/4742] [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 1531/4742] [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 1532/4742] [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 1533/4742] 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 1534/4742] [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 1535/4742] 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 1536/4742] 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 1537/4742] [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 1538/4742] [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 1539/4742] [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 1540/4742] 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 1541/4742] 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 1542/4742] [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 1543/4742] [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 1544/4742] [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 1545/4742] 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 1546/4742] 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 1547/4742] 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 1548/4742] 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 1549/4742] [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 1550/4742] 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 1551/4742] 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 1552/4742] 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 1615/4742] [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 1616/4742] 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 1617/4742] 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 1618/4742] [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 1619/4742] 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 1620/4742] 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 1621/4742] 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 1622/4742] [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 1623/4742] 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;}