codemirror upgrade
This commit is contained in:
parent
8f28d1e308
commit
037159e39e
|
@ -1,117 +0,0 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function() {
|
||||
var mode = CodeMirror.getMode({indentUnit: 4}, "verilog");
|
||||
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
|
||||
|
||||
MT("Binary literals",
|
||||
"[number 1'b0]",
|
||||
"[number 1'b1]",
|
||||
"[number 1'bx]",
|
||||
"[number 1'bz]",
|
||||
"[number 1'bX]",
|
||||
"[number 1'bZ]",
|
||||
"[number 1'B0]",
|
||||
"[number 1'B1]",
|
||||
"[number 1'Bx]",
|
||||
"[number 1'Bz]",
|
||||
"[number 1'BX]",
|
||||
"[number 1'BZ]",
|
||||
"[number 1'b0]",
|
||||
"[number 1'b1]",
|
||||
"[number 2'b01]",
|
||||
"[number 2'bxz]",
|
||||
"[number 2'b11]",
|
||||
"[number 2'b10]",
|
||||
"[number 2'b1Z]",
|
||||
"[number 12'b0101_0101_0101]",
|
||||
"[number 1'b 0]",
|
||||
"[number 'b0101]"
|
||||
);
|
||||
|
||||
MT("Octal literals",
|
||||
"[number 3'o7]",
|
||||
"[number 3'O7]",
|
||||
"[number 3'so7]",
|
||||
"[number 3'SO7]"
|
||||
);
|
||||
|
||||
MT("Decimal literals",
|
||||
"[number 0]",
|
||||
"[number 1]",
|
||||
"[number 7]",
|
||||
"[number 123_456]",
|
||||
"[number 'd33]",
|
||||
"[number 8'd255]",
|
||||
"[number 8'D255]",
|
||||
"[number 8'sd255]",
|
||||
"[number 8'SD255]",
|
||||
"[number 32'd123]",
|
||||
"[number 32 'd123]",
|
||||
"[number 32 'd 123]"
|
||||
);
|
||||
|
||||
MT("Hex literals",
|
||||
"[number 4'h0]",
|
||||
"[number 4'ha]",
|
||||
"[number 4'hF]",
|
||||
"[number 4'hx]",
|
||||
"[number 4'hz]",
|
||||
"[number 4'hX]",
|
||||
"[number 4'hZ]",
|
||||
"[number 32'hdc78]",
|
||||
"[number 32'hDC78]",
|
||||
"[number 32 'hDC78]",
|
||||
"[number 32'h DC78]",
|
||||
"[number 32 'h DC78]",
|
||||
"[number 32'h44x7]",
|
||||
"[number 32'hFFF?]"
|
||||
);
|
||||
|
||||
MT("Real number literals",
|
||||
"[number 1.2]",
|
||||
"[number 0.1]",
|
||||
"[number 2394.26331]",
|
||||
"[number 1.2E12]",
|
||||
"[number 1.2e12]",
|
||||
"[number 1.30e-2]",
|
||||
"[number 0.1e-0]",
|
||||
"[number 23E10]",
|
||||
"[number 29E-2]",
|
||||
"[number 236.123_763_e-12]"
|
||||
);
|
||||
|
||||
MT("Operators",
|
||||
"[meta ^]"
|
||||
);
|
||||
|
||||
MT("Keywords",
|
||||
"[keyword logic]",
|
||||
"[keyword logic] [variable foo]",
|
||||
"[keyword reg] [variable abc]"
|
||||
);
|
||||
|
||||
MT("Variables",
|
||||
"[variable _leading_underscore]",
|
||||
"[variable _if]",
|
||||
"[number 12] [variable foo]",
|
||||
"[variable foo] [number 14]"
|
||||
);
|
||||
|
||||
MT("Tick defines",
|
||||
"[def `FOO]",
|
||||
"[def `foo]",
|
||||
"[def `FOO_bar]"
|
||||
);
|
||||
|
||||
MT("System calls",
|
||||
"[meta $display]",
|
||||
"[meta $vpi_printf]"
|
||||
);
|
||||
|
||||
MT("Line comment", "[comment // Hello world]");
|
||||
|
||||
|
||||
|
||||
})();
|
|
@ -157,12 +157,12 @@
|
|||
// Positions of the last startString before the start of the selection, and the first endString after it.
|
||||
var lastStart = startLine.lastIndexOf(startString, from.ch);
|
||||
var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length);
|
||||
if (lastStart != -1 && firstEnd != -1) return false;
|
||||
if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false;
|
||||
// Positions of the first endString after the end of the selection, and the last startString before it.
|
||||
firstEnd = endLine.indexOf(endString, to.ch);
|
||||
var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch);
|
||||
lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart;
|
||||
if (firstEnd != -1 && lastStart != -1) return false;
|
||||
if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false;
|
||||
|
||||
self.operation(function() {
|
||||
self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
|
|
@ -15,11 +15,11 @@
|
|||
var wrap = cm.getWrapperElement();
|
||||
var dialog;
|
||||
dialog = wrap.appendChild(document.createElement("div"));
|
||||
if (bottom) {
|
||||
if (bottom)
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
|
||||
} else {
|
||||
else
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
|
||||
}
|
||||
|
||||
if (typeof template == "string") {
|
||||
dialog.innerHTML = template;
|
||||
} else { // Assuming it's a detached DOM element.
|
||||
|
@ -35,8 +35,11 @@
|
|||
}
|
||||
|
||||
CodeMirror.defineExtension("openDialog", function(template, callback, options) {
|
||||
if (!options) options = {};
|
||||
|
||||
closeNotification(this, null);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
|
||||
var dialog = dialogDiv(this, template, options.bottom);
|
||||
var closed = false, me = this;
|
||||
function close(newVal) {
|
||||
if (typeof newVal == 'string') {
|
||||
|
@ -45,34 +48,43 @@
|
|||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
|
||||
if (options.onClose) options.onClose(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
var inp = dialog.getElementsByTagName("input")[0], button;
|
||||
if (inp) {
|
||||
if (options && options.value) inp.value = options.value;
|
||||
if (options.value) inp.value = options.value;
|
||||
|
||||
if (options.onInput)
|
||||
CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
|
||||
if (options.onKeyUp)
|
||||
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
|
||||
|
||||
CodeMirror.on(inp, "keydown", function(e) {
|
||||
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
|
||||
if (e.keyCode == 13 || e.keyCode == 27) {
|
||||
if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
|
||||
inp.blur();
|
||||
CodeMirror.e_stop(e);
|
||||
close();
|
||||
me.focus();
|
||||
}
|
||||
if (e.keyCode == 13) callback(inp.value);
|
||||
}
|
||||
});
|
||||
if (options && options.onKeyUp) {
|
||||
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
|
||||
}
|
||||
if (options && options.value) inp.value = options.value;
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
|
||||
|
||||
inp.focus();
|
||||
CodeMirror.on(inp, "blur", close);
|
||||
} else if (button = dialog.getElementsByTagName("button")[0]) {
|
||||
CodeMirror.on(button, "click", function() {
|
||||
close();
|
||||
me.focus();
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
|
||||
|
||||
button.focus();
|
||||
CodeMirror.on(button, "blur", close);
|
||||
}
|
||||
return close;
|
||||
});
|
|
@ -109,6 +109,10 @@
|
|||
replacements[i] = "/" + state.context.tagName + ">";
|
||||
}
|
||||
cm.replaceSelections(replacements);
|
||||
ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++)
|
||||
if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
|
||||
cm.indentLine(ranges[i].head.line);
|
||||
}
|
||||
|
||||
function indexOf(collection, elt) {
|
|
@ -151,8 +151,9 @@
|
|||
if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
|
||||
var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
|
||||
var start = end && toTagStart(iter);
|
||||
if (!end || end == "selfClose" || !start || cmp(iter, pos) > 0) return;
|
||||
if (!end || !start || cmp(iter, pos) > 0) return;
|
||||
var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
|
||||
if (end == "selfClose") return {open: here, close: null, at: "open"};
|
||||
|
||||
if (start[1]) { // closing tag
|
||||
return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
|
|
@ -49,19 +49,16 @@
|
|||
var string = token.string.substr(1);
|
||||
var prevCur = Pos(cur.line, token.start);
|
||||
var table = editor.getTokenAt(prevCur).string;
|
||||
if( !tables.hasOwnProperty( table ) ){
|
||||
if (!tables.hasOwnProperty(table))
|
||||
table = findTableByAlias(table, editor);
|
||||
}
|
||||
var columns = tables[table];
|
||||
if(!columns) {
|
||||
return;
|
||||
}
|
||||
addMatches(result, string, columns,
|
||||
function(w) {return "." + w;});
|
||||
if (!columns) return;
|
||||
|
||||
addMatches(result, string, columns, function(w) {return "." + w;});
|
||||
}
|
||||
|
||||
function eachWord(lineText, f) {
|
||||
if( !lineText ){return;}
|
||||
if (!lineText) return;
|
||||
var excepted = /[,;]/g;
|
||||
var words = lineText.split(" ");
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
|
@ -99,7 +96,7 @@
|
|||
separator.unshift(Pos(0, 0));
|
||||
separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length));
|
||||
|
||||
//find valieRange
|
||||
//find valid range
|
||||
var prevItem = 0;
|
||||
var current = convertCurToNumber(editor.getCursor());
|
||||
for (var i=0; i< separator.length; i++) {
|
||||
|
@ -124,41 +121,40 @@
|
|||
previousWord = word;
|
||||
}
|
||||
});
|
||||
if( table ){ break; }
|
||||
if (table) break;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
function sqlHint(editor, options) {
|
||||
CodeMirror.registerHelper("hint", "sql", function(editor, options) {
|
||||
tables = (options && options.tables) || {};
|
||||
keywords = keywords || getKeywords(editor);
|
||||
var cur = editor.getCursor();
|
||||
var token = editor.getTokenAt(cur), end = token.end;
|
||||
var result = [];
|
||||
var search = token.string.trim();
|
||||
|
||||
var token = editor.getTokenAt(cur), start, end, search;
|
||||
if (token.string.match(/^[.\w@]\w*$/)) {
|
||||
search = token.string;
|
||||
start = token.start;
|
||||
end = token.end;
|
||||
} else {
|
||||
start = end = cur.ch;
|
||||
search = "";
|
||||
}
|
||||
if (search.charAt(0) == ".") {
|
||||
columnCompletion(result, editor);
|
||||
if (!result.length) {
|
||||
while (token.start && search.charAt(0) == ".") {
|
||||
while (start && search.charAt(0) == ".") {
|
||||
token = editor.getTokenAt(Pos(cur.line, token.start - 1));
|
||||
start = token.start;
|
||||
search = token.string + search;
|
||||
}
|
||||
addMatches(result, search, tables,
|
||||
function(w) {return w;});
|
||||
addMatches(result, search, tables, function(w) {return w;});
|
||||
}
|
||||
} else {
|
||||
addMatches(result, search, keywords,
|
||||
function(w) {return w.toUpperCase();});
|
||||
addMatches(result, search, tables,
|
||||
function(w) {return w;});
|
||||
addMatches(result, search, tables, function(w) {return w;});
|
||||
addMatches(result, search, keywords, function(w) {return w.toUpperCase();});
|
||||
}
|
||||
|
||||
return {
|
||||
list: result,
|
||||
from: Pos(cur.line, token.start),
|
||||
to: Pos(cur.line, end)
|
||||
};
|
||||
}
|
||||
CodeMirror.registerHelper("hint", "sql", sqlHint);
|
||||
return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
|
||||
});
|
||||
});
|
|
@ -62,6 +62,12 @@
|
|||
color: #44c;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-copy-reverse {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
color: #44c;
|
||||
}
|
||||
|
||||
.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; }
|
||||
.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; }
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
constructor: DiffView,
|
||||
init: function(pane, orig, options) {
|
||||
this.edit = this.mv.edit;
|
||||
this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: true}, copyObj(options)));
|
||||
this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options)));
|
||||
|
||||
this.diff = getDiff(asString(orig), asString(options.value));
|
||||
this.diffOutOfDate = false;
|
||||
|
@ -71,7 +71,7 @@
|
|||
function update(mode) {
|
||||
if (mode == "full") {
|
||||
if (dv.svg) clear(dv.svg);
|
||||
clear(dv.copyButtons);
|
||||
if (dv.copyButtons) clear(dv.copyButtons);
|
||||
clearMarks(dv.edit, edit.marked, dv.classes);
|
||||
clearMarks(dv.orig, orig.marked, dv.classes);
|
||||
edit.from = edit.to = orig.from = orig.to = 0;
|
||||
|
@ -257,7 +257,7 @@
|
|||
var w = dv.gap.offsetWidth;
|
||||
attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight);
|
||||
}
|
||||
clear(dv.copyButtons);
|
||||
if (dv.copyButtons) clear(dv.copyButtons);
|
||||
|
||||
var flip = dv.type == "left";
|
||||
var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport();
|
||||
|
@ -279,17 +279,30 @@
|
|||
"d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z",
|
||||
"class", dv.classes.connect);
|
||||
}
|
||||
if (dv.copyButtons) {
|
||||
var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc",
|
||||
"CodeMirror-merge-copy"));
|
||||
copy.title = "Revert chunk";
|
||||
var editOriginals = dv.mv.options.allowEditingOriginals;
|
||||
copy.title = editOriginals ? "Push to left" : "Revert chunk";
|
||||
copy.chunk = {topEdit: topEdit, botEdit: botEdit, topOrig: topOrig, botOrig: botOrig};
|
||||
copy.style.top = top + "px";
|
||||
|
||||
if (editOriginals) {
|
||||
var topReverse = dv.orig.heightAtLine(topEdit, "local") - sTopEdit;
|
||||
var copyReverse = dv.copyButtons.appendChild(elt("div", dv.type == "right" ? "\u21dd" : "\u21dc",
|
||||
"CodeMirror-merge-copy-reverse"));
|
||||
copyReverse.title = "Push to right";
|
||||
copyReverse.chunk = {topEdit: topOrig, botEdit: botOrig, topOrig: topEdit, botOrig: botEdit};
|
||||
copyReverse.style.top = topReverse + "px";
|
||||
dv.type == "right" ? copyReverse.style.left = "2px" : copyReverse.style.right = "2px";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function copyChunk(dv, chunk) {
|
||||
function copyChunk(dv, to, from, chunk) {
|
||||
if (dv.diffOutOfDate) return;
|
||||
dv.edit.replaceRange(dv.orig.getRange(Pos(chunk.topOrig, 0), Pos(chunk.botOrig, 0)),
|
||||
to.replaceRange(from.getRange(Pos(chunk.topOrig, 0), Pos(chunk.botOrig, 0)),
|
||||
Pos(chunk.topEdit, 0), Pos(chunk.botEdit, 0));
|
||||
}
|
||||
|
||||
|
@ -298,6 +311,7 @@
|
|||
var MergeView = CodeMirror.MergeView = function(node, options) {
|
||||
if (!(this instanceof MergeView)) return new MergeView(node, options);
|
||||
|
||||
this.options = options;
|
||||
var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight;
|
||||
var hasLeft = origLeft != null, hasRight = origRight != null;
|
||||
var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0);
|
||||
|
@ -323,6 +337,7 @@
|
|||
(hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost";
|
||||
|
||||
wrap.push(elt("div", null, null, "height: 0; clear: both;"));
|
||||
|
||||
var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane"));
|
||||
this.edit = CodeMirror(editPane, copyObj(options));
|
||||
|
||||
|
@ -345,12 +360,20 @@
|
|||
lock.title = "Toggle locked scrolling";
|
||||
var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap");
|
||||
CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); });
|
||||
var gapElts = [lockWrap];
|
||||
if (dv.mv.options.revertButtons !== false) {
|
||||
dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type);
|
||||
CodeMirror.on(dv.copyButtons, "click", function(e) {
|
||||
var node = e.target || e.srcElement;
|
||||
if (node.chunk) copyChunk(dv, node.chunk);
|
||||
if (!node.chunk) return;
|
||||
if (node.className == "CodeMirror-merge-copy-reverse") {
|
||||
copyChunk(dv, dv.orig, dv.edit, node.chunk);
|
||||
return;
|
||||
}
|
||||
copyChunk(dv, dv.edit, dv.orig, node.chunk);
|
||||
});
|
||||
var gapElts = [dv.copyButtons, lockWrap];
|
||||
gapElts.unshift(dv.copyButtons);
|
||||
}
|
||||
var svg = document.createElementNS && document.createElementNS(svgNS, "svg");
|
||||
if (svg && !svg.createSVGRect) svg = null;
|
||||
dv.svg = svg;
|
|
@ -71,7 +71,7 @@
|
|||
return query;
|
||||
}
|
||||
var queryDialog =
|
||||
'Search: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
|
||||
'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
|
||||
function doSearch(cm, rev) {
|
||||
var state = getSearchState(cm);
|
||||
if (state.query) return findNext(cm, rev);
|
||||
|
@ -106,8 +106,8 @@
|
|||
});}
|
||||
|
||||
var replaceQueryDialog =
|
||||
'Replace: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
|
||||
var replacementQueryDialog = 'With: <input type="text" style="width: 10em"/>';
|
||||
'Replace: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
|
||||
var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
|
||||
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
|
||||
function replace(cm, all) {
|
||||
if (cm.getOption("readOnly")) return;
|
|
@ -662,6 +662,7 @@
|
|||
function updateDisplaySimple(cm, viewport) {
|
||||
var update = new DisplayUpdate(cm, viewport);
|
||||
if (updateDisplayIfNeeded(cm, update)) {
|
||||
updateHeightsInViewport(cm);
|
||||
postUpdateDisplay(cm, update);
|
||||
var barMeasure = measureForScrollbars(cm);
|
||||
updateSelection(cm);
|
||||
|
@ -1280,8 +1281,7 @@
|
|||
return result;
|
||||
}
|
||||
|
||||
function updateSelection(cm, drawn) {
|
||||
if (!drawn) drawn = drawSelection(cm);
|
||||
function showSelection(cm, drawn) {
|
||||
removeChildrenAndAdd(cm.display.cursorDiv, drawn.cursors);
|
||||
removeChildrenAndAdd(cm.display.selectionDiv, drawn.selection);
|
||||
if (drawn.teTop != null) {
|
||||
|
@ -1290,6 +1290,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
function updateSelection(cm) {
|
||||
showSelection(cm, drawSelection(cm));
|
||||
}
|
||||
|
||||
// Draws a cursor for the given range
|
||||
function drawSelectionCursor(cm, range, output) {
|
||||
var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine);
|
||||
|
@ -1642,6 +1646,7 @@
|
|||
|
||||
var rect;
|
||||
if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
|
||||
for (;;) {
|
||||
while (start && isExtendingChar(prepared.line.text.charAt(mStart + start))) --start;
|
||||
while (mStart + end < mEnd && isExtendingChar(prepared.line.text.charAt(mStart + end))) ++end;
|
||||
if (ie && ie_version < 9 && start == 0 && end == mEnd - mStart) {
|
||||
|
@ -1655,6 +1660,11 @@
|
|||
} else {
|
||||
rect = range(node, start, end).getBoundingClientRect() || nullRect;
|
||||
}
|
||||
if (rect.left || rect.right || start == 0) break;
|
||||
end = start;
|
||||
start = start - 1;
|
||||
collapse = "right";
|
||||
}
|
||||
} else { // If it is a widget, simply get the box for the whole widget.
|
||||
if (start > 0) collapse = bias = "right";
|
||||
var rects;
|
||||
|
@ -2029,16 +2039,17 @@
|
|||
var cm = op.cm, display = cm.display;
|
||||
if (op.updatedDisplay) updateHeightsInViewport(cm);
|
||||
|
||||
op.barMeasure = measureForScrollbars(cm);
|
||||
|
||||
// If the max line changed since it was last measured, measure it,
|
||||
// and ensure the document's width matches it.
|
||||
// updateDisplayIfNeeded will use these properties to do the actual resizing
|
||||
// updateDisplay_W2 will use these properties to do the actual resizing
|
||||
if (display.maxLineChanged && !cm.options.lineWrapping) {
|
||||
op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left;
|
||||
op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
|
||||
op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo +
|
||||
scrollerCutOff - display.scroller.clientWidth);
|
||||
}
|
||||
|
||||
op.barMeasure = measureForScrollbars(cm);
|
||||
if (op.updatedDisplay || op.selectionChanged)
|
||||
op.newSelectionNodes = drawSelection(cm);
|
||||
}
|
||||
|
@ -2050,10 +2061,11 @@
|
|||
cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
|
||||
if (op.maxScrollLeft < cm.doc.scrollLeft)
|
||||
setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);
|
||||
cm.display.maxLineChanged = false;
|
||||
}
|
||||
|
||||
if (op.newSelectionNodes)
|
||||
updateSelection(cm, op.newSelectionNodes);
|
||||
showSelection(cm, op.newSelectionNodes);
|
||||
if (op.updatedDisplay)
|
||||
setDocumentHeight(cm, op.barMeasure);
|
||||
if (op.updatedDisplay || op.startHeight != cm.doc.height)
|
||||
|
@ -2068,6 +2080,9 @@
|
|||
function endOperation_finish(op) {
|
||||
var cm = op.cm, display = cm.display, doc = cm.doc;
|
||||
|
||||
if (op.adjustWidthTo != null && Math.abs(op.barMeasure.scrollWidth - cm.display.scroller.scrollWidth) > 1)
|
||||
updateScrollbars(cm);
|
||||
|
||||
if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
|
||||
|
||||
// Abort mouse wheel delta measurement, when scrolling explicitly
|
||||
|
@ -3553,7 +3568,7 @@
|
|||
|
||||
var after = i ? computeSelAfterChange(doc, change) : lst(source);
|
||||
makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
|
||||
if (!i && doc.cm) doc.cm.scrollIntoView(change);
|
||||
if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)});
|
||||
var rebased = [];
|
||||
|
||||
// Propagate to the linked documents
|
||||
|
@ -3742,6 +3757,7 @@
|
|||
if (y1 < 0) y1 = 0;
|
||||
var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
|
||||
var screen = display.scroller.clientHeight - scrollerCutOff, result = {};
|
||||
if (y2 - y1 > screen) y2 = y1 + screen;
|
||||
var docBottom = cm.doc.height + paddingVert(display);
|
||||
var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
|
||||
if (y1 < screentop) {
|
||||
|
@ -3752,16 +3768,16 @@
|
|||
}
|
||||
|
||||
var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
|
||||
var screenw = display.scroller.clientWidth - scrollerCutOff;
|
||||
x1 += display.gutters.offsetWidth; x2 += display.gutters.offsetWidth;
|
||||
var gutterw = display.gutters.offsetWidth;
|
||||
var atLeft = x1 < gutterw + 10;
|
||||
if (x1 < screenleft + gutterw || atLeft) {
|
||||
if (atLeft) x1 = 0;
|
||||
result.scrollLeft = Math.max(0, x1 - 10 - gutterw);
|
||||
} else if (x2 > screenw + screenleft - 3) {
|
||||
result.scrollLeft = x2 + 10 - screenw;
|
||||
}
|
||||
var screenw = display.scroller.clientWidth - scrollerCutOff - display.gutters.offsetWidth;
|
||||
var tooWide = x2 - x1 > screenw;
|
||||
if (tooWide) x2 = y1 + screen;
|
||||
if (x1 < 10)
|
||||
result.scrollLeft = 0;
|
||||
else if (x1 < screenleft)
|
||||
result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
|
||||
else if (x2 > screenw + screenleft - 3)
|
||||
result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4070,11 +4086,14 @@
|
|||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i];
|
||||
if (!range.empty()) {
|
||||
var start = Math.max(end, range.from().line);
|
||||
var to = range.to();
|
||||
var from = range.from(), to = range.to();
|
||||
var start = Math.max(end, from.line);
|
||||
end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
|
||||
for (var j = start; j < end; ++j)
|
||||
indentLine(this, j, how);
|
||||
var newRanges = this.doc.sel.ranges;
|
||||
if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
|
||||
replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);
|
||||
} else if (range.head.line > end) {
|
||||
indentLine(this, range.head.line, how, true);
|
||||
end = range.head.line;
|
||||
|
@ -4470,7 +4489,7 @@
|
|||
clearCaches(cm);
|
||||
regChange(cm);
|
||||
}, true);
|
||||
option("specialChars", /[\t\u0000-\u0019\u00ad\u200b\u2028\u2029\ufeff]/g, function(cm, val) {
|
||||
option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val) {
|
||||
cm.options.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
|
||||
cm.refresh();
|
||||
}, true);
|
||||
|
@ -4731,15 +4750,7 @@
|
|||
},
|
||||
goLineStartSmart: function(cm) {
|
||||
cm.extendSelectionsBy(function(range) {
|
||||
var start = lineStart(cm, range.head.line);
|
||||
var line = cm.getLineHandle(start.line);
|
||||
var order = getOrder(line);
|
||||
if (!order || order[0].level == 0) {
|
||||
var firstNonWS = Math.max(0, line.text.search(/\S/));
|
||||
var inWS = range.head.line == start.line && range.head.ch <= firstNonWS && range.head.ch;
|
||||
return Pos(start.line, inWS ? 0 : firstNonWS);
|
||||
}
|
||||
return start;
|
||||
return lineStartSmart(cm, range.head);
|
||||
}, {origin: "+move", bias: 1});
|
||||
},
|
||||
goLineEnd: function(cm) {
|
||||
|
@ -4758,6 +4769,14 @@
|
|||
return cm.coordsChar({left: 0, top: top}, "div");
|
||||
}, sel_move);
|
||||
},
|
||||
goLineLeftSmart: function(cm) {
|
||||
cm.extendSelectionsBy(function(range) {
|
||||
var top = cm.charCoords(range.head, "div").top + 5;
|
||||
var pos = cm.coordsChar({left: 0, top: top}, "div");
|
||||
if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head);
|
||||
return pos;
|
||||
}, sel_move);
|
||||
},
|
||||
goLineUp: function(cm) {cm.moveV(-1, "line");},
|
||||
goLineDown: function(cm) {cm.moveV(1, "line");},
|
||||
goPageUp: function(cm) {cm.moveV(-1, "page");},
|
||||
|
@ -6495,7 +6514,7 @@
|
|||
},
|
||||
changeGeneration: function(forceSplit) {
|
||||
if (forceSplit)
|
||||
this.history.lastOp = this.history.lastOrigin = null;
|
||||
this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;
|
||||
return this.history.generation;
|
||||
},
|
||||
isClean: function (gen) {
|
||||
|
@ -6812,7 +6831,7 @@
|
|||
// Used to track when changes can be merged into a single undo
|
||||
// event
|
||||
this.lastModTime = this.lastSelTime = 0;
|
||||
this.lastOp = null;
|
||||
this.lastOp = this.lastSelOp = null;
|
||||
this.lastOrigin = this.lastSelOrigin = null;
|
||||
// Used by the isClean() method
|
||||
this.generation = this.maxGeneration = startGen || 1;
|
||||
|
@ -6890,7 +6909,7 @@
|
|||
hist.done.push(selAfter);
|
||||
hist.generation = ++hist.maxGeneration;
|
||||
hist.lastModTime = hist.lastSelTime = time;
|
||||
hist.lastOp = opId;
|
||||
hist.lastOp = hist.lastSelOp = opId;
|
||||
hist.lastOrigin = hist.lastSelOrigin = change.origin;
|
||||
|
||||
if (!last) signal(doc, "historyAdded");
|
||||
|
@ -6916,7 +6935,7 @@
|
|||
// the current, or the origins don't allow matching. Origins
|
||||
// starting with * are always merged, those starting with + are
|
||||
// merged when similar and close together in time.
|
||||
if (opId == hist.lastOp ||
|
||||
if (opId == hist.lastSelOp ||
|
||||
(origin && hist.lastSelOrigin == origin &&
|
||||
(hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
|
||||
selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
|
||||
|
@ -6926,7 +6945,7 @@
|
|||
|
||||
hist.lastSelTime = +new Date;
|
||||
hist.lastSelOrigin = origin;
|
||||
hist.lastOp = opId;
|
||||
hist.lastSelOp = opId;
|
||||
if (options && options.clearRedo !== false)
|
||||
clearSelectionEvents(hist.undone);
|
||||
}
|
||||
|
@ -7556,6 +7575,17 @@
|
|||
var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
|
||||
return Pos(lineN == null ? lineNo(line) : lineN, ch);
|
||||
}
|
||||
function lineStartSmart(cm, pos) {
|
||||
var start = lineStart(cm, pos.line);
|
||||
var line = getLine(cm.doc, start.line);
|
||||
var order = getOrder(line);
|
||||
if (!order || order[0].level == 0) {
|
||||
var firstNonWS = Math.max(0, line.text.search(/\S/));
|
||||
var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
|
||||
return Pos(start.line, inWS ? 0 : firstNonWS);
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
function compareBidiLevel(order, a, b) {
|
||||
var linedir = order[0].level;
|
||||
|
@ -7795,7 +7825,7 @@
|
|||
|
||||
// THE END
|
||||
|
||||
CodeMirror.version = "4.4.0";
|
||||
CodeMirror.version = "4.5.0";
|
||||
|
||||
return CodeMirror;
|
||||
});
|
|
@ -17,7 +17,8 @@
|
|||
var map = CodeMirror.keyMap.sublime = {fallthrough: "default"};
|
||||
var cmds = CodeMirror.commands;
|
||||
var Pos = CodeMirror.Pos;
|
||||
var ctrl = CodeMirror.keyMap["default"] == CodeMirror.keyMap.pcDefault ? "Ctrl-" : "Cmd-";
|
||||
var mac = CodeMirror.keyMap["default"] == CodeMirror.keyMap.macDefault;
|
||||
var ctrl = mac ? "Cmd-" : "Ctrl-";
|
||||
|
||||
// This is not exactly Sublime's algorithm. I couldn't make heads or tails of that.
|
||||
function findPosSubword(doc, start, dir) {
|
||||
|
@ -186,7 +187,9 @@
|
|||
});
|
||||
};
|
||||
|
||||
cmds[map["Shift-" + ctrl + "Up"] = "swapLineUp"] = function(cm) {
|
||||
var swapLineCombo = mac ? "Cmd-Ctrl-" : "Shift-Ctrl-";
|
||||
|
||||
cmds[map[swapLineCombo + "Up"] = "swapLineUp"] = function(cm) {
|
||||
var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1, newSels = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i], from = range.from().line - 1, to = range.to().line;
|
||||
|
@ -212,7 +215,7 @@
|
|||
});
|
||||
};
|
||||
|
||||
cmds[map["Shift-" + ctrl + "Down"] = "swapLineDown"] = function(cm) {
|
||||
cmds[map[swapLineCombo + "Down"] = "swapLineDown"] = function(cm) {
|
||||
var ranges = cm.listSelections(), linesToMove = [], at = cm.lastLine() + 1;
|
||||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||||
var range = ranges[i], from = range.to().line + 1, to = range.from().line;
|
|
@ -616,7 +616,9 @@
|
|||
visualLine: false,
|
||||
visualBlock: false,
|
||||
lastSelection: null,
|
||||
lastPastedText: null
|
||||
lastPastedText: null,
|
||||
// Used by two-character ESC keymap routines. Should not be changed from false here.
|
||||
awaitingEscapeSecondCharacter: false
|
||||
};
|
||||
}
|
||||
return cm.state.vim;
|
||||
|
@ -785,17 +787,19 @@
|
|||
* pasted, should it insert itself into a new line, or should the text be
|
||||
* inserted at the cursor position.)
|
||||
*/
|
||||
function Register(text, linewise) {
|
||||
function Register(text, linewise, blockwise) {
|
||||
this.clear();
|
||||
this.keyBuffer = [text || ''];
|
||||
this.insertModeChanges = [];
|
||||
this.searchQueries = [];
|
||||
this.linewise = !!linewise;
|
||||
this.blockwise = !!blockwise;
|
||||
}
|
||||
Register.prototype = {
|
||||
setText: function(text, linewise) {
|
||||
setText: function(text, linewise, blockwise) {
|
||||
this.keyBuffer = [text || ''];
|
||||
this.linewise = !!linewise;
|
||||
this.blockwise = !!blockwise;
|
||||
},
|
||||
pushText: function(text, linewise) {
|
||||
// if this register has ever been set to linewise, use linewise.
|
||||
|
@ -840,7 +844,7 @@
|
|||
registers['/'] = new Register();
|
||||
}
|
||||
RegisterController.prototype = {
|
||||
pushText: function(registerName, operator, text, linewise) {
|
||||
pushText: function(registerName, operator, text, linewise, blockwise) {
|
||||
if (linewise && text.charAt(0) == '\n') {
|
||||
text = text.slice(1) + '\n';
|
||||
}
|
||||
|
@ -857,7 +861,7 @@
|
|||
switch (operator) {
|
||||
case 'yank':
|
||||
// The 0 register contains the text from the most recent yank.
|
||||
this.registers['0'] = new Register(text, linewise);
|
||||
this.registers['0'] = new Register(text, linewise, blockwise);
|
||||
break;
|
||||
case 'delete':
|
||||
case 'change':
|
||||
|
@ -873,7 +877,7 @@
|
|||
break;
|
||||
}
|
||||
// Make sure the unnamed register is set to what just happened
|
||||
this.unnamedRegister.setText(text, linewise);
|
||||
this.unnamedRegister.setText(text, linewise, blockwise);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -882,7 +886,7 @@
|
|||
if (append) {
|
||||
register.pushText(text, linewise);
|
||||
} else {
|
||||
register.setText(text, linewise);
|
||||
register.setText(text, linewise, blockwise);
|
||||
}
|
||||
// The unnamed register always has the same value as the last used
|
||||
// register.
|
||||
|
@ -1860,6 +1864,12 @@
|
|||
var curStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head;
|
||||
var curEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor;
|
||||
var text = cm.getSelection();
|
||||
var visualBlock = vim.visualBlock;
|
||||
if (vim.lastSelection && !vim.visualMode) {
|
||||
visualBlock = vim.lastSelection.visualBlock ? true : visualBlock;
|
||||
}
|
||||
var lastInsertModeChanges = vimGlobalState.macroModeState.lastInsertModeChanges;
|
||||
lastInsertModeChanges.inVisualBlock = visualBlock;
|
||||
var replacement = new Array(selections.length).join('1').split('1');
|
||||
// save the selectionEnd mark
|
||||
var selectionEnd = vim.marks['>'] ? vim.marks['>'].find() : cm.getCursor('head');
|
||||
|
@ -1868,7 +1878,7 @@
|
|||
operatorArgs.linewise);
|
||||
if (operatorArgs.linewise) {
|
||||
// 'C' in visual block extends the block till eol for all lines
|
||||
if (vim.visualBlock){
|
||||
if (visualBlock){
|
||||
var startLine = curStart.line;
|
||||
while (startLine <= curEnd.line) {
|
||||
var endCh = lineLength(cm, startLine);
|
||||
|
@ -1898,7 +1908,7 @@
|
|||
curEnd = offsetCursor(curEnd, 0, - match[0].length);
|
||||
}
|
||||
}
|
||||
if (vim.visualBlock) {
|
||||
if (visualBlock) {
|
||||
cm.replaceSelections(replacement);
|
||||
} else {
|
||||
cm.setCursor(curStart);
|
||||
|
@ -1916,17 +1926,19 @@
|
|||
var curEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor;
|
||||
// Save the '>' mark before cm.replaceRange clears it.
|
||||
var selectionEnd, selectionStart;
|
||||
var blockwise = vim.visualBlock;
|
||||
if (vim.visualMode) {
|
||||
selectionEnd = vim.marks['>'].find();
|
||||
selectionStart = vim.marks['<'].find();
|
||||
} else if (vim.lastSelection) {
|
||||
selectionEnd = vim.lastSelection.curStartMark.find();
|
||||
selectionStart = vim.lastSelection.curEndMark.find();
|
||||
blockwise = vim.lastSelection.visualBlock;
|
||||
}
|
||||
var text = cm.getSelection();
|
||||
vimGlobalState.registerController.pushText(
|
||||
operatorArgs.registerName, 'delete', text,
|
||||
operatorArgs.linewise);
|
||||
operatorArgs.linewise, blockwise);
|
||||
var replacement = new Array(selections.length).join('1').split('1');
|
||||
// If the ending line is past the last line, inclusive, instead of
|
||||
// including the trailing \n, include the \n before the starting line
|
||||
|
@ -1999,11 +2011,11 @@
|
|||
cm.setCursor(cursorIsBefore(curStart, curEnd) ? curStart : curEnd);
|
||||
}
|
||||
},
|
||||
yank: function(cm, operatorArgs, _vim, _curStart, _curEnd, curOriginal) {
|
||||
yank: function(cm, operatorArgs, vim, _curStart, _curEnd, curOriginal) {
|
||||
var text = cm.getSelection();
|
||||
vimGlobalState.registerController.pushText(
|
||||
operatorArgs.registerName, 'yank',
|
||||
text, operatorArgs.linewise);
|
||||
text, operatorArgs.linewise, vim.visualBlock);
|
||||
cm.setCursor(curOriginal);
|
||||
}
|
||||
};
|
||||
|
@ -2096,6 +2108,11 @@
|
|||
vim.insertMode = true;
|
||||
vim.insertModeRepeat = actionArgs && actionArgs.repeat || 1;
|
||||
var insertAt = (actionArgs) ? actionArgs.insertAt : null;
|
||||
if (vim.visualMode) {
|
||||
var selections = getSelectedAreaRange(cm, vim);
|
||||
var selectionStart = selections[0];
|
||||
var selectionEnd = selections[1];
|
||||
}
|
||||
if (insertAt == 'eol') {
|
||||
var cursor = cm.getCursor();
|
||||
cursor = Pos(cursor.line, lineLength(cm, cursor.line));
|
||||
|
@ -2103,15 +2120,34 @@
|
|||
} else if (insertAt == 'charAfter') {
|
||||
cm.setCursor(offsetCursor(cm.getCursor(), 0, 1));
|
||||
} else if (insertAt == 'firstNonBlank') {
|
||||
cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
|
||||
} else if (insertAt == 'endOfSelectedArea') {
|
||||
var selectionEnd = cm.getCursor('head');
|
||||
var selectionStart = cm.getCursor('anchor');
|
||||
if (vim.visualMode && !vim.visualBlock) {
|
||||
if (selectionEnd.line < selectionStart.line) {
|
||||
selectionEnd = Pos(selectionStart.line, 0);
|
||||
}
|
||||
cm.setCursor(selectionEnd);
|
||||
exitVisualMode(cm);
|
||||
} else {
|
||||
selectionStart = Pos(selectionStart.line, 0);
|
||||
cm.setCursor(selectionStart);
|
||||
}
|
||||
cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
|
||||
} else if (vim.visualBlock) {
|
||||
selectionEnd = Pos(selectionEnd.line, selectionStart.ch);
|
||||
cm.setCursor(selectionStart);
|
||||
selectBlock(cm, selectionEnd);
|
||||
} else {
|
||||
cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
|
||||
}
|
||||
} else if (insertAt == 'endOfSelectedArea') {
|
||||
if (vim.visualBlock) {
|
||||
selectionStart = Pos(selectionStart.line, selectionEnd.ch);
|
||||
cm.setCursor(selectionStart);
|
||||
selectBlock(cm, selectionEnd);
|
||||
} else if (selectionEnd.line < selectionStart.line) {
|
||||
selectionEnd = Pos(selectionStart.line, 0);
|
||||
cm.setCursor(selectionEnd);
|
||||
}
|
||||
} else if (insertAt == 'inplace') {
|
||||
if (vim.visualMode){
|
||||
return;
|
||||
}
|
||||
}
|
||||
cm.setOption('keyMap', 'vim-insert');
|
||||
cm.setOption('disableInput', false);
|
||||
|
@ -2129,6 +2165,9 @@
|
|||
cm.on('change', onChange);
|
||||
CodeMirror.on(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);
|
||||
}
|
||||
if (vim.visualMode) {
|
||||
exitVisualMode(cm);
|
||||
}
|
||||
},
|
||||
toggleVisualMode: function(cm, actionArgs, vim) {
|
||||
var repeat = actionArgs.repeat;
|
||||
|
@ -2339,6 +2378,7 @@
|
|||
var text = Array(actionArgs.repeat + 1).join(text);
|
||||
}
|
||||
var linewise = register.linewise;
|
||||
var blockwise = register.blockwise;
|
||||
if (linewise) {
|
||||
if(vim.visualMode) {
|
||||
text = vim.visualLine ? text.slice(0, -1) : '\n' + text.slice(0, text.length - 1) + '\n';
|
||||
|
@ -2351,6 +2391,12 @@
|
|||
cur.ch = 0;
|
||||
}
|
||||
} else {
|
||||
if (blockwise) {
|
||||
text = text.split('\n');
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
text[i] = (text[i] == '') ? ' ' : text[i];
|
||||
}
|
||||
}
|
||||
cur.ch += actionArgs.after ? 1 : 0;
|
||||
}
|
||||
var curPosFinal;
|
||||
|
@ -2362,15 +2408,57 @@
|
|||
var selectedArea = getSelectedAreaRange(cm, vim);
|
||||
var selectionStart = selectedArea[0];
|
||||
var selectionEnd = selectedArea[1];
|
||||
var selectedText = cm.getSelection();
|
||||
var selections = cm.listSelections();
|
||||
var emptyStrings = new Array(selections.length).join('1').split('1');
|
||||
// save the curEnd marker before it get cleared due to cm.replaceRange.
|
||||
if (vim.lastSelection) lastSelectionCurEnd = vim.lastSelection.curEndMark.find();
|
||||
if (vim.lastSelection) {
|
||||
lastSelectionCurEnd = vim.lastSelection.curEndMark.find();
|
||||
}
|
||||
// push the previously selected text to unnamed register
|
||||
vimGlobalState.registerController.unnamedRegister.setText(cm.getRange(selectionStart, selectionEnd));
|
||||
vimGlobalState.registerController.unnamedRegister.setText(selectedText);
|
||||
if (blockwise) {
|
||||
// first delete the selected text
|
||||
cm.replaceSelections(emptyStrings);
|
||||
// Set new selections as per the block length of the yanked text
|
||||
selectionEnd = Pos(selectionStart.line + text.length-1, selectionStart.ch);
|
||||
cm.setCursor(selectionStart);
|
||||
selectBlock(cm, selectionEnd);
|
||||
cm.replaceSelections(text);
|
||||
curPosFinal = selectionStart;
|
||||
} else if (vim.visualBlock) {
|
||||
cm.replaceSelections(emptyStrings);
|
||||
cm.setCursor(selectionStart);
|
||||
cm.replaceRange(text, selectionStart, selectionStart);
|
||||
curPosFinal = selectionStart;
|
||||
} else {
|
||||
cm.replaceRange(text, selectionStart, selectionEnd);
|
||||
// restore the the curEnd marker
|
||||
if(lastSelectionCurEnd) vim.lastSelection.curEndMark = cm.setBookmark(lastSelectionCurEnd);
|
||||
curPosFinal = cm.posFromIndex(cm.indexFromPos(selectionStart) + text.length - 1);
|
||||
if(linewise)curPosFinal.ch=0;
|
||||
}
|
||||
// restore the the curEnd marker
|
||||
if(lastSelectionCurEnd) {
|
||||
vim.lastSelection.curEndMark = cm.setBookmark(lastSelectionCurEnd);
|
||||
}
|
||||
if (linewise) {
|
||||
curPosFinal.ch=0;
|
||||
}
|
||||
} else {
|
||||
if (blockwise) {
|
||||
cm.setCursor(cur);
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
var line = cur.line+i;
|
||||
if (line > cm.lastLine()) {
|
||||
cm.replaceRange('\n', Pos(line, 0));
|
||||
}
|
||||
var lastCh = lineLength(cm, line);
|
||||
if (lastCh < cur.ch) {
|
||||
extendLineToColumn(cm, line, cur.ch);
|
||||
}
|
||||
}
|
||||
cm.setCursor(cur);
|
||||
selectBlock(cm, Pos(cur.line + text.length-1, cur.ch));
|
||||
cm.replaceSelections(text);
|
||||
curPosFinal = cur;
|
||||
} else {
|
||||
cm.replaceRange(text, cur);
|
||||
// Now fine tune the cursor to where we want it.
|
||||
|
@ -2390,6 +2478,7 @@
|
|||
curPosFinal = cm.posFromIndex(idx + text.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
cm.setCursor(curPosFinal);
|
||||
if (vim.visualMode) {
|
||||
exitVisualMode(cm);
|
||||
|
@ -2597,6 +2686,12 @@
|
|||
function escapeRegex(s) {
|
||||
return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, '\\$1');
|
||||
}
|
||||
function extendLineToColumn(cm, lineNum, column) {
|
||||
var endCh = lineLength(cm, lineNum);
|
||||
var spaces = new Array(column-endCh+1).join(' ');
|
||||
cm.setCursor(Pos(lineNum, endCh));
|
||||
cm.replaceRange(spaces, cm.getCursor());
|
||||
}
|
||||
// This functions selects a rectangular block
|
||||
// of text with selectionEnd as any of its corner
|
||||
// Height of block:
|
||||
|
@ -2606,55 +2701,86 @@
|
|||
function selectBlock(cm, selectionEnd) {
|
||||
var selections = [], ranges = cm.listSelections();
|
||||
var firstRange = ranges[0].anchor, lastRange = ranges[ranges.length-1].anchor;
|
||||
var start, end, selectionStart;
|
||||
var start, end, direction, selectionStart;
|
||||
var curEnd = cm.getCursor('head');
|
||||
var originalSelectionEnd = copyCursor(selectionEnd);
|
||||
start = firstRange.line;
|
||||
end = lastRange.line;
|
||||
if (selectionEnd.line < curEnd.line) {
|
||||
direction = 'up';
|
||||
} else if (selectionEnd.line > curEnd.line) {
|
||||
direction = 'down';
|
||||
} else {
|
||||
if (selectionEnd.ch != curEnd.ch) {
|
||||
direction = selectionEnd.ch > curEnd.ch ? 'right' : 'left';
|
||||
}
|
||||
selectionStart = cm.getCursor('anchor');
|
||||
}
|
||||
var primIndex = getIndex(ranges, curEnd);
|
||||
// sets to true when selectionEnd already lies inside the existing selections
|
||||
var contains = getIndex(ranges, selectionEnd) < 0 ? false : true;
|
||||
selectionEnd = cm.clipPos(selectionEnd);
|
||||
// difference in distance of selectionEnd from each end of the block.
|
||||
var near = Math.abs(firstRange.line - selectionEnd.line) - Math.abs(lastRange.line - selectionEnd.line);
|
||||
if (near > 0) {
|
||||
end = selectionEnd.line;
|
||||
start = firstRange.line;
|
||||
if (lastRange.line == selectionEnd.line && contains) {
|
||||
start = end;
|
||||
var contains = getIndex(ranges, selectionEnd) < 0 ? false : true;
|
||||
var isClipped = !cursorEqual(originalSelectionEnd, selectionEnd);
|
||||
// This function helps to check selection crossing
|
||||
// in case of short lines.
|
||||
var processSelectionCrossing = function() {
|
||||
if (isClipped) {
|
||||
if (curEnd.ch >= selectionStart.ch) {
|
||||
selectionStart.ch++;
|
||||
}
|
||||
} else if (near < 0) {
|
||||
start = selectionEnd.line;
|
||||
end = lastRange.line;
|
||||
if (firstRange.line == selectionEnd.line && contains) {
|
||||
end = start;
|
||||
}
|
||||
} else {
|
||||
// Case where selectionEnd line is halfway between the 2 ends.
|
||||
// We remove the primary selection in this case
|
||||
if (primIndex == 0) {
|
||||
start = selectionEnd.line;
|
||||
end = lastRange.line;
|
||||
} else {
|
||||
} else if (curEnd.ch == lineLength(cm, curEnd.line)) {
|
||||
if (cursorEqual(ranges[primIndex].anchor, ranges[primIndex].head) && ranges.length>1) {
|
||||
if (direction == 'up') {
|
||||
if (contains || primIndex>0) {
|
||||
start = firstRange.line;
|
||||
end = selectionEnd.line;
|
||||
selectionStart = ranges[primIndex-1].anchor;
|
||||
}
|
||||
} else {
|
||||
if (contains || primIndex == 0) {
|
||||
end = lastRange.line;
|
||||
start = selectionEnd.line;
|
||||
selectionStart = ranges[primIndex+1].anchor;
|
||||
}
|
||||
}
|
||||
if (start > end) {
|
||||
var tmp = start;
|
||||
start = end;
|
||||
end = tmp;
|
||||
if (selectionEnd.ch >= selectionStart.ch) {
|
||||
selectionStart.ch--;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
switch(direction) {
|
||||
case 'up':
|
||||
start = contains ? firstRange.line : selectionEnd.line;
|
||||
end = contains ? selectionEnd.line : lastRange.line;
|
||||
selectionStart = lastRange;
|
||||
processSelectionCrossing();
|
||||
break;
|
||||
case 'down':
|
||||
start = contains ? selectionEnd.line : firstRange.line;
|
||||
end = contains ? lastRange.line : selectionEnd.line;
|
||||
selectionStart = firstRange;
|
||||
processSelectionCrossing();
|
||||
break;
|
||||
case 'left':
|
||||
if ((selectionEnd.ch <= selectionStart.ch) && (curEnd.ch > selectionStart.ch)) {
|
||||
selectionStart.ch++;
|
||||
selectionEnd.ch--;
|
||||
}
|
||||
break;
|
||||
case 'right':
|
||||
if ((selectionStart.ch <= selectionEnd.ch) && (curEnd.ch < selectionStart.ch)) {
|
||||
selectionStart.ch--;
|
||||
selectionEnd.ch++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
start = selectionStart.line;
|
||||
end = selectionEnd.line;
|
||||
}
|
||||
selectionStart = (near > 0) ? firstRange : lastRange;
|
||||
while (start <= end) {
|
||||
var anchor = {line: start, ch: selectionStart.ch};
|
||||
var head = {line: start, ch: selectionEnd.ch};
|
||||
// Shift the anchor right or left
|
||||
// as each selection crosses itself.
|
||||
if ((anchor.ch < curEnd.ch) && ((head.ch == anchor.ch) || (anchor.ch - head.ch == 1))) {
|
||||
anchor.ch++;
|
||||
head.ch--;
|
||||
} else if ((anchor.ch > curEnd.ch) && ((head.ch == anchor.ch) || (anchor.ch - head.ch == -1))) {
|
||||
anchor.ch--;
|
||||
head.ch++;
|
||||
}
|
||||
var range = {anchor: anchor, head: head};
|
||||
selections.push(range);
|
||||
if (cursorEqual(head, selectionEnd)) {
|
||||
|
@ -2666,16 +2792,29 @@
|
|||
// after selection crossing
|
||||
selectionEnd.ch = selections[0].head.ch;
|
||||
selectionStart.ch = selections[0].anchor.ch;
|
||||
if (cursorEqual(selectionEnd, selections[0].head)) {
|
||||
selectionStart.line = selections[selections.length-1].anchor.line;
|
||||
} else {
|
||||
selectionStart.line = selections[0].anchor.line;
|
||||
}
|
||||
cm.setSelections(selections, primIndex);
|
||||
return selectionStart;
|
||||
}
|
||||
function getIndex(ranges, head) {
|
||||
// getIndex returns the index of the cursor in the selections.
|
||||
function getIndex(ranges, cursor, end) {
|
||||
var pos = -1;
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (cursorEqual(ranges[i].head, head)) {
|
||||
return i;
|
||||
var atAnchor = cursorEqual(ranges[i].anchor, cursor);
|
||||
var atHead = cursorEqual(ranges[i].head, cursor);
|
||||
if (end == 'head') {
|
||||
pos = atHead ? i : pos;
|
||||
} else if (end == 'anchor') {
|
||||
pos = atAnchor ? i : pos;
|
||||
} else {
|
||||
pos = (atAnchor || atHead) ? i : pos;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return pos;
|
||||
}
|
||||
function getSelectedAreaRange(cm, vim) {
|
||||
var lastSelection = vim.lastSelection;
|
||||
|
@ -2739,7 +2878,7 @@
|
|||
var ranges = cm.listSelections();
|
||||
// This check ensures to set the cursor
|
||||
// position where we left off in previous selection
|
||||
var swap = getIndex(ranges, selectionStart) > -1;
|
||||
var swap = getIndex(ranges, selectionStart, 'head') > -1;
|
||||
if (vim.visualBlock) {
|
||||
var height = Math.abs(selectionStart.line - selectionEnd.line)+1;
|
||||
var width = Math.abs(selectionStart.ch - selectionEnd.ch);
|
||||
|
@ -2759,14 +2898,16 @@
|
|||
var vim = cm.state.vim;
|
||||
var selectionStart = cm.getCursor('anchor');
|
||||
var selectionEnd = cm.getCursor('head');
|
||||
// hack to place the cursor at the right place
|
||||
// in case of visual block
|
||||
if (vim.visualBlock && (cursorIsBefore(selectionStart, selectionEnd))) {
|
||||
selectionEnd.ch--;
|
||||
}
|
||||
updateLastSelection(cm, vim);
|
||||
vim.visualMode = false;
|
||||
vim.visualLine = false;
|
||||
vim.visualBlock = false;
|
||||
if (!cursorEqual(selectionStart, selectionEnd)) {
|
||||
// Clear the selection and set the cursor only if the selection has not
|
||||
// already been cleared. Otherwise we risk moving the cursor somewhere
|
||||
// it's not supposed to be.
|
||||
cm.setCursor(clipCursorToContent(cm, selectionEnd));
|
||||
}
|
||||
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
|
||||
|
@ -4498,7 +4639,32 @@
|
|||
var macroModeState = vimGlobalState.macroModeState;
|
||||
var insertModeChangeRegister = vimGlobalState.registerController.getRegister('.');
|
||||
var isPlaying = macroModeState.isPlaying;
|
||||
var lastChange = macroModeState.lastInsertModeChanges;
|
||||
// In case of visual block, the insertModeChanges are not saved as a
|
||||
// single word, so we convert them to a single word
|
||||
// so as to update the ". register as expected in real vim.
|
||||
var text = [];
|
||||
if (!isPlaying) {
|
||||
var selLength = lastChange.inVisualBlock ? vim.lastSelection.visualBlock.height : 1;
|
||||
var changes = lastChange.changes;
|
||||
var text = [];
|
||||
var i = 0;
|
||||
// In case of multiple selections in blockwise visual,
|
||||
// the inserted text, for example: 'f<Backspace>oo', is stored as
|
||||
// 'f', 'f', InsertModeKey 'o', 'o', 'o', 'o'. (if you have a block with 2 lines).
|
||||
// We push the contents of the changes array as per the following:
|
||||
// 1. In case of InsertModeKey, just increment by 1.
|
||||
// 2. In case of a character, jump by selLength (2 in the example).
|
||||
while (i < changes.length) {
|
||||
// This loop will convert 'ff<bs>oooo' to 'f<bs>oo'.
|
||||
text.push(changes[i]);
|
||||
if (changes[i] instanceof InsertModeKey) {
|
||||
i++;
|
||||
} else {
|
||||
i+= selLength;
|
||||
}
|
||||
}
|
||||
lastChange.changes = text;
|
||||
cm.off('change', onChange);
|
||||
CodeMirror.off(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);
|
||||
}
|
||||
|
@ -4515,13 +4681,64 @@
|
|||
cm.setOption('disableInput', true);
|
||||
cm.toggleOverwrite(false); // exit replace mode if we were in it.
|
||||
// update the ". register before exiting insert mode
|
||||
insertModeChangeRegister.setText(macroModeState.lastInsertModeChanges.changes.join(''));
|
||||
insertModeChangeRegister.setText(lastChange.changes.join(''));
|
||||
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
|
||||
if (macroModeState.isRecording) {
|
||||
logInsertModeChange(macroModeState);
|
||||
}
|
||||
}
|
||||
|
||||
defineOption('enableInsertModeEscKeys', false, 'boolean');
|
||||
// Use this option to customize the two-character ESC keymap.
|
||||
// If you want to use characters other than i j or k you'll have to add
|
||||
// lines to the vim-insert and await-second keymaps later in this file.
|
||||
defineOption('insertModeEscKeys', 'kj', 'string');
|
||||
// The timeout in milliseconds for the two-character ESC keymap should be
|
||||
// adjusted according to your typing speed to prevent false positives.
|
||||
defineOption('insertModeEscKeysTimeout', 200, 'number');
|
||||
function firstEscCharacterHandler(ch) {
|
||||
return function(cm){
|
||||
var keys = getOption('insertModeEscKeys');
|
||||
var firstEscCharacter = keys && keys.length > 1 && keys.charAt(0);
|
||||
if (!getOption('enableInsertModeEscKeys')|| firstEscCharacter !== ch) {
|
||||
return CodeMirror.Pass;
|
||||
} else {
|
||||
cm.replaceRange(ch, cm.getCursor(), cm.getCursor(), "+input");
|
||||
cm.setOption('keyMap', 'await-second');
|
||||
cm.state.vim.awaitingEscapeSecondCharacter = true;
|
||||
setTimeout(
|
||||
function(){
|
||||
if(cm.state.vim.awaitingEscapeSecondCharacter) {
|
||||
cm.state.vim.awaitingEscapeSecondCharacter = false;
|
||||
cm.setOption('keyMap', 'vim-insert');
|
||||
}
|
||||
},
|
||||
getOption('insertModeEscKeysTimeout'));
|
||||
}
|
||||
};
|
||||
}
|
||||
function secondEscCharacterHandler(ch){
|
||||
return function(cm) {
|
||||
var keys = getOption('insertModeEscKeys');
|
||||
var secondEscCharacter = keys && keys.length > 1 && keys.charAt(1);
|
||||
if (!getOption('enableInsertModeEscKeys')|| secondEscCharacter !== ch) {
|
||||
return CodeMirror.Pass;
|
||||
// This is not the handler you're looking for. Just insert as usual.
|
||||
} else {
|
||||
if (cm.state.vim.insertMode) {
|
||||
var lastChange = vimGlobalState.macroModeState.lastInsertModeChanges;
|
||||
if (lastChange && lastChange.changes.length) {
|
||||
lastChange.changes.pop();
|
||||
}
|
||||
}
|
||||
cm.state.vim.awaitingEscapeSecondCharacter = false;
|
||||
cm.replaceRange('', {ch: cm.getCursor().ch - 1, line: cm.getCursor().line},
|
||||
cm.getCursor(), "+input");
|
||||
exitInsertMode(cm);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
CodeMirror.keyMap['vim-insert'] = {
|
||||
// TODO: override navigation keys so that Esc will cancel automatic
|
||||
// indentation from o, O, i_<CR>
|
||||
|
@ -4535,9 +4752,23 @@
|
|||
CodeMirror.commands.newlineAndIndent;
|
||||
fn(cm);
|
||||
},
|
||||
// The next few lines are where you'd add additional handlers if
|
||||
// you wanted to use keys other than i j and k for two-character
|
||||
// escape sequences. Don't forget to add them in the await-second
|
||||
// section as well.
|
||||
"'i'": firstEscCharacterHandler('i'),
|
||||
"'j'": firstEscCharacterHandler('j'),
|
||||
"'k'": firstEscCharacterHandler('k'),
|
||||
fallthrough: ['default']
|
||||
};
|
||||
|
||||
CodeMirror.keyMap['await-second'] = {
|
||||
"'i'": secondEscCharacterHandler('i'),
|
||||
"'j'": secondEscCharacterHandler('j'),
|
||||
"'k'": secondEscCharacterHandler('k'),
|
||||
fallthrough: ['vim-insert']
|
||||
};
|
||||
|
||||
CodeMirror.keyMap['vim-replace'] = {
|
||||
'Backspace': 'goCharLeft',
|
||||
fallthrough: ['vim-insert']
|
||||
|
@ -4710,11 +4941,7 @@
|
|||
// insert mode changes. Will conform to that behavior.
|
||||
repeat = !vim.lastEditActionCommand ? 1 : repeat;
|
||||
var changeObject = macroModeState.lastInsertModeChanges;
|
||||
// This isn't strictly necessary, but since lastInsertModeChanges is
|
||||
// supposed to be immutable during replay, this helps catch bugs.
|
||||
macroModeState.lastInsertModeChanges = {};
|
||||
repeatInsertModeChanges(cm, changeObject.changes, repeat);
|
||||
macroModeState.lastInsertModeChanges = changeObject;
|
||||
}
|
||||
}
|
||||
vim.inputState = vim.lastEditInputState;
|
||||
|
@ -4752,6 +4979,18 @@
|
|||
}
|
||||
return true;
|
||||
}
|
||||
var curStart = cm.getCursor();
|
||||
var inVisualBlock = vimGlobalState.macroModeState.lastInsertModeChanges.inVisualBlock;
|
||||
if (inVisualBlock) {
|
||||
// Set up block selection again for repeating the changes.
|
||||
var vim = cm.state.vim;
|
||||
var block = vim.lastSelection.visualBlock;
|
||||
var curEnd = Pos(curStart.line + block.height-1, curStart.ch);
|
||||
cm.setCursor(curStart);
|
||||
selectBlock(cm, curEnd);
|
||||
repeat = cm.listSelections().length;
|
||||
cm.setCursor(curStart);
|
||||
}
|
||||
for (var i = 0; i < repeat; i++) {
|
||||
for (var j = 0; j < changes.length; j++) {
|
||||
var change = changes[j];
|
||||
|
@ -4762,6 +5001,10 @@
|
|||
cm.replaceRange(change, cur, cur);
|
||||
}
|
||||
}
|
||||
if (inVisualBlock) {
|
||||
curStart.line++;
|
||||
cm.setCursor(curStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -437,4 +437,15 @@ CodeMirror.defineMode("clike", function(config, parserConfig) {
|
|||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
def("text/x-nesc", {
|
||||
name: "clike",
|
||||
keywords: words(cKeywords + "as atomic async call command component components configuration event generic " +
|
||||
"implementation includes interface module new norace nx_struct nx_union post provides " +
|
||||
"signal task uses abstract extends"),
|
||||
blockKeywords: words("case do else for if switch while struct"),
|
||||
atoms: words("null"),
|
||||
hooks: {"#": cppHook},
|
||||
modeProps: {fold: ["brace", "include"]}
|
||||
});
|
||||
|
||||
});
|
|
@ -114,7 +114,7 @@ CodeMirror.defineMode("clojure", function (options) {
|
|||
var first = stream.next();
|
||||
// Read special literals: backspace, newline, space, return.
|
||||
// Just read all lowercase letters.
|
||||
if (first.match(/[a-z]/) && stream.match(/[a-z]+/, true)) {
|
||||
if (first && first.match(/[a-z]/) && stream.match(/[a-z]+/, true)) {
|
||||
return;
|
||||
}
|
||||
// Read unicode character: \u1000 \uA0a1
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue