102 changes: 0 additions & 102 deletions addon/hint/python-hint.js

This file was deleted.

2 changes: 1 addition & 1 deletion addon/hint/show-hint.js
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@
}
}
}
var overlapX = box.left - winW;
var overlapX = box.right - winW;
if (overlapX > 0) {
if (box.right - box.left > winW) {
hints.style.width = (winW - 5) + "px";
Expand Down
11 changes: 7 additions & 4 deletions addon/hint/sql-hint.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@
}
}

function nameCompletion(result, editor) {
var cur = editor.getCursor();
var token = editor.getTokenAt(cur);
function nameCompletion(cur, token, result, editor) {
var useBacktick = (token.string.charAt(0) == "`");
var string = token.string.substr(1);
var prevToken = editor.getTokenAt(Pos(cur.line, token.start));
Expand Down Expand Up @@ -173,6 +171,11 @@
var cur = editor.getCursor();
var result = [];
var token = editor.getTokenAt(cur), start, end, search;
if (token.end > cur.ch) {
token.end = cur.ch;
token.string = token.string.slice(0, cur.ch - token.start);
}

if (token.string.match(/^[.`\w@]\w*$/)) {
search = token.string;
start = token.start;
Expand All @@ -182,7 +185,7 @@
search = "";
}
if (search.charAt(0) == "." || search.charAt(0) == "`") {
nameCompletion(result, editor);
nameCompletion(cur, token, result, editor);
} else {
addMatches(result, search, tables, function(w) {return w;});
addMatches(result, search, defaultTable, function(w) {return w;});
Expand Down
7 changes: 3 additions & 4 deletions addon/hint/xml-hint.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@
var quote = (options && options.quoteChar) || '"';
if (!tags) return;
var cur = cm.getCursor(), token = cm.getTokenAt(cur);
if (/^<\/?$/.test(token.string) && token.end == cur.ch) {
var nextToken = cm.getTokenAt(Pos(cur.line, cur.ch + 1));
if (nextToken.start == cur.ch && /\btag\b/.test(nextToken.type))
token = nextToken;
if (token.end > cur.ch) {
token.end = cur.ch;
token.string = token.string.slice(0, cur.ch - token.start);
}
var inner = CodeMirror.innerMode(cm.getMode(), token.state);
if (inner.mode.name != "xml") return;
Expand Down
14 changes: 14 additions & 0 deletions addon/merge/merge.css
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,17 @@
.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; }

.CodeMirror-merge-collapsed-widget:before {
content: "(...)";
}
.CodeMirror-merge-collapsed-widget {
cursor: pointer;
color: #88b;
background: #eef;
border: 1px solid #ddf;
font-size: 90%;
padding: 0 3px;
border-radius: 4px;
}
.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; }
233 changes: 170 additions & 63 deletions addon/merge/merge.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
insert: "CodeMirror-merge-r-inserted",
del: "CodeMirror-merge-r-deleted",
connect: "CodeMirror-merge-r-connect"};
if (mv.options.connect == "align")
this.aligners = [];
}

DiffView.prototype = {
Expand Down Expand Up @@ -81,7 +83,7 @@
updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes);
updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes);
}
drawConnectors(dv);
makeConnections(dv);
}
function set(slow) {
clearTimeout(debounceChange);
Expand All @@ -108,10 +110,10 @@

function registerScroll(dv) {
dv.edit.on("scroll", function() {
syncScroll(dv, DIFF_INSERT) && drawConnectors(dv);
syncScroll(dv, DIFF_INSERT) && makeConnections(dv);
});
dv.orig.on("scroll", function() {
syncScroll(dv, DIFF_DELETE) && drawConnectors(dv);
syncScroll(dv, DIFF_DELETE) && makeConnections(dv);
});
}

Expand All @@ -126,24 +128,29 @@
// (to prevent feedback loops)
if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 50 > now) return false;

var sInfo = editor.getScrollInfo(), halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen;
var mid = editor.lineAtHeight(midY, "local");
var around = chunkBoundariesAround(dv.diff, mid, type == DIFF_INSERT);
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);
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);
var sInfo = editor.getScrollInfo();
if (dv.mv.options.connect == "align") {
targetPos = sInfo.top;
} else {
var halfScreen = .5 * sInfo.clientHeight, midY = sInfo.top + halfScreen;
var mid = editor.lineAtHeight(midY, "local");
var around = chunkBoundariesAround(dv.diff, mid, type == DIFF_INSERT);
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);
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(sInfo.left, targetPos);
Expand All @@ -161,7 +168,7 @@

function setScrollLock(dv, val, action) {
dv.lockScroll = val;
if (val && action != false) syncScroll(dv, DIFF_INSERT) && drawConnectors(dv);
if (val && action != false) syncScroll(dv, DIFF_INSERT) && makeConnections(dv);
dv.lockButton.innerHTML = val ? "\u21db\u21da" : "\u21db&nbsp;&nbsp;\u21da";
}

Expand Down Expand Up @@ -249,55 +256,103 @@

// Updating the gap between editor and original

function drawConnectors(dv) {
function makeConnections(dv) {
if (!dv.showDifferences) return;

var align = dv.mv.options.connect == "align";
if (align) {
if (!dv.orig.curOp) return dv.orig.operation(function() {
makeConnections(dv);
});
for (var i = 0; i < dv.aligners.length; i++)
dv.aligners[i].clear();
dv.aligners.length = 0;
var extraSpaceAbove = {edit: 0, orig: 0};
}

if (dv.svg) {
clear(dv.svg);
var w = dv.gap.offsetWidth;
attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight);
}
if (dv.copyButtons) clear(dv.copyButtons);

var flip = dv.type == "left";
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)
return;
var topLpx = dv.orig.heightAtLine(topOrig, "local") - sTopOrig, top = topLpx;
if (dv.svg) {
var topRpx = dv.edit.heightAtLine(topEdit, "local") - sTopEdit;
if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; }
var botLpx = dv.orig.heightAtLine(botOrig, "local") - sTopOrig;
var botRpx = dv.edit.heightAtLine(botEdit, "local") - sTopEdit;
if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; }
var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx;
var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx;
attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")),
"d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z",
"class", dv.classes.connect);
}
if (dv.copyButtons) {
var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc",
"CodeMirror-merge-copy"));
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";
}
if (topEdit <= vpEdit.to && botEdit >= vpEdit.from &&
topOrig <= vpOrig.to && botOrig >= vpOrig.from)
drawConnectorsForChunk(dv, topOrig, botOrig, topEdit, botEdit, sTopOrig, sTopEdit, w);
if (align && (topEdit <= vpEdit.to || topOrig <= vpOrig.to)) {
var above = (botEdit < vpEdit.from && botOrig < vpOrig.from);
alignChunks(dv, topOrig, botOrig, topEdit, botEdit, above && extraSpaceAbove);
}
});
if (align) {
if (extraSpaceAbove.edit)
dv.aligners.push(padBelow(dv.edit, 0, extraSpaceAbove.edit));
if (extraSpaceAbove.orig)
dv.aligners.push(padBelow(dv.orig, 0, extraSpaceAbove.orig));
}
}

function drawConnectorsForChunk(dv, topOrig, botOrig, topEdit, botEdit, sTopOrig, sTopEdit, w) {
var flip = dv.type == "left";
var top = dv.orig.heightAtLine(topOrig, "local") - sTopOrig;
if (dv.svg) {
var topLpx = top;
var topRpx = dv.edit.heightAtLine(topEdit, "local") - sTopEdit;
if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; }
var botLpx = dv.orig.heightAtLine(botOrig, "local") - sTopOrig;
var botRpx = dv.edit.heightAtLine(botEdit, "local") - sTopEdit;
if (flip) { var tmp = botLpx; botLpx = botRpx; botRpx = tmp; }
var curveTop = " C " + w/2 + " " + topRpx + " " + w/2 + " " + topLpx + " " + (w + 2) + " " + topLpx;
var curveBot = " C " + w/2 + " " + botLpx + " " + w/2 + " " + botRpx + " -1 " + botRpx;
attrs(dv.svg.appendChild(document.createElementNS(svgNS, "path")),
"d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z",
"class", dv.classes.connect);
}
if (dv.copyButtons) {
var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc",
"CodeMirror-merge-copy"));
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 alignChunks(dv, topOrig, botOrig, topEdit, botEdit, aboveViewport) {
var topOrigPx = dv.orig.heightAtLine(topOrig, "local");
var botOrigPx = dv.orig.heightAtLine(botOrig, "local");
var topEditPx = dv.edit.heightAtLine(topEdit, "local");
var botEditPx = dv.edit.heightAtLine(botEdit, "local");
var origH = botOrigPx -topOrigPx, editH = botEditPx - topEditPx;
var diff = editH - origH;
if (diff > 1) {
if (aboveViewport) aboveViewport.orig += diff;
else dv.aligners.push(padBelow(dv.orig, botOrig - 1, diff));
} else if (diff < -1) {
if (aboveViewport) aboveViewport.edit -= diff;
else dv.aligners.push(padBelow(dv.edit, botEdit - 1, -diff));
}
return 0;
}

function padBelow(cm, line, size) {
var elt = document.createElement("div");
elt.style.height = size + "px"; elt.style.minWidth = "1px";
return cm.addLineWidget(line, elt, {height: size});
}

function copyChunk(dv, to, from, chunk) {
Expand All @@ -313,6 +368,13 @@

this.options = options;
var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight;
if (origLeft && origRight) {
if (options.connect == "align")
throw new Error("connect: \"align\" is not supported for three-way merge views");
if (options.collapseIdentical)
throw new Error("collapseIdentical option is not supported for three-way merge views");
}

var hasLeft = origLeft != null, hasRight = origRight != null;
var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0);
var wrap = [], left = this.left = null, right = this.right = null;
Expand Down Expand Up @@ -344,9 +406,12 @@
if (left) left.init(leftPane, origLeft, options);
if (right) right.init(rightPane, origRight, options);

if (options.collapseIdentical)
collapseIdenticalStretches(left || right, options.collapseIdentical);

var onResize = function() {
if (left) drawConnectors(left);
if (right) drawConnectors(right);
if (left) makeConnections(left);
if (right) makeConnections(right);
};
CodeMirror.on(window, "resize", onResize);
var resizeInterval = setInterval(function() {
Expand Down Expand Up @@ -374,10 +439,12 @@
});
gapElts.unshift(dv.copyButtons);
}
var svg = document.createElementNS && document.createElementNS(svgNS, "svg");
if (svg && !svg.createSVGRect) svg = null;
dv.svg = svg;
if (svg) gapElts.push(svg);
if (dv.mv.options.connect != "align") {
var svg = document.createElementNS && document.createElementNS(svgNS, "svg");
if (svg && !svg.createSVGRect) svg = null;
dv.svg = svg;
if (svg) gapElts.push(svg);
}

return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap");
}
Expand Down Expand Up @@ -489,6 +556,46 @@
return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}};
}

function collapseSingle(cm, from, to) {
cm.addLineClass(from, "wrap", "CodeMirror-merge-collapsed-line");
var widget = document.createElement("span");
widget.className = "CodeMirror-merge-collapsed-widget";
widget.title = "Identical text collapsed. Click to expand.";
var mark = cm.markText(Pos(from, 0), Pos(to - 1), {
inclusiveLeft: true,
inclusiveRight: true,
replacedWith: widget,
clearOnEnter: true
});
function clear() {
mark.clear();
cm.removeLineClass(from, "wrap", "CodeMirror-merge-collapsed-line");
}
widget.addEventListener("click", clear);
return {mark: mark, clear: clear};
}

function collapseStretch(dv, origStart, editStart, size) {
var mOrig = collapseSingle(dv.orig, origStart, origStart + size);
var mEdit = collapseSingle(dv.edit, editStart, editStart + size);
mOrig.mark.on("clear", function() { mEdit.clear(); });
mEdit.mark.on("clear", function() { mOrig.clear(); });
}

function collapseIdenticalStretches(dv, margin) {
if (typeof margin != "number") margin = 2;
var lastOrig = dv.orig.firstLine(), lastEdit = dv.edit.firstLine();
iterateChunks(dv.diff, function(topOrig, botOrig, _topEdit, botEdit) {
var identicalSize = topOrig - margin - lastOrig;
if (identicalSize > margin)
collapseStretch(dv, lastOrig, lastEdit, identicalSize);
lastOrig = botOrig + margin; lastEdit = botEdit + margin;
});
var bottomSize = dv.orig.lastLine() + 1 - lastOrig;
if (bottomSize > margin)
collapseStretch(dv, lastOrig, lastEdit, bottomSize);
}

// General utilities

function elt(tag, content, className, style) {
Expand Down
19 changes: 11 additions & 8 deletions addon/mode/simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
})(function(CodeMirror) {
"use strict";

CodeMirror.defineSimpleMode = function(name, states, props) {
CodeMirror.defineSimpleMode = function(name, states) {
CodeMirror.defineMode(name, function(config) {
return CodeMirror.simpleMode(config, states, props);
return CodeMirror.simpleMode(config, states);
});
};

Expand Down Expand Up @@ -194,12 +194,15 @@
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 && m[0]) {
if (rule.data.dedent && rule.data.dedentIfLineStart !== false) pos--;
if (rule.next || rule.push) rules = states[rule.next || rule.push];
textAfter = textAfter.slice(m[0].length);
continue scan;
var rule = rules[i];
if (rule.data.dedent && rule.data.dedentIfLineStart !== false) {
var m = rule.regex.exec(textAfter);
if (m && m[0]) {
pos--;
if (rule.next || rule.push) rules = states[rule.next || rule.push];
textAfter = textAfter.slice(m[0].length);
continue scan;
}
}
}
break;
Expand Down
76 changes: 76 additions & 0 deletions addon/scroll/annotatescrollbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// 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.defineExtension("annotateScrollbar", function(className) {
return new Annotation(this, className);
});

function Annotation(cm, className) {
this.cm = cm;
this.className = className;
this.annotations = [];
this.div = cm.getWrapperElement().appendChild(document.createElement("div"));
this.div.style.cssText = "position: absolute; right: 0; top: 0; z-index: 7; pointer-events: none";
this.computeScale();

var self = this;
cm.on("refresh", this.resizeHandler = function(){
if (self.computeScale()) self.redraw();
});
}

Annotation.prototype.computeScale = function() {
var cm = this.cm;
var hScale = (cm.getWrapperElement().clientHeight - cm.display.barHeight) /
cm.heightAtLine(cm.lastLine() + 1, "local");
if (hScale != this.hScale) {
this.hScale = hScale;
return true;
}
};

Annotation.prototype.update = function(annotations) {
this.annotations = annotations;
this.redraw();
};

Annotation.prototype.redraw = function() {
var cm = this.cm, hScale = this.hScale;
if (!cm.display.barWidth) return;

var frag = document.createDocumentFragment(), anns = this.annotations;
for (var i = 0, nextTop; i < anns.length; i++) {
var ann = anns[i];
var top = nextTop || cm.charCoords(ann.from, "local").top * hScale;
var bottom = cm.charCoords(ann.to, "local").bottom * hScale;
while (i < anns.length - 1) {
nextTop = cm.charCoords(anns[i + 1].from, "local").top * hScale;
if (nextTop > bottom + .9) break;
ann = anns[++i];
bottom = cm.charCoords(ann.to, "local").bottom * hScale;
}
var height = Math.max(bottom - top, 3);

var elt = frag.appendChild(document.createElement("div"));
elt.style.cssText = "position: absolute; right: 0px; width: " + Math.max(cm.display.barWidth - 1, 2) + "px; top: " + top + "px; height: " + height + "px";
elt.className = this.className;
}
this.div.textContent = "";
this.div.appendChild(frag);
};

Annotation.prototype.clear = function() {
this.cm.off("refresh", this.resizeHandler);
this.div.parentNode.removeChild(this.div);
};
});
66 changes: 66 additions & 0 deletions addon/scroll/simplescrollbars.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
.CodeMirror-simplescroll-horizontal div, .CodeMirror-simplescroll-vertical div {
position: absolute;
background: #ccc;
-moz-box-sizing: border-box;
box-sizing: border-box;
border: 1px solid #bbb;
border-radius: 2px;
}

.CodeMirror-simplescroll-horizontal, .CodeMirror-simplescroll-vertical {
position: absolute;
z-index: 6;
background: #eee;
}

.CodeMirror-simplescroll-horizontal {
bottom: 0; left: 0;
height: 8px;
}
.CodeMirror-simplescroll-horizontal div {
bottom: 0;
height: 100%;
}

.CodeMirror-simplescroll-vertical {
right: 0; top: 0;
width: 8px;
}
.CodeMirror-simplescroll-vertical div {
right: 0;
width: 100%;
}


.CodeMirror-overlayscroll .CodeMirror-scrollbar-filler, .CodeMirror-overlayscroll .CodeMirror-gutter-filler {
display: none;
}

.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {
position: absolute;
background: #bcd;
border-radius: 3px;
}

.CodeMirror-overlayscroll-horizontal, .CodeMirror-overlayscroll-vertical {
position: absolute;
z-index: 6;
}

.CodeMirror-overlayscroll-horizontal {
bottom: 0; left: 0;
height: 6px;
}
.CodeMirror-overlayscroll-horizontal div {
bottom: 0;
height: 100%;
}

.CodeMirror-overlayscroll-vertical {
right: 0; top: 0;
width: 6px;
}
.CodeMirror-overlayscroll-vertical div {
right: 0;
width: 100%;
}
139 changes: 139 additions & 0 deletions addon/scroll/simplescrollbars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// 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 Bar(cls, orientation, scroll) {
this.orientation = orientation;
this.scroll = scroll;
this.screen = this.total = this.size = 1;
this.pos = 0;

this.node = document.createElement("div");
this.node.className = cls + "-" + orientation;
this.inner = this.node.appendChild(document.createElement("div"));

var self = this;
CodeMirror.on(this.inner, "mousedown", function(e) {
if (e.which != 1) return;
CodeMirror.e_preventDefault(e);
var axis = self.orientation == "horizontal" ? "pageX" : "pageY";
var start = e[axis], startpos = self.pos;
function move(e) {
if (e.which != 1) {
CodeMirror.off(document, "mousemove", move);
return;
}
self.moveTo(startpos + (e[axis] - start) * (self.total / self.size));
}
CodeMirror.on(document, "mousemove", move);
});

CodeMirror.on(this.node, "click", function(e) {
CodeMirror.e_preventDefault(e);
var innerBox = self.inner.getBoundingClientRect(), where;
if (self.orientation == "horizontal")
where = e.clientX < innerBox.left ? -1 : e.clientX > innerBox.right ? 1 : 0;
else
where = e.clientY < innerBox.top ? -1 : e.clientY > innerBox.bottom ? 1 : 0;
self.moveTo(self.pos + where * self.screen);
});

function onWheel(e) {
var moved = CodeMirror.wheelEventPixels(e)[self.orientation == "horizontal" ? "x" : "y"];
var oldPos = self.pos;
self.moveTo(self.pos + moved);
if (self.pos != oldPos) CodeMirror.e_preventDefault(e);
}
CodeMirror.on(this.node, "mousewheel", onWheel);
CodeMirror.on(this.node, "DOMMouseScroll", onWheel);
}

Bar.prototype.moveTo = function(pos, update) {
if (pos < 0) pos = 0;
if (pos > this.total - this.screen) pos = this.total - this.screen;
if (pos == this.pos) return;
this.pos = pos;
this.inner.style[this.orientation == "horizontal" ? "left" : "top"] =
(pos * (this.size / this.total)) + "px";
if (update !== false) this.scroll(pos, this.orientation);
};

Bar.prototype.update = function(scrollSize, clientSize, barSize) {
this.screen = clientSize;
this.total = scrollSize;
this.size = barSize;

// FIXME clip to min size?
this.inner.style[this.orientation == "horizontal" ? "width" : "height"] =
this.screen * (this.size / this.total) + "px";
this.inner.style[this.orientation == "horizontal" ? "left" : "top"] =
this.pos * (this.size / this.total) + "px";
};

function SimpleScrollbars(cls, place, scroll) {
this.addClass = cls;
this.horiz = new Bar(cls, "horizontal", scroll);
place(this.horiz.node);
this.vert = new Bar(cls, "vertical", scroll);
place(this.vert.node);
this.width = null;
}

SimpleScrollbars.prototype.update = function(measure) {
if (this.width == null) {
var style = window.getComputedStyle ? window.getComputedStyle(this.horiz.node) : this.horiz.node.currentStyle;
if (style) this.width = parseInt(style.height);
}
var width = this.width || 0;

var needsH = measure.scrollWidth > measure.clientWidth + 1;
var needsV = measure.scrollHeight > measure.clientHeight + 1;
this.vert.node.style.display = needsV ? "block" : "none";
this.horiz.node.style.display = needsH ? "block" : "none";

if (needsV) {
this.vert.update(measure.scrollHeight, measure.clientHeight,
measure.viewHeight - (needsH ? width : 0));
this.vert.node.style.display = "block";
this.vert.node.style.bottom = needsH ? width + "px" : "0";
}
if (needsH) {
this.horiz.update(measure.scrollWidth, measure.clientWidth,
measure.viewWidth - (needsV ? width : 0) - measure.barLeft);
this.horiz.node.style.right = needsV ? width + "px" : "0";
this.horiz.node.style.left = measure.barLeft + "px";
}

return {right: needsV ? width : 0, bottom: needsH ? width : 0};
};

SimpleScrollbars.prototype.setScrollTop = function(pos) {
this.vert.moveTo(pos, false);
};

SimpleScrollbars.prototype.setScrollLeft = function(pos) {
this.horiz.moveTo(pos, false);
};

SimpleScrollbars.prototype.clear = function() {
var parent = this.horiz.node.parentNode;
parent.removeChild(this.horiz.node);
parent.removeChild(this.vert.node);
};

CodeMirror.scrollbarModel.simple = function(place, scroll) {
return new SimpleScrollbars("CodeMirror-simplescroll", place, scroll);
};
CodeMirror.scrollbarModel.overlay = function(place, scroll) {
return new SimpleScrollbars("CodeMirror-overlayscroll", place, scroll);
};
});
8 changes: 8 additions & 0 deletions addon/search/matchesonscrollbar.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.CodeMirror-search-match {
background: gold;
border-top: 1px solid orange;
border-bottom: 1px solid orange;
-moz-box-sizing: border-box;
box-sizing: border-box;
opacity: .5;
}
90 changes: 90 additions & 0 deletions addon/search/matchesonscrollbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// 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"), require("./searchcursor"), require("../scroll/annotatescrollbar"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, className) {
return new SearchAnnotation(this, query, caseFold, className);
});

function SearchAnnotation(cm, query, caseFold, className) {
this.cm = cm;
this.annotation = cm.annotateScrollbar(className || "CodeMirror-search-match");
this.query = query;
this.caseFold = caseFold;
this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1};
this.matches = [];
this.update = null;

this.findMatches();
this.annotation.update(this.matches);

var self = this;
cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); });
}

var MAX_MATCHES = 1000;

SearchAnnotation.prototype.findMatches = function() {
if (!this.gap) return;
for (var i = 0; i < this.matches.length; i++) {
var match = this.matches[i];
if (match.from.line >= this.gap.to) break;
if (match.to.line >= this.gap.from) this.matches.splice(i--, 1);
}
var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), this.caseFold);
while (cursor.findNext()) {
var match = {from: cursor.from(), to: cursor.to()};
if (match.from.line >= this.gap.to) break;
this.matches.splice(i++, 0, match);
if (this.matches.length > MAX_MATCHES) break;
}
this.gap = null;
};

function offsetLine(line, changeStart, sizeChange) {
if (line <= changeStart) return line;
return Math.max(changeStart, line + sizeChange);
}

SearchAnnotation.prototype.onChange = function(change) {
var startLine = change.from.line;
var endLine = CodeMirror.changeEnd(change).line;
var sizeChange = endLine - change.to.line;
if (this.gap) {
this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line);
this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line);
} else {
this.gap = {from: change.from.line, to: endLine + 1};
}

if (sizeChange) for (var i = 0; i < this.matches.length; i++) {
var match = this.matches[i];
var newFrom = offsetLine(match.from.line, startLine, sizeChange);
if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch);
var newTo = offsetLine(match.to.line, startLine, sizeChange);
if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch);
}
clearTimeout(this.update);
var self = this;
this.update = setTimeout(function() { self.updateAfterChange(); }, 250);
};

SearchAnnotation.prototype.updateAfterChange = function() {
this.findMatches();
this.annotation.update(this.matches);
};

SearchAnnotation.prototype.clear = function() {
this.cm.off("change", this.changeHandler);
this.annotation.clear();
};
});
13 changes: 9 additions & 4 deletions addon/search/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@
function parseQuery(query) {
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
if (isRE) {
query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i");
if (query.test("")) query = /x^/;
} else if (query == "") {
query = /x^/;
try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
catch(e) {} // Not a regular expression after all, do a string search
}
if (typeof query == "string" ? query == "" : query.test(""))
query = /x^/;
return query;
}
var queryDialog =
Expand All @@ -82,6 +82,10 @@
cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
cm.addOverlay(state.overlay);
if (cm.showMatchesOnScrollbar) {
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
}
state.posFrom = state.posTo = cm.getCursor();
findNext(cm, rev);
});
Expand All @@ -103,6 +107,7 @@
if (!state.query) return;
state.query = null;
cm.removeOverlay(state.overlay);
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
});}

var replaceQueryDialog =
Expand Down
8 changes: 5 additions & 3 deletions addon/tern/tern.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@
cm.showHint({hint: this.getHint});
},

showType: function(cm, pos, c) { showType(this, cm, pos, c); },
showType: function(cm, pos, c) { showContextInfo(this, cm, pos, "type", c); },

showDocs: function(cm, pos, c) { showContextInfo(this, cm, pos, "documentation", c); },

updateArgHints: function(cm) { updateArgHints(this, cm); },

Expand Down Expand Up @@ -239,8 +241,8 @@

// Type queries

function showType(ts, cm, pos, c) {
ts.request(cm, "type", function(error, data) {
function showContextInfo(ts, cm, pos, queryName, c) {
ts.request(cm, queryName, function(error, data) {
if (error) return showError(ts, cm, error);
if (ts.options.typeTip) {
var tip = ts.options.typeTip(data);
Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codemirror",
"version":"4.8.0",
"version":"4.9.0",
"main": ["lib/codemirror.js", "lib/codemirror.css"],
"ignore": [
"**/.*",
Expand Down
28 changes: 18 additions & 10 deletions demo/merge.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,41 +41,49 @@ <h2>merge view demo</h2>

<p>The <a href="../doc/manual.html#addon_merge"><code>merge</code></a>
addon provides an interface for displaying and merging diffs,
either <span class=clicky onclick="initUI(2)">two-way</span>
or <span class=clicky onclick="initUI(3)">three-way</span>. The left
(or center) pane is editable, and the differences with the other
pane(s) are <span class=clicky onclick="toggleDifferences()">optionally</span> shown live as you edit it.</p>
either <span class=clicky onclick="panes = 2; initUI()">two-way</span>
or <span class=clicky onclick="panes = 3; initUI()">three-way</span>.
The left (or center) pane is editable, and the differences with the
other pane(s) are <span class=clicky
onclick="toggleDifferences()">optionally</span> shown live as you edit
it. In the two-way configuration, there are also options to pad changed
sections to <span class=clicky onclick="connect = connect ? null :
'align'; initUI()">align</span> them, and to <span class=clicky
onclick="collapse = !collapse; initUI()">collapse</span> unchanged
stretches of text.</p>

<p>This addon depends on
the <a href="https://code.google.com/p/google-diff-match-patch/">google-diff-match-patch</a>
library to compute the diffs.</p>

<script>
var value, orig1, orig2, dv, hilight= true;
function initUI(panes) {
var value, orig1, orig2, dv, panes = 2, highlight = true, connect = null, collapse = false;
function initUI() {
if (value == null) return;
var target = document.getElementById("view");
target.innerHTML = "";
dv = CodeMirror.MergeView(target, {
value: value,
origLeft: panes == 3 ? orig1 : null,
origLeft: panes == 3 && !collapse && !connect ? orig1 : null,
orig: orig2,
lineNumbers: true,
mode: "text/html",
highlightDifferences: hilight
highlightDifferences: highlight,
connect: connect,
collapseIdentical: collapse
});
}

function toggleDifferences() {
dv.setShowDifferences(hilight = !hilight);
dv.setShowDifferences(highlight = !highlight);
}

window.onload = function() {
value = document.documentElement.innerHTML;
orig1 = value.replace(/\.\.\//g, "codemirror/").replace("yellow", "orange");
orig2 = value.replace(/\u003cscript/g, "\u003cscript type=text/javascript ")
.replace("white", "purple;\n font: comic sans;\n text-decoration: underline;\n height: 15em");
initUI(2);
initUI();
};

function mergeViewHeight(mergeView) {
Expand Down
64 changes: 64 additions & 0 deletions demo/panel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<!doctype html>

<title>CodeMirror: Panel Demo</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="../mode/javascript/javascript.js"></script>
<script src="../addon/display/panel.js"></script>
<style type="text/css">
.border {border: 1px solid black; border-bottom: 1px solid black;}
.add { background: orange; padding: 1px 3px; color: white !important; border-radius: 4px; }
.panel {
background-image: linear-gradient(to bottom, #ffffaa, #ffffdd);
padding: 3px 7px;
}
.panel.top { border-bottom: 1px solid #dd6; }
.panel.bottom { border-top: 1px solid #dd6; }
.panel span { cursor: pointer; }
</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 class=active href="#">Panel</a>
</ul>
</div>

<article>
<h2>Panel Demo</h2>
<form><div class="border"><textarea id="code" name="code"></textarea></div></form>

<script id="localscript">var textarea = document.getElementById("code");
var script = document.getElementById("localscript");
textarea.value = (script.textContent ||
script.innerText ||
script.innerHTML);
editor = CodeMirror.fromTextArea(textarea, {
lineNumbers: true
});

function addPanel(where) {
var node = document.createElement("div");
node.className = "panel " + where;
var close = node.appendChild(document.createElement("span"));
close.textContent = "âś– Remove this panel";
var widget = editor.addPanel(node, {position: where});
CodeMirror.on(close, "click", function() { widget.clear(); });
}</script>

<p>The <a href="../doc/manual.html#addon_panel"><code>panel</code></a>
addon allows you to display panels <a class=add
href="javascript:addPanel('top')">above</a> or <a class=add
href="javascript:addPanel('bottom')">below</a> an editor. Click the
links in the previous paragraph to add panels to the editor.</p>

</article>
11 changes: 2 additions & 9 deletions demo/resize.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@
border: 1px solid #eee;
height: auto;
}
.CodeMirror-scroll {
overflow-y: hidden;
overflow-x: auto;
}
</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../doc/logo.png"></a>
Expand All @@ -37,13 +33,10 @@ <h2>Autoresize Demo</h2>
border: 1px solid #eee;
height: auto;
}
.CodeMirror-scroll {
overflow-y: hidden;
overflow-x: auto;
}
</textarea></form>

<p>By setting a few CSS properties, and giving
<p>By setting an editor's <code>height</code> style
to <code>auto</code> and giving
the <a href="../doc/manual.html#option_viewportMargin"><code>viewportMargin</code></a>
a value of <code>Infinity</code>, CodeMirror can be made to
automatically resize to fit its content.</p>
Expand Down
8 changes: 7 additions & 1 deletion demo/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@

<link rel="stylesheet" href="../lib/codemirror.css">
<link rel="stylesheet" href="../addon/dialog/dialog.css">
<link rel="stylesheet" href="../addon/search/matchesonscrollbar.css">
<script src="../lib/codemirror.js"></script>
<script src="../mode/xml/xml.js"></script>
<script src="../addon/dialog/dialog.js"></script>
<script src="../addon/search/searchcursor.js"></script>
<script src="../addon/search/search.js"></script>
<script src="../addon/scroll/annotatescrollbar.js"></script>
<script src="../addon/search/matchesonscrollbar.js"></script>
<style type="text/css">
.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
dt {font-family: monospace; color: #666;}
Expand Down Expand Up @@ -66,7 +69,10 @@ <h2>Search/Replace Demo</h2>
</textarea></form>

<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {mode: "text/html", lineNumbers: true});
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: "text/html",
lineNumbers: true
});
</script>

<p>Demonstration of primitive search/replace functionality. The
Expand Down
82 changes: 82 additions & 0 deletions demo/simplescrollbars.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<!doctype html>

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

<link rel="stylesheet" href="../lib/codemirror.css">
<link rel="stylesheet" href="../addon/scroll/simplescrollbars.css">
<script src="../lib/codemirror.js"></script>
<script src="../mode/markdown/markdown.js"></script>
<script src="../mode/xml/xml.js"></script>
<script src="../addon/scroll/simplescrollbars.js"></script>

<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 class=active href="#">Simple Scrollbar</a>
</ul>
</div>

<article>
<h2>Simple Scrollbar Demo</h2>
<form><textarea id="code" name="code"># Custom Scrollbars

This is a piece of text that creates scrollbars

Lorem ipsum dolor sit amet, turpis nec facilisis neque vestibulum adipiscing, magna nunc est luctus orci a,
aliquam duis ad volutpat nostra. Vestibulum ultricies suspendisse commodo volutpat pede sed. Bibendum odio
dignissim, ad vitae mollis ac sed nibh quis, suspendisse diam, risus quas blandit phasellus luctus nec,
integer nunc vitae posuere scelerisque. Lobortis quam porta conubia nulla. Et nisl ac, imperdiet vitae ac.
Parturient sit. Et vestibulum euismod, rutrum nunc libero mauris purus convallis. Cum id adipiscing et eget
pretium rutrum, ultrices sapien magnis fringilla sit lorem, eu vitae scelerisque ipsum aliquet, magna sed
fusce vel.

Lectus ultricies libero dolor convallis, sed etiam vel hendrerit egestas viverra, at urna mauris, eget
vulputate dolor voluptatem, nulla eget sollicitudin. Sed tincidunt, elit sociis. Mattis mi tortor dui id
sodales mi, maecenas nam fringilla risus turpis mauris praesent, imperdiet maecenas ultrices nonummy tellus
quis est. Scelerisque nec pharetra quis varius fringilla. Varius vestibulum non dictum pharetra, tincidunt in
vestibulum iaculis molestie, id condimentum blandit elit urna magna pulvinar, quam suspendisse pellentesque
donec. Vel amet ad ac. Nec aut viverra, morbi mi neque massa, turpis enim proin. Tellus eu, fermentum velit
est convallis aliquam velit, rutrum in diam lacus, praesent tempor pellentesque dictum semper augue. Felis
explicabo massa amet lectus phasellus dolor. Ut lorem quis arcu neque felis ultricies, senectus vitae
curabitur sed pellentesque et, id sed risus in sed ac accumsan, blandit arcu quam duis nunc.

Sed leo sollicitudin odio vitae, purus sit egestas, justo eros inceptos auctor fermentum lectus. Ligula luctus
turpis, quod massa vitae elementum orci, nullam fringilla elit tortor. Justo ante tempor amet quam posuere
volutpat. Facilisis pede erat ut hac ultrices ipsum, wisi duis sit metus. Dolor vitae est sed sed vitae. Sed
eu ligula, morbi vestibulum nunc nibh velit ut taciti, ligula elit semper sagittis in, auctor arcu vel eget.
Mauris at vitae nec suspendisse et, aenean proin blandit suscipit. Morbi quam, dolor ultricies. Viverra
tempus. Suspendisse sit dapibus, ac fuga aenean, magna nisl nonummy augue posuere, dictum ut fuga velit
parturient augue interdum, mattis sit tellus.

Vehicula commodo tempus curabitur eros, lacinia erat vulputate lorem vel fermentum donec, lectus sed conubia
id pellentesque. Vel senectus donec pede aliquet dolor sit, nec vivamus justo placerat interdum maecenas,
sodales euismod. Quis netus sapien amet, vestibulum quam nec amet lacinia, quis aliquet, tempor vivamus tellus
enim, suscipit quis eleifend. Amet class phasellus orci pretium, risus in nulla. Neque sit ullamcorper,
ultricies platea id nec suspendisse ac. Et elementum. Dictum nam, ut dui fermentum egestas facilisis elit
augue, adipiscing donec ipsum erat nam pellentesque convallis, vestibulum vestibulum risus id nulla ut mauris,
curabitur aute aptent. Ultrices orci wisi dui ipsum praesent, pharetra felis eu quis. Est fringilla etiam,
maxime sem dapibus et eget, mi enim dignissim nec pretium, augue vehicula, volutpat proin. Et occaecati
lobortis viverra, cum in sed, vivamus tellus. Libero at malesuada est vivamus leo tortor.
</textarea></form>

<p>The <a href="../doc/manual.html#addon_simplescrollbars"><code>simplescrollbars</code></a> addon defines two
styles of non-native scrollbars: <a href="javascript:editor.setOption('scrollbarStyle', 'simple')"><code>"simple"</code></a> and <a href="javascript:editor.setOption('scrollbarStyle', 'overlay')"><code>"overlay"</code></a> (click to try), which can be passed to
the <a href="../doc/manual.html#option_scrollbarStyle"><code>scrollbarStyle</code></a> option. These implement
the scrollbar using DOM elements, allowing more control over
its <a href="../addon/scroll/simplescrollbars.css">appearance</a>.</p>

<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
scrollbarStyle: "simple"
});
</script>
</article>
4 changes: 3 additions & 1 deletion demo/tern.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<article>
<h2>Tern Demo</h2>
<form><textarea id="code" name="code">// Use ctrl-space to complete something
// Put the cursor in or after an expression, press ctrl-i to
// Put the cursor in or after an expression, press ctrl-o to
// find its type

var foo = ["array", "of", "strings"];
Expand Down Expand Up @@ -83,6 +83,7 @@ <h2>Tern Demo</h2>

<dl>
<dt>Ctrl-Space</dt><dd>Autocomplete</dd>
<dt>Ctrl-O</dt><dd>Find docs for the expression at the cursor</dd>
<dt>Ctrl-I</dt><dd>Find type at cursor</dd>
<dt>Alt-.</dt><dd>Jump to definition (Alt-, to jump back)</dd>
<dt>Ctrl-Q</dt><dd>Rename variable</dd>
Expand Down Expand Up @@ -114,6 +115,7 @@ <h2>Tern Demo</h2>
editor.setOption("extraKeys", {
"Ctrl-Space": function(cm) { server.complete(cm); },
"Ctrl-I": function(cm) { server.showType(cm); },
"Ctrl-O": function(cm) { server.showDocs(cm); },
"Alt-.": function(cm) { server.jumpToDef(cm); },
"Alt-,": function(cm) { server.jumpBack(cm); },
"Ctrl-Q": function(cm) { server.rename(cm); },
Expand Down
4 changes: 4 additions & 0 deletions demo/theme.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@
<link rel="stylesheet" href="../theme/rubyblue.css">
<link rel="stylesheet" href="../theme/solarized.css">
<link rel="stylesheet" href="../theme/the-matrix.css">
<link rel="stylesheet" href="../theme/tomorrow-night-bright.css">
<link rel="stylesheet" href="../theme/tomorrow-night-eighties.css">
<link rel="stylesheet" href="../theme/twilight.css">
<link rel="stylesheet" href="../theme/vibrant-ink.css">
<link rel="stylesheet" href="../theme/xq-dark.css">
<link rel="stylesheet" href="../theme/xq-light.css">
<link rel="stylesheet" href="../theme/zenburn.css">
<script src="../lib/codemirror.js"></script>
<script src="../mode/javascript/javascript.js"></script>
<script src="../addon/selection/active-line.js"></script>
Expand Down Expand Up @@ -97,11 +99,13 @@ <h2>Theme Demo</h2>
<option>solarized dark</option>
<option>solarized light</option>
<option>the-matrix</option>
<option>tomorrow-night-bright</option>
<option>tomorrow-night-eighties</option>
<option>twilight</option>
<option>vibrant-ink</option>
<option>xq-dark</option>
<option>xq-light</option>
<option>zenburn</option>
</select>
</p>

Expand Down
10 changes: 8 additions & 2 deletions doc/compress.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ <h2>Script compression helper</h2>
<input type="hidden" id="download" name="download" value="codemirror-compressed.js"/>
<p>Version: <select id="version" onchange="setVersion(this);" style="padding: 1px;">
<option value="http://codemirror.net/">HEAD</option>
<option value="http://marijnhaverbeke.nl/git/codemirror?a=blob_plain;hb=4.9.0;f=">4.9</option>
<option value="http://marijnhaverbeke.nl/git/codemirror?a=blob_plain;hb=4.8.0;f=">4.8</option>
<option value="http://marijnhaverbeke.nl/git/codemirror?a=blob_plain;hb=4.7.0;f=">4.7</option>
<option value="http://marijnhaverbeke.nl/git/codemirror?a=blob_plain;hb=4.6.0;f=">4.6</option>
Expand Down Expand Up @@ -105,11 +106,13 @@ <h2>Script compression helper</h2>
<option value="http://codemirror.net/mode/css/css.js">css.js</option>
<option value="http://codemirror.net/mode/cypher/cypher.js">cypher.js</option>
<option value="http://codemirror.net/mode/d/d.js">d.js</option>
<option value="http://codemirror.net/mode/dart/dart.js">dart.js</option>
<option value="http://codemirror.net/mode/diff/diff.js">diff.js</option>
<option value="http://codemirror.net/mode/django/django.js">django.js</option>
<option value="http://codemirror.net/mode/dockerfile/dockerfile.js">dockerfile.js</option>
<option value="http://codemirror.net/mode/dtd/dtd.js">dtd.js</option>
<option value="http://codemirror.net/mode/dylan/dylan.js">dylan.js</option>
<option value="http://codemirror.net/mode/ebnf/ebnf.js">ebnf.js</option>
<option value="http://codemirror.net/mode/ecl/ecl.js">ecl.js</option>
<option value="http://codemirror.net/mode/eiffel/eiffel.js">eiffel.js</option>
<option value="http://codemirror.net/mode/erlang/erlang.js">erlang.js</option>
Expand Down Expand Up @@ -163,8 +166,11 @@ <h2>Script compression helper</h2>
<option value="http://codemirror.net/mode/smalltalk/smalltalk.js">smalltalk.js</option>
<option value="http://codemirror.net/mode/smarty/smarty.js">smarty.js</option>
<option value="http://codemirror.net/mode/smartymixed/smartymixed.js">smartymixed.js</option>
<option value="http://codemirror.net/mode/sql/sql.js">sql.js</option>
<option value="http://codemirror.net/mode/solr/solr.js">solr.js</option>
<option value="http://codemirror.net/mode/soy/soy.js">soy.js</option>
<option value="http://codemirror.net/mode/sparql/sparql.js">sparql.js</option>
<option value="http://codemirror.net/mode/spreadsheet/spreadsheet.js">spreadsheet.js</option>
<option value="http://codemirror.net/mode/sql/sql.js">sql.js</option>
<option value="http://codemirror.net/mode/stex/stex.js">stex.js</option>
<option value="http://codemirror.net/mode/tcl/tcl.js">tcl.js</option>
<option value="http://codemirror.net/mode/textile/textile.js">textile.js</option>
Expand Down Expand Up @@ -215,7 +221,6 @@ <h2>Script compression helper</h2>
<option value="http://codemirror.net/addon/mode/multiplex.js">multiplex.js</option>
<option value="http://codemirror.net/addon/mode/overlay.js">overlay.js</option>
<option value="http://codemirror.net/addon/display/placeholder.js">placeholder.js</option>
<option value="http://codemirror.net/addon/hint/python-hint.js">python-hint.js</option>
<option value="http://codemirror.net/addon/display/rulers.js">rulers.js</option>
<option value="http://codemirror.net/addon/runmode/runmode.js">runmode.js</option>
<option value="http://codemirror.net/addon/runmode/runmode.node.js">runmode.node.js</option>
Expand All @@ -224,6 +229,7 @@ <h2>Script compression helper</h2>
<option value="http://codemirror.net/addon/search/searchcursor.js">searchcursor.js</option>
<option value="http://codemirror.net/addon/hint/show-hint.js">show-hint.js</option>
<option value="http://codemirror.net/addon/mode/simple.js">simple.js</option>
<option value="http://codemirror.net/addon/scroll/simplescrollbars.js">simplescrollbars.js</option>
<option value="http://codemirror.net/addon/hint/sql-hint.js">sql-hint.js</option>
<option value="http://codemirror.net/addon/edit/trailingspace.js">trailingspace.js</option>
<option value="http://codemirror.net/addon/tern/tern.js">tern.js</option>
Expand Down
129 changes: 105 additions & 24 deletions doc/manual.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,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 4.8.0</span>
<span style="color: #888; font-size: 1rem; position: absolute; right: 0; bottom: 0">version 4.9.0</span>
</h2>

<p>CodeMirror is a code-editor component that can be embedded in
Expand Down Expand Up @@ -318,6 +318,14 @@ <h2>Configuration</h2>
horizontally (false) or whether it stays fixed during horizontal
scrolling (true, the default).</dd>

<dt id="option_scrollbarStyle"><code><strong>scrollbarStyle</strong>: string</code></dt>
<dd>Chooses a scrollbar implementation. The default
is <code>"native"</code>, showing native scrollbars. The core
library also provides the <code>"null"</code> style, which
completely hides the
scrollbars. <a href="#addon_simplescrollbars">Addons</a> can
implement additional scrollbar models.</dd>

<dt id="option_coverGutterNextToScrollbar"><code><strong>coverGutterNextToScrollbar</strong>: boolean</code></dt>
<dd>When <a href="#option_fixedGutter"><code>fixedGutter</code></a>
is on, and there is a horizontal scrollbar, by default the
Expand Down Expand Up @@ -998,16 +1006,12 @@ <h2>Customized Styling</h2>
<dd>The outer element of the editor. This should be used for the
editor width, height, borders and positioning. Can also be used
to set styles that should hold for everything inside the editor
(such as font and font size), or to set a background.</dd>

<dt id="class_CodeMirror_scroll"><code><strong>CodeMirror-scroll</strong></code></dt>
<dd>Whether the editor scrolls (<code>overflow: auto</code> +
fixed height). By default, it does. Setting
the <code>CodeMirror</code> class to have <code>height:
auto</code> and giving this class <code>overflow-x: auto;
overflow-y: hidden;</code> will cause the editor
to <a href="../demo/resize.html">resize to fit its
content</a>.</dd>
(such as font and font size), or to set a background. Setting
this class' <code>height</code> style to <code>auto</code> will
make the editor <a href="../demo/resize.html">resize to fit its
content</a> (it is recommended to also set
the <a href="#option_viewportMargin"><code>viewportMargin</code>
option</a> to <code>Infinity</code> when doing this.</dd>

<dt id="class_CodeMirror_focused"><code><strong>CodeMirror-focused</strong></code></dt>
<dd>Whenever the editor is focused, the top element gets this
Expand Down Expand Up @@ -1561,6 +1565,8 @@ <h3 id="api_marker">Text-marking methods</h3>
is part of the marker.</dd>
<dt id="mark_endStyle"><code><strong>endStyle</strong>: string</code></dt><dd>Equivalent
to <code>startStyle</code>, but for the rightmost span.</dd>
<dt id="mark_css"><code><strong>css</strong>: string</code></dt>
<dd>A string of CSS to be applied to the covered text. For example <code>"color: #fe3"</code>.</dd>
<dt id="mark_title"><code><strong>title</strong>:
string</code></dt><dd>When given, will give the nodes created
for this span a HTML <code>title</code> attribute with the
Expand Down Expand Up @@ -2161,6 +2167,28 @@ <h2 id="addons">Addons</h2>
of <a href="#addon_dialog"><code>openDialog</code></a> when
available to make prompting for search queries less ugly.</dd>

<dt id="addon_matchesonscrollbar"><a href="../addon/search/matchesonscrollbar.js"><code>search/matchesonscrollbar.js</code></a></dt>
<dd>Adds a <code>showMatchesOnScrollbar</code> method to editor
instances, which should be given a query (string or regular
expression), optionally a case-fold flag (only applicable for
strings), and optionally a class name (defaults
to <code>CodeMirror-search-match</code>) as arguments. When
called, matches of the given query will be displayed on the
editor's vertical scrollbar. The method returns an object with
a <code>clear</code> method that can be called to remove the
matches. Depends on
the <a href="#addon_annotatescrollbar"><code>annotatescrollbar</code></a>
addon, and
the <a href="../addon/search/matchesonscrollbar.css"><code>matchesonscrollbar.css</code></a>
file provides a default (transparent yellowish) definition of
the CSS class applied to the matches. Note that the matches are
only perfectly aligned if your scrollbar does not have buttons
at the top and bottom. You can use
the <a href="#addon_simplescrollbars"><code>simplescrollbar</code></a>
addon to make sure of this. If this addon is loaded,
the <a href="#addon_search"><code>search</code></a> addon will
automatically use it.</dd>

<dt id="addon_matchbrackets"><a href="../addon/edit/matchbrackets.js"><code>edit/matchbrackets.js</code></a></dt>
<dd>Defines an option <code>matchBrackets</code> which, when set
to true, causes matching brackets to be highlighted whenever the
Expand Down Expand Up @@ -2540,10 +2568,6 @@ <h2 id="addons">Addons</h2>
<dd>A hinting function for CSS, SCSS, or LESS code.
Defines <code>CodeMirror.hint.css</code>.</dd>

<dt id="addon_python-hint"><a href="../addon/hint/python-hint.js"><code>hint/python-hint.js</code></a></dt>
<dd>A very simple hinting function for Python code.
Defines <code>CodeMirror.hint.python</code>.</dd>

<dt id="addon_anyword-hint"><a href="../addon/hint/anyword-hint.js"><code>hint/anyword-hint.js</code></a></dt>
<dd>A very simple hinting function
(<code>CodeMirror.hint.anyword</code>) that simply looks for
Expand Down Expand Up @@ -2660,6 +2684,28 @@ <h2 id="addons">Addons</h2>
on <a href="../addon/display/fullscreen.css"><code>fullscreen.css</code></a>. <a href="../demo/fullscreen.html">Demo
here</a>.</dd>

<dt id="addon_simplescrollbars"><a href="../addon/scroll/simplescrollbars.js"><code>scroll/simplescrollbars.js</code></a></dt>
<dd>Defines two additional scrollbar
models, <code>"simple"</code> and <code>"overlay"</code>
(see <a href="../demo/simplescrollbars.html">demo</a>) that can
be selected with
the <a href="#option_scrollbarStyle"><code>scrollbarStyle</code></a>
option. Depends
on <a href="../addon/scroll/simplescrollbars.css"><code>simplescrollbars.css</code></a>,
which can be further overridden to style your own
scrollbars.</dd>

<dt id="addon_annotatescrollbar"><a href="../addon/scroll/annotatescrollbar.js"><code>scroll/annotatescrollbar.js</code></a></dt>
<dd>Provides functionality for showing markers on the scrollbar
to call out certain parts of the document. Adds a
method <code>annotateScrollbar</code> to editor instances that
can be called, with a CSS class name as argument, to create a
set of annotations. The method returns an object
whose <code>update</code> method can be called with an array
of <code>{from: Pos, to: Pos}</code> objects marking the ranges
to be higlighed. To detach the annotations, call the
object's <code>clear</code> method.</dd>

<dt id="addon_rulers"><a href="../addon/display/rulers.js"><code>display/rulers.js</code></a></dt>
<dd>Adds a <code>rulers</code> option, which can be used to show
one or more vertical rulers in the editor. The option, if
Expand All @@ -2671,6 +2717,19 @@ <h2 id="addons">Addons</h2>
custom style to a ruler. <a href="../demo/rulers.html">Demo
here</a>.</dd>

<dt id="addon_panel"><a href="../addon/display/panel.js"><code>display/panel.js</code></a></dt>
<dd>Defines an <code>addPanel</code> method for CodeMirror
instances, which places a DOM node above or below an editor, and
shrinks the editor to make room for the node. The method takes
as first argument as DOM node, and as second an optional options
object. By default, the panel ends up above the editor. This can
be changed by passing a <code>position</code> option with the
value <code>"bottom"</code>. The object returned by this method
has a <code>clear</code> method that is used to remove the
panel, and a <code>changed</code> method that can be used to
notify the addon when the size of the panel's DOM node has
changed.</dd>

<dt id="addon_hardwrap"><a href="../addon/wrap/hardwrap.js"><code>wrap/hardwrap.js</code></a></dt>
<dd>Addon to perform hard line wrapping/breaking for paragraphs
of text. Adds these methods to editor instances:
Expand Down Expand Up @@ -2710,15 +2769,37 @@ <h2 id="addons">Addons</h2>
constructor takes arguments similar to
the <a href="#CodeMirror"><code>CodeMirror</code></a>
constructor, first a node to append the interface to, and then
an options object. Two extra optional options are
recognized, <code>origLeft</code> and <code>origRight</code>,
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), and, unless a <code>revertButtons</code> option
of <code>false</code> is given, show buttons that allow the user
to revert changes (<a href="../demo/merge.html">demo</a>).</dd>
an options object. Options are passed through to the editors
inside the view. These extra options are recognized:
<dl>
<dt><code><strong>origLeft</strong></code> and <code><strong>origRight</strong>: string</code></dt>
<dd>If given these 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). To create a 2-way (as opposed
to 3-way) merge view, provide only one of them.</dd>
<dt><code><strong>revertButtons</strong>: boolean</code></dt>
<dd>Determines whether buttons that allow the user to revert
changes are shown. Defaults to true.</dd>
<dt><code><strong>connect</strong>: string</code></dt>
<dd>Sets the style used to connect changed chunks of code.
By default, connectors are drawn. When this is set
to <code>"align"</code>, the smaller chunk is padded to
align with the bigger chunk instead.</dd>
<dt><code><strong>collapseIdentical</strong>: boolean|number</code></dt>
<dd>When true (default is false), stretches of unchanged
text will be collapsed. When a number is given, this
indicates the amount of lines to leave visible around such
stretches (which defaults to 2).</dd>
<dt><code><strong>allowEditingOriginals</strong>: boolean</code></dt>
<dd>Determines whether the original editor allows editing.
Defaults to false.</dd>
<dt><code><strong>showDifferences</strong>: boolean</code></dt>
<dd>When true (the default), changed pieces of text are
highlighted.</dd>
</dl>
<a href="../demo/merge.html">Demo here</a>.</dd>

<dt id="addon_tern"><a href="../addon/tern/tern.js"><code>tern/tern.js</code></a></dt>
<dd>Provides integration with
Expand Down
4 changes: 4 additions & 0 deletions doc/realworld.html
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ <h2>CodeMirror real-world uses</h2>
<li><a href="http://extensions.joomla.org/extensions/edition/editors/8723">Joomla plugin</a></li>
<li><a href="http://jqfundamentals.com/">jQuery fundamentals</a> (interactive tutorial)</li>
<li><a href="http://jsbin.com">jsbin.com</a> (JS playground)</li>
<li><a href="http://tool.jser.com/preprocessor">JSER preprocessor</a></li>
<li><a href="https://github.com/kucherenko/jscpd">jscpd</a> (code duplication detector)</li>
<li><a href="http://jsfiddle.com">jsfiddle.com</a> (another JS playground)</li>
<li><a href="http://www.jshint.com/">JSHint</a> (JS linter)</li>
Expand Down Expand Up @@ -138,18 +139,21 @@ <h2>CodeMirror real-world uses</h2>
<li><a href="http://snippets.pro/">Snippets.pro</a> (code snippet sharing)</li>
<li><a href="http://www.solidshops.com/">SolidShops</a> (hosted e-commerce platform)</li>
<li><a href="http://sqlfiddle.com">SQLFiddle</a> (SQL playground)</li>
<li><a href="http://www.subte.org/page/programar-ta-te-ti-online/">SubTe</a> (AI bot programming environment)</li>
<li><a href="http://xuanji.appspot.com/isicp/">Structure and Interpretation of Computer Programs</a>, Interactive Version</li>
<li><a href="http://syframework.alwaysdata.net">SyBox</a> (PHP playground)</li>
<li><a href="http://www.tagspaces.org/">TagSpaces</a> (personal data manager)</li>
<li><a href="https://thefiletree.com">The File Tree</a> (collab editor)</li>
<li><a href="http://www.mapbox.com/tilemill/">TileMill</a> (map design tool)</li>
<li><a href="http://doc.tiki.org/Syntax+Highlighter">Tiki</a> (wiki CMS groupware)</li>
<li><a href="http://www.toolsverse.com/products/data-explorer/">Toolsverse Data Explorer</a> (database management)</li>
<li><a href="http://enjalot.com/tributary/2636296/sinwaves.js">Tributary</a> (augmented editing)</li>
<li><a href="http://blog.englard.net/post/39608000629/codeintumblr">Tumblr code highlighting shim</a></li>
<li><a href="http://turbopy.com/">TurboPY</a> (web publishing framework)</li>
<li><a href="http://uicod.com/">uiCod</a> (animation demo gallery and sharing)</li>
<li><a href="http://cruise.eecs.uottawa.ca/umpleonline/">UmpleOnline</a> (model-oriented programming tool)</li>
<li><a href="https://upsource.jetbrains.com/#idea/view/923f30395f2603cd9f42a32bcafd13b6c28de0ff/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/style/ReplaceAbstractClassInstanceByMapIntention.java">Upsource</a> (code viewer)</li>
<li><a href="https://github.com/mgaitan/waliki">Waliki</a> (wiki engine)</li>
<li><a href="http://wamer.net/">Wamer</a> (web application builder)</li>
<li><a href="https://github.com/brettz9/webappfind">webappfind</a> (windows file bindings for webapps)</li>
<li><a href="http://www.webglacademy.com/">WebGL academy</a> (learning WebGL)</li>
Expand Down
23 changes: 23 additions & 0 deletions doc/releases.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,29 @@ <h2>Release notes and version history</h2>

<h2>Version 4.x</h2>

<p class="rel">23-12-2014: <a href="http://codemirror.net/codemirror-4.9.zip">Version 4.9</a>:</p>

<ul class="rel-note">
<li>Overhauled scroll bar handling.
Add pluggable <a href="../demo/simplescrollbars.html">scrollbar
implementations</a>.</li>
<li>Tweaked behavior for
the <a href="manual.html#addon_show-hint">completion addons</a> to
not take text after cursor into account.</li>
<li>Two new optional features in
the <a href="manual.html#addon_merge">merge addon</a>: aligning
editors, and folding unchanged text.</li>
<li>New
modes: <a href="../mode/dart/index.html">Dart</a>, <a href="../mode/ebnf/index.html">EBNF</a>, <a href="../mode/spreadsheet/index.html">spreadsheet</a>,
and <a href="../mode/soy/index.html">Soy</a>.</li>
<li>New <a href="../demo/panel.html">addon</a> to show persistent panels below/above an editor.</li>
<li>New themes: <a href="../demo/theme.html?zenburn">zenburn</a>
and <a href="../demo/theme.html?tomorrow-night-bright">tomorrow night
bright</a>.</li>
<li>Allow ctrl-click to clear existing cursors.</li>
<li>Full <a href="https://github.com/codemirror/CodeMirror/compare/4.8.0...4.9.0">list of patches</a>.</li>
</ul>

<p class="rel">22-11-2014: <a href="http://codemirror.net/codemirror-4.8.zip">Version 4.8</a>:</p>

<ul class="rel-note">
Expand Down
9 changes: 5 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ <h2>This is CodeMirror</h2>
<option value="demo/tern.html">Tern integration</option>
<option value="demo/merge.html">Merge/diff interface</option>
<option value="demo/fullscreen.html">Full-screen editor</option>
<option value="demo/simplescrollbars.html">Custom scrollbars</option>
</select></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("demotext"), {
Expand All @@ -85,15 +86,15 @@ <h2>This is CodeMirror</h2>
</script>
<div style="position: relative; margin: 1em 0;">
<a class="bigbutton left" href="http://codemirror.net/codemirror.zip">DOWNLOAD LATEST RELEASE</a>
<div><strong>version 4.8</strong> (<a href="doc/releases.html">Release notes</a>)</div>
<div><strong>version 4.9</strong> (<a href="doc/releases.html">Release notes</a>)</div>
<div>or use the <a href="doc/compress.html">minification helper</a></div>
<div style="position: absolute; top: 0; right: 0; text-align: right">
<span class="bigbutton right" onclick="document.getElementById('paypal').submit();">DONATE WITH PAYPAL</span>
<div style="position: relative">
or <span onclick="document.getElementById('bankinfo').style.display = 'block';" class=quasilink>Bank</span>,
<span onclick="document.getElementById('bcinfo').style.display = 'block';" class=quasilink>Bitcoin</span>,
<a href="https://www.gittip.com/marijnh">Gittip</a>,
<a href="https://flattr.com/profile/marijnh">Flattr</a><br>
<a href="http://www.patreon.com/marijn">Patreon</a><br>
<a href="https://gratipay.com/marijnh/">Gratipay</a><br>
<div id=bankinfo class=bankinfo>
<span class=bankinfo_close onclick="document.getElementById('bankinfo').style.display = '';">Ă—</span>
Bank: <i>Rabobank</i><br/>
Expand Down Expand Up @@ -182,7 +183,7 @@ <h2>Community</h2>
<section id=browsersupport>
<h2>Browser support</h2>
<p>The <em>desktop</em> versions of the following browsers,
in <em>standards mode</em> (HTML5 <code>&lt;!doctype html></code>
in <em>standards mode</em> (HTML5 <code>&lt;!doctype html></code>
recommended) are supported:</p>
<table style="margin-bottom: 1em">
<tr><th>Firefox</th><td>version 4 and up</td></tr>
Expand Down
32 changes: 25 additions & 7 deletions keymap/emacs.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@
};
}

function findEnd(cm, by, dir) {
var pos = cm.getCursor(), prefix = getPrefix(cm);
function findEnd(cm, pos, by, dir) {
var prefix = getPrefix(cm);
if (prefix < 0) { dir = -dir; prefix = -prefix; }
for (var i = 0; i < prefix; ++i) {
var newPos = by(cm, pos, dir);
Expand All @@ -145,14 +145,31 @@

function move(by, dir) {
var f = function(cm) {
cm.extendSelection(findEnd(cm, by, dir));
cm.extendSelection(findEnd(cm, cm.getCursor(), by, dir));
};
f.motion = true;
return f;
}

function killTo(cm, by, dir) {
kill(cm, cm.getCursor(), findEnd(cm, by, dir), true);
var selections = cm.listSelections(), cursor;
var i = selections.length;
while (i--) {
cursor = selections[i].head;
kill(cm, cursor, findEnd(cm, cursor, by, dir), true);
}
}

function killRegion(cm) {
if (cm.somethingSelected()) {
var selections = cm.listSelections(), selection;
var i = selections.length;
while (i--) {
selection = selections[i];
kill(cm, selection.anchor, selection.head);
}
return true;
}
}

function addPrefix(cm, digit) {
Expand Down Expand Up @@ -283,9 +300,9 @@
"Ctrl-F": move(byChar, 1), "Ctrl-B": move(byChar, -1),
"Right": move(byChar, 1), "Left": move(byChar, -1),
"Ctrl-D": function(cm) { killTo(cm, byChar, 1); },
"Delete": function(cm) { killTo(cm, byChar, 1); },
"Delete": function(cm) { killRegion(cm) || killTo(cm, byChar, 1); },
"Ctrl-H": function(cm) { killTo(cm, byChar, -1); },
"Backspace": function(cm) { killTo(cm, byChar, -1); },
"Backspace": function(cm) { killRegion(cm) || killTo(cm, byChar, -1); },

"Alt-F": move(byWord, 1), "Alt-B": move(byWord, -1),
"Alt-D": function(cm) { killTo(cm, byWord, 1); },
Expand All @@ -309,7 +326,8 @@
"Ctrl-Alt-F": move(byExpr, 1), "Ctrl-Alt-B": move(byExpr, -1),

"Shift-Ctrl-Alt-2": function(cm) {
cm.setSelection(findEnd(cm, byExpr, 1), cm.getCursor());
var cursor = cm.getCursor();
cm.setSelection(findEnd(cm, cursor, byExpr, 1), cursor);
},
"Ctrl-Alt-T": function(cm) {
var leftStart = byExpr(cm, cm.getCursor(), -1), leftEnd = byExpr(cm, leftStart, 1);
Expand Down
290 changes: 181 additions & 109 deletions keymap/vim.js

Large diffs are not rendered by default.

13 changes: 2 additions & 11 deletions lib/codemirror.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
font-family: monospace;
height: 300px;
}
.CodeMirror-scroll {
/* Set scrolling behaviour here */
overflow: auto;
}

/* PADDING */

Expand Down Expand Up @@ -151,6 +147,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
}

.CodeMirror-scroll {
overflow: scroll !important; /* Things will break if this is overridden */
/* 30px is the magic margin used to hide the element's real scrollbars */
/* See overflow: hidden in .CodeMirror */
margin-bottom: -30px; margin-right: -30px;
Expand Down Expand Up @@ -195,17 +192,15 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}

.CodeMirror-gutters {
position: absolute; left: 0; top: 0;
padding-bottom: 30px;
z-index: 3;
}
.CodeMirror-gutter {
white-space: normal;
height: 100%;
-moz-box-sizing: content-box;
box-sizing: content-box;
padding-bottom: 30px;
margin-bottom: -32px;
display: inline-block;
margin-bottom: -30px;
/* Hack to make IE7 behave */
*zoom:1;
*display:inline;
Expand Down Expand Up @@ -261,10 +256,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}

.CodeMirror-widget {}

.CodeMirror-wrap .CodeMirror-scroll {
overflow-x: hidden;
}

.CodeMirror-measure {
position: absolute;
width: 100%;
Expand Down
473 changes: 289 additions & 184 deletions lib/codemirror.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions mode/coffeescript/coffeescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
})(function(CodeMirror) {
"use strict";

CodeMirror.defineMode("coffeescript", function(conf) {
CodeMirror.defineMode("coffeescript", function(conf, parserConf) {
var ERRORCLASS = "error";

function wordRegexp(words) {
Expand Down Expand Up @@ -191,7 +191,7 @@ CodeMirror.defineMode("coffeescript", function(conf) {
}
}
if (singleline) {
if (conf.mode.singleLineStringErrors) {
if (parserConf.singleLineStringErrors) {
outclass = ERRORCLASS;
} else {
state.tokenize = tokenBase;
Expand Down
8 changes: 5 additions & 3 deletions mode/commonlisp/commonlisp.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"use strict";

CodeMirror.defineMode("commonlisp", function (config) {
var specialForm = /^(block|let*|return-from|catch|load-time-value|setq|eval-when|locally|symbol-macrolet|flet|macrolet|tagbody|function|multiple-value-call|the|go|multiple-value-prog1|throw|if|progn|unwind-protect|labels|progv|let|quote)$/;
var assumeBody = /^with|^def|^do|^prog|case$|^cond$|bind$|when$|unless$/;
var numLiteral = /^(?:[+\-]?(?:\d+|\d*\.\d+)(?:[efd][+\-]?\d+)?|[+\-]?\d+(?:\/[+\-]?\d+)?|#b[+\-]?[01]+|#o[+\-]?[0-7]+|#x[+\-]?[\da-f]+)/;
var symbol = /[^\s'`,@()\[\]";]/;
Expand Down Expand Up @@ -52,8 +53,8 @@ CodeMirror.defineMode("commonlisp", function (config) {
var name = readSym(stream);
if (name == ".") return null;
type = "symbol";
if (name == "nil" || name == "t") return "atom";
if (name.charAt(0) == ":") return "keyword";
if (name == "nil" || name == "t" || name.charAt(0) == ":") return "atom";
if (state.lastType == "open" && (specialForm.test(name) || assumeBody.test(name))) return "keyword";
if (name.charAt(0) == "&") return "variable-2";
return "variable";
}
Expand All @@ -80,7 +81,7 @@ CodeMirror.defineMode("commonlisp", function (config) {

return {
startState: function () {
return {ctx: {prev: null, start: 0, indentTo: 0}, tokenize: base};
return {ctx: {prev: null, start: 0, indentTo: 0}, lastType: null, tokenize: base};
},

token: function (stream, state) {
Expand All @@ -98,6 +99,7 @@ CodeMirror.defineMode("commonlisp", function (config) {
} else if (state.ctx.indentTo == "next") {
state.ctx.indentTo = stream.column();
}
state.lastType = type;
}
if (type == "open") state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null};
else if (type == "close") state.ctx = state.ctx.prev || state.ctx;
Expand Down
7 changes: 6 additions & 1 deletion mode/css/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
<link rel=stylesheet href="../../doc/docs.css">

<link rel="stylesheet" href="../../lib/codemirror.css">
<link rel="stylesheet" href="../../addon/hint/show-hint.css">
<script src="../../lib/codemirror.js"></script>
<script src="css.js"></script>
<script src="../../addon/hint/show-hint.js"></script>
<script src="../../addon/hint/css-hint.js"></script>
<style>.CodeMirror {background: #f8f8f8;}</style>
<div id=nav>
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
Expand Down Expand Up @@ -60,7 +63,9 @@ <h2>CSS mode</h2>
}
</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
extraKeys: {"Ctrl-Space": "autocomplete"},
});
</script>

<p><strong>MIME types defined:</strong> <code>text/css</code>, <code>text/x-scss</code> (<a href="scss.html">demo</a>), <code>text/x-less</code> (<a href="less.html">demo</a>).</p>
Expand Down
2 changes: 1 addition & 1 deletion mode/cypher/cypher.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
var curPunc;
var funcs = wordRegexp(["abs", "acos", "allShortestPaths", "asin", "atan", "atan2", "avg", "ceil", "coalesce", "collect", "cos", "cot", "count", "degrees", "e", "endnode", "exp", "extract", "filter", "floor", "haversin", "head", "id", "labels", "last", "left", "length", "log", "log10", "lower", "ltrim", "max", "min", "node", "nodes", "percentileCont", "percentileDisc", "pi", "radians", "rand", "range", "reduce", "rel", "relationship", "relationships", "replace", "right", "round", "rtrim", "shortestPath", "sign", "sin", "split", "sqrt", "startnode", "stdev", "stdevp", "str", "substring", "sum", "tail", "tan", "timestamp", "toFloat", "toInt", "trim", "type", "upper"]);
var preds = wordRegexp(["all", "and", "any", "has", "in", "none", "not", "or", "single", "xor"]);
var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "distinct", "drop", "else", "end", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "remove", "return", "scan", "set", "skip", "start", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with"]);
var keywords = wordRegexp(["as", "asc", "ascending", "assert", "by", "case", "commit", "constraint", "create", "csv", "cypher", "delete", "desc", "descending", "distinct", "drop", "else", "end", "explain", "false", "fieldterminator", "foreach", "from", "headers", "in", "index", "is", "limit", "load", "match", "merge", "null", "on", "optional", "order", "periodic", "profile", "remove", "return", "scan", "set", "skip", "start", "then", "true", "union", "unique", "unwind", "using", "when", "where", "with"]);
var operatorChars = /[*+\-<>=&|~%^]/;

return {
Expand Down
50 changes: 50 additions & 0 deletions mode/dart/dart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// 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"), require("../clike/clike"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../clike/clike"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";

var keywords = ("this super static final const abstract class extends external factory " +
"implements get native operator set typedef with enum throw rethrow " +
"assert break case continue default in return new deferred async await " +
"try catch finally do else for if switch while import library export " +
"part of show hide is").split(" ");
var blockKeywords = "try catch finally do else for if switch while".split(" ");
var atoms = "true false null".split(" ");
var builtins = "void bool num int double dynamic var String".split(" ");

function set(words) {
var obj = {};
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
return obj;
}

CodeMirror.defineMIME("application/dart", {
name: "clike",
keywords: set(keywords),
multiLineStrings: true,
blockKeywords: set(blockKeywords),
builtin: set(builtins),
atoms: set(atoms),
hooks: {
"@": function(stream) {
stream.eatWhile(/[\w\$_]/);
return "meta";
}
}
});

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

// This is needed to make loading through meta.js work.
CodeMirror.defineMode("dart", function(conf) {
return CodeMirror.getMode(conf, "application/dart");
}, "clike");
});
71 changes: 71 additions & 0 deletions mode/dart/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<!doctype html>

<title>CodeMirror: Dart 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="../clike/clike.js"></script>
<script src="dart.js"></script>
<style>.CodeMirror {border: 1px solid #dee;}</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="#">Dart</a>
</ul>
</div>

<article>
<h2>Dart mode</h2>
<form>
<textarea id="code" name="code">
import 'dart:math' show Random;

void main() {
print(new Die(n: 12).roll());
}

// Define a class.
class Die {
// Define a class variable.
static Random shaker = new Random();

// Define instance variables.
int sides, value;

// Define a method using shorthand syntax.
String toString() => '$value';

// Define a constructor.
Die({int n: 6}) {
if (4 <= n && n <= 20) {
sides = n;
} else {
// Support for errors and exceptions.
throw new ArgumentError(/* */);
}
}

// Define an instance method.
int roll() {
return value = shaker.nextInt(sides) + 1;
}
}
</textarea>
</form>

<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
mode: "application/dart"
});
</script>

</article>
14 changes: 5 additions & 9 deletions mode/dockerfile/dockerfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,22 @@
// Block comment: This is a line starting with a comment
{
regex: /#.*$/,
token: "comment",
next: "start"
token: "comment"
},
// Highlight an instruction without any arguments (for convenience)
{
regex: instructionOnlyLine,
token: "variable-2",
next: "start"
token: "variable-2"
},
// Highlight an instruction followed by arguments
{
regex: instructionWithArguments,
token: ["variable-2", null],
next: "arguments"
},
// Fail-safe return to start
{
token: null,
next: "start"
regex: /./,
token: null
}
],
arguments: [
Expand All @@ -54,8 +51,7 @@
},
{
regex: /[^#]+\\$/,
token: null,
next: "arguments"
token: null
},
{
// Match everything except for the inline comment
Expand Down
3 changes: 2 additions & 1 deletion mode/dockerfile/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ <h2>Dockerfile mode</h2>
});
</script>

<p>Dockerfile syntac highlighting for CodeMirror.</p>
<p>Dockerfile syntax highlighting for CodeMirror. Depends on
the <a href="../../demo/simplemode.html">simplemode</a> addon.</p>

<p><strong>MIME types defined:</strong> <code>text/x-dockerfile</code></p>
</article>
195 changes: 195 additions & 0 deletions mode/ebnf/ebnf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
// 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("ebnf", function (config) {
var commentType = {slash: 0, parenthesis: 1};
var stateType = {comment: 0, _string: 1, characterClass: 2};
var bracesMode = null;

if (config.bracesMode)
bracesMode = CodeMirror.getMode(config, config.bracesMode);

return {
startState: function () {
return {
stringType: null,
commentType: null,
braced: 0,
lhs: true,
localState: null,
stack: [],
inDefinition: false
};
},
token: function (stream, state) {
if (!stream) return;

//check for state changes
if (state.stack.length === 0) {
//strings
if ((stream.peek() == '"') || (stream.peek() == "'")) {
state.stringType = stream.peek();
stream.next(); // Skip quote
state.stack.unshift(stateType._string);
} else if (stream.match(/^\/\*/)) { //comments starting with /*
state.stack.unshift(stateType.comment);
state.commentType = commentType.slash;
} else if (stream.match(/^\(\*/)) { //comments starting with (*
state.stack.unshift(stateType.comment);
state.commentType = commentType.parenthesis;
}
}

//return state
//stack has
switch (state.stack[0]) {
case stateType._string:
while (state.stack[0] === stateType._string && !stream.eol()) {
if (stream.peek() === state.stringType) {
stream.next(); // Skip quote
state.stack.shift(); // Clear flag
} else if (stream.peek() === "\\") {
stream.next();
stream.next();
} else {
stream.match(/^.[^\\\"\']*/);
}
}
return state.lhs ? "property string" : "string"; // Token style

case stateType.comment:
while (state.stack[0] === stateType.comment && !stream.eol()) {
if (state.commentType === commentType.slash && stream.match(/\*\//)) {
state.stack.shift(); // Clear flag
state.commentType = null;
} else if (state.commentType === commentType.parenthesis && stream.match(/\*\)/)) {
state.stack.shift(); // Clear flag
state.commentType = null;
} else {
stream.match(/^.[^\*]*/);
}
}
return "comment";

case stateType.characterClass:
while (state.stack[0] === stateType.characterClass && !stream.eol()) {
if (!(stream.match(/^[^\]\\]+/) || stream.match(/^\\./))) {
state.stack.shift();
}
}
return "operator";
}

var peek = stream.peek();

if (bracesMode !== null && (state.braced || peek === "{")) {
if (state.localState === null)
state.localState = bracesMode.startState();

var token = bracesMode.token(stream, state.localState),
text = stream.current();

if (!token) {
for (var i = 0; i < text.length; i++) {
if (text[i] === "{") {
if (state.braced === 0) {
token = "matchingbracket";
}
state.braced++;
} else if (text[i] === "}") {
state.braced--;
if (state.braced === 0) {
token = "matchingbracket";
}
}
}
}
return token;
}

//no stack
switch (peek) {
case "[":
stream.next();
state.stack.unshift(stateType.characterClass);
return "bracket";
case ":":
case "|":
case ";":
stream.next();
return "operator";
case "%":
if (stream.match("%%")) {
return "header";
} else if (stream.match(/[%][A-Za-z]+/)) {
return "keyword";
} else if (stream.match(/[%][}]/)) {
return "matchingbracket";
}
break;
case "/":
if (stream.match(/[\/][A-Za-z]+/)) {
return "keyword";
}
case "\\":
if (stream.match(/[\][a-z]+/)) {
return "string-2";
}
case ".":
if (stream.match(".")) {
return "atom";
}
case "*":
case "-":
case "+":
case "^":
if (stream.match(peek)) {
return "atom";
}
case "$":
if (stream.match("$$")) {
return "builtin";
} else if (stream.match(/[$][0-9]+/)) {
return "variable-3";
}
case "<":
if (stream.match(/<<[a-zA-Z_]+>>/)) {
return "builtin";
}
}

if (stream.match(/^\/\//)) {
stream.skipToEnd();
return "comment";
} else if (stream.match(/return/)) {
return "operator";
} else if (stream.match(/^[a-zA-Z_][a-zA-Z0-9_]*/)) {
if (stream.match(/(?=[\(.])/)) {
return "variable";
} else if (stream.match(/(?=[\s\n]*[:=])/)) {
return "def";
}
return "variable-2";
} else if (["[", "]", "(", ")"].indexOf(stream.peek()) != -1) {
stream.next();
return "bracket";
} else if (!stream.eatSpace()) {
stream.next();
}
return null;
}
};
});

CodeMirror.defineMIME("text/x-ebnf", "ebnf");
});
102 changes: 102 additions & 0 deletions mode/ebnf/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!doctype html>
<html>
<head>
<title>CodeMirror: EBNF 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="../javascript/javascript.js"></script>
<script src="ebnf.js"></script>
<style type="text/css">.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}</style>
</head>
<body>
<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="#">EBNF Mode</a>
</ul>
</div>

<article>
<h2>EBNF Mode (bracesMode setting = "javascript")</h2>
<form><textarea id="code" name="code">
/* description: Parses end executes mathematical expressions. */

/* lexical grammar */
%lex

%%
\s+ /* skip whitespace */
[0-9]+("."[0-9]+)?\b return 'NUMBER';
"*" return '*';
"/" return '/';
"-" return '-';
"+" return '+';
"^" return '^';
"(" return '(';
")" return ')';
"PI" return 'PI';
"E" return 'E';
&lt;&lt;EOF&gt;&gt; return 'EOF';

/lex

/* operator associations and precedence */

%left '+' '-'
%left '*' '/'
%left '^'
%left UMINUS

%start expressions

%% /* language grammar */

expressions
: e EOF
{print($1); return $1;}
;

e
: e '+' e
{$$ = $1+$3;}
| e '-' e
{$$ = $1-$3;}
| e '*' e
{$$ = $1*$3;}
| e '/' e
{$$ = $1/$3;}
| e '^' e
{$$ = Math.pow($1, $3);}
| '-' e %prec UMINUS
{$$ = -$2;}
| '(' e ')'
{$$ = $2;}
| NUMBER
{$$ = Number(yytext);}
| E
{$$ = Math.E;}
| PI
{$$ = Math.PI;}
;</textarea></form>
<script>
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: {name: "ebnf"},
lineNumbers: true,
bracesMode: 'javascript'
});
</script>
<h3>The EBNF Mode</h3>
<p> Created by <a href="https://github.com/robertleeplummerjr">Robert Plummer</a></p>
</article>
</body>
</html>
12 changes: 8 additions & 4 deletions mode/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@

<article>

<h2>Language modes</h2>
<h2>Language modes</h2>

<p>This is a list of every mode in the distribution. Each mode lives
<p>This is a list of every mode in the distribution. Each mode lives
in a subdirectory of the <code>mode/</code> directory, and typically
defines a single JavaScript file that implements the mode. Loading
such file will make the language available to CodeMirror, through
the <a href="manual.html#option_mode"><code>mode</code></a>
the <a href="../doc/manual.html#option_mode"><code>mode</code></a>
option.</p>

<div style="-webkit-columns: 100px 2; -moz-columns: 100px 2; columns: 100px 2;">
<div style="-webkit-columns: 100px 2; -moz-columns: 100px 2; columns: 100px 2;">
<ul style="margin-top: 0">
<li><a href="apl/index.html">APL</a></li>
<li><a href="asterisk/index.html">Asterisk dialplan</a></li>
Expand All @@ -41,11 +41,13 @@ <h2>Language modes</h2>
<li><a href="cypher/index.html">Cypher</a></li>
<li><a href="python/index.html">Cython</a></li>
<li><a href="d/index.html">D</a></li>
<li><a href="dart/index.html">Dart</a></li>
<li><a href="django/index.html">Django</a> (templating language)</li>
<li><a href="dockerfile/index.html">Dockerfile</a></li>
<li><a href="diff/index.html">diff</a></li>
<li><a href="dtd/index.html">DTD</a></li>
<li><a href="dylan/index.html">Dylan</a></li>
<li><a href="ebnf/index.html">EBNF</a></li>
<li><a href="ecl/index.html">ECL</a></li>
<li><a href="eiffel/index.html">Eiffel</a></li>
<li><a href="erlang/index.html">Erlang</a></li>
Expand Down Expand Up @@ -94,6 +96,7 @@ <h2>Language modes</h2>
<li><a href="ruby/index.html">Ruby</a></li>
<li><a href="rust/index.html">Rust</a></li>
<li><a href="sass/index.html">Sass</a></li>
<li><a href="spreadsheet/index.html">Spreadsheet</a></li>
<li><a href="clike/scala.html">Scala</a></li>
<li><a href="scheme/index.html">Scheme</a></li>
<li><a href="css/scss.html">SCSS</a></li>
Expand All @@ -104,6 +107,7 @@ <h2>Language modes</h2>
<li><a href="smarty/index.html">Smarty</a></li>
<li><a href="smartymixed/index.html">Smarty/HTML mixed</a></li>
<li><a href="solr/index.html">Solr</a></li>
<li><a href="soy/index.html">Soy</a></li>
<li><a href="sql/index.html">SQL</a> (several dialects)</li>
<li><a href="sparql/index.html">SPARQL</a></li>
<li><a href="stex/index.html">sTeX, LaTeX</a></li>
Expand Down
2 changes: 2 additions & 0 deletions mode/javascript/javascript.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
++depth;
} else if (wordRE.test(ch)) {
sawSomething = true;
} else if (/["'\/]/.test(ch)) {
return;
} else if (sawSomething && !depth) {
++pos;
break;
Expand Down
6 changes: 6 additions & 0 deletions mode/javascript/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@
" [keyword yield] [variable-2 i];",
"}");

MT("quotedStringAddition",
"[keyword let] [variable f] [operator =] [variable a] [operator +] [string 'fatarrow'] [operator +] [variable c];");

MT("quotedFatArrow",
"[keyword let] [variable f] [operator =] [variable a] [operator +] [string '=>'] [operator +] [variable c];");

MT("fatArrow",
"[variable array].[property filter]([def a] [operator =>] [variable-2 a] [operator +] [number 1]);",
"[variable a];", // No longer in scope
Expand Down
6 changes: 3 additions & 3 deletions mode/markdown/markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror", require("../xml/xml"), require("../meta")));
mod(require("../../lib/codemirror"), require("../xml/xml"), require("../meta"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../xml/xml", "../meta"], mod);
else // Plain browser env
Expand Down Expand Up @@ -396,13 +396,13 @@ CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
return image;
}

if (ch === '[' && stream.match(/.*\](\(| ?\[)/, false)) {
if (ch === '[' && stream.match(/.*\](\(.*\)| ?\[.*\])/, false)) {
state.linkText = true;
if (modeCfg.highlightFormatting) state.formatting = "link";
return getType(state);
}

if (ch === ']' && state.linkText) {
if (ch === ']' && state.linkText && stream.match(/\(.*\)| ?\[.*\]/, false)) {
if (modeCfg.highlightFormatting) state.formatting = "link";
var type = getType(state);
state.linkText = false;
Expand Down
Loading