5 changes: 3 additions & 2 deletions doc/manual.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
<section class=first id=overview>
<h2 style="position: relative">
User manual and reference guide
<span style="color: #888; font-size: 1rem; position: absolute; right: 0; bottom: 0">version 5.12.0</span>
<span style="color: #888; font-size: 1rem; position: absolute; right: 0; bottom: 0">version 5.13.0</span>
</h2>

<p>CodeMirror is a code-editor component that can be embedded in
Expand Down Expand Up @@ -657,7 +657,8 @@ <h2>Events</h2>
<strong>"keydown"</strong>, <strong>"keypress"</strong>,
<strong>"keyup"</strong>, <strong>"cut"</strong>, <strong>"copy"</strong>, <strong>"paste"</strong>,
<strong>"dragstart"</strong>, <strong>"dragenter"</strong>,
<strong>"dragover"</strong>, <strong>"drop"</strong>
<strong>"dragover"</strong>, <strong>"dragleave"</strong>,
<strong>"drop"</strong>
(instance: CodeMirror, event: Event)</code></dt>
<dd>Fired when CodeMirror is handling a DOM event of this type.
You can <code>preventDefault</code> the event, or give it a
Expand Down
21 changes: 19 additions & 2 deletions doc/releases.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,26 @@ <h2>Release notes and version history</h2>

<h2>Version 5.x</h2>

<p class="rel">21-03-2016: <a href="http://codemirror.net/codemirror-5.13.zip">Version 5.13</a>:</p>

<ul class="rel-note">
<li>New DOM event forwarded: <a href="http://codemirror.net/doc/manual.html#event_dom"><code>&quot;dragleave&quot;</code></a>.</li>
<li><a href="http://codemirror.net/mode/protobuf/index.html">protobuf mode</a>: Newly added.</li>
<li>Fix problem where <a href="http://codemirror.net/doc/manual.html#findMarks"><code>findMarks</code></a> sometimes failed to find multi-line marks.</li>
<li>Fix crash that showed up when atomic ranges and bidi text were combined.</li>
<li><a href="http://codemirror.net/demo/complete.html">show-hint addon</a>: Completion widgets no longer close when the line indented or dedented.</li>
<li><a href="http://codemirror.net/demo/merge.html">merge addon</a>: Fix bug when merging chunks at the end of the file.</li>
<li><a href="http://codemirror.net/doc/manual.html#addon_placeholder">placeholder addon</a>: No longer gets confused by <a href="http://codemirror.net/doc/manual.html#swapDoc"><code>swapDoc</code></a>.</li>
<li><a href="http://codemirror.net/doc/manual.html#addon_simplescrollbars">simplescrollbars addon</a>: Fix invalid state when deleting at end of document.</li>
<li><a href="http://codemirror.net/mode/clike/index.html">clike mode</a>: No longer gets confused when a comment starts after an operator.</li>
<li><a href="http://codemirror.net/mode/markdown/index.html">markdown mode</a>: Now supports CommonMark-style flexible list indentation.</li>
<li><a href="http://codemirror.net/mode/dylan/index.html">dylan mode</a>: Several improvements and fixes.</li>
<li>Full <a href="https://github.com/codemirror/CodeMirror/compare/5.12.0...5.13.0">list of patches</a></li>
</ul>

<p class="rel">19-02-2016: <a href="http://codemirror.net/codemirror-5.12.zip">Version 5.12</a>:</p>

<ul>
<ul class="rel-note">
<li><a href="http://codemirror.net/demo/vim.html">Vim bindings</a>: Ctrl-Q is now an alias for Ctrl-V.</li>
<li><a href="http://codemirror.net/demo/vim.html">Vim bindings</a>: The Vim API now exposes an <code>unmap</code> method to unmap bindings.</li>
<li><a href="http://codemirror.net/demo/activeline.html">active-line addon</a>: This addon can now style the active line's gutter.</li>
Expand All @@ -55,7 +72,7 @@ <h2>Version 5.x</h2>

<p class="rel">20-01-2016: <a href="http://codemirror.net/codemirror-5.11.zip">Version 5.11</a>:</p>

<ul>
<ul class="rel-note">
<li>New modes: <a href="../mode/jsx/index.html">JSX</a>, <a href="../mode/haskell-literate/index.html">literate Haskell</a></li>
<li>The editor now forwards more <a href="manual.html#event_dom">DOM events</a>: <code>cut</code>, <code>copy</code>, <code>paste</code>, and <code>touchstart</code>. It will also forward <code>mousedown</code> for drag events</li>
<li>Fixes a bug where bookmarks next to collapsed spans were not rendered</li>
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ <h2>This is CodeMirror</h2>
</div>
</div>
<div class=actionsleft>
Get the current version: <a href="http://codemirror.net/codemirror.zip">5.12</a>.<br>
Get the current version: <a href="http://codemirror.net/codemirror.zip">5.13</a>.<br>
You can see the <a href="https://github.com/codemirror/codemirror" title="Github repository">code</a> or<br>
read the <a href="doc/releases.html">release notes</a>.<br>
There is a <a href="doc/compress.html">minification helper</a>.
Expand Down
15 changes: 8 additions & 7 deletions keymap/vim.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@
{ keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>', context: 'insert' },
{ keys: '<C-c>', type: 'keyToKey', toKeys: '<Esc>', context: 'insert' },
{ keys: 's', type: 'keyToKey', toKeys: 'cl', context: 'normal' },
{ keys: 's', type: 'keyToKey', toKeys: 'xi', context: 'visual'},
{ keys: 's', type: 'keyToKey', toKeys: 'c', context: 'visual'},
{ keys: 'S', type: 'keyToKey', toKeys: 'cc', context: 'normal' },
{ keys: 'S', type: 'keyToKey', toKeys: 'dcc', context: 'visual' },
{ keys: 'S', type: 'keyToKey', toKeys: 'VdO', context: 'visual' },
{ keys: '<Home>', type: 'keyToKey', toKeys: '0' },
{ keys: '<End>', type: 'keyToKey', toKeys: '$' },
{ keys: '<PageUp>', type: 'keyToKey', toKeys: '<C-b>' },
Expand Down Expand Up @@ -1696,11 +1696,12 @@
var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat;
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;
// Vim go to line begin or line end when cursor at first/last line and
// move to previous/next line is triggered.
if (line < first && cur.line == first){
return this.moveToStartOfLine(cm, head, motionArgs, vim);
}else if (line > last && cur.line == last){
return this.moveToEol(cm, head, motionArgs, vim);
}
if (motionArgs.toFirstChar){
endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line));
Expand Down
21 changes: 14 additions & 7 deletions lib/codemirror.js
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,7 @@

function postUpdateDisplay(cm, update) {
var viewport = update.viewport;

for (var first = true;; first = false) {
if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
// Clip forced viewport to actual scrollable area.
Expand All @@ -766,6 +767,9 @@
updateScrollbars(cm, barMeasure);
}

if (parseInt(cm.display.gutters.style.height) > cm.display.scroller.clientHeight)
cm.display.gutters.style.height = cm.display.scroller.clientHeight + "px"

update.signal(cm, "update", cm);
if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
Expand Down Expand Up @@ -2258,13 +2262,15 @@

if (oldPos) {
var near = m.find(dir < 0 ? 1 : -1), diff;
if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) near = movePos(doc, near, -dir, line);
if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null);
if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
return skipAtomicInner(doc, near, pos, dir, mayClear);
}

var far = m.find(dir < 0 ? -1 : 1);
if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) far = movePos(doc, far, dir, line);
if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
far = movePos(doc, far, dir, far.line == pos.line ? line : null);
return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null;
}
}
Expand Down Expand Up @@ -2311,6 +2317,7 @@
for (var i = 0; i < doc.sel.ranges.length; i++) {
if (primary === false && i == doc.sel.primIndex) continue;
var range = doc.sel.ranges[i];
if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue;
var collapsed = range.empty();
if (collapsed || cm.options.showCursorWhenSelecting)
drawSelectionCursor(cm, range.head, curFragment);
Expand Down Expand Up @@ -3492,7 +3499,7 @@
over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
start: function(e){onDragStart(cm, e);},
drop: operation(cm, onDrop),
leave: function() {clearDragCursor(cm);}
leave: function(e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
};

var inp = d.input.getField();
Expand Down Expand Up @@ -7622,9 +7629,9 @@
var spans = line.markedSpans;
if (spans) for (var i = 0; i < spans.length; i++) {
var span = spans[i];
if (!(lineNo == from.line && from.ch > span.to ||
span.from == null && lineNo != from.line||
lineNo == to.line && span.from > to.ch) &&
if (!(span.to != null && lineNo == from.line && from.ch > span.to ||
span.from == null && lineNo != from.line ||
span.from != null && lineNo == to.line && span.from > to.ch) &&
(!filter || filter(span.marker)))
found.push(span.marker.parent || span.marker);
}
Expand Down Expand Up @@ -8886,7 +8893,7 @@

// THE END

CodeMirror.version = "5.12.0";
CodeMirror.version = "5.13.0";

return CodeMirror;
});
2 changes: 1 addition & 1 deletion mode/clike/clike.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
}
}
if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {}
return "operator";
}
stream.eatWhile(/[\w\$_\xa1-\uffff]/);
Expand Down
1 change: 1 addition & 0 deletions mode/clojure/clojure.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,5 +245,6 @@ CodeMirror.defineMode("clojure", function (options) {

CodeMirror.defineMIME("text/x-clojure", "clojure");
CodeMirror.defineMIME("text/x-clojurescript", "clojure");
CodeMirror.defineMIME("application/edn", "clojure");

});
27 changes: 27 additions & 0 deletions mode/dart/dart.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@
return null;
}
return false;
},

"/": function(stream, state) {
if (!stream.eat("*")) return false
state.tokenize = tokenNestedComment(1)
return state.tokenize(stream, state)
}
}
});
Expand Down Expand Up @@ -121,6 +127,27 @@
return "variable";
}

function tokenNestedComment(depth) {
return function (stream, state) {
var ch
while (ch = stream.next()) {
if (ch == "*" && stream.eat("/")) {
if (depth == 1) {
state.tokenize = null
break
} else {
state.tokenize = tokenNestedComment(depth - 1)
return state.tokenize(stream, state)
}
} else if (ch == "/" && stream.eat("*")) {
state.tokenize = tokenNestedComment(depth + 1)
return state.tokenize(stream, state)
}
}
return "comment"
}
}

CodeMirror.registerHelper("hintWords", "application/dart", keywords.concat(atoms).concat(builtins));

// This is needed to make loading through meta.js work.
Expand Down
85 changes: 69 additions & 16 deletions mode/dylan/dylan.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,16 @@ CodeMirror.defineMode("dylan", function(_config) {
} else if (stream.eat("/")) {
stream.skipToEnd();
return "comment";
} else {
stream.skipTo(" ");
return "operator";
}
stream.backUp(1);
}
// Decimal
else if (/\d/.test(ch)) {
stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/);
return "number";
else if (/[+\-\d\.]/.test(ch)) {
if (stream.match(/^[+-]?[0-9]*\.[0-9]*([esdx][+-]?[0-9]+)?/i) ||
stream.match(/^[+-]?[0-9]+([esdx][+-]?[0-9]+)/i) ||
stream.match(/^[+-]?\d+/)) {
return "number";
}
}
// Hash
else if (ch == "#") {
Expand All @@ -186,7 +187,7 @@ CodeMirror.defineMode("dylan", function(_config) {
ch = stream.peek();
if (ch == '"') {
stream.next();
return chain(stream, state, tokenString('"', "string-2"));
return chain(stream, state, tokenString('"', "string"));
}
// Binary number
else if (ch == "b") {
Expand All @@ -206,11 +207,51 @@ CodeMirror.defineMode("dylan", function(_config) {
stream.eatWhile(/[0-7]/);
return "number";
}
// Token concatenation in macros
else if (ch == '#') {
stream.next();
return "punctuation";
}
// Sequence literals
else if ((ch == '[') || (ch == '(')) {
stream.next();
return "bracket";
// Hash symbol
else {
} else if (stream.match(/f|t|all-keys|include|key|next|rest/i)) {
return "atom";
} else {
stream.eatWhile(/[-a-zA-Z]/);
return "keyword";
return "error";
}
} else if (ch == "~") {
stream.next();
ch = stream.peek();
if (ch == "=") {
stream.next();
ch = stream.peek();
if (ch == "=") {
stream.next();
return "operator";
}
return "operator";
}
return "operator";
} else if (ch == ":") {
stream.next();
ch = stream.peek();
if (ch == "=") {
stream.next();
return "operator";
} else if (ch == ":") {
stream.next();
return "punctuation";
}
} else if ("[](){}".indexOf(ch) != -1) {
stream.next();
return "bracket";
} else if (".,".indexOf(ch) != -1) {
stream.next();
return "punctuation";
} else if (stream.match("end")) {
return "keyword";
}
Expand All @@ -223,6 +264,10 @@ CodeMirror.defineMode("dylan", function(_config) {
return patternStyles[name];
}
}
if (/[+\-*\/^=<>&|]/.test(ch)) {
stream.next();
return "operator";
}
if (stream.match("define")) {
return "def";
} else {
Expand All @@ -240,29 +285,37 @@ CodeMirror.defineMode("dylan", function(_config) {
}

function tokenComment(stream, state) {
var maybeEnd = false,
ch;
var maybeEnd = false, maybeNested = false, nestedCount = 0, ch;
while ((ch = stream.next())) {
if (ch == "/" && maybeEnd) {
state.tokenize = tokenBase;
break;
if (nestedCount > 0) {
nestedCount--;
} else {
state.tokenize = tokenBase;
break;
}
} else if (ch == "*" && maybeNested) {
nestedCount++;
}
maybeEnd = (ch == "*");
maybeNested = (ch == "/");
}
return "comment";
}

function tokenString(quote, style) {
return function(stream, state) {
var next, end = false;
var escaped = false, next, end = false;
while ((next = stream.next()) != null) {
if (next == quote) {
if (next == quote && !escaped) {
end = true;
break;
}
escaped = !escaped && next == "\\";
}
if (end)
if (end || !escaped) {
state.tokenize = tokenBase;
}
return style;
};
}
Expand Down
88 changes: 88 additions & 0 deletions mode/dylan/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function() {
var mode = CodeMirror.getMode({indentUnit: 2}, "dylan");
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }

MT('comments',
'[comment // This is a line comment]',
'[comment /* This is a block comment */]',
'[comment /* This is a multi]',
'[comment line comment]',
'[comment */]',
'[comment /* And this is a /*]',
'[comment /* nested */ comment */]');

MT('unary_operators',
'[operator -][variable a]',
'[operator -] [variable a]',
'[operator ~][variable a]',
'[operator ~] [variable a]');

MT('binary_operators',
'[variable a] [operator +] [variable b]',
'[variable a] [operator -] [variable b]',
'[variable a] [operator *] [variable b]',
'[variable a] [operator /] [variable b]',
'[variable a] [operator ^] [variable b]',
'[variable a] [operator =] [variable b]',
'[variable a] [operator ==] [variable b]',
'[variable a] [operator ~=] [variable b]',
'[variable a] [operator ~==] [variable b]',
'[variable a] [operator <] [variable b]',
'[variable a] [operator <=] [variable b]',
'[variable a] [operator >] [variable b]',
'[variable a] [operator >=] [variable b]',
'[variable a] [operator &] [variable b]',
'[variable a] [operator |] [variable b]',
'[variable a] [operator :=] [variable b]');

MT('integers',
'[number 1]',
'[number 123]',
'[number -123]',
'[number +456]',
'[number #b010]',
'[number #o073]',
'[number #xabcDEF123]');

MT('floats',
'[number .3]',
'[number -1.]',
'[number -2.335]',
'[number +3.78d1]',
'[number 3.78s-1]',
'[number -3.32e+5]');

MT('characters_and_strings',
"[string 'a']",
"[string '\\\\'']",
'[string ""]',
'[string "a"]',
'[string "abc def"]',
'[string "More escaped characters: \\\\\\\\ \\\\a \\\\b \\\\e \\\\f \\\\n \\\\r \\\\t \\\\0 ..."]');

MT('brackets',
'[bracket #[[]]]',
'[bracket #()]',
'[bracket #(][number 1][bracket )]',
'[bracket [[][number 1][punctuation ,] [number 3][bracket ]]]',
'[bracket ()]',
'[bracket {}]',
'[keyword if] [bracket (][variable foo][bracket )]',
'[bracket (][number 1][bracket )]',
'[bracket [[][number 1][bracket ]]]');

MT('hash_words',
'[punctuation ##]',
'[atom #f]', '[atom #F]',
'[atom #t]', '[atom #T]',
'[atom #all-keys]',
'[atom #include]',
'[atom #key]',
'[atom #next]',
'[atom #rest]',
'[string #"foo"]',
'[error #invalid]');
})();
2 changes: 1 addition & 1 deletion mode/haskell-literate/haskell-literate.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@
}, "haskell")

CodeMirror.defineMIME("text/x-literate-haskell", "haskell-literate")
})
});
1 change: 1 addition & 0 deletions mode/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ <h2>Language modes</h2>
<li><a href="php/index.html">PHP</a></li>
<li><a href="pig/index.html">Pig Latin</a></li>
<li><a href="properties/index.html">Properties files</a></li>
<li><a href="protobuf/index.html">ProtoBuf</a></li>
<li><a href="puppet/index.html">Puppet</a></li>
<li><a href="python/index.html">Python</a></li>
<li><a href="q/index.html">Q</a></li>
Expand Down
6 changes: 3 additions & 3 deletions mode/jsx/jsx.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
context.prev && copyContext(context.prev))
}

CodeMirror.defineMode("jsx", function(config) {
CodeMirror.defineMode("jsx", function(config, modeConfig) {
var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false})
var jsMode = CodeMirror.getMode(config, "javascript")
var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript")

function flatXMLIndent(state) {
var tagName = state.tagName
Expand Down Expand Up @@ -144,4 +144,4 @@
}, "xml", "javascript")

CodeMirror.defineMIME("text/jsx", "jsx")
})
});
27 changes: 16 additions & 11 deletions mode/markdown/markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
state.list = null;
} else if (state.indentation > 0) {
state.list = null;
state.listDepth = Math.floor(state.indentation / 4);
} else { // No longer a list
state.list = false;
state.listDepth = 0;
}
}

Expand Down Expand Up @@ -199,7 +197,17 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
}
state.indentation = stream.column() + stream.current().length;
state.list = true;
state.listDepth++;

// While this list item's marker's indentation
// is less than the deepest list item's content's indentation,
// pop the deepest list item indentation off the stack.
while (state.listStack && stream.column() < state.listStack[state.listStack.length - 1]) {
state.listStack.pop();
}

// Add this list item's content's indentation to the stack
state.listStack.push(state.indentation);

if (modeCfg.taskLists && stream.match(taskListRE, false)) {
state.taskList = true;
}
Expand Down Expand Up @@ -321,7 +329,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
}

if (state.list !== false) {
var listMod = (state.listDepth - 1) % 3;
var listMod = (state.listStack.length - 1) % 3;
if (!listMod) {
styles.push(tokenTypes.list1);
} else if (listMod === 1) {
Expand Down Expand Up @@ -697,7 +705,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
hr: false,
taskList: false,
list: false,
listDepth: 0,
listStack: [],
quote: 0,
trailingSpace: 0,
trailingSpaceNewLine: false,
Expand Down Expand Up @@ -732,7 +740,7 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
hr: s.hr,
taskList: s.taskList,
list: s.list,
listDepth: s.listDepth,
listStack: s.listStack.slice(0),
quote: s.quote,
indentedCode: s.indentedCode,
trailingSpace: s.trailingSpace,
Expand Down Expand Up @@ -772,11 +780,8 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {

state.f = state.block;
var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
var difference = Math.floor((indentation - state.indentation) / 4) * 4;
if (difference > 4) difference = 4;
var adjustedIndentation = state.indentation + difference;
state.indentationDiff = adjustedIndentation - state.indentation;
state.indentation = adjustedIndentation;
state.indentationDiff = Math.min(indentation - state.indentation, 4);
state.indentation = state.indentation + state.indentationDiff;
if (indentation > 0) return null;
}
return state.f(stream, state);
Expand Down
12 changes: 12 additions & 0 deletions mode/markdown/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,18 @@
"",
"hello");

MT("listCommonMarkIndentationCode",
"[variable-2 * Code blocks also affect]",
" [variable-3 * The next level starts where the contents start.]",
" [variable-3 * Anything less than that will keep the item on the same level.]",
" [variable-3 * Each list item can indent the first level further and further.]",
" [variable-3 * For the most part, this makes sense while writing a list.]",
" [keyword * This means two items with same indentation can be different levels.]",
" [keyword * Each level has an indent requirement that can change between items.]",
" [keyword * A list item that meets this will be part of the next level.]",
" [variable-3 * Otherwise, it will be part of the level where it does meet this.]",
" [variable-2 * World]");

// Blockquote
MT("blockquote",
"[variable-2 * foo]",
Expand Down
9 changes: 5 additions & 4 deletions mode/meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
{name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]},
{name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]},
{name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]},
{name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj"]},
{name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj", "cljc", "cljx"]},
{name: "ClojureScript", mime: "text/x-clojurescript", mode: "clojure", ext: ["cljs"]},
{name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]},
{name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/},
Expand All @@ -41,6 +41,7 @@
{name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]},
{name: "EBNF", mime: "text/x-ebnf", mode: "ebnf"},
{name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]},
{name: "edn", mime: "application/edn", mode: "clojure", ext: ["edn"]},
{name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]},
{name: "Elm", mime: "text/x-elm", mode: "elm", ext: ["elm"]},
{name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]},
Expand Down Expand Up @@ -84,7 +85,7 @@
{name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"},
{name: "Mathematica", mime: "text/x-mathematica", mode: "mathematica", ext: ["m", "nb"]},
{name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]},
{name: "MUMPS", mime: "text/x-mumps", mode: "mumps"},
{name: "MUMPS", mime: "text/x-mumps", mode: "mumps", ext: ["mps"]},
{name: "MS SQL", mime: "text/x-mssql", mode: "sql"},
{name: "MySQL", mime: "text/x-mysql", mode: "sql"},
{name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx", file: /nginx.*\.conf$/i},
Expand All @@ -102,6 +103,7 @@
{name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]},
{name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]},
{name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]},
{name: "ProtoBuf", mime: "text/x-protobuf", mode: "protobuf", ext: ["proto"]},
{name: "Python", mime: "text/x-python", mode: "python", ext: ["py", "pyw"]},
{name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]},
{name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]},
Expand All @@ -127,7 +129,6 @@
{name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]},
{name: "Squirrel", mime: "text/x-squirrel", mode: "clike", ext: ["nut"]},
{name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]},
{name: "MariaDB", mime: "text/x-mariadb", mode: "sql"},
{name: "sTeX", mime: "text/x-stex", mode: "stex"},
{name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"], alias: ["tex"]},
{name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v"]},
Expand All @@ -137,7 +138,7 @@
{name: "Tiki wiki", mime: "text/tiki", mode: "tiki"},
{name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]},
{name: "Tornado", mime: "text/x-tornado", mode: "tornado"},
{name: "troff", mime: "troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]},
{name: "troff", mime: "text/troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]},
{name: "TTCN", mime: "text/x-ttcn", mode: "ttcn", ext: ["ttcn", "ttcn3", "ttcnpp"]},
{name: "TTCN_CFG", mime: "text/x-ttcn-cfg", mode: "ttcn-cfg", ext: ["cfg"]},
{name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]},
Expand Down
64 changes: 64 additions & 0 deletions mode/protobuf/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<!doctype html>

<title>CodeMirror: ProtoBuf mode</title>
<meta charset="utf-8"/>
<link rel=stylesheet href="../../doc/docs.css">

<link rel="stylesheet" href="../../lib/codemirror.css">
<script src="../../lib/codemirror.js"></script>
<script src="protobuf.js"></script>
<style>.CodeMirror { border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; }</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>

<ul>
<li><a href="../../index.html">Home</a>
<li><a href="../../doc/manual.html">Manual</a>
<li><a href="https://github.com/codemirror/codemirror">Code</a>
</ul>
<ul>
<li><a href="../index.html">Language modes</a>
<li><a class=active href="#">ProtoBuf</a>
</ul>
</div>

<article>
<h2>ProtoBuf mode</h2>
<form><textarea id="code" name="code">
package addressbook;

message Address {
required string street = 1;
required string postCode = 2;
}

message PhoneNumber {
required string number = 1;
}

message Person {
optional int32 id = 1;
required string name = 2;
required string surname = 3;
optional Address address = 4;
repeated PhoneNumber phoneNumbers = 5;
optional uint32 age = 6;
repeated uint32 favouriteNumbers = 7;
optional string license = 8;
enum Gender {
MALE = 0;
FEMALE = 1;
}
optional Gender gender = 9;
optional fixed64 lastUpdate = 10;
required bool deleted = 11 [default = false];
}

</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
</script>

<p><strong>MIME types defined:</strong> <code>text/x-protobuf</code>.</p>

</article>
68 changes: 68 additions & 0 deletions mode/protobuf/protobuf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// 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";

function wordRegexp(words) {
return new RegExp("^((" + words.join(")|(") + "))\\b", "i");
};

var keywordArray = [
"package", "message", "import", "syntax",
"required", "optional", "repeated", "reserved", "default", "extensions", "packed",
"bool", "bytes", "double", "enum", "float", "string",
"int32", "int64", "uint32", "uint64", "sint32", "sint64", "fixed32", "fixed64", "sfixed32", "sfixed64"
];
var keywords = wordRegexp(keywordArray);

CodeMirror.registerHelper("hintWords", "protobuf", keywordArray);

var identifiers = new RegExp("^[_A-Za-z\xa1-\uffff][_A-Za-z0-9\xa1-\uffff]*");

function tokenBase(stream) {
// whitespaces
if (stream.eatSpace()) return null;

// Handle one line Comments
if (stream.match("//")) {
stream.skipToEnd();
return "comment";
}

// Handle Number Literals
if (stream.match(/^[0-9\.+-]/, false)) {
if (stream.match(/^[+-]?0x[0-9a-fA-F]+/))
return "number";
if (stream.match(/^[+-]?\d*\.\d+([EeDd][+-]?\d+)?/))
return "number";
if (stream.match(/^[+-]?\d+([EeDd][+-]?\d+)?/))
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(identifiers)) { return "variable"; } ;

// Handle non-detected items
stream.next();
return null;
};

CodeMirror.defineMode("protobuf", function() {
return {token: tokenBase};
});

CodeMirror.defineMIME("text/x-protobuf", "protobuf");
});
2 changes: 2 additions & 0 deletions mode/r/r.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
})(function(CodeMirror) {
"use strict";

CodeMirror.registerHelper("wordChars", "r", /[\w.]/);

CodeMirror.defineMode("r", function(config) {
function wordObj(str) {
var words = str.split(" "), res = {};
Expand Down
2 changes: 1 addition & 1 deletion mode/swift/swift.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,4 @@
})

CodeMirror.defineMIME("text/x-swift","swift")
})
});
32 changes: 12 additions & 20 deletions mode/tcl/tcl.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,42 +42,34 @@ CodeMirror.defineMode("tcl", function() {
var beforeParams = state.beforeParams;
state.beforeParams = false;
var ch = stream.next();
if ((ch == '"' || ch == "'") && state.inParams)
if ((ch == '"' || ch == "'") && state.inParams) {
return chain(stream, state, tokenString(ch));
else if (/[\[\]{}\(\),;\.]/.test(ch)) {
} else if (/[\[\]{}\(\),;\.]/.test(ch)) {
if (ch == "(" && beforeParams) state.inParams = true;
else if (ch == ")") state.inParams = false;
return null;
}
else if (/\d/.test(ch)) {
} else if (/\d/.test(ch)) {
stream.eatWhile(/[\w\.]/);
return "number";
}
else if (ch == "#" && stream.eat("*")) {
return chain(stream, state, tokenComment);
}
else if (ch == "#" && stream.match(/ *\[ *\[/)) {
return chain(stream, state, tokenUnparsed);
}
else if (ch == "#" && stream.eat("#")) {
} else if (ch == "#") {
if (stream.eat("*"))
return chain(stream, state, tokenComment);
if (ch == "#" && stream.match(/ *\[ *\[/))
return chain(stream, state, tokenUnparsed);
stream.skipToEnd();
return "comment";
}
else if (ch == '"') {
} else if (ch == '"') {
stream.skipTo(/"/);
return "comment";
}
else if (ch == "$") {
} else if (ch == "$") {
stream.eatWhile(/[$_a-z0-9A-Z\.{:]/);
stream.eatWhile(/}/);
state.beforeParams = true;
return "builtin";
}
else if (isOperatorChar.test(ch)) {
} else if (isOperatorChar.test(ch)) {
stream.eatWhile(isOperatorChar);
return "comment";
}
else {
} else {
stream.eatWhile(/[\w\$_{}\xa1-\uffff]/);
var word = stream.current().toLowerCase();
if (keywords && keywords.propertyIsEnumerable(word))
Expand Down
4 changes: 3 additions & 1 deletion mode/troff/troff.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ CodeMirror.defineMode('troff', function() {
};
});

CodeMirror.defineMIME('troff', 'troff');
CodeMirror.defineMIME('text/troff', 'troff');
CodeMirror.defineMIME('text/x-troff', 'troff');
CodeMirror.defineMIME('application/x-troff', 'troff');

});
15 changes: 12 additions & 3 deletions mode/twig/twig.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
mod(require("../../lib/codemirror"), require("../../addon/mode/multiplex"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
define(["../../lib/codemirror", "../../addon/mode/multiplex"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("twig", function() {
CodeMirror.defineMode("twig:inner", function() {
var keywords = ["and", "as", "autoescape", "endautoescape", "block", "do", "endblock", "else", "elseif", "extends", "for", "endfor", "embed", "endembed", "filter", "endfilter", "flush", "from", "if", "endif", "in", "is", "include", "import", "not", "or", "set", "spaceless", "endspaceless", "with", "endwith", "trans", "endtrans", "blocktrans", "endblocktrans", "macro", "endmacro", "use", "verbatim", "endverbatim"],
operator = /^[+\-*&%=<>!?|~^]/,
sign = /^[:\[\(\{]/,
Expand Down Expand Up @@ -128,5 +128,14 @@
};
});

CodeMirror.defineMode("twig", function(config, parserConfig) {
var twigInner = CodeMirror.getMode(config, "twig:inner");
if (!parserConfig || !parserConfig.base) return twigInner;
return CodeMirror.multiplexingMode(
CodeMirror.getMode(config, parserConfig.base), {
open: /\{[{#%]/, close: /[}#%]\}/, mode: twigInner, parseDelimiters: true
}
);
});
CodeMirror.defineMIME("text/x-twig", "twig");
});
2 changes: 2 additions & 0 deletions mode/velocity/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ <h2>Velocity mode</h2>

$someObject("This plus $something in the middle").method(7567).property

#set($something = "Parseable string with '$quotes'!")

#macro( tablerows $color $somelist )
#foreach( $something in $somelist )
<tr><td bgcolor=$color>$something</td></tr>
Expand Down
2 changes: 1 addition & 1 deletion mode/velocity/velocity.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ CodeMirror.defineMode("velocity", function() {
state.beforeParams = false;
var ch = stream.next();
// start of unparsed string?
if ((ch == "'") && state.inParams) {
if ((ch == "'") && !state.inString && state.inParams) {
state.lastTokenWasBuiltin = false;
return chain(stream, state, tokenString(ch));
}
Expand Down
2 changes: 1 addition & 1 deletion mode/yaml-frontmatter/yaml-frontmatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,4 @@
}
}
})
})
});
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codemirror",
"version":"5.12.0",
"version":"5.13.0",
"main": "lib/codemirror.js",
"description": "In-browser code editing made bearable",
"license": "MIT",
Expand Down
2 changes: 2 additions & 0 deletions test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<script src="../keymap/vim.js"></script>
<script src="../mode/rust/rust.js"></script>
<script src="../mode/mscgen/mscgen.js"></script>
<script src="../mode/dylan/dylan.js"></script>

<style type="text/css">
.ok {color: #090;}
Expand Down Expand Up @@ -123,6 +124,7 @@ <h2>Test Suite</h2>
<script src="../mode/mscgen/mscgen_test.js"></script>
<script src="../mode/mscgen/xu_test.js"></script>
<script src="../mode/mscgen/msgenny_test.js"></script>
<script src="../mode/dylan/test.js"></script>
<script src="../addon/mode/multiplex_test.js"></script>
<script src="emacs_test.js"></script>
<script src="sql-hint-test.js"></script>
Expand Down
7 changes: 7 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,13 @@ testCM("markClearBetween", function(cm) {
eq(cm.findMarksAt(Pos(1, 1)).length, 0);
});

testCM("findMarksMiddle", function(cm) {
var mark = cm.markText(Pos(1, 1), Pos(3, 1));
var found = cm.findMarks(Pos(2, 1), Pos(2, 2));
eq(found.length, 1);
eq(found[0], mark);
}, {value: "line 0\nline 1\nline 2\nline 3"});

testCM("deleteSpanCollapsedInclusiveLeft", function(cm) {
var from = Pos(1, 0), to = Pos(1, 1);
var m = cm.markText(from, to, {collapsed: true, inclusiveLeft: true});
Expand Down
30 changes: 22 additions & 8 deletions test/vim_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -634,11 +634,11 @@ testVim('dj_end_of_document', function(cm, vim, helpers) {
var curStart = makeCursor(0, 3);
cm.setCursor(curStart);
helpers.doKeys('d', 'j');
eq(' word1 ', cm.getValue());
eq('', cm.getValue());
var register = helpers.getRegisterController().getRegister();
eq('', register.toString());
is(!register.linewise);
helpers.assertCursorAt(0, 3);
eq(' word1 \n', register.toString());
is(register.linewise);
helpers.assertCursorAt(0, 0);
}, { value: ' word1 ' });
testVim('dk', function(cm, vim, helpers) {
var curStart = makeCursor(1, 3);
Expand All @@ -654,11 +654,11 @@ testVim('dk_start_of_document', function(cm, vim, helpers) {
var curStart = makeCursor(0, 3);
cm.setCursor(curStart);
helpers.doKeys('d', 'k');
eq(' word1 ', cm.getValue());
eq('', cm.getValue());
var register = helpers.getRegisterController().getRegister();
eq('', register.toString());
is(!register.linewise);
helpers.assertCursorAt(0, 3);
eq(' word1 \n', register.toString());
is(register.linewise);
helpers.assertCursorAt(0, 0);
}, { value: ' word1 ' });
testVim('dw_space', function(cm, vim, helpers) {
var curStart = makeCursor(0, 0);
Expand Down Expand Up @@ -1045,6 +1045,20 @@ testVim('D_visual_block', function(cm, vim, helpers) {
eq('1\n5\na', cm.getValue());
}, {value: '1234\n5678\nabcdefg'});

testVim('s_visual_block', function(cm, vim, helpers) {
cm.setCursor(0, 1);
helpers.doKeys('<C-v>', '2', 'j', 'l', 'l', 'l', 's');
var replacement = fillArray('hello{', 3);
cm.replaceSelections(replacement);
eq('1hello{\n5hello{\nahello{fg\n', cm.getValue());
helpers.doKeys('<Esc>');
cm.setCursor(2, 3);
helpers.doKeys('<C-v>', '1', 'k', 'h', 'S');
replacement = fillArray('world', 1);
cm.replaceSelections(replacement);
eq('1hello{\n world\n', cm.getValue());
}, {value: '1234\n5678\nabcdefg\n'});

// 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
Expand Down
3 changes: 1 addition & 2 deletions theme/night.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
.cm-s-night .CodeMirror-linenumber { color: #f8f8f8; }
.cm-s-night .CodeMirror-cursor { border-left: 1px solid white; }

.cm-s-night span.cm-comment { color: #6900a1; }
.cm-s-night span.cm-comment { color: #8900d1; }
.cm-s-night span.cm-atom { color: #845dc4; }
.cm-s-night span.cm-number, .cm-s-night span.cm-attribute { color: #ffd500; }
.cm-s-night span.cm-keyword { color: #599eff; }
Expand All @@ -19,7 +19,6 @@
.cm-s-night span.cm-variable-2, .cm-s-night span.cm-tag { color: #99b2ff; }
.cm-s-night span.cm-variable-3, .cm-s-night span.cm-def { color: white; }
.cm-s-night span.cm-bracket { color: #8da6ce; }
.cm-s-night span.cm-comment { color: #6900a1; }
.cm-s-night span.cm-builtin, .cm-s-night span.cm-special { color: #ff9e59; }
.cm-s-night span.cm-link { color: #845dc4; }
.cm-s-night span.cm-error { color: #9d1e15; }
Expand Down