Update CodeMirror from 4.8 to 4.10
This commit is contained in:
parent
8188d7d89c
commit
c672903794
|
@ -41,7 +41,7 @@ const (
|
|||
// WideVersion holds the current wide version.
|
||||
WideVersion = "1.1.0"
|
||||
// CodeMirrorVer holds the current editor version.
|
||||
CodeMirrorVer = "4.8"
|
||||
CodeMirrorVer = "4.10"
|
||||
)
|
||||
|
||||
// Configuration.
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
CodeMirror.e_stop(e);
|
||||
close();
|
||||
}
|
||||
if (e.keyCode == 13) callback(inp.value);
|
||||
if (e.keyCode == 13) callback(inp.value, e);
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
|
|
@ -0,0 +1,94 @@
|
|||
// 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) {
|
||||
CodeMirror.defineExtension("addPanel", function(node, options) {
|
||||
if (!this.state.panels) initPanels(this);
|
||||
|
||||
var info = this.state.panels;
|
||||
if (options && options.position == "bottom")
|
||||
info.wrapper.appendChild(node);
|
||||
else
|
||||
info.wrapper.insertBefore(node, info.wrapper.firstChild);
|
||||
var height = (options && options.height) || node.offsetHeight;
|
||||
this._setSize(null, info.heightLeft -= height);
|
||||
info.panels++;
|
||||
return new Panel(this, node, options, height);
|
||||
});
|
||||
|
||||
function Panel(cm, node, options, height) {
|
||||
this.cm = cm;
|
||||
this.node = node;
|
||||
this.options = options;
|
||||
this.height = height;
|
||||
this.cleared = false;
|
||||
}
|
||||
|
||||
Panel.prototype.clear = function() {
|
||||
if (this.cleared) return;
|
||||
this.cleared = true;
|
||||
var info = this.cm.state.panels;
|
||||
this.cm._setSize(null, info.heightLeft += this.height);
|
||||
info.wrapper.removeChild(this.node);
|
||||
if (--info.panels == 0) removePanels(this.cm);
|
||||
};
|
||||
|
||||
Panel.prototype.changed = function(height) {
|
||||
var newHeight = height == null ? this.node.offsetHeight : height;
|
||||
var info = this.cm.state.panels;
|
||||
this.cm._setSize(null, info.height += (newHeight - this.height));
|
||||
this.height = newHeight;
|
||||
};
|
||||
|
||||
function initPanels(cm) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle;
|
||||
var height = parseInt(style.height);
|
||||
var info = cm.state.panels = {
|
||||
setHeight: wrap.style.height,
|
||||
heightLeft: height,
|
||||
panels: 0,
|
||||
wrapper: document.createElement("div")
|
||||
};
|
||||
wrap.parentNode.insertBefore(info.wrapper, wrap);
|
||||
var hasFocus = cm.hasFocus();
|
||||
info.wrapper.appendChild(wrap);
|
||||
if (hasFocus) cm.focus();
|
||||
|
||||
cm._setSize = cm.setSize;
|
||||
if (height != null) cm.setSize = function(width, newHeight) {
|
||||
if (newHeight == null) return this._setSize(width, newHeight);
|
||||
info.setHeight = newHeight;
|
||||
if (typeof newHeight != "number") {
|
||||
var px = /^(\d+\.?\d*)px$/.exec(newHeight);
|
||||
if (px) {
|
||||
newHeight = Number(px[1]);
|
||||
} else {
|
||||
info.wrapper.style.height = newHeight;
|
||||
newHeight = info.wrapper.offsetHeight;
|
||||
info.wrapper.style.height = "";
|
||||
}
|
||||
}
|
||||
cm._setSize(width, info.heightLeft += (newHeight - height));
|
||||
height = newHeight;
|
||||
};
|
||||
}
|
||||
|
||||
function removePanels(cm) {
|
||||
var info = cm.state.panels;
|
||||
cm.state.panels = null;
|
||||
|
||||
var wrap = cm.getWrapperElement();
|
||||
info.wrapper.parentNode.replaceChild(wrap, info.wrapper);
|
||||
wrap.style.height = info.setHeight;
|
||||
cm.setSize = cm._setSize;
|
||||
cm.setSize();
|
||||
}
|
||||
});
|
|
@ -11,9 +11,9 @@
|
|||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var listRE = /^(\s*)([> ]+|[*+-]|(\d+)\.)(\s+)/,
|
||||
emptyListRE = /^(\s*)([> ]+|[*+-]|(\d+)\.)(\s*)$/,
|
||||
unorderedBullets = "*+-";
|
||||
var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)\.)(\s*)/,
|
||||
emptyListRE = /^(\s*)(>[> ]*|[*+-]|(\d+)\.)(\s*)$/,
|
||||
unorderedListRE = /[*+-]\s/;
|
||||
|
||||
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
|
@ -38,7 +38,7 @@
|
|||
|
||||
} else {
|
||||
var indent = match[1], after = match[4];
|
||||
var bullet = unorderedBullets.indexOf(match[2]) >= 0 || match[2].indexOf(">") >= 0
|
||||
var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0
|
||||
? match[2]
|
||||
: (parseInt(match[3], 10) + 1) + ".";
|
||||
|
|
@ -17,8 +17,7 @@
|
|||
var word = options && options.word || WORD;
|
||||
var range = options && options.range || RANGE;
|
||||
var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
|
||||
var start = cur.ch, end = start;
|
||||
while (end < curLine.length && word.test(curLine.charAt(end))) ++end;
|
||||
var end = cur.ch, start = end;
|
||||
while (start && word.test(curLine.charAt(start - 1))) --start;
|
||||
var curWord = start != end && curLine.slice(start, end);
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
var inner = CodeMirror.innerMode(cm.getMode(), token.state);
|
||||
if (inner.mode.name != "css") return;
|
||||
|
||||
var word = token.string, start = token.start, end = token.end;
|
||||
var start = token.start, end = cur.ch, word = token.string.slice(0, end - start);
|
||||
if (/[^\w$_-]/.test(word)) {
|
||||
word = ""; start = end = cur.ch;
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror", "./xml-hint"));
|
||||
mod(require("../../lib/codemirror"), require("./xml-hint"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "./xml-hint"], mod);
|
||||
else // Plain browser env
|
|
@ -30,15 +30,20 @@
|
|||
|
||||
function scriptHint(editor, keywords, getToken, options) {
|
||||
// Find the token at the cursor
|
||||
var cur = editor.getCursor(), token = getToken(editor, cur), tprop = token;
|
||||
var cur = editor.getCursor(), token = getToken(editor, cur);
|
||||
if (/\b(?:string|comment)\b/.test(token.type)) return;
|
||||
token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;
|
||||
|
||||
// If it's not a 'word-style' token, ignore the token.
|
||||
if (!/^[\w$_]*$/.test(token.string)) {
|
||||
token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||
token = {start: cur.ch, end: cur.ch, string: "", state: token.state,
|
||||
type: token.string == "." ? "property" : null};
|
||||
} else if (token.end > cur.ch) {
|
||||
token.end = cur.ch;
|
||||
token.string = token.string.slice(0, cur.ch - token.start);
|
||||
}
|
||||
|
||||
var tprop = token;
|
||||
// If it is a property, find out what it is a property of.
|
||||
while (tprop.type == "property") {
|
||||
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
|
@ -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";
|
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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;});
|
|
@ -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;
|
|
@ -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; }
|
|
@ -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 = {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -126,7 +128,11 @@
|
|||
// (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 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);
|
||||
|
@ -145,6 +151,7 @@
|
|||
if (botDistOther > botDist && (mix = botDist / halfScreen) < 1)
|
||||
targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix);
|
||||
}
|
||||
}
|
||||
|
||||
other.scrollTo(sInfo.left, targetPos);
|
||||
other.state.scrollSetAt = now;
|
||||
|
@ -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 \u21da";
|
||||
}
|
||||
|
||||
|
@ -249,9 +256,20 @@
|
|||
|
||||
// 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;
|
||||
|
@ -259,15 +277,30 @@
|
|||
}
|
||||
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 (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;
|
||||
|
@ -297,7 +330,29 @@
|
|||
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) {
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -374,10 +439,12 @@
|
|||
});
|
||||
gapElts.unshift(dv.copyButtons);
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
@ -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) {
|
|
@ -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);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -194,14 +194,17 @@
|
|||
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);
|
||||
var rule = rules[i];
|
||||
if (rule.data.dedent && rule.data.dedentIfLineStart !== false) {
|
||||
var m = rule.regex.exec(textAfter);
|
||||
if (m && m[0]) {
|
||||
if (rule.data.dedent && rule.data.dedentIfLineStart !== false) pos--;
|
||||
pos--;
|
||||
if (rule.next || rule.push) rules = states[rule.next || rule.push];
|
||||
textAfter = textAfter.slice(m[0].length);
|
||||
continue scan;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return pos < 0 ? 0 : state.indent[pos];
|
|
@ -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);
|
||||
};
|
||||
});
|
|
@ -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%;
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
});
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
};
|
||||
});
|
|
@ -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 =
|
||||
|
@ -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);
|
||||
});
|
||||
|
@ -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 =
|
|
@ -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); },
|
||||
|
||||
|
@ -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);
|
|
@ -5,10 +5,6 @@
|
|||
font-family: monospace;
|
||||
height: 300px;
|
||||
}
|
||||
.CodeMirror-scroll {
|
||||
/* Set scrolling behaviour here */
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* PADDING */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -195,7 +192,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
|||
|
||||
.CodeMirror-gutters {
|
||||
position: absolute; left: 0; top: 0;
|
||||
padding-bottom: 30px;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
|
@ -203,9 +199,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
|||
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;
|
||||
|
@ -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%;
|
|
@ -77,6 +77,7 @@
|
|||
if (options.lineWrapping)
|
||||
this.display.wrapper.className += " CodeMirror-wrap";
|
||||
if (options.autofocus && !mobile) focusInput(this);
|
||||
initScrollbars(this);
|
||||
|
||||
this.state = {
|
||||
keyMaps: [], // stores maps added by addKeyMap
|
||||
|
@ -137,14 +138,13 @@
|
|||
|
||||
// Wraps and hides input textarea
|
||||
d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
|
||||
// The fake scrollbar elements.
|
||||
d.scrollbarH = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
|
||||
d.scrollbarV = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
|
||||
// Covers bottom-right square when both scrollbars are present.
|
||||
d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
|
||||
d.scrollbarFiller.setAttribute("not-content", "true");
|
||||
// Covers bottom of gutter when coverGutterNextToScrollbar is on
|
||||
// and h scrollbar is present.
|
||||
d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
|
||||
d.gutterFiller.setAttribute("not-content", "true");
|
||||
// Will contain the actual code, positioned to cover the viewport.
|
||||
d.lineDiv = elt("div", null, "CodeMirror-code");
|
||||
// Elements are added to these to represent selection and cursors.
|
||||
|
@ -161,10 +161,11 @@
|
|||
d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
|
||||
// Set to the height of the document, allowing scrolling.
|
||||
d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
|
||||
d.sizerWidth = null;
|
||||
// Behavior of elts with overflow: auto and padding is
|
||||
// inconsistent across browsers. This is used to ensure the
|
||||
// scrollable area is big enough.
|
||||
d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerCutOff + "px; width: 1px;");
|
||||
d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
|
||||
// Will contain the gutters, if any.
|
||||
d.gutters = elt("div", null, "CodeMirror-gutters");
|
||||
d.lineGutter = null;
|
||||
|
@ -172,8 +173,7 @@
|
|||
d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
|
||||
d.scroller.setAttribute("tabIndex", "-1");
|
||||
// The element in which the editor lives.
|
||||
d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV,
|
||||
d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
|
||||
d.wrapper = elt("div", [d.inputDiv, d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
|
||||
|
||||
// Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
|
||||
if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
|
||||
|
@ -182,8 +182,6 @@
|
|||
if (!webkit) d.scroller.draggable = true;
|
||||
// Needed to handle Tab key in KHTML
|
||||
if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; }
|
||||
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
|
||||
if (ie && ie_version < 8) d.scrollbarH.style.minHeight = d.scrollbarV.style.minWidth = "18px";
|
||||
|
||||
if (place) {
|
||||
if (place.appendChild) place.appendChild(d.wrapper);
|
||||
|
@ -192,8 +190,10 @@
|
|||
|
||||
// Current rendered range (may be bigger than the view window).
|
||||
d.viewFrom = d.viewTo = doc.first;
|
||||
d.reportedViewFrom = d.reportedViewTo = doc.first;
|
||||
// Information about the rendered lines.
|
||||
d.view = [];
|
||||
d.renderedView = null;
|
||||
// Holds info about a single rendered line when it was rendered
|
||||
// for measurement, while not in view.
|
||||
d.externalMeasured = null;
|
||||
|
@ -202,6 +202,9 @@
|
|||
d.lastWrapHeight = d.lastWrapWidth = 0;
|
||||
d.updateLineNumbers = null;
|
||||
|
||||
d.nativeBarWidth = d.barHeight = d.barWidth = 0;
|
||||
d.scrollbarsClipped = false;
|
||||
|
||||
// Used to only resize the line number gutter when necessary (when
|
||||
// the amount of lines crosses a boundary that makes its width change)
|
||||
d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
|
||||
|
@ -265,6 +268,7 @@
|
|||
if (cm.options.lineWrapping) {
|
||||
addClass(cm.display.wrapper, "CodeMirror-wrap");
|
||||
cm.display.sizer.style.minWidth = "";
|
||||
cm.display.sizerWidth = null;
|
||||
} else {
|
||||
rmClass(cm.display.wrapper, "CodeMirror-wrap");
|
||||
findMaxLine(cm);
|
||||
|
@ -336,7 +340,6 @@
|
|||
function updateGutterSpace(cm) {
|
||||
var width = cm.display.gutters.offsetWidth;
|
||||
cm.display.sizer.style.marginLeft = width + "px";
|
||||
cm.display.scrollbarH.style.left = cm.options.fixedGutter ? width + "px" : 0;
|
||||
}
|
||||
|
||||
// Compute the character length of a line, taking into account
|
||||
|
@ -389,78 +392,166 @@
|
|||
|
||||
// SCROLLBARS
|
||||
|
||||
function hScrollbarTakesSpace(cm) {
|
||||
return cm.display.scroller.clientHeight - cm.display.wrapper.clientHeight < scrollerCutOff - 3;
|
||||
}
|
||||
|
||||
// Prepare DOM reads needed to update the scrollbars. Done in one
|
||||
// shot to minimize update/measure roundtrips.
|
||||
function measureForScrollbars(cm) {
|
||||
var scroll = cm.display.scroller;
|
||||
var d = cm.display, gutterW = d.gutters.offsetWidth;
|
||||
var docH = Math.round(cm.doc.height + paddingVert(cm.display));
|
||||
return {
|
||||
clientHeight: scroll.clientHeight,
|
||||
barHeight: cm.display.scrollbarV.clientHeight,
|
||||
scrollWidth: scroll.scrollWidth, clientWidth: scroll.clientWidth,
|
||||
hScrollbarTakesSpace: hScrollbarTakesSpace(cm),
|
||||
barWidth: cm.display.scrollbarH.clientWidth,
|
||||
docHeight: Math.round(cm.doc.height + paddingVert(cm.display))
|
||||
clientHeight: d.scroller.clientHeight,
|
||||
viewHeight: d.wrapper.clientHeight,
|
||||
scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
|
||||
viewWidth: d.wrapper.clientWidth,
|
||||
barLeft: cm.options.fixedGutter ? gutterW : 0,
|
||||
docHeight: docH,
|
||||
scrollHeight: docH + scrollGap(cm) + d.barHeight,
|
||||
nativeBarWidth: d.nativeBarWidth,
|
||||
gutterWidth: gutterW
|
||||
};
|
||||
}
|
||||
|
||||
function NativeScrollbars(place, scroll, cm) {
|
||||
this.cm = cm;
|
||||
var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
|
||||
var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
|
||||
place(vert); place(horiz);
|
||||
|
||||
on(vert, "scroll", function() {
|
||||
if (vert.clientHeight) scroll(vert.scrollTop, "vertical");
|
||||
});
|
||||
on(horiz, "scroll", function() {
|
||||
if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
|
||||
});
|
||||
|
||||
this.checkedOverlay = false;
|
||||
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
|
||||
if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
|
||||
}
|
||||
|
||||
NativeScrollbars.prototype = copyObj({
|
||||
update: function(measure) {
|
||||
var needsH = measure.scrollWidth > measure.clientWidth + 1;
|
||||
var needsV = measure.scrollHeight > measure.clientHeight + 1;
|
||||
var sWidth = measure.nativeBarWidth;
|
||||
|
||||
if (needsV) {
|
||||
this.vert.style.display = "block";
|
||||
this.vert.style.bottom = needsH ? sWidth + "px" : "0";
|
||||
var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
|
||||
// A bug in IE8 can cause this value to be negative, so guard it.
|
||||
this.vert.firstChild.style.height =
|
||||
Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
|
||||
} else {
|
||||
this.vert.style.display = "";
|
||||
this.vert.firstChild.style.height = "0";
|
||||
}
|
||||
|
||||
if (needsH) {
|
||||
this.horiz.style.display = "block";
|
||||
this.horiz.style.right = needsV ? sWidth + "px" : "0";
|
||||
this.horiz.style.left = measure.barLeft + "px";
|
||||
var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
|
||||
this.horiz.firstChild.style.width =
|
||||
(measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
|
||||
} else {
|
||||
this.horiz.style.display = "";
|
||||
this.horiz.firstChild.style.width = "0";
|
||||
}
|
||||
|
||||
if (!this.checkedOverlay && measure.clientHeight > 0) {
|
||||
if (sWidth == 0) this.overlayHack();
|
||||
this.checkedOverlay = true;
|
||||
}
|
||||
|
||||
return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
|
||||
},
|
||||
setScrollLeft: function(pos) {
|
||||
if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
|
||||
},
|
||||
setScrollTop: function(pos) {
|
||||
if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
|
||||
},
|
||||
overlayHack: function() {
|
||||
var w = mac && !mac_geMountainLion ? "12px" : "18px";
|
||||
this.horiz.style.minHeight = this.vert.style.minWidth = w;
|
||||
var self = this;
|
||||
var barMouseDown = function(e) {
|
||||
if (e_target(e) != self.vert && e_target(e) != self.horiz)
|
||||
operation(self.cm, onMouseDown)(e);
|
||||
};
|
||||
on(this.vert, "mousedown", barMouseDown);
|
||||
on(this.horiz, "mousedown", barMouseDown);
|
||||
},
|
||||
clear: function() {
|
||||
var parent = this.horiz.parentNode;
|
||||
parent.removeChild(this.horiz);
|
||||
parent.removeChild(this.vert);
|
||||
}
|
||||
}, NativeScrollbars.prototype);
|
||||
|
||||
function NullScrollbars() {}
|
||||
|
||||
NullScrollbars.prototype = copyObj({
|
||||
update: function() { return {bottom: 0, right: 0}; },
|
||||
setScrollLeft: function() {},
|
||||
setScrollTop: function() {},
|
||||
clear: function() {}
|
||||
}, NullScrollbars.prototype);
|
||||
|
||||
CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
|
||||
|
||||
function initScrollbars(cm) {
|
||||
if (cm.display.scrollbars) {
|
||||
cm.display.scrollbars.clear();
|
||||
if (cm.display.scrollbars.addClass)
|
||||
rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);
|
||||
}
|
||||
|
||||
cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {
|
||||
cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
|
||||
on(node, "mousedown", function() {
|
||||
if (cm.state.focused) setTimeout(bind(focusInput, cm), 0);
|
||||
});
|
||||
node.setAttribute("not-content", "true");
|
||||
}, function(pos, axis) {
|
||||
if (axis == "horizontal") setScrollLeft(cm, pos);
|
||||
else setScrollTop(cm, pos);
|
||||
}, cm);
|
||||
if (cm.display.scrollbars.addClass)
|
||||
addClass(cm.display.wrapper, cm.display.scrollbars.addClass);
|
||||
}
|
||||
|
||||
function updateScrollbars(cm, measure) {
|
||||
if (!measure) measure = measureForScrollbars(cm);
|
||||
var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
|
||||
updateScrollbarsInner(cm, measure);
|
||||
for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
|
||||
if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
|
||||
updateHeightsInViewport(cm);
|
||||
updateScrollbarsInner(cm, measureForScrollbars(cm));
|
||||
startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// Re-synchronize the fake scrollbars with the actual size of the
|
||||
// content.
|
||||
function updateScrollbars(cm, measure) {
|
||||
if (!measure) measure = measureForScrollbars(cm);
|
||||
var d = cm.display, sWidth = scrollbarWidth(d.measure);
|
||||
var scrollHeight = measure.docHeight + scrollerCutOff;
|
||||
var needsH = measure.scrollWidth > measure.clientWidth;
|
||||
if (needsH && measure.scrollWidth <= measure.clientWidth + 1 &&
|
||||
sWidth > 0 && !measure.hScrollbarTakesSpace)
|
||||
needsH = false; // (Issue #2562)
|
||||
var needsV = scrollHeight > measure.clientHeight;
|
||||
function updateScrollbarsInner(cm, measure) {
|
||||
var d = cm.display;
|
||||
var sizes = d.scrollbars.update(measure);
|
||||
|
||||
if (needsV) {
|
||||
d.scrollbarV.style.display = "block";
|
||||
d.scrollbarV.style.bottom = needsH ? sWidth + "px" : "0";
|
||||
// A bug in IE8 can cause this value to be negative, so guard it.
|
||||
d.scrollbarV.firstChild.style.height =
|
||||
Math.max(0, scrollHeight - measure.clientHeight + (measure.barHeight || d.scrollbarV.clientHeight)) + "px";
|
||||
} else {
|
||||
d.scrollbarV.style.display = "";
|
||||
d.scrollbarV.firstChild.style.height = "0";
|
||||
}
|
||||
if (needsH) {
|
||||
d.scrollbarH.style.display = "block";
|
||||
d.scrollbarH.style.right = needsV ? sWidth + "px" : "0";
|
||||
d.scrollbarH.firstChild.style.width =
|
||||
(measure.scrollWidth - measure.clientWidth + (measure.barWidth || d.scrollbarH.clientWidth)) + "px";
|
||||
} else {
|
||||
d.scrollbarH.style.display = "";
|
||||
d.scrollbarH.firstChild.style.width = "0";
|
||||
}
|
||||
if (needsH && needsV) {
|
||||
d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
|
||||
d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
|
||||
|
||||
if (sizes.right && sizes.bottom) {
|
||||
d.scrollbarFiller.style.display = "block";
|
||||
d.scrollbarFiller.style.height = d.scrollbarFiller.style.width = sWidth + "px";
|
||||
d.scrollbarFiller.style.height = sizes.bottom + "px";
|
||||
d.scrollbarFiller.style.width = sizes.right + "px";
|
||||
} else d.scrollbarFiller.style.display = "";
|
||||
if (needsH && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
|
||||
if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
|
||||
d.gutterFiller.style.display = "block";
|
||||
d.gutterFiller.style.height = sWidth + "px";
|
||||
d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
|
||||
d.gutterFiller.style.height = sizes.bottom + "px";
|
||||
d.gutterFiller.style.width = measure.gutterWidth + "px";
|
||||
} else d.gutterFiller.style.display = "";
|
||||
|
||||
if (!cm.state.checkedOverlayScrollbar && measure.clientHeight > 0) {
|
||||
if (sWidth === 0) {
|
||||
var w = mac && !mac_geMountainLion ? "12px" : "18px";
|
||||
d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = w;
|
||||
var barMouseDown = function(e) {
|
||||
if (e_target(e) != d.scrollbarV && e_target(e) != d.scrollbarH)
|
||||
operation(cm, onMouseDown)(e);
|
||||
};
|
||||
on(d.scrollbarV, "mousedown", barMouseDown);
|
||||
on(d.scrollbarH, "mousedown", barMouseDown);
|
||||
}
|
||||
cm.state.checkedOverlayScrollbar = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the lines that are visible in a given viewport (defaults
|
||||
|
@ -476,12 +567,13 @@
|
|||
// forces those lines into the viewport (if possible).
|
||||
if (viewport && viewport.ensure) {
|
||||
var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
|
||||
if (ensureFrom < from)
|
||||
return {from: ensureFrom,
|
||||
to: lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)};
|
||||
if (Math.min(ensureTo, doc.lastLine()) >= to)
|
||||
return {from: lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight),
|
||||
to: ensureTo};
|
||||
if (ensureFrom < from) {
|
||||
from = ensureFrom;
|
||||
to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
|
||||
} else if (Math.min(ensureTo, doc.lastLine()) >= to) {
|
||||
from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
|
||||
to = ensureTo;
|
||||
}
|
||||
}
|
||||
return {from: from, to: Math.max(to, from + 1)};
|
||||
}
|
||||
|
@ -549,17 +641,28 @@
|
|||
this.editorIsHidden = !display.wrapper.offsetWidth;
|
||||
this.wrapperHeight = display.wrapper.clientHeight;
|
||||
this.wrapperWidth = display.wrapper.clientWidth;
|
||||
this.oldViewFrom = display.viewFrom; this.oldViewTo = display.viewTo;
|
||||
this.oldScrollerWidth = display.scroller.clientWidth;
|
||||
this.oldDisplayWidth = displayWidth(cm);
|
||||
this.force = force;
|
||||
this.dims = getDimensions(cm);
|
||||
}
|
||||
|
||||
function maybeClipScrollbars(cm) {
|
||||
var display = cm.display;
|
||||
if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
|
||||
display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
|
||||
display.heightForcer.style.height = scrollGap(cm) + "px";
|
||||
display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
|
||||
display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
|
||||
display.scrollbarsClipped = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Does the actual updating of the line display. Bails out
|
||||
// (returning false) when there is nothing to be done and forced is
|
||||
// false.
|
||||
function updateDisplayIfNeeded(cm, update) {
|
||||
var display = cm.display, doc = cm.doc;
|
||||
|
||||
if (update.editorIsHidden) {
|
||||
resetView(cm);
|
||||
return false;
|
||||
|
@ -569,7 +672,7 @@
|
|||
if (!update.force &&
|
||||
update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
|
||||
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
|
||||
countDirtyView(cm) == 0)
|
||||
display.renderedView == display.view && countDirtyView(cm) == 0)
|
||||
return false;
|
||||
|
||||
if (maybeUpdateLineNumberWidth(cm)) {
|
||||
|
@ -597,7 +700,7 @@
|
|||
cm.display.mover.style.top = display.viewOffset + "px";
|
||||
|
||||
var toUpdate = countDirtyView(cm);
|
||||
if (!different && toUpdate == 0 && !update.force &&
|
||||
if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
|
||||
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
|
||||
return false;
|
||||
|
||||
|
@ -607,14 +710,16 @@
|
|||
if (toUpdate > 4) display.lineDiv.style.display = "none";
|
||||
patchDisplay(cm, display.updateLineNumbers, update.dims);
|
||||
if (toUpdate > 4) display.lineDiv.style.display = "";
|
||||
display.renderedView = display.view;
|
||||
// There might have been a widget with a focused element that got
|
||||
// hidden or updated, if so re-focus it.
|
||||
if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
|
||||
|
||||
// Prevent selection and cursors from interfering with the scroll
|
||||
// width.
|
||||
// width and height.
|
||||
removeChildren(display.cursorDiv);
|
||||
removeChildren(display.selectionDiv);
|
||||
display.heightForcer.style.top = display.gutters.style.height = 0;
|
||||
|
||||
if (different) {
|
||||
display.lastWrapHeight = update.wrapperHeight;
|
||||
|
@ -630,14 +735,13 @@
|
|||
function postUpdateDisplay(cm, update) {
|
||||
var force = update.force, viewport = update.viewport;
|
||||
for (var first = true;; first = false) {
|
||||
if (first && cm.options.lineWrapping && update.oldScrollerWidth != cm.display.scroller.clientWidth) {
|
||||
if (first && cm.options.lineWrapping && update.oldDisplayWidth != displayWidth(cm)) {
|
||||
force = true;
|
||||
} else {
|
||||
force = false;
|
||||
// Clip forced viewport to actual scrollable area.
|
||||
if (viewport && viewport.top != null)
|
||||
viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - scrollerCutOff -
|
||||
cm.display.scroller.clientHeight, viewport.top)};
|
||||
viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};
|
||||
// Updated line heights might result in the drawn area not
|
||||
// actually covering the viewport. Keep looping until it does.
|
||||
update.visible = visibleLines(cm.display, cm.doc, viewport);
|
||||
|
@ -653,8 +757,10 @@
|
|||
}
|
||||
|
||||
signalLater(cm, "update", cm);
|
||||
if (cm.display.viewFrom != update.oldViewFrom || cm.display.viewTo != update.oldViewTo)
|
||||
if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
|
||||
signalLater(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
|
||||
cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
|
||||
}
|
||||
}
|
||||
|
||||
function updateDisplaySimple(cm, viewport) {
|
||||
|
@ -670,17 +776,10 @@
|
|||
}
|
||||
|
||||
function setDocumentHeight(cm, measure) {
|
||||
cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measure.docHeight + "px";
|
||||
cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + "px";
|
||||
}
|
||||
|
||||
function checkForWebkitWidthBug(cm, measure) {
|
||||
// Work around Webkit bug where it sometimes reserves space for a
|
||||
// non-existing phantom scrollbar in the scroller (Issue #2420)
|
||||
if (cm.display.sizer.offsetWidth + cm.display.gutters.offsetWidth < cm.display.scroller.clientWidth - 1) {
|
||||
cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = "0px";
|
||||
cm.display.gutters.style.height = measure.docHeight + "px";
|
||||
}
|
||||
cm.display.sizer.style.minHeight = measure.docHeight + "px";
|
||||
var plusGap = measure.docHeight + scrollGap(cm);
|
||||
cm.display.heightForcer.style.top = plusGap + "px";
|
||||
cm.display.gutters.style.height = Math.max(plusGap, measure.clientHeight) + "px";
|
||||
}
|
||||
|
||||
// Read the actual heights of the rendered lines, and update their
|
||||
|
@ -924,7 +1023,7 @@
|
|||
var wrap = ensureLineWrapped(lineView);
|
||||
for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
|
||||
var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
|
||||
if (!widget.handleMouseEvents) node.ignoreEvents = true;
|
||||
if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true");
|
||||
positionLineWidget(widget, node, lineView, dims);
|
||||
if (allowAbove && widget.above)
|
||||
wrap.insertBefore(node, lineView.gutter || lineView.text);
|
||||
|
@ -1319,7 +1418,8 @@
|
|||
function drawSelectionRange(cm, range, output) {
|
||||
var display = cm.display, doc = cm.doc;
|
||||
var fragment = document.createDocumentFragment();
|
||||
var padding = paddingH(cm.display), leftSide = padding.left, rightSide = display.lineSpace.offsetWidth - padding.right;
|
||||
var padding = paddingH(cm.display), leftSide = padding.left;
|
||||
var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
|
||||
|
||||
function add(left, top, width, bottom) {
|
||||
if (top < 0) top = 0;
|
||||
|
@ -1498,13 +1598,21 @@
|
|||
return data;
|
||||
}
|
||||
|
||||
function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; }
|
||||
function displayWidth(cm) {
|
||||
return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth;
|
||||
}
|
||||
function displayHeight(cm) {
|
||||
return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight;
|
||||
}
|
||||
|
||||
// Ensure the lineView.wrapping.heights array is populated. This is
|
||||
// an array of bottom offsets for the lines that make up a drawn
|
||||
// line. When lineWrapping is on, there might be more than one
|
||||
// height.
|
||||
function ensureLineHeights(cm, lineView, rect) {
|
||||
var wrapping = cm.options.lineWrapping;
|
||||
var curWidth = wrapping && cm.display.scroller.clientWidth;
|
||||
var curWidth = wrapping && displayWidth(cm);
|
||||
if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
|
||||
var heights = lineView.measure.heights = [];
|
||||
if (wrapping) {
|
||||
|
@ -2022,6 +2130,7 @@
|
|||
|
||||
function endOperation_R1(op) {
|
||||
var cm = op.cm, display = cm.display;
|
||||
maybeClipScrollbars(cm);
|
||||
if (op.updateMaxLine) findMaxLine(cm);
|
||||
|
||||
op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
|
||||
|
@ -2047,8 +2156,10 @@
|
|||
// updateDisplay_W2 will use these properties to do the actual resizing
|
||||
if (display.maxLineChanged && !cm.options.lineWrapping) {
|
||||
op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
|
||||
op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo +
|
||||
scrollerCutOff - display.scroller.clientWidth);
|
||||
cm.display.sizerWidth = op.adjustWidthTo;
|
||||
op.barMeasure.scrollWidth =
|
||||
Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
|
||||
op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
|
||||
}
|
||||
|
||||
if (op.updatedDisplay || op.selectionChanged)
|
||||
|
@ -2081,9 +2192,6 @@
|
|||
function endOperation_finish(op) {
|
||||
var cm = op.cm, display = cm.display, doc = cm.doc;
|
||||
|
||||
if (op.adjustWidthTo != null && Math.abs(op.barMeasure.scrollWidth - cm.display.scroller.scrollWidth) > 1)
|
||||
updateScrollbars(cm);
|
||||
|
||||
if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
|
||||
|
||||
// Abort mouse wheel delta measurement, when scrolling explicitly
|
||||
|
@ -2092,12 +2200,14 @@
|
|||
|
||||
// Propagate the scroll position to the actual DOM scroller
|
||||
if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
|
||||
var top = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
|
||||
display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top;
|
||||
doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
|
||||
display.scrollbars.setScrollTop(doc.scrollTop);
|
||||
display.scroller.scrollTop = doc.scrollTop;
|
||||
}
|
||||
if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
|
||||
var left = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft));
|
||||
display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left;
|
||||
doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));
|
||||
display.scrollbars.setScrollLeft(doc.scrollLeft);
|
||||
display.scroller.scrollLeft = doc.scrollLeft;
|
||||
alignHorizontally(cm);
|
||||
}
|
||||
// If we need to scroll a specific position into view, do so.
|
||||
|
@ -2118,16 +2228,6 @@
|
|||
if (display.wrapper.offsetHeight)
|
||||
doc.scrollTop = cm.display.scroller.scrollTop;
|
||||
|
||||
// Apply workaround for two webkit bugs
|
||||
if (op.updatedDisplay && webkit) {
|
||||
if (cm.options.lineWrapping)
|
||||
checkForWebkitWidthBug(cm, op.barMeasure); // (Issue #2420)
|
||||
if (op.barMeasure.scrollWidth > op.barMeasure.clientWidth &&
|
||||
op.barMeasure.scrollWidth < op.barMeasure.clientWidth + 1 &&
|
||||
!hScrollbarTakesSpace(cm))
|
||||
updateScrollbars(cm); // (Issue #2562)
|
||||
}
|
||||
|
||||
// Fire change events, and delayed event handlers
|
||||
if (op.changeObjs)
|
||||
signal(cm, "changes", cm, op.changeObjs);
|
||||
|
@ -2486,6 +2586,7 @@
|
|||
// Reset the input to correspond to the selection (or to be empty,
|
||||
// when not typing and nothing is selected)
|
||||
function resetInput(cm, typing) {
|
||||
if (cm.display.contextMenuPending) return;
|
||||
var minimal, selected, doc = cm.doc;
|
||||
if (cm.somethingSelected()) {
|
||||
cm.display.prevInput = "";
|
||||
|
@ -2552,28 +2653,18 @@
|
|||
signal(cm, "scroll", cm);
|
||||
}
|
||||
});
|
||||
on(d.scrollbarV, "scroll", function() {
|
||||
if (d.scroller.clientHeight) setScrollTop(cm, d.scrollbarV.scrollTop);
|
||||
});
|
||||
on(d.scrollbarH, "scroll", function() {
|
||||
if (d.scroller.clientHeight) setScrollLeft(cm, d.scrollbarH.scrollLeft);
|
||||
});
|
||||
|
||||
// Listen to wheel events in order to try and update the viewport on time.
|
||||
on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
|
||||
on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
|
||||
|
||||
// Prevent clicks in the scrollbars from killing focus
|
||||
function reFocus() { if (cm.state.focused) setTimeout(bind(focusInput, cm), 0); }
|
||||
on(d.scrollbarH, "mousedown", reFocus);
|
||||
on(d.scrollbarV, "mousedown", reFocus);
|
||||
// Prevent wrapper from ever scrolling
|
||||
on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
|
||||
|
||||
on(d.input, "keyup", function(e) { onKeyUp.call(cm, e); });
|
||||
on(d.input, "input", function() {
|
||||
if (ie && ie_version >= 9 && cm.display.inputHasSelection) cm.display.inputHasSelection = null;
|
||||
fastPoll(cm);
|
||||
readInput(cm);
|
||||
});
|
||||
on(d.input, "keydown", operation(cm, onKeyDown));
|
||||
on(d.input, "keypress", operation(cm, onKeyPress));
|
||||
|
@ -2659,6 +2750,7 @@
|
|||
return;
|
||||
// Might be a text scaling operation, clear size caches.
|
||||
d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
|
||||
d.scrollbarsClipped = false;
|
||||
cm.setSize();
|
||||
}
|
||||
|
||||
|
@ -2667,7 +2759,7 @@
|
|||
// Return true when the given mouse event happened in a widget
|
||||
function eventInWidget(display, e) {
|
||||
for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
|
||||
if (!n || n.ignoreEvents || n.parentNode == display.sizer && n != display.mover) return true;
|
||||
if (!n || n.getAttribute("cm-ignore-events") == "true" || n.parentNode == display.sizer && n != display.mover) return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2678,11 +2770,8 @@
|
|||
// coordinates beyond the right of the text.
|
||||
function posFromMouse(cm, e, liberal, forRect) {
|
||||
var display = cm.display;
|
||||
if (!liberal) {
|
||||
var target = e_target(e);
|
||||
if (target == display.scrollbarH || target == display.scrollbarV ||
|
||||
target == display.scrollbarFiller || target == display.gutterFiller) return null;
|
||||
}
|
||||
if (!liberal && e_target(e).getAttribute("not-content") == "true") return null;
|
||||
|
||||
var x, y, space = display.lineSpace.getBoundingClientRect();
|
||||
// Fails unpredictably on IE[67] when mouse is dragged around quickly.
|
||||
try { x = e.clientX - space.left; y = e.clientY - space.top; }
|
||||
|
@ -2752,9 +2841,10 @@
|
|||
lastClick = {time: now, pos: start};
|
||||
}
|
||||
|
||||
var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey;
|
||||
var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
|
||||
if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
|
||||
type == "single" && sel.contains(start) > -1 && sel.somethingSelected())
|
||||
type == "single" && (contained = sel.contains(start)) > -1 &&
|
||||
!sel.ranges[contained].empty())
|
||||
leftButtonStartDrag(cm, e, start, modifier);
|
||||
else
|
||||
leftButtonSelect(cm, e, start, type, modifier);
|
||||
|
@ -2793,11 +2883,11 @@
|
|||
var display = cm.display, doc = cm.doc;
|
||||
e_preventDefault(e);
|
||||
|
||||
var ourRange, ourIndex, startSel = doc.sel;
|
||||
var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
|
||||
if (addNew && !e.shiftKey) {
|
||||
ourIndex = doc.sel.contains(start);
|
||||
if (ourIndex > -1)
|
||||
ourRange = doc.sel.ranges[ourIndex];
|
||||
ourRange = ranges[ourIndex];
|
||||
else
|
||||
ourRange = new Range(start, start);
|
||||
} else {
|
||||
|
@ -2829,12 +2919,15 @@
|
|||
ourIndex = 0;
|
||||
setSelection(doc, new Selection([ourRange], 0), sel_mouse);
|
||||
startSel = doc.sel;
|
||||
} else if (ourIndex > -1) {
|
||||
replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
|
||||
} else {
|
||||
ourIndex = doc.sel.ranges.length;
|
||||
setSelection(doc, normalizeSelection(doc.sel.ranges.concat([ourRange]), ourIndex),
|
||||
} else if (ourIndex == -1) {
|
||||
ourIndex = ranges.length;
|
||||
setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
|
||||
{scroll: false, origin: "*mouse"});
|
||||
} else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single") {
|
||||
setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0));
|
||||
startSel = doc.sel;
|
||||
} else {
|
||||
replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
|
||||
}
|
||||
|
||||
var lastPos = start;
|
||||
|
@ -3040,7 +3133,7 @@
|
|||
cm.doc.scrollTop = val;
|
||||
if (!gecko) updateDisplaySimple(cm, {top: val});
|
||||
if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
|
||||
if (cm.display.scrollbarV.scrollTop != val) cm.display.scrollbarV.scrollTop = val;
|
||||
cm.display.scrollbars.setScrollTop(val);
|
||||
if (gecko) updateDisplaySimple(cm);
|
||||
startWorker(cm, 100);
|
||||
}
|
||||
|
@ -3052,7 +3145,7 @@
|
|||
cm.doc.scrollLeft = val;
|
||||
alignHorizontally(cm);
|
||||
if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
|
||||
if (cm.display.scrollbarH.scrollLeft != val) cm.display.scrollbarH.scrollLeft = val;
|
||||
cm.display.scrollbars.setScrollLeft(val);
|
||||
}
|
||||
|
||||
// Since the delta values reported on mouse wheel events are
|
||||
|
@ -3076,11 +3169,22 @@
|
|||
else if (chrome) wheelPixelsPerUnit = -.7;
|
||||
else if (safari) wheelPixelsPerUnit = -1/3;
|
||||
|
||||
function onScrollWheel(cm, e) {
|
||||
var wheelEventDelta = function(e) {
|
||||
var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
|
||||
if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
|
||||
if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
|
||||
else if (dy == null) dy = e.wheelDelta;
|
||||
return {x: dx, y: dy};
|
||||
};
|
||||
CodeMirror.wheelEventPixels = function(e) {
|
||||
var delta = wheelEventDelta(e);
|
||||
delta.x *= wheelPixelsPerUnit;
|
||||
delta.y *= wheelPixelsPerUnit;
|
||||
return delta;
|
||||
};
|
||||
|
||||
function onScrollWheel(cm, e) {
|
||||
var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
|
||||
|
||||
var display = cm.display, scroll = display.scroller;
|
||||
// Quit if there's nothing to scroll here
|
||||
|
@ -3173,11 +3277,11 @@
|
|||
|
||||
function lookupKeyForEditor(cm, name, handle) {
|
||||
for (var i = 0; i < cm.state.keyMaps.length; i++) {
|
||||
var result = lookupKey(name, cm.state.keyMaps[i], handle);
|
||||
var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
|
||||
if (result) return result;
|
||||
}
|
||||
return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle))
|
||||
|| lookupKey(name, cm.options.keyMap, handle);
|
||||
return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
|
||||
|| lookupKey(name, cm.options.keyMap, handle, cm);
|
||||
}
|
||||
|
||||
var stopSeq = new Delayed;
|
||||
|
@ -3351,6 +3455,7 @@
|
|||
resetInput(cm);
|
||||
// Adds "Select all" to context menu in FF
|
||||
if (!cm.somethingSelected()) display.input.value = display.prevInput = " ";
|
||||
display.contextMenuPending = true;
|
||||
display.selForContextMenu = cm.doc.sel;
|
||||
clearTimeout(display.detectingSelectAll);
|
||||
|
||||
|
@ -3369,9 +3474,10 @@
|
|||
}
|
||||
}
|
||||
function rehide() {
|
||||
display.contextMenuPending = false;
|
||||
display.inputDiv.style.position = "relative";
|
||||
display.input.style.cssText = oldCSS;
|
||||
if (ie && ie_version < 9) display.scrollbarV.scrollTop = display.scroller.scrollTop = scrollPos;
|
||||
if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
|
||||
slowPoll(cm);
|
||||
|
||||
// Try to detect the user choosing select-all
|
||||
|
@ -3721,7 +3827,7 @@
|
|||
if (doScroll != null && !phantom) {
|
||||
var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
|
||||
(coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
|
||||
(coords.bottom - coords.top + scrollerCutOff) + "px; left: " +
|
||||
(coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " +
|
||||
coords.left + "px; width: 2px;");
|
||||
cm.display.lineSpace.appendChild(scrollNode);
|
||||
scrollNode.scrollIntoView(doScroll);
|
||||
|
@ -3750,8 +3856,9 @@
|
|||
setScrollLeft(cm, scrollPos.scrollLeft);
|
||||
if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
|
||||
}
|
||||
if (!changed) return coords;
|
||||
if (!changed) break;
|
||||
}
|
||||
return coords;
|
||||
}
|
||||
|
||||
// Scroll a given set of coordinates into view (immediately).
|
||||
|
@ -3769,7 +3876,7 @@
|
|||
var display = cm.display, snapMargin = textHeight(cm.display);
|
||||
if (y1 < 0) y1 = 0;
|
||||
var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
|
||||
var screen = display.scroller.clientHeight - scrollerCutOff, result = {};
|
||||
var screen = displayHeight(cm), result = {};
|
||||
if (y2 - y1 > screen) y2 = y1 + screen;
|
||||
var docBottom = cm.doc.height + paddingVert(display);
|
||||
var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
|
||||
|
@ -3781,7 +3888,7 @@
|
|||
}
|
||||
|
||||
var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
|
||||
var screenw = display.scroller.clientWidth - scrollerCutOff - display.gutters.offsetWidth;
|
||||
var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
|
||||
var tooWide = x2 - x1 > screenw;
|
||||
if (tooWide) x2 = x1 + screenw;
|
||||
if (x1 < 10)
|
||||
|
@ -3790,7 +3897,6 @@
|
|||
result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
|
||||
else if (x2 > screenw + screenleft - 3)
|
||||
result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4245,6 +4351,7 @@
|
|||
pos = cursorCoords(this, clipPos(this.doc, pos));
|
||||
var top = pos.bottom, left = pos.left;
|
||||
node.style.position = "absolute";
|
||||
node.setAttribute("cm-ignore-events", "true");
|
||||
display.sizer.appendChild(node);
|
||||
if (vert == "over") {
|
||||
top = pos.top;
|
||||
|
@ -4379,10 +4486,11 @@
|
|||
if (y != null) this.curOp.scrollTop = y;
|
||||
}),
|
||||
getScrollInfo: function() {
|
||||
var scroller = this.display.scroller, co = scrollerCutOff;
|
||||
var scroller = this.display.scroller;
|
||||
return {left: scroller.scrollLeft, top: scroller.scrollTop,
|
||||
height: scroller.scrollHeight - co, width: scroller.scrollWidth - co,
|
||||
clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
|
||||
height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
|
||||
width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
|
||||
clientHeight: displayHeight(this), clientWidth: displayWidth(this)};
|
||||
},
|
||||
|
||||
scrollIntoView: methodOp(function(range, margin) {
|
||||
|
@ -4524,7 +4632,13 @@
|
|||
cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
|
||||
cm.refresh();
|
||||
}, true);
|
||||
option("coverGutterNextToScrollbar", false, updateScrollbars, true);
|
||||
option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true);
|
||||
option("scrollbarStyle", "native", function(cm) {
|
||||
initScrollbars(cm);
|
||||
updateScrollbars(cm);
|
||||
cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
|
||||
cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
|
||||
}, true);
|
||||
option("lineNumbers", false, function(cm) {
|
||||
setGuttersForLineNumbers(cm.options);
|
||||
guttersChanged(cm);
|
||||
|
@ -4954,18 +5068,18 @@
|
|||
return keymap;
|
||||
};
|
||||
|
||||
var lookupKey = CodeMirror.lookupKey = function(key, map, handle) {
|
||||
var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) {
|
||||
map = getKeyMap(map);
|
||||
var found = map.call ? map.call(key) : map[key];
|
||||
var found = map.call ? map.call(key, context) : map[key];
|
||||
if (found === false) return "nothing";
|
||||
if (found === "...") return "multi";
|
||||
if (found != null && handle(found)) return "handled";
|
||||
|
||||
if (map.fallthrough) {
|
||||
if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
|
||||
return lookupKey(key, map.fallthrough, handle);
|
||||
return lookupKey(key, map.fallthrough, handle, context);
|
||||
for (var i = 0; i < map.fallthrough.length; i++) {
|
||||
var result = lookupKey(key, map.fallthrough[i], handle);
|
||||
var result = lookupKey(key, map.fallthrough[i], handle, context);
|
||||
if (result) return result;
|
||||
}
|
||||
}
|
||||
|
@ -5272,7 +5386,7 @@
|
|||
// Showing up as a widget implies collapsed (widget replaces text)
|
||||
marker.collapsed = true;
|
||||
marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
|
||||
if (!options.handleMouseEvents) marker.widgetNode.ignoreEvents = true;
|
||||
if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true");
|
||||
if (options.insertLeft) marker.widgetNode.insertLeft = true;
|
||||
}
|
||||
if (marker.collapsed) {
|
||||
|
@ -5316,7 +5430,7 @@
|
|||
if (updateMaxLine) cm.curOp.updateMaxLine = true;
|
||||
if (marker.collapsed)
|
||||
regChange(cm, from.line, to.line + 1);
|
||||
else if (marker.className || marker.title || marker.startStyle || marker.endStyle)
|
||||
else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
|
||||
for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
|
||||
if (marker.atomic) reCheckSelection(cm.doc);
|
||||
signalLater(cm, "markerAdded", cm, marker);
|
||||
|
@ -5896,8 +6010,11 @@
|
|||
if (mName) style = "m-" + (style ? mName + " " + style : mName);
|
||||
}
|
||||
if (!flattenSpans || curStyle != style) {
|
||||
if (curStart < stream.start) f(stream.start, curStyle);
|
||||
curStart = stream.start; curStyle = style;
|
||||
while (curStart < stream.start) {
|
||||
curStart = Math.min(stream.start, curStart + 50000);
|
||||
f(curStart, curStyle);
|
||||
}
|
||||
curStyle = style;
|
||||
}
|
||||
stream.start = stream.pos;
|
||||
}
|
||||
|
@ -6054,7 +6171,7 @@
|
|||
|
||||
// Build up the DOM representation for a single token, and add it to
|
||||
// the line map. Takes care to render special characters separately.
|
||||
function buildToken(builder, text, style, startStyle, endStyle, title) {
|
||||
function buildToken(builder, text, style, startStyle, endStyle, title, css) {
|
||||
if (!text) return;
|
||||
var special = builder.cm.options.specialChars, mustWrap = false;
|
||||
if (!special.test(text)) {
|
||||
|
@ -6093,11 +6210,11 @@
|
|||
builder.pos++;
|
||||
}
|
||||
}
|
||||
if (style || startStyle || endStyle || mustWrap) {
|
||||
if (style || startStyle || endStyle || mustWrap || css) {
|
||||
var fullStyle = style || "";
|
||||
if (startStyle) fullStyle += startStyle;
|
||||
if (endStyle) fullStyle += endStyle;
|
||||
var token = elt("span", [content], fullStyle);
|
||||
var token = elt("span", [content], fullStyle, css);
|
||||
if (title) token.title = title;
|
||||
return builder.content.appendChild(token);
|
||||
}
|
||||
|
@ -6156,11 +6273,11 @@
|
|||
return;
|
||||
}
|
||||
|
||||
var len = allText.length, pos = 0, i = 1, text = "", style;
|
||||
var len = allText.length, pos = 0, i = 1, text = "", style, css;
|
||||
var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
|
||||
for (;;) {
|
||||
if (nextChange == pos) { // Update current marker set
|
||||
spanStyle = spanEndStyle = spanStartStyle = title = "";
|
||||
spanStyle = spanEndStyle = spanStartStyle = title = css = "";
|
||||
collapsed = null; nextChange = Infinity;
|
||||
var foundBookmarks = [];
|
||||
for (var j = 0; j < spans.length; ++j) {
|
||||
|
@ -6168,6 +6285,7 @@
|
|||
if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
|
||||
if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
|
||||
if (m.className) spanStyle += " " + m.className;
|
||||
if (m.css) css = m.css;
|
||||
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
|
||||
if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
|
||||
if (m.title && !title) title = m.title;
|
||||
|
@ -6195,7 +6313,7 @@
|
|||
if (!collapsed) {
|
||||
var tokenText = end > upto ? text.slice(0, upto - pos) : text;
|
||||
builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
|
||||
spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title);
|
||||
spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
|
||||
}
|
||||
if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
|
||||
pos = end;
|
||||
|
@ -6622,7 +6740,7 @@
|
|||
});
|
||||
}),
|
||||
removeLineClass: docMethodOp(function(handle, where, cls) {
|
||||
return changeLine(this, handle, "class", function(line) {
|
||||
return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
|
||||
var prop = where == "text" ? "textClass"
|
||||
: where == "background" ? "bgClass"
|
||||
: where == "gutter" ? "gutterClass" : "wrapClass";
|
||||
|
@ -7278,7 +7396,7 @@
|
|||
// MISC UTILITIES
|
||||
|
||||
// Number of pixels added to scroller and sizer to hide scrollbar
|
||||
var scrollerCutOff = 30;
|
||||
var scrollerGap = 30;
|
||||
|
||||
// Returned or thrown by various protocols to signal 'I'm not
|
||||
// handling this'.
|
||||
|
@ -7504,7 +7622,6 @@
|
|||
on(window, "resize", function() {
|
||||
if (resizeTimer == null) resizeTimer = setTimeout(function() {
|
||||
resizeTimer = null;
|
||||
knownScrollbarWidth = null;
|
||||
forEachCodeMirror(onResize);
|
||||
}, 100);
|
||||
});
|
||||
|
@ -7525,16 +7642,6 @@
|
|||
return "draggable" in div || "dragDrop" in div;
|
||||
}();
|
||||
|
||||
var knownScrollbarWidth;
|
||||
function scrollbarWidth(measure) {
|
||||
if (knownScrollbarWidth != null) return knownScrollbarWidth;
|
||||
var test = elt("div", null, null, "width: 50px; height: 50px; overflow-x: scroll");
|
||||
removeChildrenAndAdd(measure, test);
|
||||
if (test.offsetWidth)
|
||||
knownScrollbarWidth = test.offsetHeight - test.clientHeight;
|
||||
return knownScrollbarWidth || 0;
|
||||
}
|
||||
|
||||
var zwspSupported;
|
||||
function zeroWidthElement(measure) {
|
||||
if (zwspSupported == null) {
|
||||
|
@ -7916,7 +8023,7 @@
|
|||
|
||||
// THE END
|
||||
|
||||
CodeMirror.version = "4.8.0";
|
||||
CodeMirror.version = "4.10.0";
|
||||
|
||||
return CodeMirror;
|
||||
});
|
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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); },
|
||||
|
@ -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);
|
|
@ -77,11 +77,11 @@
|
|||
{ keys: '<Up>', type: 'keyToKey', toKeys: 'k' },
|
||||
{ keys: '<Down>', type: 'keyToKey', toKeys: 'j' },
|
||||
{ keys: '<Space>', type: 'keyToKey', toKeys: 'l' },
|
||||
{ keys: '<BS>', type: 'keyToKey', toKeys: 'h' },
|
||||
{ keys: '<BS>', type: 'keyToKey', toKeys: 'h', context: 'normal'},
|
||||
{ keys: '<C-Space>', type: 'keyToKey', toKeys: 'W' },
|
||||
{ keys: '<C-BS>', type: 'keyToKey', toKeys: 'B' },
|
||||
{ keys: '<C-BS>', type: 'keyToKey', toKeys: 'B', context: 'normal' },
|
||||
{ keys: '<S-Space>', type: 'keyToKey', toKeys: 'w' },
|
||||
{ keys: '<S-BS>', type: 'keyToKey', toKeys: 'b' },
|
||||
{ keys: '<S-BS>', type: 'keyToKey', toKeys: 'b', context: 'normal' },
|
||||
{ keys: '<C-n>', type: 'keyToKey', toKeys: 'j' },
|
||||
{ keys: '<C-p>', type: 'keyToKey', toKeys: 'k' },
|
||||
{ keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>' },
|
||||
|
@ -229,55 +229,7 @@
|
|||
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
var modifierCodes = [16, 17, 18, 91];
|
||||
var specialKey = {Enter:'CR',Backspace:'BS',Delete:'Del'};
|
||||
var mac = /Mac/.test(navigator.platform);
|
||||
var Vim = function() {
|
||||
function lookupKey(e) {
|
||||
var keyCode = e.keyCode;
|
||||
if (modifierCodes.indexOf(keyCode) != -1) { return; }
|
||||
var hasModifier = e.ctrlKey || e.metaKey;
|
||||
var key = CodeMirror.keyNames[keyCode];
|
||||
key = specialKey[key] || key;
|
||||
var name = '';
|
||||
if (e.ctrlKey) { name += 'C-'; }
|
||||
if (e.altKey) { name += 'A-'; }
|
||||
if (mac && e.metaKey || (!hasModifier && e.shiftKey) && key.length < 2) {
|
||||
// Shift key bindings can only specified for special characters.
|
||||
return;
|
||||
} else if (e.shiftKey && !/^[A-Za-z]$/.test(key)) {
|
||||
name += 'S-';
|
||||
}
|
||||
if (key.length == 1) { key = key.toLowerCase(); }
|
||||
name += key;
|
||||
if (name.length > 1) { name = '<' + name + '>'; }
|
||||
return name;
|
||||
}
|
||||
// Keys with modifiers are handled using keydown due to limitations of
|
||||
// keypress event.
|
||||
function handleKeyDown(cm, e) {
|
||||
var name = lookupKey(e);
|
||||
if (!name) { return; }
|
||||
|
||||
CodeMirror.signal(cm, 'vim-keypress', name);
|
||||
if (CodeMirror.Vim.handleKey(cm, name, 'user')) {
|
||||
CodeMirror.e_stop(e);
|
||||
}
|
||||
}
|
||||
// Keys without modifiers are handled using keypress to work best with
|
||||
// non-standard keyboard layouts.
|
||||
function handleKeyPress(cm, e) {
|
||||
var code = e.charCode || e.keyCode;
|
||||
if (e.ctrlKey || e.metaKey || e.altKey ||
|
||||
e.shiftKey && code < 32) { return; }
|
||||
var name = String.fromCharCode(code);
|
||||
|
||||
CodeMirror.signal(cm, 'vim-keypress', name);
|
||||
if (CodeMirror.Vim.handleKey(cm, name, 'user')) {
|
||||
CodeMirror.e_stop(e);
|
||||
}
|
||||
}
|
||||
|
||||
function enterVimMode(cm) {
|
||||
cm.setOption('disableInput', true);
|
||||
cm.setOption('showCursorWhenSelecting', false);
|
||||
|
@ -285,8 +237,6 @@
|
|||
cm.on('cursorActivity', onCursorActivity);
|
||||
maybeInitVimState(cm);
|
||||
CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm));
|
||||
cm.on('keypress', handleKeyPress);
|
||||
cm.on('keydown', handleKeyDown);
|
||||
}
|
||||
|
||||
function leaveVimMode(cm) {
|
||||
|
@ -294,8 +244,6 @@
|
|||
cm.off('cursorActivity', onCursorActivity);
|
||||
CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm));
|
||||
cm.state.vim = null;
|
||||
cm.off('keypress', handleKeyPress);
|
||||
cm.off('keydown', handleKeyDown);
|
||||
}
|
||||
|
||||
function detachVimMap(cm, next) {
|
||||
|
@ -320,6 +268,60 @@
|
|||
else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption("keyMap")))
|
||||
cm.setOption("keyMap", "default");
|
||||
});
|
||||
|
||||
function cmKey(key, cm) {
|
||||
if (!cm) { return undefined; }
|
||||
var vimKey = cmKeyToVimKey(key);
|
||||
if (!vimKey) {
|
||||
return false;
|
||||
}
|
||||
var cmd = CodeMirror.Vim.findKey(cm, vimKey);
|
||||
if (typeof cmd == 'function') {
|
||||
CodeMirror.signal(cm, 'vim-keypress', vimKey);
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
var modifiers = {'Shift': 'S', 'Ctrl': 'C', 'Alt': 'A', 'Cmd': 'D', 'Mod': 'A'};
|
||||
var specialKeys = {Enter:'CR',Backspace:'BS',Delete:'Del'};
|
||||
function cmKeyToVimKey(key) {
|
||||
if (key.charAt(0) == '\'') {
|
||||
// Keypress character binding of format "'a'"
|
||||
return key.charAt(1);
|
||||
}
|
||||
var pieces = key.split('-');
|
||||
if (/-$/.test(key)) {
|
||||
// If the - key was typed, split will result in 2 extra empty strings
|
||||
// in the array. Replace them with 1 '-'.
|
||||
pieces.splice(-2, 2, '-');
|
||||
}
|
||||
var lastPiece = pieces[pieces.length - 1];
|
||||
if (pieces.length == 1 && pieces[0].length == 1) {
|
||||
// No-modifier bindings use literal character bindings above. Skip.
|
||||
return false;
|
||||
} else if (pieces.length == 2 && pieces[0] == 'Shift' && lastPiece.length == 1) {
|
||||
// Ignore Shift+char bindings as they should be handled by literal character.
|
||||
return false;
|
||||
}
|
||||
var hasCharacter = false;
|
||||
for (var i = 0; i < pieces.length; i++) {
|
||||
var piece = pieces[i];
|
||||
if (piece in modifiers) { pieces[i] = modifiers[piece]; }
|
||||
else { hasCharacter = true; }
|
||||
if (piece in specialKeys) { pieces[i] = specialKeys[piece]; }
|
||||
}
|
||||
if (!hasCharacter) {
|
||||
// Vim does not support modifier only keys.
|
||||
return false;
|
||||
}
|
||||
// TODO: Current bindings expect the character to be lower case, but
|
||||
// it looks like vim key notation uses upper case.
|
||||
if (isUpperCase(lastPiece)) {
|
||||
pieces[pieces.length - 1] = lastPiece.toLowerCase();
|
||||
}
|
||||
return '<' + pieces.join('-') + '>';
|
||||
}
|
||||
|
||||
function getOnPasteFn(cm) {
|
||||
var vim = cm.state.vim;
|
||||
if (!vim.onPasteFn) {
|
||||
|
@ -614,6 +616,8 @@
|
|||
// Testing hook.
|
||||
maybeInitVimState_: maybeInitVimState,
|
||||
|
||||
suppressErrorLogging: false,
|
||||
|
||||
InsertModeKey: InsertModeKey,
|
||||
map: function(lhs, rhs, ctx) {
|
||||
// Add user defined key bindings.
|
||||
|
@ -629,9 +633,23 @@
|
|||
exCommands[name]=func;
|
||||
exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'};
|
||||
},
|
||||
// This is the outermost function called by CodeMirror, after keys have
|
||||
// been mapped to their Vim equivalents.
|
||||
handleKey: function (cm, key, origin) {
|
||||
var command = this.findKey(cm, key, origin);
|
||||
if (typeof command === 'function') {
|
||||
return command();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* This is the outermost function called by CodeMirror, after keys have
|
||||
* been mapped to their Vim equivalents.
|
||||
*
|
||||
* Finds a command based on the key (and cached keys if there is a
|
||||
* multi-key sequence). Returns `undefined` if no key is matched, a noop
|
||||
* function if a partial match is found (multi-key), and a function to
|
||||
* execute the bound command if a a key is matched. The function always
|
||||
* returns true.
|
||||
*/
|
||||
findKey: function(cm, key, origin) {
|
||||
var vim = maybeInitVimState(cm);
|
||||
function handleMacroRecording() {
|
||||
var macroModeState = vimGlobalState.macroModeState;
|
||||
|
@ -697,13 +715,7 @@
|
|||
cm.replaceRange('', offsetCursor(here, 0, -(keys.length - 1)), here, '+input');
|
||||
}
|
||||
clearInputState(cm);
|
||||
var command = match.command;
|
||||
if (command.type == 'keyToKey') {
|
||||
doKeyToKey(command.toKeys);
|
||||
} else {
|
||||
commandDispatcher.processCommand(cm, vim, command);
|
||||
}
|
||||
return true;
|
||||
return match.command;
|
||||
}
|
||||
|
||||
function handleKeyNonInsertMode() {
|
||||
|
@ -721,31 +733,46 @@
|
|||
else if (match.type == 'partial') { return true; }
|
||||
|
||||
vim.inputState.keyBuffer = '';
|
||||
var command = match.command;
|
||||
var keysMatcher = /^(\d*)(.*)$/.exec(keys);
|
||||
if (keysMatcher[1] && keysMatcher[1] != '0') {
|
||||
vim.inputState.pushRepeatDigit(keysMatcher[1]);
|
||||
}
|
||||
return match.command;
|
||||
}
|
||||
|
||||
var command;
|
||||
if (vim.insertMode) { command = handleKeyInsertMode(); }
|
||||
else { command = handleKeyNonInsertMode(); }
|
||||
if (command === false) {
|
||||
return undefined;
|
||||
} else if (command === true) {
|
||||
// TODO: Look into using CodeMirror's multi-key handling.
|
||||
// Return no-op since we are caching the key. Counts as handled, but
|
||||
// don't want act on it just yet.
|
||||
return function() {};
|
||||
} else {
|
||||
return function() {
|
||||
return cm.operation(function() {
|
||||
cm.curOp.isVimOp = true;
|
||||
try {
|
||||
if (command.type == 'keyToKey') {
|
||||
doKeyToKey(command.toKeys);
|
||||
} else {
|
||||
commandDispatcher.processCommand(cm, vim, command);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return cm.operation(function() {
|
||||
cm.curOp.isVimOp = true;
|
||||
try {
|
||||
if (vim.insertMode) { return handleKeyInsertMode(); }
|
||||
else { return handleKeyNonInsertMode(); }
|
||||
} catch (e) {
|
||||
// clear VIM state in case it's in a bad state.
|
||||
cm.state.vim = undefined;
|
||||
maybeInitVimState(cm);
|
||||
if (!CodeMirror.Vim.suppressErrorLogging) {
|
||||
console['log'](e);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
}
|
||||
},
|
||||
handleEx: function(cm, input) {
|
||||
exCommandDispatcher.processCommand(cm, input);
|
||||
|
@ -1306,7 +1333,9 @@
|
|||
newHead = copyCursor(origHead);
|
||||
}
|
||||
if (vim.visualMode) {
|
||||
if (!(vim.visualBlock && newHead.ch === Infinity)) {
|
||||
newHead = clipCursorToContent(cm, newHead, vim.visualBlock);
|
||||
}
|
||||
if (newAnchor) {
|
||||
newAnchor = clipCursorToContent(cm, newAnchor, true);
|
||||
}
|
||||
|
@ -1610,20 +1639,8 @@
|
|||
return cm.findPosV(curStart, (motionArgs.forward ? repeat : -repeat), 'page');
|
||||
},
|
||||
moveByParagraph: function(cm, head, motionArgs) {
|
||||
var line = head.line;
|
||||
var repeat = motionArgs.repeat;
|
||||
var inc = motionArgs.forward ? 1 : -1;
|
||||
for (var i = 0; i < repeat; i++) {
|
||||
if ((!motionArgs.forward && line === cm.firstLine() ) ||
|
||||
(motionArgs.forward && line == cm.lastLine())) {
|
||||
break;
|
||||
}
|
||||
line += inc;
|
||||
while (line !== cm.firstLine() && line != cm.lastLine() && cm.getLine(line)) {
|
||||
line += inc;
|
||||
}
|
||||
}
|
||||
return Pos(line, 0);
|
||||
var dir = motionArgs.forward ? 1 : -1;
|
||||
return findParagraph(cm, head, motionArgs.repeat, dir);
|
||||
},
|
||||
moveByScroll: function(cm, head, motionArgs, vim) {
|
||||
var scrollbox = cm.getScrollInfo();
|
||||
|
@ -1723,7 +1740,7 @@
|
|||
return Pos(lineNum,
|
||||
findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum)));
|
||||
},
|
||||
textObjectManipulation: function(cm, head, motionArgs) {
|
||||
textObjectManipulation: function(cm, head, motionArgs, vim) {
|
||||
// TODO: lots of possible exceptions that can be thrown here. Try da(
|
||||
// outside of a () block.
|
||||
|
||||
|
@ -1761,6 +1778,16 @@
|
|||
} else if (character === 'w') {
|
||||
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
|
||||
false /** bigWord */);
|
||||
} else if (character === 'p') {
|
||||
tmp = findParagraph(cm, head, motionArgs.repeat, 0, inclusive);
|
||||
motionArgs.linewise = true;
|
||||
if (vim.visualMode) {
|
||||
if (!vim.visualLine) { vim.visualLine = true; }
|
||||
} else {
|
||||
var operatorArgs = vim.inputState.operatorArgs;
|
||||
if (operatorArgs) { operatorArgs.linewise = true; }
|
||||
tmp.end.line--;
|
||||
}
|
||||
} else {
|
||||
// No text object defined for this, don't move.
|
||||
return null;
|
||||
|
@ -3268,6 +3295,54 @@
|
|||
return idx;
|
||||
}
|
||||
|
||||
function findParagraph(cm, head, repeat, dir, inclusive) {
|
||||
var line = head.line;
|
||||
var min = cm.firstLine();
|
||||
var max = cm.lastLine();
|
||||
var start, end, i = line;
|
||||
function isEmpty(i) { return !cm.getLine(i); }
|
||||
function isBoundary(i, dir, any) {
|
||||
if (any) { return isEmpty(i) != isEmpty(i + dir); }
|
||||
return !isEmpty(i) && isEmpty(i + dir);
|
||||
}
|
||||
if (dir) {
|
||||
while (min <= i && i <= max && repeat > 0) {
|
||||
if (isBoundary(i, dir)) { repeat--; }
|
||||
i += dir;
|
||||
}
|
||||
return new Pos(i, 0);
|
||||
}
|
||||
|
||||
var vim = cm.state.vim;
|
||||
if (vim.visualLine && isBoundary(line, 1, true)) {
|
||||
var anchor = vim.sel.anchor;
|
||||
if (isBoundary(anchor.line, -1, true)) {
|
||||
if (!inclusive || anchor.line != line) {
|
||||
line += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
var startState = isEmpty(line);
|
||||
for (i = line; i <= max && repeat; i++) {
|
||||
if (isBoundary(i, 1, true)) {
|
||||
if (!inclusive || isEmpty(i) != startState) {
|
||||
repeat--;
|
||||
}
|
||||
}
|
||||
}
|
||||
end = new Pos(i, 0);
|
||||
// select boundary before paragraph for the last one
|
||||
if (i > max && !startState) { startState = true; }
|
||||
else { inclusive = false; }
|
||||
for (i = line; i > min; i--) {
|
||||
if (!inclusive || isEmpty(i) == startState || i == line) {
|
||||
if (isBoundary(i, -1, true)) { break; }
|
||||
}
|
||||
}
|
||||
start = new Pos(i, 0);
|
||||
return { start: start, end: end };
|
||||
}
|
||||
|
||||
// TODO: perhaps this finagling of start and end positions belonds
|
||||
// in codmirror/replaceRange?
|
||||
function selectCompanionObject(cm, head, symb, inclusive) {
|
||||
|
@ -4476,7 +4551,8 @@
|
|||
|
||||
CodeMirror.keyMap.vim = {
|
||||
attach: attachVimMap,
|
||||
detach: detachVimMap
|
||||
detach: detachVimMap,
|
||||
call: cmKey
|
||||
};
|
||||
|
||||
function exitInsertMode(cm) {
|
||||
|
@ -4549,20 +4625,16 @@
|
|||
},
|
||||
fallthrough: ['default'],
|
||||
attach: attachVimMap,
|
||||
detach: detachVimMap
|
||||
};
|
||||
|
||||
CodeMirror.keyMap['await-second'] = {
|
||||
fallthrough: ['vim-insert'],
|
||||
attach: attachVimMap,
|
||||
detach: detachVimMap
|
||||
detach: detachVimMap,
|
||||
call: cmKey
|
||||
};
|
||||
|
||||
CodeMirror.keyMap['vim-replace'] = {
|
||||
'Backspace': 'goCharLeft',
|
||||
fallthrough: ['vim-insert'],
|
||||
attach: attachVimMap,
|
||||
detach: detachVimMap
|
||||
detach: detachVimMap,
|
||||
call: cmKey
|
||||
};
|
||||
|
||||
function executeMacroRegister(cm, vim, macroModeState, registerName) {
|
|
@ -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) {
|
||||
|
@ -191,7 +191,7 @@ CodeMirror.defineMode("coffeescript", function(conf) {
|
|||
}
|
||||
}
|
||||
if (singleline) {
|
||||
if (conf.mode.singleLineStringErrors) {
|
||||
if (parserConf.singleLineStringErrors) {
|
||||
outclass = ERRORCLASS;
|
||||
} else {
|
||||
state.tokenize = tokenBase;
|
|
@ -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'`,@()\[\]";]/;
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
|
@ -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>
|
||||
|
@ -60,7 +63,9 @@ code {
|
|||
}
|
||||
</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>
|
|
@ -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 {
|
|
@ -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");
|
||||
});
|
|
@ -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>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue