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 holds the current wide version.
|
||||||
WideVersion = "1.1.0"
|
WideVersion = "1.1.0"
|
||||||
// CodeMirrorVer holds the current editor version.
|
// CodeMirrorVer holds the current editor version.
|
||||||
CodeMirrorVer = "4.8"
|
CodeMirrorVer = "4.10"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configuration.
|
// Configuration.
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
CodeMirror.e_stop(e);
|
CodeMirror.e_stop(e);
|
||||||
close();
|
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);
|
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) {
|
})(function(CodeMirror) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var listRE = /^(\s*)([> ]+|[*+-]|(\d+)\.)(\s+)/,
|
var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)\.)(\s*)/,
|
||||||
emptyListRE = /^(\s*)([> ]+|[*+-]|(\d+)\.)(\s*)$/,
|
emptyListRE = /^(\s*)(>[> ]*|[*+-]|(\d+)\.)(\s*)$/,
|
||||||
unorderedBullets = "*+-";
|
unorderedListRE = /[*+-]\s/;
|
||||||
|
|
||||||
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
|
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
|
||||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
var indent = match[1], after = match[4];
|
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]
|
? match[2]
|
||||||
: (parseInt(match[3], 10) + 1) + ".";
|
: (parseInt(match[3], 10) + 1) + ".";
|
||||||
|
|
|
@ -17,8 +17,7 @@
|
||||||
var word = options && options.word || WORD;
|
var word = options && options.word || WORD;
|
||||||
var range = options && options.range || RANGE;
|
var range = options && options.range || RANGE;
|
||||||
var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
|
var cur = editor.getCursor(), curLine = editor.getLine(cur.line);
|
||||||
var start = cur.ch, end = start;
|
var end = cur.ch, start = end;
|
||||||
while (end < curLine.length && word.test(curLine.charAt(end))) ++end;
|
|
||||||
while (start && word.test(curLine.charAt(start - 1))) --start;
|
while (start && word.test(curLine.charAt(start - 1))) --start;
|
||||||
var curWord = start != end && curLine.slice(start, end);
|
var curWord = start != end && curLine.slice(start, end);
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
var inner = CodeMirror.innerMode(cm.getMode(), token.state);
|
var inner = CodeMirror.innerMode(cm.getMode(), token.state);
|
||||||
if (inner.mode.name != "css") return;
|
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)) {
|
if (/[^\w$_-]/.test(word)) {
|
||||||
word = ""; start = end = cur.ch;
|
word = ""; start = end = cur.ch;
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
(function(mod) {
|
(function(mod) {
|
||||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
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
|
else if (typeof define == "function" && define.amd) // AMD
|
||||||
define(["../../lib/codemirror", "./xml-hint"], mod);
|
define(["../../lib/codemirror", "./xml-hint"], mod);
|
||||||
else // Plain browser env
|
else // Plain browser env
|
|
@ -30,15 +30,20 @@
|
||||||
|
|
||||||
function scriptHint(editor, keywords, getToken, options) {
|
function scriptHint(editor, keywords, getToken, options) {
|
||||||
// Find the token at the cursor
|
// 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;
|
if (/\b(?:string|comment)\b/.test(token.type)) return;
|
||||||
token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;
|
token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;
|
||||||
|
|
||||||
// If it's not a 'word-style' token, ignore the token.
|
// If it's not a 'word-style' token, ignore the token.
|
||||||
if (!/^[\w$_]*$/.test(token.string)) {
|
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};
|
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.
|
// If it is a property, find out what it is a property of.
|
||||||
while (tprop.type == "property") {
|
while (tprop.type == "property") {
|
||||||
tprop = getToken(editor, Pos(cur.line, tprop.start));
|
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 (overlapX > 0) {
|
||||||
if (box.right - box.left > winW) {
|
if (box.right - box.left > winW) {
|
||||||
hints.style.width = (winW - 5) + "px";
|
hints.style.width = (winW - 5) + "px";
|
|
@ -44,9 +44,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function nameCompletion(result, editor) {
|
function nameCompletion(cur, token, result, editor) {
|
||||||
var cur = editor.getCursor();
|
|
||||||
var token = editor.getTokenAt(cur);
|
|
||||||
var useBacktick = (token.string.charAt(0) == "`");
|
var useBacktick = (token.string.charAt(0) == "`");
|
||||||
var string = token.string.substr(1);
|
var string = token.string.substr(1);
|
||||||
var prevToken = editor.getTokenAt(Pos(cur.line, token.start));
|
var prevToken = editor.getTokenAt(Pos(cur.line, token.start));
|
||||||
|
@ -173,6 +171,11 @@
|
||||||
var cur = editor.getCursor();
|
var cur = editor.getCursor();
|
||||||
var result = [];
|
var result = [];
|
||||||
var token = editor.getTokenAt(cur), start, end, search;
|
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*$/)) {
|
if (token.string.match(/^[.`\w@]\w*$/)) {
|
||||||
search = token.string;
|
search = token.string;
|
||||||
start = token.start;
|
start = token.start;
|
||||||
|
@ -182,7 +185,7 @@
|
||||||
search = "";
|
search = "";
|
||||||
}
|
}
|
||||||
if (search.charAt(0) == "." || search.charAt(0) == "`") {
|
if (search.charAt(0) == "." || search.charAt(0) == "`") {
|
||||||
nameCompletion(result, editor);
|
nameCompletion(cur, token, result, editor);
|
||||||
} else {
|
} else {
|
||||||
addMatches(result, search, tables, function(w) {return w;});
|
addMatches(result, search, tables, function(w) {return w;});
|
||||||
addMatches(result, search, defaultTable, function(w) {return w;});
|
addMatches(result, search, defaultTable, function(w) {return w;});
|
|
@ -18,10 +18,9 @@
|
||||||
var quote = (options && options.quoteChar) || '"';
|
var quote = (options && options.quoteChar) || '"';
|
||||||
if (!tags) return;
|
if (!tags) return;
|
||||||
var cur = cm.getCursor(), token = cm.getTokenAt(cur);
|
var cur = cm.getCursor(), token = cm.getTokenAt(cur);
|
||||||
if (/^<\/?$/.test(token.string) && token.end == cur.ch) {
|
if (token.end > cur.ch) {
|
||||||
var nextToken = cm.getTokenAt(Pos(cur.line, cur.ch + 1));
|
token.end = cur.ch;
|
||||||
if (nextToken.start == cur.ch && /\btag\b/.test(nextToken.type))
|
token.string = token.string.slice(0, cur.ch - token.start);
|
||||||
token = nextToken;
|
|
||||||
}
|
}
|
||||||
var inner = CodeMirror.innerMode(cm.getMode(), token.state);
|
var inner = CodeMirror.innerMode(cm.getMode(), token.state);
|
||||||
if (inner.mode.name != "xml") return;
|
if (inner.mode.name != "xml") return;
|
|
@ -96,3 +96,17 @@
|
||||||
.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; }
|
.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-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-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",
|
insert: "CodeMirror-merge-r-inserted",
|
||||||
del: "CodeMirror-merge-r-deleted",
|
del: "CodeMirror-merge-r-deleted",
|
||||||
connect: "CodeMirror-merge-r-connect"};
|
connect: "CodeMirror-merge-r-connect"};
|
||||||
|
if (mv.options.connect == "align")
|
||||||
|
this.aligners = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
DiffView.prototype = {
|
DiffView.prototype = {
|
||||||
|
@ -81,7 +83,7 @@
|
||||||
updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes);
|
updateMarks(dv.edit, dv.diff, edit, DIFF_INSERT, dv.classes);
|
||||||
updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes);
|
updateMarks(dv.orig, dv.diff, orig, DIFF_DELETE, dv.classes);
|
||||||
}
|
}
|
||||||
drawConnectors(dv);
|
makeConnections(dv);
|
||||||
}
|
}
|
||||||
function set(slow) {
|
function set(slow) {
|
||||||
clearTimeout(debounceChange);
|
clearTimeout(debounceChange);
|
||||||
|
@ -108,10 +110,10 @@
|
||||||
|
|
||||||
function registerScroll(dv) {
|
function registerScroll(dv) {
|
||||||
dv.edit.on("scroll", function() {
|
dv.edit.on("scroll", function() {
|
||||||
syncScroll(dv, DIFF_INSERT) && drawConnectors(dv);
|
syncScroll(dv, DIFF_INSERT) && makeConnections(dv);
|
||||||
});
|
});
|
||||||
dv.orig.on("scroll", function() {
|
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)
|
// (to prevent feedback loops)
|
||||||
if (editor.state.scrollSetBy == dv && (editor.state.scrollSetAt || 0) + 50 > now) return false;
|
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 mid = editor.lineAtHeight(midY, "local");
|
||||||
var around = chunkBoundariesAround(dv.diff, mid, type == DIFF_INSERT);
|
var around = chunkBoundariesAround(dv.diff, mid, type == DIFF_INSERT);
|
||||||
var off = getOffsets(editor, type == DIFF_INSERT ? around.edit : around.orig);
|
var off = getOffsets(editor, type == DIFF_INSERT ? around.edit : around.orig);
|
||||||
|
@ -145,6 +151,7 @@
|
||||||
if (botDistOther > botDist && (mix = botDist / halfScreen) < 1)
|
if (botDistOther > botDist && (mix = botDist / halfScreen) < 1)
|
||||||
targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix);
|
targetPos = targetPos * mix + (otherInfo.height - otherInfo.clientHeight - botDist) * (1 - mix);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
other.scrollTo(sInfo.left, targetPos);
|
other.scrollTo(sInfo.left, targetPos);
|
||||||
other.state.scrollSetAt = now;
|
other.state.scrollSetAt = now;
|
||||||
|
@ -161,7 +168,7 @@
|
||||||
|
|
||||||
function setScrollLock(dv, val, action) {
|
function setScrollLock(dv, val, action) {
|
||||||
dv.lockScroll = val;
|
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";
|
dv.lockButton.innerHTML = val ? "\u21db\u21da" : "\u21db \u21da";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,9 +256,20 @@
|
||||||
|
|
||||||
// Updating the gap between editor and original
|
// Updating the gap between editor and original
|
||||||
|
|
||||||
function drawConnectors(dv) {
|
function makeConnections(dv) {
|
||||||
if (!dv.showDifferences) return;
|
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) {
|
if (dv.svg) {
|
||||||
clear(dv.svg);
|
clear(dv.svg);
|
||||||
var w = dv.gap.offsetWidth;
|
var w = dv.gap.offsetWidth;
|
||||||
|
@ -259,15 +277,30 @@
|
||||||
}
|
}
|
||||||
if (dv.copyButtons) clear(dv.copyButtons);
|
if (dv.copyButtons) clear(dv.copyButtons);
|
||||||
|
|
||||||
var flip = dv.type == "left";
|
|
||||||
var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport();
|
var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport();
|
||||||
var sTopEdit = dv.edit.getScrollInfo().top, sTopOrig = dv.orig.getScrollInfo().top;
|
var sTopEdit = dv.edit.getScrollInfo().top, sTopOrig = dv.orig.getScrollInfo().top;
|
||||||
iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) {
|
iterateChunks(dv.diff, function(topOrig, botOrig, topEdit, botEdit) {
|
||||||
if (topEdit > vpEdit.to || botEdit < vpEdit.from ||
|
if (topEdit <= vpEdit.to && botEdit >= vpEdit.from &&
|
||||||
topOrig > vpOrig.to || botOrig < vpOrig.from)
|
topOrig <= vpOrig.to && botOrig >= vpOrig.from)
|
||||||
return;
|
drawConnectorsForChunk(dv, topOrig, botOrig, topEdit, botEdit, sTopOrig, sTopEdit, w);
|
||||||
var topLpx = dv.orig.heightAtLine(topOrig, "local") - sTopOrig, top = topLpx;
|
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) {
|
if (dv.svg) {
|
||||||
|
var topLpx = top;
|
||||||
var topRpx = dv.edit.heightAtLine(topEdit, "local") - sTopEdit;
|
var topRpx = dv.edit.heightAtLine(topEdit, "local") - sTopEdit;
|
||||||
if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; }
|
if (flip) { var tmp = topLpx; topLpx = topRpx; topRpx = tmp; }
|
||||||
var botLpx = dv.orig.heightAtLine(botOrig, "local") - sTopOrig;
|
var botLpx = dv.orig.heightAtLine(botOrig, "local") - sTopOrig;
|
||||||
|
@ -297,7 +330,29 @@
|
||||||
dv.type == "right" ? copyReverse.style.left = "2px" : copyReverse.style.right = "2px";
|
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) {
|
function copyChunk(dv, to, from, chunk) {
|
||||||
|
@ -313,6 +368,13 @@
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight;
|
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 hasLeft = origLeft != null, hasRight = origRight != null;
|
||||||
var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0);
|
var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0);
|
||||||
var wrap = [], left = this.left = null, right = this.right = null;
|
var wrap = [], left = this.left = null, right = this.right = null;
|
||||||
|
@ -344,9 +406,12 @@
|
||||||
if (left) left.init(leftPane, origLeft, options);
|
if (left) left.init(leftPane, origLeft, options);
|
||||||
if (right) right.init(rightPane, origRight, options);
|
if (right) right.init(rightPane, origRight, options);
|
||||||
|
|
||||||
|
if (options.collapseIdentical)
|
||||||
|
collapseIdenticalStretches(left || right, options.collapseIdentical);
|
||||||
|
|
||||||
var onResize = function() {
|
var onResize = function() {
|
||||||
if (left) drawConnectors(left);
|
if (left) makeConnections(left);
|
||||||
if (right) drawConnectors(right);
|
if (right) makeConnections(right);
|
||||||
};
|
};
|
||||||
CodeMirror.on(window, "resize", onResize);
|
CodeMirror.on(window, "resize", onResize);
|
||||||
var resizeInterval = setInterval(function() {
|
var resizeInterval = setInterval(function() {
|
||||||
|
@ -374,10 +439,12 @@
|
||||||
});
|
});
|
||||||
gapElts.unshift(dv.copyButtons);
|
gapElts.unshift(dv.copyButtons);
|
||||||
}
|
}
|
||||||
|
if (dv.mv.options.connect != "align") {
|
||||||
var svg = document.createElementNS && document.createElementNS(svgNS, "svg");
|
var svg = document.createElementNS && document.createElementNS(svgNS, "svg");
|
||||||
if (svg && !svg.createSVGRect) svg = null;
|
if (svg && !svg.createSVGRect) svg = null;
|
||||||
dv.svg = svg;
|
dv.svg = svg;
|
||||||
if (svg) gapElts.push(svg);
|
if (svg) gapElts.push(svg);
|
||||||
|
}
|
||||||
|
|
||||||
return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap");
|
return dv.gap = elt("div", gapElts, "CodeMirror-merge-gap");
|
||||||
}
|
}
|
||||||
|
@ -489,6 +556,46 @@
|
||||||
return {edit: {before: beforeE, after: afterE}, orig: {before: beforeO, after: afterO}};
|
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
|
// General utilities
|
||||||
|
|
||||||
function elt(tag, content, className, style) {
|
function elt(tag, content, className, style) {
|
|
@ -11,9 +11,9 @@
|
||||||
})(function(CodeMirror) {
|
})(function(CodeMirror) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
CodeMirror.defineSimpleMode = function(name, states, props) {
|
CodeMirror.defineSimpleMode = function(name, states) {
|
||||||
CodeMirror.defineMode(name, function(config) {
|
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];
|
var pos = state.indent.length - 1, rules = states[state.state];
|
||||||
scan: for (;;) {
|
scan: for (;;) {
|
||||||
for (var i = 0; i < rules.length; i++) {
|
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 (m && m[0]) {
|
||||||
if (rule.data.dedent && rule.data.dedentIfLineStart !== false) pos--;
|
pos--;
|
||||||
if (rule.next || rule.push) rules = states[rule.next || rule.push];
|
if (rule.next || rule.push) rules = states[rule.next || rule.push];
|
||||||
textAfter = textAfter.slice(m[0].length);
|
textAfter = textAfter.slice(m[0].length);
|
||||||
continue scan;
|
continue scan;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return pos < 0 ? 0 : state.indent[pos];
|
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) {
|
function parseQuery(query) {
|
||||||
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
|
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
|
||||||
if (isRE) {
|
if (isRE) {
|
||||||
query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i");
|
try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
|
||||||
if (query.test("")) query = /x^/;
|
catch(e) {} // Not a regular expression after all, do a string search
|
||||||
} else if (query == "") {
|
|
||||||
query = /x^/;
|
|
||||||
}
|
}
|
||||||
|
if (typeof query == "string" ? query == "" : query.test(""))
|
||||||
|
query = /x^/;
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
var queryDialog =
|
var queryDialog =
|
||||||
|
@ -82,6 +82,10 @@
|
||||||
cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
|
cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
|
||||||
state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
|
state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
|
||||||
cm.addOverlay(state.overlay);
|
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();
|
state.posFrom = state.posTo = cm.getCursor();
|
||||||
findNext(cm, rev);
|
findNext(cm, rev);
|
||||||
});
|
});
|
||||||
|
@ -103,6 +107,7 @@
|
||||||
if (!state.query) return;
|
if (!state.query) return;
|
||||||
state.query = null;
|
state.query = null;
|
||||||
cm.removeOverlay(state.overlay);
|
cm.removeOverlay(state.overlay);
|
||||||
|
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
|
||||||
});}
|
});}
|
||||||
|
|
||||||
var replaceQueryDialog =
|
var replaceQueryDialog =
|
|
@ -106,7 +106,9 @@
|
||||||
cm.showHint({hint: this.getHint});
|
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); },
|
updateArgHints: function(cm) { updateArgHints(this, cm); },
|
||||||
|
|
||||||
|
@ -239,8 +241,8 @@
|
||||||
|
|
||||||
// Type queries
|
// Type queries
|
||||||
|
|
||||||
function showType(ts, cm, pos, c) {
|
function showContextInfo(ts, cm, pos, queryName, c) {
|
||||||
ts.request(cm, "type", function(error, data) {
|
ts.request(cm, queryName, function(error, data) {
|
||||||
if (error) return showError(ts, cm, error);
|
if (error) return showError(ts, cm, error);
|
||||||
if (ts.options.typeTip) {
|
if (ts.options.typeTip) {
|
||||||
var tip = ts.options.typeTip(data);
|
var tip = ts.options.typeTip(data);
|
|
@ -5,10 +5,6 @@
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
height: 300px;
|
height: 300px;
|
||||||
}
|
}
|
||||||
.CodeMirror-scroll {
|
|
||||||
/* Set scrolling behaviour here */
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* PADDING */
|
/* PADDING */
|
||||||
|
|
||||||
|
@ -151,6 +147,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
||||||
}
|
}
|
||||||
|
|
||||||
.CodeMirror-scroll {
|
.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 */
|
/* 30px is the magic margin used to hide the element's real scrollbars */
|
||||||
/* See overflow: hidden in .CodeMirror */
|
/* See overflow: hidden in .CodeMirror */
|
||||||
margin-bottom: -30px; margin-right: -30px;
|
margin-bottom: -30px; margin-right: -30px;
|
||||||
|
@ -195,7 +192,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
||||||
|
|
||||||
.CodeMirror-gutters {
|
.CodeMirror-gutters {
|
||||||
position: absolute; left: 0; top: 0;
|
position: absolute; left: 0; top: 0;
|
||||||
padding-bottom: 30px;
|
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
.CodeMirror-gutter {
|
.CodeMirror-gutter {
|
||||||
|
@ -203,9 +199,8 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
||||||
height: 100%;
|
height: 100%;
|
||||||
-moz-box-sizing: content-box;
|
-moz-box-sizing: content-box;
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
padding-bottom: 30px;
|
|
||||||
margin-bottom: -32px;
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
margin-bottom: -30px;
|
||||||
/* Hack to make IE7 behave */
|
/* Hack to make IE7 behave */
|
||||||
*zoom:1;
|
*zoom:1;
|
||||||
*display:inline;
|
*display:inline;
|
||||||
|
@ -261,10 +256,6 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
||||||
|
|
||||||
.CodeMirror-widget {}
|
.CodeMirror-widget {}
|
||||||
|
|
||||||
.CodeMirror-wrap .CodeMirror-scroll {
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.CodeMirror-measure {
|
.CodeMirror-measure {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
|
@ -77,6 +77,7 @@
|
||||||
if (options.lineWrapping)
|
if (options.lineWrapping)
|
||||||
this.display.wrapper.className += " CodeMirror-wrap";
|
this.display.wrapper.className += " CodeMirror-wrap";
|
||||||
if (options.autofocus && !mobile) focusInput(this);
|
if (options.autofocus && !mobile) focusInput(this);
|
||||||
|
initScrollbars(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
keyMaps: [], // stores maps added by addKeyMap
|
keyMaps: [], // stores maps added by addKeyMap
|
||||||
|
@ -137,14 +138,13 @@
|
||||||
|
|
||||||
// Wraps and hides input textarea
|
// Wraps and hides input textarea
|
||||||
d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
|
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.
|
// Covers bottom-right square when both scrollbars are present.
|
||||||
d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
|
d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
|
||||||
|
d.scrollbarFiller.setAttribute("not-content", "true");
|
||||||
// Covers bottom of gutter when coverGutterNextToScrollbar is on
|
// Covers bottom of gutter when coverGutterNextToScrollbar is on
|
||||||
// and h scrollbar is present.
|
// and h scrollbar is present.
|
||||||
d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
|
d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
|
||||||
|
d.gutterFiller.setAttribute("not-content", "true");
|
||||||
// Will contain the actual code, positioned to cover the viewport.
|
// Will contain the actual code, positioned to cover the viewport.
|
||||||
d.lineDiv = elt("div", null, "CodeMirror-code");
|
d.lineDiv = elt("div", null, "CodeMirror-code");
|
||||||
// Elements are added to these to represent selection and cursors.
|
// 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");
|
d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
|
||||||
// Set to the height of the document, allowing scrolling.
|
// Set to the height of the document, allowing scrolling.
|
||||||
d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
|
d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
|
||||||
|
d.sizerWidth = null;
|
||||||
// Behavior of elts with overflow: auto and padding is
|
// Behavior of elts with overflow: auto and padding is
|
||||||
// inconsistent across browsers. This is used to ensure the
|
// inconsistent across browsers. This is used to ensure the
|
||||||
// scrollable area is big enough.
|
// 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.
|
// Will contain the gutters, if any.
|
||||||
d.gutters = elt("div", null, "CodeMirror-gutters");
|
d.gutters = elt("div", null, "CodeMirror-gutters");
|
||||||
d.lineGutter = null;
|
d.lineGutter = null;
|
||||||
|
@ -172,8 +173,7 @@
|
||||||
d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
|
d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
|
||||||
d.scroller.setAttribute("tabIndex", "-1");
|
d.scroller.setAttribute("tabIndex", "-1");
|
||||||
// The element in which the editor lives.
|
// The element in which the editor lives.
|
||||||
d.wrapper = elt("div", [d.inputDiv, d.scrollbarH, d.scrollbarV,
|
d.wrapper = elt("div", [d.inputDiv, d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
|
||||||
d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
|
|
||||||
|
|
||||||
// Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
|
// 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; }
|
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;
|
if (!webkit) d.scroller.draggable = true;
|
||||||
// Needed to handle Tab key in KHTML
|
// Needed to handle Tab key in KHTML
|
||||||
if (khtml) { d.inputDiv.style.height = "1px"; d.inputDiv.style.position = "absolute"; }
|
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) {
|
||||||
if (place.appendChild) place.appendChild(d.wrapper);
|
if (place.appendChild) place.appendChild(d.wrapper);
|
||||||
|
@ -192,8 +190,10 @@
|
||||||
|
|
||||||
// Current rendered range (may be bigger than the view window).
|
// Current rendered range (may be bigger than the view window).
|
||||||
d.viewFrom = d.viewTo = doc.first;
|
d.viewFrom = d.viewTo = doc.first;
|
||||||
|
d.reportedViewFrom = d.reportedViewTo = doc.first;
|
||||||
// Information about the rendered lines.
|
// Information about the rendered lines.
|
||||||
d.view = [];
|
d.view = [];
|
||||||
|
d.renderedView = null;
|
||||||
// Holds info about a single rendered line when it was rendered
|
// Holds info about a single rendered line when it was rendered
|
||||||
// for measurement, while not in view.
|
// for measurement, while not in view.
|
||||||
d.externalMeasured = null;
|
d.externalMeasured = null;
|
||||||
|
@ -202,6 +202,9 @@
|
||||||
d.lastWrapHeight = d.lastWrapWidth = 0;
|
d.lastWrapHeight = d.lastWrapWidth = 0;
|
||||||
d.updateLineNumbers = null;
|
d.updateLineNumbers = null;
|
||||||
|
|
||||||
|
d.nativeBarWidth = d.barHeight = d.barWidth = 0;
|
||||||
|
d.scrollbarsClipped = false;
|
||||||
|
|
||||||
// Used to only resize the line number gutter when necessary (when
|
// Used to only resize the line number gutter when necessary (when
|
||||||
// the amount of lines crosses a boundary that makes its width change)
|
// the amount of lines crosses a boundary that makes its width change)
|
||||||
d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
|
d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
|
||||||
|
@ -265,6 +268,7 @@
|
||||||
if (cm.options.lineWrapping) {
|
if (cm.options.lineWrapping) {
|
||||||
addClass(cm.display.wrapper, "CodeMirror-wrap");
|
addClass(cm.display.wrapper, "CodeMirror-wrap");
|
||||||
cm.display.sizer.style.minWidth = "";
|
cm.display.sizer.style.minWidth = "";
|
||||||
|
cm.display.sizerWidth = null;
|
||||||
} else {
|
} else {
|
||||||
rmClass(cm.display.wrapper, "CodeMirror-wrap");
|
rmClass(cm.display.wrapper, "CodeMirror-wrap");
|
||||||
findMaxLine(cm);
|
findMaxLine(cm);
|
||||||
|
@ -336,7 +340,6 @@
|
||||||
function updateGutterSpace(cm) {
|
function updateGutterSpace(cm) {
|
||||||
var width = cm.display.gutters.offsetWidth;
|
var width = cm.display.gutters.offsetWidth;
|
||||||
cm.display.sizer.style.marginLeft = width + "px";
|
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
|
// Compute the character length of a line, taking into account
|
||||||
|
@ -389,78 +392,166 @@
|
||||||
|
|
||||||
// SCROLLBARS
|
// 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
|
// Prepare DOM reads needed to update the scrollbars. Done in one
|
||||||
// shot to minimize update/measure roundtrips.
|
// shot to minimize update/measure roundtrips.
|
||||||
function measureForScrollbars(cm) {
|
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 {
|
return {
|
||||||
clientHeight: scroll.clientHeight,
|
clientHeight: d.scroller.clientHeight,
|
||||||
barHeight: cm.display.scrollbarV.clientHeight,
|
viewHeight: d.wrapper.clientHeight,
|
||||||
scrollWidth: scroll.scrollWidth, clientWidth: scroll.clientWidth,
|
scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
|
||||||
hScrollbarTakesSpace: hScrollbarTakesSpace(cm),
|
viewWidth: d.wrapper.clientWidth,
|
||||||
barWidth: cm.display.scrollbarH.clientWidth,
|
barLeft: cm.options.fixedGutter ? gutterW : 0,
|
||||||
docHeight: Math.round(cm.doc.height + paddingVert(cm.display))
|
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
|
// Re-synchronize the fake scrollbars with the actual size of the
|
||||||
// content.
|
// content.
|
||||||
function updateScrollbars(cm, measure) {
|
function updateScrollbarsInner(cm, measure) {
|
||||||
if (!measure) measure = measureForScrollbars(cm);
|
var d = cm.display;
|
||||||
var d = cm.display, sWidth = scrollbarWidth(d.measure);
|
var sizes = d.scrollbars.update(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;
|
|
||||||
|
|
||||||
if (needsV) {
|
d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
|
||||||
d.scrollbarV.style.display = "block";
|
d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
|
||||||
d.scrollbarV.style.bottom = needsH ? sWidth + "px" : "0";
|
|
||||||
// A bug in IE8 can cause this value to be negative, so guard it.
|
if (sizes.right && sizes.bottom) {
|
||||||
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.scrollbarFiller.style.display = "block";
|
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 = "";
|
} 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.display = "block";
|
||||||
d.gutterFiller.style.height = sWidth + "px";
|
d.gutterFiller.style.height = sizes.bottom + "px";
|
||||||
d.gutterFiller.style.width = d.gutters.offsetWidth + "px";
|
d.gutterFiller.style.width = measure.gutterWidth + "px";
|
||||||
} else d.gutterFiller.style.display = "";
|
} 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
|
// Compute the lines that are visible in a given viewport (defaults
|
||||||
|
@ -476,12 +567,13 @@
|
||||||
// forces those lines into the viewport (if possible).
|
// forces those lines into the viewport (if possible).
|
||||||
if (viewport && viewport.ensure) {
|
if (viewport && viewport.ensure) {
|
||||||
var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
|
var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
|
||||||
if (ensureFrom < from)
|
if (ensureFrom < from) {
|
||||||
return {from: ensureFrom,
|
from = ensureFrom;
|
||||||
to: lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)};
|
to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
|
||||||
if (Math.min(ensureTo, doc.lastLine()) >= to)
|
} else if (Math.min(ensureTo, doc.lastLine()) >= to) {
|
||||||
return {from: lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight),
|
from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
|
||||||
to: ensureTo};
|
to = ensureTo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return {from: from, to: Math.max(to, from + 1)};
|
return {from: from, to: Math.max(to, from + 1)};
|
||||||
}
|
}
|
||||||
|
@ -549,17 +641,28 @@
|
||||||
this.editorIsHidden = !display.wrapper.offsetWidth;
|
this.editorIsHidden = !display.wrapper.offsetWidth;
|
||||||
this.wrapperHeight = display.wrapper.clientHeight;
|
this.wrapperHeight = display.wrapper.clientHeight;
|
||||||
this.wrapperWidth = display.wrapper.clientWidth;
|
this.wrapperWidth = display.wrapper.clientWidth;
|
||||||
this.oldViewFrom = display.viewFrom; this.oldViewTo = display.viewTo;
|
this.oldDisplayWidth = displayWidth(cm);
|
||||||
this.oldScrollerWidth = display.scroller.clientWidth;
|
|
||||||
this.force = force;
|
this.force = force;
|
||||||
this.dims = getDimensions(cm);
|
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
|
// Does the actual updating of the line display. Bails out
|
||||||
// (returning false) when there is nothing to be done and forced is
|
// (returning false) when there is nothing to be done and forced is
|
||||||
// false.
|
// false.
|
||||||
function updateDisplayIfNeeded(cm, update) {
|
function updateDisplayIfNeeded(cm, update) {
|
||||||
var display = cm.display, doc = cm.doc;
|
var display = cm.display, doc = cm.doc;
|
||||||
|
|
||||||
if (update.editorIsHidden) {
|
if (update.editorIsHidden) {
|
||||||
resetView(cm);
|
resetView(cm);
|
||||||
return false;
|
return false;
|
||||||
|
@ -569,7 +672,7 @@
|
||||||
if (!update.force &&
|
if (!update.force &&
|
||||||
update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
|
update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
|
||||||
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
|
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
|
||||||
countDirtyView(cm) == 0)
|
display.renderedView == display.view && countDirtyView(cm) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (maybeUpdateLineNumberWidth(cm)) {
|
if (maybeUpdateLineNumberWidth(cm)) {
|
||||||
|
@ -597,7 +700,7 @@
|
||||||
cm.display.mover.style.top = display.viewOffset + "px";
|
cm.display.mover.style.top = display.viewOffset + "px";
|
||||||
|
|
||||||
var toUpdate = countDirtyView(cm);
|
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))
|
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -607,14 +710,16 @@
|
||||||
if (toUpdate > 4) display.lineDiv.style.display = "none";
|
if (toUpdate > 4) display.lineDiv.style.display = "none";
|
||||||
patchDisplay(cm, display.updateLineNumbers, update.dims);
|
patchDisplay(cm, display.updateLineNumbers, update.dims);
|
||||||
if (toUpdate > 4) display.lineDiv.style.display = "";
|
if (toUpdate > 4) display.lineDiv.style.display = "";
|
||||||
|
display.renderedView = display.view;
|
||||||
// There might have been a widget with a focused element that got
|
// There might have been a widget with a focused element that got
|
||||||
// hidden or updated, if so re-focus it.
|
// hidden or updated, if so re-focus it.
|
||||||
if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
|
if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
|
||||||
|
|
||||||
// Prevent selection and cursors from interfering with the scroll
|
// Prevent selection and cursors from interfering with the scroll
|
||||||
// width.
|
// width and height.
|
||||||
removeChildren(display.cursorDiv);
|
removeChildren(display.cursorDiv);
|
||||||
removeChildren(display.selectionDiv);
|
removeChildren(display.selectionDiv);
|
||||||
|
display.heightForcer.style.top = display.gutters.style.height = 0;
|
||||||
|
|
||||||
if (different) {
|
if (different) {
|
||||||
display.lastWrapHeight = update.wrapperHeight;
|
display.lastWrapHeight = update.wrapperHeight;
|
||||||
|
@ -630,14 +735,13 @@
|
||||||
function postUpdateDisplay(cm, update) {
|
function postUpdateDisplay(cm, update) {
|
||||||
var force = update.force, viewport = update.viewport;
|
var force = update.force, viewport = update.viewport;
|
||||||
for (var first = true;; first = false) {
|
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;
|
force = true;
|
||||||
} else {
|
} else {
|
||||||
force = false;
|
force = false;
|
||||||
// Clip forced viewport to actual scrollable area.
|
// Clip forced viewport to actual scrollable area.
|
||||||
if (viewport && viewport.top != null)
|
if (viewport && viewport.top != null)
|
||||||
viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - scrollerCutOff -
|
viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};
|
||||||
cm.display.scroller.clientHeight, viewport.top)};
|
|
||||||
// Updated line heights might result in the drawn area not
|
// Updated line heights might result in the drawn area not
|
||||||
// actually covering the viewport. Keep looping until it does.
|
// actually covering the viewport. Keep looping until it does.
|
||||||
update.visible = visibleLines(cm.display, cm.doc, viewport);
|
update.visible = visibleLines(cm.display, cm.doc, viewport);
|
||||||
|
@ -653,8 +757,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
signalLater(cm, "update", cm);
|
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);
|
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) {
|
function updateDisplaySimple(cm, viewport) {
|
||||||
|
@ -670,17 +776,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDocumentHeight(cm, measure) {
|
function setDocumentHeight(cm, measure) {
|
||||||
cm.display.sizer.style.minHeight = cm.display.heightForcer.style.top = measure.docHeight + "px";
|
cm.display.sizer.style.minHeight = measure.docHeight + "px";
|
||||||
cm.display.gutters.style.height = Math.max(measure.docHeight, measure.clientHeight - scrollerCutOff) + "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";
|
||||||
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";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the actual heights of the rendered lines, and update their
|
// Read the actual heights of the rendered lines, and update their
|
||||||
|
@ -924,7 +1023,7 @@
|
||||||
var wrap = ensureLineWrapped(lineView);
|
var wrap = ensureLineWrapped(lineView);
|
||||||
for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
|
for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
|
||||||
var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
|
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);
|
positionLineWidget(widget, node, lineView, dims);
|
||||||
if (allowAbove && widget.above)
|
if (allowAbove && widget.above)
|
||||||
wrap.insertBefore(node, lineView.gutter || lineView.text);
|
wrap.insertBefore(node, lineView.gutter || lineView.text);
|
||||||
|
@ -1319,7 +1418,8 @@
|
||||||
function drawSelectionRange(cm, range, output) {
|
function drawSelectionRange(cm, range, output) {
|
||||||
var display = cm.display, doc = cm.doc;
|
var display = cm.display, doc = cm.doc;
|
||||||
var fragment = document.createDocumentFragment();
|
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) {
|
function add(left, top, width, bottom) {
|
||||||
if (top < 0) top = 0;
|
if (top < 0) top = 0;
|
||||||
|
@ -1498,13 +1598,21 @@
|
||||||
return data;
|
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
|
// Ensure the lineView.wrapping.heights array is populated. This is
|
||||||
// an array of bottom offsets for the lines that make up a drawn
|
// an array of bottom offsets for the lines that make up a drawn
|
||||||
// line. When lineWrapping is on, there might be more than one
|
// line. When lineWrapping is on, there might be more than one
|
||||||
// height.
|
// height.
|
||||||
function ensureLineHeights(cm, lineView, rect) {
|
function ensureLineHeights(cm, lineView, rect) {
|
||||||
var wrapping = cm.options.lineWrapping;
|
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) {
|
if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
|
||||||
var heights = lineView.measure.heights = [];
|
var heights = lineView.measure.heights = [];
|
||||||
if (wrapping) {
|
if (wrapping) {
|
||||||
|
@ -2022,6 +2130,7 @@
|
||||||
|
|
||||||
function endOperation_R1(op) {
|
function endOperation_R1(op) {
|
||||||
var cm = op.cm, display = cm.display;
|
var cm = op.cm, display = cm.display;
|
||||||
|
maybeClipScrollbars(cm);
|
||||||
if (op.updateMaxLine) findMaxLine(cm);
|
if (op.updateMaxLine) findMaxLine(cm);
|
||||||
|
|
||||||
op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
|
op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
|
||||||
|
@ -2047,8 +2156,10 @@
|
||||||
// updateDisplay_W2 will use these properties to do the actual resizing
|
// updateDisplay_W2 will use these properties to do the actual resizing
|
||||||
if (display.maxLineChanged && !cm.options.lineWrapping) {
|
if (display.maxLineChanged && !cm.options.lineWrapping) {
|
||||||
op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
|
op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
|
||||||
op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo +
|
cm.display.sizerWidth = op.adjustWidthTo;
|
||||||
scrollerCutOff - display.scroller.clientWidth);
|
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)
|
if (op.updatedDisplay || op.selectionChanged)
|
||||||
|
@ -2081,9 +2192,6 @@
|
||||||
function endOperation_finish(op) {
|
function endOperation_finish(op) {
|
||||||
var cm = op.cm, display = cm.display, doc = cm.doc;
|
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);
|
if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
|
||||||
|
|
||||||
// Abort mouse wheel delta measurement, when scrolling explicitly
|
// Abort mouse wheel delta measurement, when scrolling explicitly
|
||||||
|
@ -2092,12 +2200,14 @@
|
||||||
|
|
||||||
// Propagate the scroll position to the actual DOM scroller
|
// Propagate the scroll position to the actual DOM scroller
|
||||||
if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
|
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));
|
doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
|
||||||
display.scroller.scrollTop = display.scrollbarV.scrollTop = doc.scrollTop = top;
|
display.scrollbars.setScrollTop(doc.scrollTop);
|
||||||
|
display.scroller.scrollTop = doc.scrollTop;
|
||||||
}
|
}
|
||||||
if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
|
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));
|
doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));
|
||||||
display.scroller.scrollLeft = display.scrollbarH.scrollLeft = doc.scrollLeft = left;
|
display.scrollbars.setScrollLeft(doc.scrollLeft);
|
||||||
|
display.scroller.scrollLeft = doc.scrollLeft;
|
||||||
alignHorizontally(cm);
|
alignHorizontally(cm);
|
||||||
}
|
}
|
||||||
// If we need to scroll a specific position into view, do so.
|
// If we need to scroll a specific position into view, do so.
|
||||||
|
@ -2118,16 +2228,6 @@
|
||||||
if (display.wrapper.offsetHeight)
|
if (display.wrapper.offsetHeight)
|
||||||
doc.scrollTop = cm.display.scroller.scrollTop;
|
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
|
// Fire change events, and delayed event handlers
|
||||||
if (op.changeObjs)
|
if (op.changeObjs)
|
||||||
signal(cm, "changes", cm, op.changeObjs);
|
signal(cm, "changes", cm, op.changeObjs);
|
||||||
|
@ -2486,6 +2586,7 @@
|
||||||
// Reset the input to correspond to the selection (or to be empty,
|
// Reset the input to correspond to the selection (or to be empty,
|
||||||
// when not typing and nothing is selected)
|
// when not typing and nothing is selected)
|
||||||
function resetInput(cm, typing) {
|
function resetInput(cm, typing) {
|
||||||
|
if (cm.display.contextMenuPending) return;
|
||||||
var minimal, selected, doc = cm.doc;
|
var minimal, selected, doc = cm.doc;
|
||||||
if (cm.somethingSelected()) {
|
if (cm.somethingSelected()) {
|
||||||
cm.display.prevInput = "";
|
cm.display.prevInput = "";
|
||||||
|
@ -2552,28 +2653,18 @@
|
||||||
signal(cm, "scroll", cm);
|
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.
|
// 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, "mousewheel", function(e){onScrollWheel(cm, e);});
|
||||||
on(d.scroller, "DOMMouseScroll", 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
|
// Prevent wrapper from ever scrolling
|
||||||
on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
|
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, "keyup", function(e) { onKeyUp.call(cm, e); });
|
||||||
on(d.input, "input", function() {
|
on(d.input, "input", function() {
|
||||||
if (ie && ie_version >= 9 && cm.display.inputHasSelection) cm.display.inputHasSelection = null;
|
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, "keydown", operation(cm, onKeyDown));
|
||||||
on(d.input, "keypress", operation(cm, onKeyPress));
|
on(d.input, "keypress", operation(cm, onKeyPress));
|
||||||
|
@ -2659,6 +2750,7 @@
|
||||||
return;
|
return;
|
||||||
// Might be a text scaling operation, clear size caches.
|
// Might be a text scaling operation, clear size caches.
|
||||||
d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
|
d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
|
||||||
|
d.scrollbarsClipped = false;
|
||||||
cm.setSize();
|
cm.setSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2667,7 +2759,7 @@
|
||||||
// Return true when the given mouse event happened in a widget
|
// Return true when the given mouse event happened in a widget
|
||||||
function eventInWidget(display, e) {
|
function eventInWidget(display, e) {
|
||||||
for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
|
for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
|
||||||
if (!n || 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.
|
// coordinates beyond the right of the text.
|
||||||
function posFromMouse(cm, e, liberal, forRect) {
|
function posFromMouse(cm, e, liberal, forRect) {
|
||||||
var display = cm.display;
|
var display = cm.display;
|
||||||
if (!liberal) {
|
if (!liberal && e_target(e).getAttribute("not-content") == "true") return null;
|
||||||
var target = e_target(e);
|
|
||||||
if (target == display.scrollbarH || target == display.scrollbarV ||
|
|
||||||
target == display.scrollbarFiller || target == display.gutterFiller) return null;
|
|
||||||
}
|
|
||||||
var x, y, space = display.lineSpace.getBoundingClientRect();
|
var x, y, space = display.lineSpace.getBoundingClientRect();
|
||||||
// Fails unpredictably on IE[67] when mouse is dragged around quickly.
|
// Fails unpredictably on IE[67] when mouse is dragged around quickly.
|
||||||
try { x = e.clientX - space.left; y = e.clientY - space.top; }
|
try { x = e.clientX - space.left; y = e.clientY - space.top; }
|
||||||
|
@ -2752,9 +2841,10 @@
|
||||||
lastClick = {time: now, pos: start};
|
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) &&
|
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);
|
leftButtonStartDrag(cm, e, start, modifier);
|
||||||
else
|
else
|
||||||
leftButtonSelect(cm, e, start, type, modifier);
|
leftButtonSelect(cm, e, start, type, modifier);
|
||||||
|
@ -2793,11 +2883,11 @@
|
||||||
var display = cm.display, doc = cm.doc;
|
var display = cm.display, doc = cm.doc;
|
||||||
e_preventDefault(e);
|
e_preventDefault(e);
|
||||||
|
|
||||||
var ourRange, ourIndex, startSel = doc.sel;
|
var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
|
||||||
if (addNew && !e.shiftKey) {
|
if (addNew && !e.shiftKey) {
|
||||||
ourIndex = doc.sel.contains(start);
|
ourIndex = doc.sel.contains(start);
|
||||||
if (ourIndex > -1)
|
if (ourIndex > -1)
|
||||||
ourRange = doc.sel.ranges[ourIndex];
|
ourRange = ranges[ourIndex];
|
||||||
else
|
else
|
||||||
ourRange = new Range(start, start);
|
ourRange = new Range(start, start);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2829,12 +2919,15 @@
|
||||||
ourIndex = 0;
|
ourIndex = 0;
|
||||||
setSelection(doc, new Selection([ourRange], 0), sel_mouse);
|
setSelection(doc, new Selection([ourRange], 0), sel_mouse);
|
||||||
startSel = doc.sel;
|
startSel = doc.sel;
|
||||||
} else if (ourIndex > -1) {
|
} else if (ourIndex == -1) {
|
||||||
replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
|
ourIndex = ranges.length;
|
||||||
} else {
|
setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
|
||||||
ourIndex = doc.sel.ranges.length;
|
|
||||||
setSelection(doc, normalizeSelection(doc.sel.ranges.concat([ourRange]), ourIndex),
|
|
||||||
{scroll: false, origin: "*mouse"});
|
{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;
|
var lastPos = start;
|
||||||
|
@ -3040,7 +3133,7 @@
|
||||||
cm.doc.scrollTop = val;
|
cm.doc.scrollTop = val;
|
||||||
if (!gecko) updateDisplaySimple(cm, {top: val});
|
if (!gecko) updateDisplaySimple(cm, {top: val});
|
||||||
if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = 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);
|
if (gecko) updateDisplaySimple(cm);
|
||||||
startWorker(cm, 100);
|
startWorker(cm, 100);
|
||||||
}
|
}
|
||||||
|
@ -3052,7 +3145,7 @@
|
||||||
cm.doc.scrollLeft = val;
|
cm.doc.scrollLeft = val;
|
||||||
alignHorizontally(cm);
|
alignHorizontally(cm);
|
||||||
if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
|
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
|
// Since the delta values reported on mouse wheel events are
|
||||||
|
@ -3076,11 +3169,22 @@
|
||||||
else if (chrome) wheelPixelsPerUnit = -.7;
|
else if (chrome) wheelPixelsPerUnit = -.7;
|
||||||
else if (safari) wheelPixelsPerUnit = -1/3;
|
else if (safari) wheelPixelsPerUnit = -1/3;
|
||||||
|
|
||||||
function onScrollWheel(cm, e) {
|
var wheelEventDelta = function(e) {
|
||||||
var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
|
var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
|
||||||
if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
|
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;
|
if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
|
||||||
else if (dy == null) dy = e.wheelDelta;
|
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;
|
var display = cm.display, scroll = display.scroller;
|
||||||
// Quit if there's nothing to scroll here
|
// Quit if there's nothing to scroll here
|
||||||
|
@ -3173,11 +3277,11 @@
|
||||||
|
|
||||||
function lookupKeyForEditor(cm, name, handle) {
|
function lookupKeyForEditor(cm, name, handle) {
|
||||||
for (var i = 0; i < cm.state.keyMaps.length; i++) {
|
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;
|
if (result) return result;
|
||||||
}
|
}
|
||||||
return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle))
|
return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
|
||||||
|| lookupKey(name, cm.options.keyMap, handle);
|
|| lookupKey(name, cm.options.keyMap, handle, cm);
|
||||||
}
|
}
|
||||||
|
|
||||||
var stopSeq = new Delayed;
|
var stopSeq = new Delayed;
|
||||||
|
@ -3351,6 +3455,7 @@
|
||||||
resetInput(cm);
|
resetInput(cm);
|
||||||
// Adds "Select all" to context menu in FF
|
// Adds "Select all" to context menu in FF
|
||||||
if (!cm.somethingSelected()) display.input.value = display.prevInput = " ";
|
if (!cm.somethingSelected()) display.input.value = display.prevInput = " ";
|
||||||
|
display.contextMenuPending = true;
|
||||||
display.selForContextMenu = cm.doc.sel;
|
display.selForContextMenu = cm.doc.sel;
|
||||||
clearTimeout(display.detectingSelectAll);
|
clearTimeout(display.detectingSelectAll);
|
||||||
|
|
||||||
|
@ -3369,9 +3474,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function rehide() {
|
function rehide() {
|
||||||
|
display.contextMenuPending = false;
|
||||||
display.inputDiv.style.position = "relative";
|
display.inputDiv.style.position = "relative";
|
||||||
display.input.style.cssText = oldCSS;
|
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);
|
slowPoll(cm);
|
||||||
|
|
||||||
// Try to detect the user choosing select-all
|
// Try to detect the user choosing select-all
|
||||||
|
@ -3721,7 +3827,7 @@
|
||||||
if (doScroll != null && !phantom) {
|
if (doScroll != null && !phantom) {
|
||||||
var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
|
var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
|
||||||
(coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
|
(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;");
|
coords.left + "px; width: 2px;");
|
||||||
cm.display.lineSpace.appendChild(scrollNode);
|
cm.display.lineSpace.appendChild(scrollNode);
|
||||||
scrollNode.scrollIntoView(doScroll);
|
scrollNode.scrollIntoView(doScroll);
|
||||||
|
@ -3750,8 +3856,9 @@
|
||||||
setScrollLeft(cm, scrollPos.scrollLeft);
|
setScrollLeft(cm, scrollPos.scrollLeft);
|
||||||
if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
|
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).
|
// Scroll a given set of coordinates into view (immediately).
|
||||||
|
@ -3769,7 +3876,7 @@
|
||||||
var display = cm.display, snapMargin = textHeight(cm.display);
|
var display = cm.display, snapMargin = textHeight(cm.display);
|
||||||
if (y1 < 0) y1 = 0;
|
if (y1 < 0) y1 = 0;
|
||||||
var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
|
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;
|
if (y2 - y1 > screen) y2 = y1 + screen;
|
||||||
var docBottom = cm.doc.height + paddingVert(display);
|
var docBottom = cm.doc.height + paddingVert(display);
|
||||||
var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
|
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 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;
|
var tooWide = x2 - x1 > screenw;
|
||||||
if (tooWide) x2 = x1 + screenw;
|
if (tooWide) x2 = x1 + screenw;
|
||||||
if (x1 < 10)
|
if (x1 < 10)
|
||||||
|
@ -3790,7 +3897,6 @@
|
||||||
result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
|
result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
|
||||||
else if (x2 > screenw + screenleft - 3)
|
else if (x2 > screenw + screenleft - 3)
|
||||||
result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
|
result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4245,6 +4351,7 @@
|
||||||
pos = cursorCoords(this, clipPos(this.doc, pos));
|
pos = cursorCoords(this, clipPos(this.doc, pos));
|
||||||
var top = pos.bottom, left = pos.left;
|
var top = pos.bottom, left = pos.left;
|
||||||
node.style.position = "absolute";
|
node.style.position = "absolute";
|
||||||
|
node.setAttribute("cm-ignore-events", "true");
|
||||||
display.sizer.appendChild(node);
|
display.sizer.appendChild(node);
|
||||||
if (vert == "over") {
|
if (vert == "over") {
|
||||||
top = pos.top;
|
top = pos.top;
|
||||||
|
@ -4379,10 +4486,11 @@
|
||||||
if (y != null) this.curOp.scrollTop = y;
|
if (y != null) this.curOp.scrollTop = y;
|
||||||
}),
|
}),
|
||||||
getScrollInfo: function() {
|
getScrollInfo: function() {
|
||||||
var scroller = this.display.scroller, co = scrollerCutOff;
|
var scroller = this.display.scroller;
|
||||||
return {left: scroller.scrollLeft, top: scroller.scrollTop,
|
return {left: scroller.scrollLeft, top: scroller.scrollTop,
|
||||||
height: scroller.scrollHeight - co, width: scroller.scrollWidth - co,
|
height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
|
||||||
clientHeight: scroller.clientHeight - co, clientWidth: scroller.clientWidth - co};
|
width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
|
||||||
|
clientHeight: displayHeight(this), clientWidth: displayWidth(this)};
|
||||||
},
|
},
|
||||||
|
|
||||||
scrollIntoView: methodOp(function(range, margin) {
|
scrollIntoView: methodOp(function(range, margin) {
|
||||||
|
@ -4524,7 +4632,13 @@
|
||||||
cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
|
cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
|
||||||
cm.refresh();
|
cm.refresh();
|
||||||
}, true);
|
}, 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) {
|
option("lineNumbers", false, function(cm) {
|
||||||
setGuttersForLineNumbers(cm.options);
|
setGuttersForLineNumbers(cm.options);
|
||||||
guttersChanged(cm);
|
guttersChanged(cm);
|
||||||
|
@ -4954,18 +5068,18 @@
|
||||||
return keymap;
|
return keymap;
|
||||||
};
|
};
|
||||||
|
|
||||||
var lookupKey = CodeMirror.lookupKey = function(key, map, handle) {
|
var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) {
|
||||||
map = getKeyMap(map);
|
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 === false) return "nothing";
|
||||||
if (found === "...") return "multi";
|
if (found === "...") return "multi";
|
||||||
if (found != null && handle(found)) return "handled";
|
if (found != null && handle(found)) return "handled";
|
||||||
|
|
||||||
if (map.fallthrough) {
|
if (map.fallthrough) {
|
||||||
if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
|
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++) {
|
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;
|
if (result) return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5272,7 +5386,7 @@
|
||||||
// Showing up as a widget implies collapsed (widget replaces text)
|
// Showing up as a widget implies collapsed (widget replaces text)
|
||||||
marker.collapsed = true;
|
marker.collapsed = true;
|
||||||
marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
|
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 (options.insertLeft) marker.widgetNode.insertLeft = true;
|
||||||
}
|
}
|
||||||
if (marker.collapsed) {
|
if (marker.collapsed) {
|
||||||
|
@ -5316,7 +5430,7 @@
|
||||||
if (updateMaxLine) cm.curOp.updateMaxLine = true;
|
if (updateMaxLine) cm.curOp.updateMaxLine = true;
|
||||||
if (marker.collapsed)
|
if (marker.collapsed)
|
||||||
regChange(cm, from.line, to.line + 1);
|
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");
|
for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
|
||||||
if (marker.atomic) reCheckSelection(cm.doc);
|
if (marker.atomic) reCheckSelection(cm.doc);
|
||||||
signalLater(cm, "markerAdded", cm, marker);
|
signalLater(cm, "markerAdded", cm, marker);
|
||||||
|
@ -5896,8 +6010,11 @@
|
||||||
if (mName) style = "m-" + (style ? mName + " " + style : mName);
|
if (mName) style = "m-" + (style ? mName + " " + style : mName);
|
||||||
}
|
}
|
||||||
if (!flattenSpans || curStyle != style) {
|
if (!flattenSpans || curStyle != style) {
|
||||||
if (curStart < stream.start) f(stream.start, curStyle);
|
while (curStart < stream.start) {
|
||||||
curStart = stream.start; curStyle = style;
|
curStart = Math.min(stream.start, curStart + 50000);
|
||||||
|
f(curStart, curStyle);
|
||||||
|
}
|
||||||
|
curStyle = style;
|
||||||
}
|
}
|
||||||
stream.start = stream.pos;
|
stream.start = stream.pos;
|
||||||
}
|
}
|
||||||
|
@ -6054,7 +6171,7 @@
|
||||||
|
|
||||||
// Build up the DOM representation for a single token, and add it to
|
// Build up the DOM representation for a single token, and add it to
|
||||||
// the line map. Takes care to render special characters separately.
|
// 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;
|
if (!text) return;
|
||||||
var special = builder.cm.options.specialChars, mustWrap = false;
|
var special = builder.cm.options.specialChars, mustWrap = false;
|
||||||
if (!special.test(text)) {
|
if (!special.test(text)) {
|
||||||
|
@ -6093,11 +6210,11 @@
|
||||||
builder.pos++;
|
builder.pos++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (style || startStyle || endStyle || mustWrap) {
|
if (style || startStyle || endStyle || mustWrap || css) {
|
||||||
var fullStyle = style || "";
|
var fullStyle = style || "";
|
||||||
if (startStyle) fullStyle += startStyle;
|
if (startStyle) fullStyle += startStyle;
|
||||||
if (endStyle) fullStyle += endStyle;
|
if (endStyle) fullStyle += endStyle;
|
||||||
var token = elt("span", [content], fullStyle);
|
var token = elt("span", [content], fullStyle, css);
|
||||||
if (title) token.title = title;
|
if (title) token.title = title;
|
||||||
return builder.content.appendChild(token);
|
return builder.content.appendChild(token);
|
||||||
}
|
}
|
||||||
|
@ -6156,11 +6273,11 @@
|
||||||
return;
|
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;
|
var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (nextChange == pos) { // Update current marker set
|
if (nextChange == pos) { // Update current marker set
|
||||||
spanStyle = spanEndStyle = spanStartStyle = title = "";
|
spanStyle = spanEndStyle = spanStartStyle = title = css = "";
|
||||||
collapsed = null; nextChange = Infinity;
|
collapsed = null; nextChange = Infinity;
|
||||||
var foundBookmarks = [];
|
var foundBookmarks = [];
|
||||||
for (var j = 0; j < spans.length; ++j) {
|
for (var j = 0; j < spans.length; ++j) {
|
||||||
|
@ -6168,6 +6285,7 @@
|
||||||
if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
|
if (sp.from <= pos && (sp.to == null || sp.to > pos)) {
|
||||||
if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
|
if (sp.to != null && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; }
|
||||||
if (m.className) spanStyle += " " + m.className;
|
if (m.className) spanStyle += " " + m.className;
|
||||||
|
if (m.css) css = m.css;
|
||||||
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
|
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
|
||||||
if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
|
if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
|
||||||
if (m.title && !title) title = m.title;
|
if (m.title && !title) title = m.title;
|
||||||
|
@ -6195,7 +6313,7 @@
|
||||||
if (!collapsed) {
|
if (!collapsed) {
|
||||||
var tokenText = end > upto ? text.slice(0, upto - pos) : text;
|
var tokenText = end > upto ? text.slice(0, upto - pos) : text;
|
||||||
builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
|
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;}
|
if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
|
||||||
pos = end;
|
pos = end;
|
||||||
|
@ -6622,7 +6740,7 @@
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
removeLineClass: docMethodOp(function(handle, where, cls) {
|
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"
|
var prop = where == "text" ? "textClass"
|
||||||
: where == "background" ? "bgClass"
|
: where == "background" ? "bgClass"
|
||||||
: where == "gutter" ? "gutterClass" : "wrapClass";
|
: where == "gutter" ? "gutterClass" : "wrapClass";
|
||||||
|
@ -7278,7 +7396,7 @@
|
||||||
// MISC UTILITIES
|
// MISC UTILITIES
|
||||||
|
|
||||||
// Number of pixels added to scroller and sizer to hide scrollbar
|
// 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
|
// Returned or thrown by various protocols to signal 'I'm not
|
||||||
// handling this'.
|
// handling this'.
|
||||||
|
@ -7504,7 +7622,6 @@
|
||||||
on(window, "resize", function() {
|
on(window, "resize", function() {
|
||||||
if (resizeTimer == null) resizeTimer = setTimeout(function() {
|
if (resizeTimer == null) resizeTimer = setTimeout(function() {
|
||||||
resizeTimer = null;
|
resizeTimer = null;
|
||||||
knownScrollbarWidth = null;
|
|
||||||
forEachCodeMirror(onResize);
|
forEachCodeMirror(onResize);
|
||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
|
@ -7525,16 +7642,6 @@
|
||||||
return "draggable" in div || "dragDrop" in div;
|
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;
|
var zwspSupported;
|
||||||
function zeroWidthElement(measure) {
|
function zeroWidthElement(measure) {
|
||||||
if (zwspSupported == null) {
|
if (zwspSupported == null) {
|
||||||
|
@ -7916,7 +8023,7 @@
|
||||||
|
|
||||||
// THE END
|
// THE END
|
||||||
|
|
||||||
CodeMirror.version = "4.8.0";
|
CodeMirror.version = "4.10.0";
|
||||||
|
|
||||||
return CodeMirror;
|
return CodeMirror;
|
||||||
});
|
});
|
|
@ -132,8 +132,8 @@
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function findEnd(cm, by, dir) {
|
function findEnd(cm, pos, by, dir) {
|
||||||
var pos = cm.getCursor(), prefix = getPrefix(cm);
|
var prefix = getPrefix(cm);
|
||||||
if (prefix < 0) { dir = -dir; prefix = -prefix; }
|
if (prefix < 0) { dir = -dir; prefix = -prefix; }
|
||||||
for (var i = 0; i < prefix; ++i) {
|
for (var i = 0; i < prefix; ++i) {
|
||||||
var newPos = by(cm, pos, dir);
|
var newPos = by(cm, pos, dir);
|
||||||
|
@ -145,14 +145,31 @@
|
||||||
|
|
||||||
function move(by, dir) {
|
function move(by, dir) {
|
||||||
var f = function(cm) {
|
var f = function(cm) {
|
||||||
cm.extendSelection(findEnd(cm, by, dir));
|
cm.extendSelection(findEnd(cm, cm.getCursor(), by, dir));
|
||||||
};
|
};
|
||||||
f.motion = true;
|
f.motion = true;
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
function killTo(cm, by, dir) {
|
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) {
|
function addPrefix(cm, digit) {
|
||||||
|
@ -283,9 +300,9 @@
|
||||||
"Ctrl-F": move(byChar, 1), "Ctrl-B": move(byChar, -1),
|
"Ctrl-F": move(byChar, 1), "Ctrl-B": move(byChar, -1),
|
||||||
"Right": move(byChar, 1), "Left": move(byChar, -1),
|
"Right": move(byChar, 1), "Left": move(byChar, -1),
|
||||||
"Ctrl-D": function(cm) { killTo(cm, 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); },
|
"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-F": move(byWord, 1), "Alt-B": move(byWord, -1),
|
||||||
"Alt-D": function(cm) { killTo(cm, 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),
|
"Ctrl-Alt-F": move(byExpr, 1), "Ctrl-Alt-B": move(byExpr, -1),
|
||||||
|
|
||||||
"Shift-Ctrl-Alt-2": function(cm) {
|
"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) {
|
"Ctrl-Alt-T": function(cm) {
|
||||||
var leftStart = byExpr(cm, cm.getCursor(), -1), leftEnd = byExpr(cm, leftStart, 1);
|
var leftStart = byExpr(cm, cm.getCursor(), -1), leftEnd = byExpr(cm, leftStart, 1);
|
|
@ -77,11 +77,11 @@
|
||||||
{ keys: '<Up>', type: 'keyToKey', toKeys: 'k' },
|
{ keys: '<Up>', type: 'keyToKey', toKeys: 'k' },
|
||||||
{ keys: '<Down>', type: 'keyToKey', toKeys: 'j' },
|
{ keys: '<Down>', type: 'keyToKey', toKeys: 'j' },
|
||||||
{ keys: '<Space>', type: 'keyToKey', toKeys: 'l' },
|
{ 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-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-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-n>', type: 'keyToKey', toKeys: 'j' },
|
||||||
{ keys: '<C-p>', type: 'keyToKey', toKeys: 'k' },
|
{ keys: '<C-p>', type: 'keyToKey', toKeys: 'k' },
|
||||||
{ keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>' },
|
{ keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>' },
|
||||||
|
@ -229,55 +229,7 @@
|
||||||
|
|
||||||
var Pos = CodeMirror.Pos;
|
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() {
|
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) {
|
function enterVimMode(cm) {
|
||||||
cm.setOption('disableInput', true);
|
cm.setOption('disableInput', true);
|
||||||
cm.setOption('showCursorWhenSelecting', false);
|
cm.setOption('showCursorWhenSelecting', false);
|
||||||
|
@ -285,8 +237,6 @@
|
||||||
cm.on('cursorActivity', onCursorActivity);
|
cm.on('cursorActivity', onCursorActivity);
|
||||||
maybeInitVimState(cm);
|
maybeInitVimState(cm);
|
||||||
CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm));
|
CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm));
|
||||||
cm.on('keypress', handleKeyPress);
|
|
||||||
cm.on('keydown', handleKeyDown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function leaveVimMode(cm) {
|
function leaveVimMode(cm) {
|
||||||
|
@ -294,8 +244,6 @@
|
||||||
cm.off('cursorActivity', onCursorActivity);
|
cm.off('cursorActivity', onCursorActivity);
|
||||||
CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm));
|
CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm));
|
||||||
cm.state.vim = null;
|
cm.state.vim = null;
|
||||||
cm.off('keypress', handleKeyPress);
|
|
||||||
cm.off('keydown', handleKeyDown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function detachVimMap(cm, next) {
|
function detachVimMap(cm, next) {
|
||||||
|
@ -320,6 +268,60 @@
|
||||||
else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption("keyMap")))
|
else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption("keyMap")))
|
||||||
cm.setOption("keyMap", "default");
|
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) {
|
function getOnPasteFn(cm) {
|
||||||
var vim = cm.state.vim;
|
var vim = cm.state.vim;
|
||||||
if (!vim.onPasteFn) {
|
if (!vim.onPasteFn) {
|
||||||
|
@ -614,6 +616,8 @@
|
||||||
// Testing hook.
|
// Testing hook.
|
||||||
maybeInitVimState_: maybeInitVimState,
|
maybeInitVimState_: maybeInitVimState,
|
||||||
|
|
||||||
|
suppressErrorLogging: false,
|
||||||
|
|
||||||
InsertModeKey: InsertModeKey,
|
InsertModeKey: InsertModeKey,
|
||||||
map: function(lhs, rhs, ctx) {
|
map: function(lhs, rhs, ctx) {
|
||||||
// Add user defined key bindings.
|
// Add user defined key bindings.
|
||||||
|
@ -629,9 +633,23 @@
|
||||||
exCommands[name]=func;
|
exCommands[name]=func;
|
||||||
exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'};
|
exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'};
|
||||||
},
|
},
|
||||||
// This is the outermost function called by CodeMirror, after keys have
|
handleKey: function (cm, key, origin) {
|
||||||
// been mapped to their Vim equivalents.
|
var command = this.findKey(cm, key, origin);
|
||||||
handleKey: function(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);
|
var vim = maybeInitVimState(cm);
|
||||||
function handleMacroRecording() {
|
function handleMacroRecording() {
|
||||||
var macroModeState = vimGlobalState.macroModeState;
|
var macroModeState = vimGlobalState.macroModeState;
|
||||||
|
@ -697,13 +715,7 @@
|
||||||
cm.replaceRange('', offsetCursor(here, 0, -(keys.length - 1)), here, '+input');
|
cm.replaceRange('', offsetCursor(here, 0, -(keys.length - 1)), here, '+input');
|
||||||
}
|
}
|
||||||
clearInputState(cm);
|
clearInputState(cm);
|
||||||
var command = match.command;
|
return match.command;
|
||||||
if (command.type == 'keyToKey') {
|
|
||||||
doKeyToKey(command.toKeys);
|
|
||||||
} else {
|
|
||||||
commandDispatcher.processCommand(cm, vim, command);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleKeyNonInsertMode() {
|
function handleKeyNonInsertMode() {
|
||||||
|
@ -721,31 +733,46 @@
|
||||||
else if (match.type == 'partial') { return true; }
|
else if (match.type == 'partial') { return true; }
|
||||||
|
|
||||||
vim.inputState.keyBuffer = '';
|
vim.inputState.keyBuffer = '';
|
||||||
var command = match.command;
|
|
||||||
var keysMatcher = /^(\d*)(.*)$/.exec(keys);
|
var keysMatcher = /^(\d*)(.*)$/.exec(keys);
|
||||||
if (keysMatcher[1] && keysMatcher[1] != '0') {
|
if (keysMatcher[1] && keysMatcher[1] != '0') {
|
||||||
vim.inputState.pushRepeatDigit(keysMatcher[1]);
|
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') {
|
if (command.type == 'keyToKey') {
|
||||||
doKeyToKey(command.toKeys);
|
doKeyToKey(command.toKeys);
|
||||||
} else {
|
} else {
|
||||||
commandDispatcher.processCommand(cm, vim, command);
|
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) {
|
} catch (e) {
|
||||||
// clear VIM state in case it's in a bad state.
|
// clear VIM state in case it's in a bad state.
|
||||||
cm.state.vim = undefined;
|
cm.state.vim = undefined;
|
||||||
maybeInitVimState(cm);
|
maybeInitVimState(cm);
|
||||||
|
if (!CodeMirror.Vim.suppressErrorLogging) {
|
||||||
|
console['log'](e);
|
||||||
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleEx: function(cm, input) {
|
handleEx: function(cm, input) {
|
||||||
exCommandDispatcher.processCommand(cm, input);
|
exCommandDispatcher.processCommand(cm, input);
|
||||||
|
@ -1306,7 +1333,9 @@
|
||||||
newHead = copyCursor(origHead);
|
newHead = copyCursor(origHead);
|
||||||
}
|
}
|
||||||
if (vim.visualMode) {
|
if (vim.visualMode) {
|
||||||
|
if (!(vim.visualBlock && newHead.ch === Infinity)) {
|
||||||
newHead = clipCursorToContent(cm, newHead, vim.visualBlock);
|
newHead = clipCursorToContent(cm, newHead, vim.visualBlock);
|
||||||
|
}
|
||||||
if (newAnchor) {
|
if (newAnchor) {
|
||||||
newAnchor = clipCursorToContent(cm, newAnchor, true);
|
newAnchor = clipCursorToContent(cm, newAnchor, true);
|
||||||
}
|
}
|
||||||
|
@ -1610,20 +1639,8 @@
|
||||||
return cm.findPosV(curStart, (motionArgs.forward ? repeat : -repeat), 'page');
|
return cm.findPosV(curStart, (motionArgs.forward ? repeat : -repeat), 'page');
|
||||||
},
|
},
|
||||||
moveByParagraph: function(cm, head, motionArgs) {
|
moveByParagraph: function(cm, head, motionArgs) {
|
||||||
var line = head.line;
|
var dir = motionArgs.forward ? 1 : -1;
|
||||||
var repeat = motionArgs.repeat;
|
return findParagraph(cm, head, motionArgs.repeat, dir);
|
||||||
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);
|
|
||||||
},
|
},
|
||||||
moveByScroll: function(cm, head, motionArgs, vim) {
|
moveByScroll: function(cm, head, motionArgs, vim) {
|
||||||
var scrollbox = cm.getScrollInfo();
|
var scrollbox = cm.getScrollInfo();
|
||||||
|
@ -1723,7 +1740,7 @@
|
||||||
return Pos(lineNum,
|
return Pos(lineNum,
|
||||||
findFirstNonWhiteSpaceCharacter(cm.getLine(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(
|
// TODO: lots of possible exceptions that can be thrown here. Try da(
|
||||||
// outside of a () block.
|
// outside of a () block.
|
||||||
|
|
||||||
|
@ -1761,6 +1778,16 @@
|
||||||
} else if (character === 'w') {
|
} else if (character === 'w') {
|
||||||
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
|
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
|
||||||
false /** bigWord */);
|
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 {
|
} else {
|
||||||
// No text object defined for this, don't move.
|
// No text object defined for this, don't move.
|
||||||
return null;
|
return null;
|
||||||
|
@ -3268,6 +3295,54 @@
|
||||||
return idx;
|
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
|
// TODO: perhaps this finagling of start and end positions belonds
|
||||||
// in codmirror/replaceRange?
|
// in codmirror/replaceRange?
|
||||||
function selectCompanionObject(cm, head, symb, inclusive) {
|
function selectCompanionObject(cm, head, symb, inclusive) {
|
||||||
|
@ -4476,7 +4551,8 @@
|
||||||
|
|
||||||
CodeMirror.keyMap.vim = {
|
CodeMirror.keyMap.vim = {
|
||||||
attach: attachVimMap,
|
attach: attachVimMap,
|
||||||
detach: detachVimMap
|
detach: detachVimMap,
|
||||||
|
call: cmKey
|
||||||
};
|
};
|
||||||
|
|
||||||
function exitInsertMode(cm) {
|
function exitInsertMode(cm) {
|
||||||
|
@ -4549,20 +4625,16 @@
|
||||||
},
|
},
|
||||||
fallthrough: ['default'],
|
fallthrough: ['default'],
|
||||||
attach: attachVimMap,
|
attach: attachVimMap,
|
||||||
detach: detachVimMap
|
detach: detachVimMap,
|
||||||
};
|
call: cmKey
|
||||||
|
|
||||||
CodeMirror.keyMap['await-second'] = {
|
|
||||||
fallthrough: ['vim-insert'],
|
|
||||||
attach: attachVimMap,
|
|
||||||
detach: detachVimMap
|
|
||||||
};
|
};
|
||||||
|
|
||||||
CodeMirror.keyMap['vim-replace'] = {
|
CodeMirror.keyMap['vim-replace'] = {
|
||||||
'Backspace': 'goCharLeft',
|
'Backspace': 'goCharLeft',
|
||||||
fallthrough: ['vim-insert'],
|
fallthrough: ['vim-insert'],
|
||||||
attach: attachVimMap,
|
attach: attachVimMap,
|
||||||
detach: detachVimMap
|
detach: detachVimMap,
|
||||||
|
call: cmKey
|
||||||
};
|
};
|
||||||
|
|
||||||
function executeMacroRegister(cm, vim, macroModeState, registerName) {
|
function executeMacroRegister(cm, vim, macroModeState, registerName) {
|
|
@ -15,7 +15,7 @@
|
||||||
})(function(CodeMirror) {
|
})(function(CodeMirror) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
CodeMirror.defineMode("coffeescript", function(conf) {
|
CodeMirror.defineMode("coffeescript", function(conf, parserConf) {
|
||||||
var ERRORCLASS = "error";
|
var ERRORCLASS = "error";
|
||||||
|
|
||||||
function wordRegexp(words) {
|
function wordRegexp(words) {
|
||||||
|
@ -191,7 +191,7 @@ CodeMirror.defineMode("coffeescript", function(conf) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (singleline) {
|
if (singleline) {
|
||||||
if (conf.mode.singleLineStringErrors) {
|
if (parserConf.singleLineStringErrors) {
|
||||||
outclass = ERRORCLASS;
|
outclass = ERRORCLASS;
|
||||||
} else {
|
} else {
|
||||||
state.tokenize = tokenBase;
|
state.tokenize = tokenBase;
|
|
@ -12,6 +12,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
CodeMirror.defineMode("commonlisp", function (config) {
|
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 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 numLiteral = /^(?:[+\-]?(?:\d+|\d*\.\d+)(?:[efd][+\-]?\d+)?|[+\-]?\d+(?:\/[+\-]?\d+)?|#b[+\-]?[01]+|#o[+\-]?[0-7]+|#x[+\-]?[\da-f]+)/;
|
||||||
var symbol = /[^\s'`,@()\[\]";]/;
|
var symbol = /[^\s'`,@()\[\]";]/;
|
||||||
|
@ -52,8 +53,8 @@ CodeMirror.defineMode("commonlisp", function (config) {
|
||||||
var name = readSym(stream);
|
var name = readSym(stream);
|
||||||
if (name == ".") return null;
|
if (name == ".") return null;
|
||||||
type = "symbol";
|
type = "symbol";
|
||||||
if (name == "nil" || name == "t") return "atom";
|
if (name == "nil" || name == "t" || name.charAt(0) == ":") return "atom";
|
||||||
if (name.charAt(0) == ":") return "keyword";
|
if (state.lastType == "open" && (specialForm.test(name) || assumeBody.test(name))) return "keyword";
|
||||||
if (name.charAt(0) == "&") return "variable-2";
|
if (name.charAt(0) == "&") return "variable-2";
|
||||||
return "variable";
|
return "variable";
|
||||||
}
|
}
|
||||||
|
@ -80,7 +81,7 @@ CodeMirror.defineMode("commonlisp", function (config) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
startState: function () {
|
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) {
|
token: function (stream, state) {
|
||||||
|
@ -98,6 +99,7 @@ CodeMirror.defineMode("commonlisp", function (config) {
|
||||||
} else if (state.ctx.indentTo == "next") {
|
} else if (state.ctx.indentTo == "next") {
|
||||||
state.ctx.indentTo = stream.column();
|
state.ctx.indentTo = stream.column();
|
||||||
}
|
}
|
||||||
|
state.lastType = type;
|
||||||
}
|
}
|
||||||
if (type == "open") state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null};
|
if (type == "open") state.ctx = {prev: state.ctx, start: stream.column(), indentTo: null};
|
||||||
else if (type == "close") state.ctx = state.ctx.prev || state.ctx;
|
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="../../doc/docs.css">
|
||||||
|
|
||||||
<link rel="stylesheet" href="../../lib/codemirror.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="../../lib/codemirror.js"></script>
|
||||||
<script src="css.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>
|
<style>.CodeMirror {background: #f8f8f8;}</style>
|
||||||
<div id=nav>
|
<div id=nav>
|
||||||
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
|
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
|
||||||
|
@ -60,7 +63,9 @@ code {
|
||||||
}
|
}
|
||||||
</textarea></form>
|
</textarea></form>
|
||||||
<script>
|
<script>
|
||||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {});
|
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||||
|
extraKeys: {"Ctrl-Space": "autocomplete"},
|
||||||
|
});
|
||||||
</script>
|
</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>
|
<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 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 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 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 = /[*+\-<>=&|~%^]/;
|
var operatorChars = /[*+\-<>=&|~%^]/;
|
||||||
|
|
||||||
return {
|
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