codemirror-rails 4.4 → 4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/codemirror/rails/version.rb +2 -2
- data/vendor/assets/javascripts/codemirror.js +77 -47
- data/vendor/assets/javascripts/codemirror/addons/comment/comment.js +2 -2
- data/vendor/assets/javascripts/codemirror/addons/dialog/dialog.js +26 -14
- data/vendor/assets/javascripts/codemirror/addons/edit/closetag.js +4 -0
- data/vendor/assets/javascripts/codemirror/addons/fold/xml-fold.js +2 -1
- data/vendor/assets/javascripts/codemirror/addons/hint/sql-hint.js +53 -57
- data/vendor/assets/javascripts/codemirror/addons/merge/merge.js +39 -16
- data/vendor/assets/javascripts/codemirror/addons/search/search.js +3 -3
- data/vendor/assets/javascripts/codemirror/keymaps/sublime.js +6 -3
- data/vendor/assets/javascripts/codemirror/keymaps/vim.js +333 -90
- data/vendor/assets/javascripts/codemirror/modes/clike.js +11 -0
- data/vendor/assets/javascripts/codemirror/modes/clojure.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/javascript.js +5 -4
- data/vendor/assets/javascripts/codemirror/modes/perl.js +1 -1
- data/vendor/assets/javascripts/codemirror/modes/php.js +2 -2
- data/vendor/assets/javascripts/codemirror/modes/ruby.js +15 -9
- data/vendor/assets/javascripts/codemirror/modes/sass.js +91 -110
- data/vendor/assets/javascripts/codemirror/modes/slim.js +575 -0
- data/vendor/assets/javascripts/codemirror/modes/verilog.js +5 -0
- data/vendor/assets/stylesheets/codemirror/addons/merge/merge.css +6 -0
- metadata +3 -2
@@ -37,7 +37,7 @@
|
|
37
37
|
constructor: DiffView,
|
38
38
|
init: function(pane, orig, options) {
|
39
39
|
this.edit = this.mv.edit;
|
40
|
-
this.orig = CodeMirror(pane, copyObj({value: orig, readOnly:
|
40
|
+
this.orig = CodeMirror(pane, copyObj({value: orig, readOnly: !this.mv.options.allowEditingOriginals}, copyObj(options)));
|
41
41
|
|
42
42
|
this.diff = getDiff(asString(orig), asString(options.value));
|
43
43
|
this.diffOutOfDate = false;
|
@@ -71,7 +71,7 @@
|
|
71
71
|
function update(mode) {
|
72
72
|
if (mode == "full") {
|
73
73
|
if (dv.svg) clear(dv.svg);
|
74
|
-
clear(dv.copyButtons);
|
74
|
+
if (dv.copyButtons) clear(dv.copyButtons);
|
75
75
|
clearMarks(dv.edit, edit.marked, dv.classes);
|
76
76
|
clearMarks(dv.orig, orig.marked, dv.classes);
|
77
77
|
edit.from = edit.to = orig.from = orig.to = 0;
|
@@ -257,7 +257,7 @@
|
|
257
257
|
var w = dv.gap.offsetWidth;
|
258
258
|
attrs(dv.svg, "width", w, "height", dv.gap.offsetHeight);
|
259
259
|
}
|
260
|
-
clear(dv.copyButtons);
|
260
|
+
if (dv.copyButtons) clear(dv.copyButtons);
|
261
261
|
|
262
262
|
var flip = dv.type == "left";
|
263
263
|
var vpEdit = dv.edit.getViewport(), vpOrig = dv.orig.getViewport();
|
@@ -279,17 +279,30 @@
|
|
279
279
|
"d", "M -1 " + topRpx + curveTop + " L " + (w + 2) + " " + botLpx + curveBot + " z",
|
280
280
|
"class", dv.classes.connect);
|
281
281
|
}
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
282
|
+
if (dv.copyButtons) {
|
283
|
+
var copy = dv.copyButtons.appendChild(elt("div", dv.type == "left" ? "\u21dd" : "\u21dc",
|
284
|
+
"CodeMirror-merge-copy"));
|
285
|
+
var editOriginals = dv.mv.options.allowEditingOriginals;
|
286
|
+
copy.title = editOriginals ? "Push to left" : "Revert chunk";
|
287
|
+
copy.chunk = {topEdit: topEdit, botEdit: botEdit, topOrig: topOrig, botOrig: botOrig};
|
288
|
+
copy.style.top = top + "px";
|
289
|
+
|
290
|
+
if (editOriginals) {
|
291
|
+
var topReverse = dv.orig.heightAtLine(topEdit, "local") - sTopEdit;
|
292
|
+
var copyReverse = dv.copyButtons.appendChild(elt("div", dv.type == "right" ? "\u21dd" : "\u21dc",
|
293
|
+
"CodeMirror-merge-copy-reverse"));
|
294
|
+
copyReverse.title = "Push to right";
|
295
|
+
copyReverse.chunk = {topEdit: topOrig, botEdit: botOrig, topOrig: topEdit, botOrig: botEdit};
|
296
|
+
copyReverse.style.top = topReverse + "px";
|
297
|
+
dv.type == "right" ? copyReverse.style.left = "2px" : copyReverse.style.right = "2px";
|
298
|
+
}
|
299
|
+
}
|
287
300
|
});
|
288
301
|
}
|
289
302
|
|
290
|
-
function copyChunk(dv, chunk) {
|
303
|
+
function copyChunk(dv, to, from, chunk) {
|
291
304
|
if (dv.diffOutOfDate) return;
|
292
|
-
|
305
|
+
to.replaceRange(from.getRange(Pos(chunk.topOrig, 0), Pos(chunk.botOrig, 0)),
|
293
306
|
Pos(chunk.topEdit, 0), Pos(chunk.botEdit, 0));
|
294
307
|
}
|
295
308
|
|
@@ -298,6 +311,7 @@
|
|
298
311
|
var MergeView = CodeMirror.MergeView = function(node, options) {
|
299
312
|
if (!(this instanceof MergeView)) return new MergeView(node, options);
|
300
313
|
|
314
|
+
this.options = options;
|
301
315
|
var origLeft = options.origLeft, origRight = options.origRight == null ? options.orig : options.origRight;
|
302
316
|
var hasLeft = origLeft != null, hasRight = origRight != null;
|
303
317
|
var panes = 1 + (hasLeft ? 1 : 0) + (hasRight ? 1 : 0);
|
@@ -323,6 +337,7 @@
|
|
323
337
|
(hasRight ? rightPane : editPane).className += " CodeMirror-merge-pane-rightmost";
|
324
338
|
|
325
339
|
wrap.push(elt("div", null, null, "height: 0; clear: both;"));
|
340
|
+
|
326
341
|
var wrapElt = this.wrap = node.appendChild(elt("div", wrap, "CodeMirror-merge CodeMirror-merge-" + panes + "pane"));
|
327
342
|
this.edit = CodeMirror(editPane, copyObj(options));
|
328
343
|
|
@@ -345,12 +360,20 @@
|
|
345
360
|
lock.title = "Toggle locked scrolling";
|
346
361
|
var lockWrap = elt("div", [lock], "CodeMirror-merge-scrolllock-wrap");
|
347
362
|
CodeMirror.on(lock, "click", function() { setScrollLock(dv, !dv.lockScroll); });
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
363
|
+
var gapElts = [lockWrap];
|
364
|
+
if (dv.mv.options.revertButtons !== false) {
|
365
|
+
dv.copyButtons = elt("div", null, "CodeMirror-merge-copybuttons-" + dv.type);
|
366
|
+
CodeMirror.on(dv.copyButtons, "click", function(e) {
|
367
|
+
var node = e.target || e.srcElement;
|
368
|
+
if (!node.chunk) return;
|
369
|
+
if (node.className == "CodeMirror-merge-copy-reverse") {
|
370
|
+
copyChunk(dv, dv.orig, dv.edit, node.chunk);
|
371
|
+
return;
|
372
|
+
}
|
373
|
+
copyChunk(dv, dv.edit, dv.orig, node.chunk);
|
374
|
+
});
|
375
|
+
gapElts.unshift(dv.copyButtons);
|
376
|
+
}
|
354
377
|
var svg = document.createElementNS && document.createElementNS(svgNS, "svg");
|
355
378
|
if (svg && !svg.createSVGRect) svg = null;
|
356
379
|
dv.svg = svg;
|
@@ -71,7 +71,7 @@
|
|
71
71
|
return query;
|
72
72
|
}
|
73
73
|
var queryDialog =
|
74
|
-
'Search: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
|
74
|
+
'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>';
|
75
75
|
function doSearch(cm, rev) {
|
76
76
|
var state = getSearchState(cm);
|
77
77
|
if (state.query) return findNext(cm, rev);
|
@@ -106,8 +106,8 @@
|
|
106
106
|
});}
|
107
107
|
|
108
108
|
var replaceQueryDialog =
|
109
|
-
'Replace: <input type="text" style="width: 10em"/> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
|
110
|
-
var replacementQueryDialog = 'With: <input type="text" style="width: 10em"/>';
|
109
|
+
'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>';
|
110
|
+
var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
|
111
111
|
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
|
112
112
|
function replace(cm, all) {
|
113
113
|
if (cm.getOption("readOnly")) return;
|
@@ -17,7 +17,8 @@
|
|
17
17
|
var map = CodeMirror.keyMap.sublime = {fallthrough: "default"};
|
18
18
|
var cmds = CodeMirror.commands;
|
19
19
|
var Pos = CodeMirror.Pos;
|
20
|
-
var
|
20
|
+
var mac = CodeMirror.keyMap["default"] == CodeMirror.keyMap.macDefault;
|
21
|
+
var ctrl = mac ? "Cmd-" : "Ctrl-";
|
21
22
|
|
22
23
|
// This is not exactly Sublime's algorithm. I couldn't make heads or tails of that.
|
23
24
|
function findPosSubword(doc, start, dir) {
|
@@ -186,7 +187,9 @@
|
|
186
187
|
});
|
187
188
|
};
|
188
189
|
|
189
|
-
|
190
|
+
var swapLineCombo = mac ? "Cmd-Ctrl-" : "Shift-Ctrl-";
|
191
|
+
|
192
|
+
cmds[map[swapLineCombo + "Up"] = "swapLineUp"] = function(cm) {
|
190
193
|
var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1, newSels = [];
|
191
194
|
for (var i = 0; i < ranges.length; i++) {
|
192
195
|
var range = ranges[i], from = range.from().line - 1, to = range.to().line;
|
@@ -212,7 +215,7 @@
|
|
212
215
|
});
|
213
216
|
};
|
214
217
|
|
215
|
-
cmds[map[
|
218
|
+
cmds[map[swapLineCombo + "Down"] = "swapLineDown"] = function(cm) {
|
216
219
|
var ranges = cm.listSelections(), linesToMove = [], at = cm.lastLine() + 1;
|
217
220
|
for (var i = ranges.length - 1; i >= 0; i--) {
|
218
221
|
var range = ranges[i], from = range.to().line + 1, to = range.from().line;
|
@@ -616,7 +616,9 @@
|
|
616
616
|
visualLine: false,
|
617
617
|
visualBlock: false,
|
618
618
|
lastSelection: null,
|
619
|
-
lastPastedText: null
|
619
|
+
lastPastedText: null,
|
620
|
+
// Used by two-character ESC keymap routines. Should not be changed from false here.
|
621
|
+
awaitingEscapeSecondCharacter: false
|
620
622
|
};
|
621
623
|
}
|
622
624
|
return cm.state.vim;
|
@@ -785,17 +787,19 @@
|
|
785
787
|
* pasted, should it insert itself into a new line, or should the text be
|
786
788
|
* inserted at the cursor position.)
|
787
789
|
*/
|
788
|
-
function Register(text, linewise) {
|
790
|
+
function Register(text, linewise, blockwise) {
|
789
791
|
this.clear();
|
790
792
|
this.keyBuffer = [text || ''];
|
791
793
|
this.insertModeChanges = [];
|
792
794
|
this.searchQueries = [];
|
793
795
|
this.linewise = !!linewise;
|
796
|
+
this.blockwise = !!blockwise;
|
794
797
|
}
|
795
798
|
Register.prototype = {
|
796
|
-
setText: function(text, linewise) {
|
799
|
+
setText: function(text, linewise, blockwise) {
|
797
800
|
this.keyBuffer = [text || ''];
|
798
801
|
this.linewise = !!linewise;
|
802
|
+
this.blockwise = !!blockwise;
|
799
803
|
},
|
800
804
|
pushText: function(text, linewise) {
|
801
805
|
// if this register has ever been set to linewise, use linewise.
|
@@ -840,7 +844,7 @@
|
|
840
844
|
registers['/'] = new Register();
|
841
845
|
}
|
842
846
|
RegisterController.prototype = {
|
843
|
-
pushText: function(registerName, operator, text, linewise) {
|
847
|
+
pushText: function(registerName, operator, text, linewise, blockwise) {
|
844
848
|
if (linewise && text.charAt(0) == '\n') {
|
845
849
|
text = text.slice(1) + '\n';
|
846
850
|
}
|
@@ -857,7 +861,7 @@
|
|
857
861
|
switch (operator) {
|
858
862
|
case 'yank':
|
859
863
|
// The 0 register contains the text from the most recent yank.
|
860
|
-
this.registers['0'] = new Register(text, linewise);
|
864
|
+
this.registers['0'] = new Register(text, linewise, blockwise);
|
861
865
|
break;
|
862
866
|
case 'delete':
|
863
867
|
case 'change':
|
@@ -873,7 +877,7 @@
|
|
873
877
|
break;
|
874
878
|
}
|
875
879
|
// Make sure the unnamed register is set to what just happened
|
876
|
-
this.unnamedRegister.setText(text, linewise);
|
880
|
+
this.unnamedRegister.setText(text, linewise, blockwise);
|
877
881
|
return;
|
878
882
|
}
|
879
883
|
|
@@ -882,7 +886,7 @@
|
|
882
886
|
if (append) {
|
883
887
|
register.pushText(text, linewise);
|
884
888
|
} else {
|
885
|
-
register.setText(text, linewise);
|
889
|
+
register.setText(text, linewise, blockwise);
|
886
890
|
}
|
887
891
|
// The unnamed register always has the same value as the last used
|
888
892
|
// register.
|
@@ -1860,6 +1864,12 @@
|
|
1860
1864
|
var curStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head;
|
1861
1865
|
var curEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor;
|
1862
1866
|
var text = cm.getSelection();
|
1867
|
+
var visualBlock = vim.visualBlock;
|
1868
|
+
if (vim.lastSelection && !vim.visualMode) {
|
1869
|
+
visualBlock = vim.lastSelection.visualBlock ? true : visualBlock;
|
1870
|
+
}
|
1871
|
+
var lastInsertModeChanges = vimGlobalState.macroModeState.lastInsertModeChanges;
|
1872
|
+
lastInsertModeChanges.inVisualBlock = visualBlock;
|
1863
1873
|
var replacement = new Array(selections.length).join('1').split('1');
|
1864
1874
|
// save the selectionEnd mark
|
1865
1875
|
var selectionEnd = vim.marks['>'] ? vim.marks['>'].find() : cm.getCursor('head');
|
@@ -1868,7 +1878,7 @@
|
|
1868
1878
|
operatorArgs.linewise);
|
1869
1879
|
if (operatorArgs.linewise) {
|
1870
1880
|
// 'C' in visual block extends the block till eol for all lines
|
1871
|
-
if (
|
1881
|
+
if (visualBlock){
|
1872
1882
|
var startLine = curStart.line;
|
1873
1883
|
while (startLine <= curEnd.line) {
|
1874
1884
|
var endCh = lineLength(cm, startLine);
|
@@ -1898,7 +1908,7 @@
|
|
1898
1908
|
curEnd = offsetCursor(curEnd, 0, - match[0].length);
|
1899
1909
|
}
|
1900
1910
|
}
|
1901
|
-
if (
|
1911
|
+
if (visualBlock) {
|
1902
1912
|
cm.replaceSelections(replacement);
|
1903
1913
|
} else {
|
1904
1914
|
cm.setCursor(curStart);
|
@@ -1916,17 +1926,19 @@
|
|
1916
1926
|
var curEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor;
|
1917
1927
|
// Save the '>' mark before cm.replaceRange clears it.
|
1918
1928
|
var selectionEnd, selectionStart;
|
1929
|
+
var blockwise = vim.visualBlock;
|
1919
1930
|
if (vim.visualMode) {
|
1920
1931
|
selectionEnd = vim.marks['>'].find();
|
1921
1932
|
selectionStart = vim.marks['<'].find();
|
1922
1933
|
} else if (vim.lastSelection) {
|
1923
1934
|
selectionEnd = vim.lastSelection.curStartMark.find();
|
1924
1935
|
selectionStart = vim.lastSelection.curEndMark.find();
|
1936
|
+
blockwise = vim.lastSelection.visualBlock;
|
1925
1937
|
}
|
1926
1938
|
var text = cm.getSelection();
|
1927
1939
|
vimGlobalState.registerController.pushText(
|
1928
1940
|
operatorArgs.registerName, 'delete', text,
|
1929
|
-
operatorArgs.linewise);
|
1941
|
+
operatorArgs.linewise, blockwise);
|
1930
1942
|
var replacement = new Array(selections.length).join('1').split('1');
|
1931
1943
|
// If the ending line is past the last line, inclusive, instead of
|
1932
1944
|
// including the trailing \n, include the \n before the starting line
|
@@ -1999,11 +2011,11 @@
|
|
1999
2011
|
cm.setCursor(cursorIsBefore(curStart, curEnd) ? curStart : curEnd);
|
2000
2012
|
}
|
2001
2013
|
},
|
2002
|
-
yank: function(cm, operatorArgs,
|
2014
|
+
yank: function(cm, operatorArgs, vim, _curStart, _curEnd, curOriginal) {
|
2003
2015
|
var text = cm.getSelection();
|
2004
2016
|
vimGlobalState.registerController.pushText(
|
2005
2017
|
operatorArgs.registerName, 'yank',
|
2006
|
-
text, operatorArgs.linewise);
|
2018
|
+
text, operatorArgs.linewise, vim.visualBlock);
|
2007
2019
|
cm.setCursor(curOriginal);
|
2008
2020
|
}
|
2009
2021
|
};
|
@@ -2096,6 +2108,11 @@
|
|
2096
2108
|
vim.insertMode = true;
|
2097
2109
|
vim.insertModeRepeat = actionArgs && actionArgs.repeat || 1;
|
2098
2110
|
var insertAt = (actionArgs) ? actionArgs.insertAt : null;
|
2111
|
+
if (vim.visualMode) {
|
2112
|
+
var selections = getSelectedAreaRange(cm, vim);
|
2113
|
+
var selectionStart = selections[0];
|
2114
|
+
var selectionEnd = selections[1];
|
2115
|
+
}
|
2099
2116
|
if (insertAt == 'eol') {
|
2100
2117
|
var cursor = cm.getCursor();
|
2101
2118
|
cursor = Pos(cursor.line, lineLength(cm, cursor.line));
|
@@ -2103,15 +2120,34 @@
|
|
2103
2120
|
} else if (insertAt == 'charAfter') {
|
2104
2121
|
cm.setCursor(offsetCursor(cm.getCursor(), 0, 1));
|
2105
2122
|
} else if (insertAt == 'firstNonBlank') {
|
2106
|
-
|
2123
|
+
if (vim.visualMode && !vim.visualBlock) {
|
2124
|
+
if (selectionEnd.line < selectionStart.line) {
|
2125
|
+
cm.setCursor(selectionEnd);
|
2126
|
+
} else {
|
2127
|
+
selectionStart = Pos(selectionStart.line, 0);
|
2128
|
+
cm.setCursor(selectionStart);
|
2129
|
+
}
|
2130
|
+
cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
|
2131
|
+
} else if (vim.visualBlock) {
|
2132
|
+
selectionEnd = Pos(selectionEnd.line, selectionStart.ch);
|
2133
|
+
cm.setCursor(selectionStart);
|
2134
|
+
selectBlock(cm, selectionEnd);
|
2135
|
+
} else {
|
2136
|
+
cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm));
|
2137
|
+
}
|
2107
2138
|
} else if (insertAt == 'endOfSelectedArea') {
|
2108
|
-
|
2109
|
-
|
2110
|
-
|
2139
|
+
if (vim.visualBlock) {
|
2140
|
+
selectionStart = Pos(selectionStart.line, selectionEnd.ch);
|
2141
|
+
cm.setCursor(selectionStart);
|
2142
|
+
selectBlock(cm, selectionEnd);
|
2143
|
+
} else if (selectionEnd.line < selectionStart.line) {
|
2111
2144
|
selectionEnd = Pos(selectionStart.line, 0);
|
2145
|
+
cm.setCursor(selectionEnd);
|
2146
|
+
}
|
2147
|
+
} else if (insertAt == 'inplace') {
|
2148
|
+
if (vim.visualMode){
|
2149
|
+
return;
|
2112
2150
|
}
|
2113
|
-
cm.setCursor(selectionEnd);
|
2114
|
-
exitVisualMode(cm);
|
2115
2151
|
}
|
2116
2152
|
cm.setOption('keyMap', 'vim-insert');
|
2117
2153
|
cm.setOption('disableInput', false);
|
@@ -2129,6 +2165,9 @@
|
|
2129
2165
|
cm.on('change', onChange);
|
2130
2166
|
CodeMirror.on(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);
|
2131
2167
|
}
|
2168
|
+
if (vim.visualMode) {
|
2169
|
+
exitVisualMode(cm);
|
2170
|
+
}
|
2132
2171
|
},
|
2133
2172
|
toggleVisualMode: function(cm, actionArgs, vim) {
|
2134
2173
|
var repeat = actionArgs.repeat;
|
@@ -2339,6 +2378,7 @@
|
|
2339
2378
|
var text = Array(actionArgs.repeat + 1).join(text);
|
2340
2379
|
}
|
2341
2380
|
var linewise = register.linewise;
|
2381
|
+
var blockwise = register.blockwise;
|
2342
2382
|
if (linewise) {
|
2343
2383
|
if(vim.visualMode) {
|
2344
2384
|
text = vim.visualLine ? text.slice(0, -1) : '\n' + text.slice(0, text.length - 1) + '\n';
|
@@ -2351,6 +2391,12 @@
|
|
2351
2391
|
cur.ch = 0;
|
2352
2392
|
}
|
2353
2393
|
} else {
|
2394
|
+
if (blockwise) {
|
2395
|
+
text = text.split('\n');
|
2396
|
+
for (var i = 0; i < text.length; i++) {
|
2397
|
+
text[i] = (text[i] == '') ? ' ' : text[i];
|
2398
|
+
}
|
2399
|
+
}
|
2354
2400
|
cur.ch += actionArgs.after ? 1 : 0;
|
2355
2401
|
}
|
2356
2402
|
var curPosFinal;
|
@@ -2362,32 +2408,75 @@
|
|
2362
2408
|
var selectedArea = getSelectedAreaRange(cm, vim);
|
2363
2409
|
var selectionStart = selectedArea[0];
|
2364
2410
|
var selectionEnd = selectedArea[1];
|
2411
|
+
var selectedText = cm.getSelection();
|
2412
|
+
var selections = cm.listSelections();
|
2413
|
+
var emptyStrings = new Array(selections.length).join('1').split('1');
|
2365
2414
|
// save the curEnd marker before it get cleared due to cm.replaceRange.
|
2366
|
-
if (vim.lastSelection)
|
2415
|
+
if (vim.lastSelection) {
|
2416
|
+
lastSelectionCurEnd = vim.lastSelection.curEndMark.find();
|
2417
|
+
}
|
2367
2418
|
// push the previously selected text to unnamed register
|
2368
|
-
vimGlobalState.registerController.unnamedRegister.setText(
|
2369
|
-
|
2419
|
+
vimGlobalState.registerController.unnamedRegister.setText(selectedText);
|
2420
|
+
if (blockwise) {
|
2421
|
+
// first delete the selected text
|
2422
|
+
cm.replaceSelections(emptyStrings);
|
2423
|
+
// Set new selections as per the block length of the yanked text
|
2424
|
+
selectionEnd = Pos(selectionStart.line + text.length-1, selectionStart.ch);
|
2425
|
+
cm.setCursor(selectionStart);
|
2426
|
+
selectBlock(cm, selectionEnd);
|
2427
|
+
cm.replaceSelections(text);
|
2428
|
+
curPosFinal = selectionStart;
|
2429
|
+
} else if (vim.visualBlock) {
|
2430
|
+
cm.replaceSelections(emptyStrings);
|
2431
|
+
cm.setCursor(selectionStart);
|
2432
|
+
cm.replaceRange(text, selectionStart, selectionStart);
|
2433
|
+
curPosFinal = selectionStart;
|
2434
|
+
} else {
|
2435
|
+
cm.replaceRange(text, selectionStart, selectionEnd);
|
2436
|
+
curPosFinal = cm.posFromIndex(cm.indexFromPos(selectionStart) + text.length - 1);
|
2437
|
+
}
|
2370
2438
|
// restore the the curEnd marker
|
2371
|
-
if(lastSelectionCurEnd)
|
2372
|
-
|
2373
|
-
|
2439
|
+
if(lastSelectionCurEnd) {
|
2440
|
+
vim.lastSelection.curEndMark = cm.setBookmark(lastSelectionCurEnd);
|
2441
|
+
}
|
2442
|
+
if (linewise) {
|
2443
|
+
curPosFinal.ch=0;
|
2444
|
+
}
|
2374
2445
|
} else {
|
2375
|
-
|
2376
|
-
|
2377
|
-
|
2378
|
-
|
2446
|
+
if (blockwise) {
|
2447
|
+
cm.setCursor(cur);
|
2448
|
+
for (var i = 0; i < text.length; i++) {
|
2449
|
+
var line = cur.line+i;
|
2450
|
+
if (line > cm.lastLine()) {
|
2451
|
+
cm.replaceRange('\n', Pos(line, 0));
|
2452
|
+
}
|
2453
|
+
var lastCh = lineLength(cm, line);
|
2454
|
+
if (lastCh < cur.ch) {
|
2455
|
+
extendLineToColumn(cm, line, cur.ch);
|
2456
|
+
}
|
2457
|
+
}
|
2458
|
+
cm.setCursor(cur);
|
2459
|
+
selectBlock(cm, Pos(cur.line + text.length-1, cur.ch));
|
2460
|
+
cm.replaceSelections(text);
|
2461
|
+
curPosFinal = cur;
|
2462
|
+
} else {
|
2463
|
+
cm.replaceRange(text, cur);
|
2464
|
+
// Now fine tune the cursor to where we want it.
|
2465
|
+
if (linewise && actionArgs.after) {
|
2466
|
+
curPosFinal = Pos(
|
2379
2467
|
cur.line + 1,
|
2380
2468
|
findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line + 1)));
|
2381
|
-
|
2382
|
-
|
2383
|
-
|
2384
|
-
|
2385
|
-
|
2386
|
-
|
2387
|
-
|
2388
|
-
|
2389
|
-
|
2390
|
-
|
2469
|
+
} else if (linewise && !actionArgs.after) {
|
2470
|
+
curPosFinal = Pos(
|
2471
|
+
cur.line,
|
2472
|
+
findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line)));
|
2473
|
+
} else if (!linewise && actionArgs.after) {
|
2474
|
+
idx = cm.indexFromPos(cur);
|
2475
|
+
curPosFinal = cm.posFromIndex(idx + text.length - 1);
|
2476
|
+
} else {
|
2477
|
+
idx = cm.indexFromPos(cur);
|
2478
|
+
curPosFinal = cm.posFromIndex(idx + text.length);
|
2479
|
+
}
|
2391
2480
|
}
|
2392
2481
|
}
|
2393
2482
|
cm.setCursor(curPosFinal);
|
@@ -2597,6 +2686,12 @@
|
|
2597
2686
|
function escapeRegex(s) {
|
2598
2687
|
return s.replace(/([.?*+$\[\]\/\\(){}|\-])/g, '\\$1');
|
2599
2688
|
}
|
2689
|
+
function extendLineToColumn(cm, lineNum, column) {
|
2690
|
+
var endCh = lineLength(cm, lineNum);
|
2691
|
+
var spaces = new Array(column-endCh+1).join(' ');
|
2692
|
+
cm.setCursor(Pos(lineNum, endCh));
|
2693
|
+
cm.replaceRange(spaces, cm.getCursor());
|
2694
|
+
}
|
2600
2695
|
// This functions selects a rectangular block
|
2601
2696
|
// of text with selectionEnd as any of its corner
|
2602
2697
|
// Height of block:
|
@@ -2606,55 +2701,86 @@
|
|
2606
2701
|
function selectBlock(cm, selectionEnd) {
|
2607
2702
|
var selections = [], ranges = cm.listSelections();
|
2608
2703
|
var firstRange = ranges[0].anchor, lastRange = ranges[ranges.length-1].anchor;
|
2609
|
-
var start, end, selectionStart;
|
2704
|
+
var start, end, direction, selectionStart;
|
2610
2705
|
var curEnd = cm.getCursor('head');
|
2706
|
+
var originalSelectionEnd = copyCursor(selectionEnd);
|
2707
|
+
start = firstRange.line;
|
2708
|
+
end = lastRange.line;
|
2709
|
+
if (selectionEnd.line < curEnd.line) {
|
2710
|
+
direction = 'up';
|
2711
|
+
} else if (selectionEnd.line > curEnd.line) {
|
2712
|
+
direction = 'down';
|
2713
|
+
} else {
|
2714
|
+
if (selectionEnd.ch != curEnd.ch) {
|
2715
|
+
direction = selectionEnd.ch > curEnd.ch ? 'right' : 'left';
|
2716
|
+
}
|
2717
|
+
selectionStart = cm.getCursor('anchor');
|
2718
|
+
}
|
2611
2719
|
var primIndex = getIndex(ranges, curEnd);
|
2612
2720
|
// sets to true when selectionEnd already lies inside the existing selections
|
2613
|
-
var contains = getIndex(ranges, selectionEnd) < 0 ? false : true;
|
2614
2721
|
selectionEnd = cm.clipPos(selectionEnd);
|
2615
|
-
|
2616
|
-
var
|
2617
|
-
|
2618
|
-
|
2619
|
-
|
2620
|
-
if (
|
2621
|
-
|
2622
|
-
|
2623
|
-
|
2624
|
-
|
2625
|
-
|
2626
|
-
|
2627
|
-
|
2722
|
+
var contains = getIndex(ranges, selectionEnd) < 0 ? false : true;
|
2723
|
+
var isClipped = !cursorEqual(originalSelectionEnd, selectionEnd);
|
2724
|
+
// This function helps to check selection crossing
|
2725
|
+
// in case of short lines.
|
2726
|
+
var processSelectionCrossing = function() {
|
2727
|
+
if (isClipped) {
|
2728
|
+
if (curEnd.ch >= selectionStart.ch) {
|
2729
|
+
selectionStart.ch++;
|
2730
|
+
}
|
2731
|
+
} else if (curEnd.ch == lineLength(cm, curEnd.line)) {
|
2732
|
+
if (cursorEqual(ranges[primIndex].anchor, ranges[primIndex].head) && ranges.length>1) {
|
2733
|
+
if (direction == 'up') {
|
2734
|
+
if (contains || primIndex>0) {
|
2735
|
+
start = firstRange.line;
|
2736
|
+
end = selectionEnd.line;
|
2737
|
+
selectionStart = ranges[primIndex-1].anchor;
|
2738
|
+
}
|
2739
|
+
} else {
|
2740
|
+
if (contains || primIndex == 0) {
|
2741
|
+
end = lastRange.line;
|
2742
|
+
start = selectionEnd.line;
|
2743
|
+
selectionStart = ranges[primIndex+1].anchor;
|
2744
|
+
}
|
2745
|
+
}
|
2746
|
+
if (selectionEnd.ch >= selectionStart.ch) {
|
2747
|
+
selectionStart.ch--;
|
2748
|
+
}
|
2749
|
+
}
|
2628
2750
|
}
|
2629
|
-
}
|
2630
|
-
|
2631
|
-
|
2632
|
-
|
2633
|
-
|
2634
|
-
|
2635
|
-
|
2636
|
-
|
2751
|
+
};
|
2752
|
+
switch(direction) {
|
2753
|
+
case 'up':
|
2754
|
+
start = contains ? firstRange.line : selectionEnd.line;
|
2755
|
+
end = contains ? selectionEnd.line : lastRange.line;
|
2756
|
+
selectionStart = lastRange;
|
2757
|
+
processSelectionCrossing();
|
2758
|
+
break;
|
2759
|
+
case 'down':
|
2760
|
+
start = contains ? selectionEnd.line : firstRange.line;
|
2761
|
+
end = contains ? lastRange.line : selectionEnd.line;
|
2762
|
+
selectionStart = firstRange;
|
2763
|
+
processSelectionCrossing();
|
2764
|
+
break;
|
2765
|
+
case 'left':
|
2766
|
+
if ((selectionEnd.ch <= selectionStart.ch) && (curEnd.ch > selectionStart.ch)) {
|
2767
|
+
selectionStart.ch++;
|
2768
|
+
selectionEnd.ch--;
|
2769
|
+
}
|
2770
|
+
break;
|
2771
|
+
case 'right':
|
2772
|
+
if ((selectionStart.ch <= selectionEnd.ch) && (curEnd.ch < selectionStart.ch)) {
|
2773
|
+
selectionStart.ch--;
|
2774
|
+
selectionEnd.ch++;
|
2775
|
+
}
|
2776
|
+
break;
|
2777
|
+
default:
|
2778
|
+
start = selectionStart.line;
|
2637
2779
|
end = selectionEnd.line;
|
2638
|
-
}
|
2639
|
-
}
|
2640
|
-
if (start > end) {
|
2641
|
-
var tmp = start;
|
2642
|
-
start = end;
|
2643
|
-
end = tmp;
|
2644
2780
|
}
|
2645
|
-
selectionStart = (near > 0) ? firstRange : lastRange;
|
2646
2781
|
while (start <= end) {
|
2647
2782
|
var anchor = {line: start, ch: selectionStart.ch};
|
2648
2783
|
var head = {line: start, ch: selectionEnd.ch};
|
2649
|
-
// Shift the anchor right or left
|
2650
|
-
// as each selection crosses itself.
|
2651
|
-
if ((anchor.ch < curEnd.ch) && ((head.ch == anchor.ch) || (anchor.ch - head.ch == 1))) {
|
2652
|
-
anchor.ch++;
|
2653
|
-
head.ch--;
|
2654
|
-
} else if ((anchor.ch > curEnd.ch) && ((head.ch == anchor.ch) || (anchor.ch - head.ch == -1))) {
|
2655
|
-
anchor.ch--;
|
2656
|
-
head.ch++;
|
2657
|
-
}
|
2658
2784
|
var range = {anchor: anchor, head: head};
|
2659
2785
|
selections.push(range);
|
2660
2786
|
if (cursorEqual(head, selectionEnd)) {
|
@@ -2666,16 +2792,29 @@
|
|
2666
2792
|
// after selection crossing
|
2667
2793
|
selectionEnd.ch = selections[0].head.ch;
|
2668
2794
|
selectionStart.ch = selections[0].anchor.ch;
|
2795
|
+
if (cursorEqual(selectionEnd, selections[0].head)) {
|
2796
|
+
selectionStart.line = selections[selections.length-1].anchor.line;
|
2797
|
+
} else {
|
2798
|
+
selectionStart.line = selections[0].anchor.line;
|
2799
|
+
}
|
2669
2800
|
cm.setSelections(selections, primIndex);
|
2670
2801
|
return selectionStart;
|
2671
2802
|
}
|
2672
|
-
|
2803
|
+
// getIndex returns the index of the cursor in the selections.
|
2804
|
+
function getIndex(ranges, cursor, end) {
|
2805
|
+
var pos = -1;
|
2673
2806
|
for (var i = 0; i < ranges.length; i++) {
|
2674
|
-
|
2675
|
-
|
2807
|
+
var atAnchor = cursorEqual(ranges[i].anchor, cursor);
|
2808
|
+
var atHead = cursorEqual(ranges[i].head, cursor);
|
2809
|
+
if (end == 'head') {
|
2810
|
+
pos = atHead ? i : pos;
|
2811
|
+
} else if (end == 'anchor') {
|
2812
|
+
pos = atAnchor ? i : pos;
|
2813
|
+
} else {
|
2814
|
+
pos = (atAnchor || atHead) ? i : pos;
|
2676
2815
|
}
|
2677
2816
|
}
|
2678
|
-
return
|
2817
|
+
return pos;
|
2679
2818
|
}
|
2680
2819
|
function getSelectedAreaRange(cm, vim) {
|
2681
2820
|
var lastSelection = vim.lastSelection;
|
@@ -2739,7 +2878,7 @@
|
|
2739
2878
|
var ranges = cm.listSelections();
|
2740
2879
|
// This check ensures to set the cursor
|
2741
2880
|
// position where we left off in previous selection
|
2742
|
-
var swap = getIndex(ranges, selectionStart) > -1;
|
2881
|
+
var swap = getIndex(ranges, selectionStart, 'head') > -1;
|
2743
2882
|
if (vim.visualBlock) {
|
2744
2883
|
var height = Math.abs(selectionStart.line - selectionEnd.line)+1;
|
2745
2884
|
var width = Math.abs(selectionStart.ch - selectionEnd.ch);
|
@@ -2759,14 +2898,16 @@
|
|
2759
2898
|
var vim = cm.state.vim;
|
2760
2899
|
var selectionStart = cm.getCursor('anchor');
|
2761
2900
|
var selectionEnd = cm.getCursor('head');
|
2901
|
+
// hack to place the cursor at the right place
|
2902
|
+
// in case of visual block
|
2903
|
+
if (vim.visualBlock && (cursorIsBefore(selectionStart, selectionEnd))) {
|
2904
|
+
selectionEnd.ch--;
|
2905
|
+
}
|
2762
2906
|
updateLastSelection(cm, vim);
|
2763
2907
|
vim.visualMode = false;
|
2764
2908
|
vim.visualLine = false;
|
2765
2909
|
vim.visualBlock = false;
|
2766
2910
|
if (!cursorEqual(selectionStart, selectionEnd)) {
|
2767
|
-
// Clear the selection and set the cursor only if the selection has not
|
2768
|
-
// already been cleared. Otherwise we risk moving the cursor somewhere
|
2769
|
-
// it's not supposed to be.
|
2770
2911
|
cm.setCursor(clipCursorToContent(cm, selectionEnd));
|
2771
2912
|
}
|
2772
2913
|
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
|
@@ -4498,7 +4639,32 @@
|
|
4498
4639
|
var macroModeState = vimGlobalState.macroModeState;
|
4499
4640
|
var insertModeChangeRegister = vimGlobalState.registerController.getRegister('.');
|
4500
4641
|
var isPlaying = macroModeState.isPlaying;
|
4642
|
+
var lastChange = macroModeState.lastInsertModeChanges;
|
4643
|
+
// In case of visual block, the insertModeChanges are not saved as a
|
4644
|
+
// single word, so we convert them to a single word
|
4645
|
+
// so as to update the ". register as expected in real vim.
|
4646
|
+
var text = [];
|
4501
4647
|
if (!isPlaying) {
|
4648
|
+
var selLength = lastChange.inVisualBlock ? vim.lastSelection.visualBlock.height : 1;
|
4649
|
+
var changes = lastChange.changes;
|
4650
|
+
var text = [];
|
4651
|
+
var i = 0;
|
4652
|
+
// In case of multiple selections in blockwise visual,
|
4653
|
+
// the inserted text, for example: 'f<Backspace>oo', is stored as
|
4654
|
+
// 'f', 'f', InsertModeKey 'o', 'o', 'o', 'o'. (if you have a block with 2 lines).
|
4655
|
+
// We push the contents of the changes array as per the following:
|
4656
|
+
// 1. In case of InsertModeKey, just increment by 1.
|
4657
|
+
// 2. In case of a character, jump by selLength (2 in the example).
|
4658
|
+
while (i < changes.length) {
|
4659
|
+
// This loop will convert 'ff<bs>oooo' to 'f<bs>oo'.
|
4660
|
+
text.push(changes[i]);
|
4661
|
+
if (changes[i] instanceof InsertModeKey) {
|
4662
|
+
i++;
|
4663
|
+
} else {
|
4664
|
+
i+= selLength;
|
4665
|
+
}
|
4666
|
+
}
|
4667
|
+
lastChange.changes = text;
|
4502
4668
|
cm.off('change', onChange);
|
4503
4669
|
CodeMirror.off(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);
|
4504
4670
|
}
|
@@ -4515,13 +4681,64 @@
|
|
4515
4681
|
cm.setOption('disableInput', true);
|
4516
4682
|
cm.toggleOverwrite(false); // exit replace mode if we were in it.
|
4517
4683
|
// update the ". register before exiting insert mode
|
4518
|
-
insertModeChangeRegister.setText(
|
4684
|
+
insertModeChangeRegister.setText(lastChange.changes.join(''));
|
4519
4685
|
CodeMirror.signal(cm, "vim-mode-change", {mode: "normal"});
|
4520
4686
|
if (macroModeState.isRecording) {
|
4521
4687
|
logInsertModeChange(macroModeState);
|
4522
4688
|
}
|
4523
4689
|
}
|
4524
4690
|
|
4691
|
+
defineOption('enableInsertModeEscKeys', false, 'boolean');
|
4692
|
+
// Use this option to customize the two-character ESC keymap.
|
4693
|
+
// If you want to use characters other than i j or k you'll have to add
|
4694
|
+
// lines to the vim-insert and await-second keymaps later in this file.
|
4695
|
+
defineOption('insertModeEscKeys', 'kj', 'string');
|
4696
|
+
// The timeout in milliseconds for the two-character ESC keymap should be
|
4697
|
+
// adjusted according to your typing speed to prevent false positives.
|
4698
|
+
defineOption('insertModeEscKeysTimeout', 200, 'number');
|
4699
|
+
function firstEscCharacterHandler(ch) {
|
4700
|
+
return function(cm){
|
4701
|
+
var keys = getOption('insertModeEscKeys');
|
4702
|
+
var firstEscCharacter = keys && keys.length > 1 && keys.charAt(0);
|
4703
|
+
if (!getOption('enableInsertModeEscKeys')|| firstEscCharacter !== ch) {
|
4704
|
+
return CodeMirror.Pass;
|
4705
|
+
} else {
|
4706
|
+
cm.replaceRange(ch, cm.getCursor(), cm.getCursor(), "+input");
|
4707
|
+
cm.setOption('keyMap', 'await-second');
|
4708
|
+
cm.state.vim.awaitingEscapeSecondCharacter = true;
|
4709
|
+
setTimeout(
|
4710
|
+
function(){
|
4711
|
+
if(cm.state.vim.awaitingEscapeSecondCharacter) {
|
4712
|
+
cm.state.vim.awaitingEscapeSecondCharacter = false;
|
4713
|
+
cm.setOption('keyMap', 'vim-insert');
|
4714
|
+
}
|
4715
|
+
},
|
4716
|
+
getOption('insertModeEscKeysTimeout'));
|
4717
|
+
}
|
4718
|
+
};
|
4719
|
+
}
|
4720
|
+
function secondEscCharacterHandler(ch){
|
4721
|
+
return function(cm) {
|
4722
|
+
var keys = getOption('insertModeEscKeys');
|
4723
|
+
var secondEscCharacter = keys && keys.length > 1 && keys.charAt(1);
|
4724
|
+
if (!getOption('enableInsertModeEscKeys')|| secondEscCharacter !== ch) {
|
4725
|
+
return CodeMirror.Pass;
|
4726
|
+
// This is not the handler you're looking for. Just insert as usual.
|
4727
|
+
} else {
|
4728
|
+
if (cm.state.vim.insertMode) {
|
4729
|
+
var lastChange = vimGlobalState.macroModeState.lastInsertModeChanges;
|
4730
|
+
if (lastChange && lastChange.changes.length) {
|
4731
|
+
lastChange.changes.pop();
|
4732
|
+
}
|
4733
|
+
}
|
4734
|
+
cm.state.vim.awaitingEscapeSecondCharacter = false;
|
4735
|
+
cm.replaceRange('', {ch: cm.getCursor().ch - 1, line: cm.getCursor().line},
|
4736
|
+
cm.getCursor(), "+input");
|
4737
|
+
exitInsertMode(cm);
|
4738
|
+
}
|
4739
|
+
};
|
4740
|
+
}
|
4741
|
+
|
4525
4742
|
CodeMirror.keyMap['vim-insert'] = {
|
4526
4743
|
// TODO: override navigation keys so that Esc will cancel automatic
|
4527
4744
|
// indentation from o, O, i_<CR>
|
@@ -4535,9 +4752,23 @@
|
|
4535
4752
|
CodeMirror.commands.newlineAndIndent;
|
4536
4753
|
fn(cm);
|
4537
4754
|
},
|
4755
|
+
// The next few lines are where you'd add additional handlers if
|
4756
|
+
// you wanted to use keys other than i j and k for two-character
|
4757
|
+
// escape sequences. Don't forget to add them in the await-second
|
4758
|
+
// section as well.
|
4759
|
+
"'i'": firstEscCharacterHandler('i'),
|
4760
|
+
"'j'": firstEscCharacterHandler('j'),
|
4761
|
+
"'k'": firstEscCharacterHandler('k'),
|
4538
4762
|
fallthrough: ['default']
|
4539
4763
|
};
|
4540
4764
|
|
4765
|
+
CodeMirror.keyMap['await-second'] = {
|
4766
|
+
"'i'": secondEscCharacterHandler('i'),
|
4767
|
+
"'j'": secondEscCharacterHandler('j'),
|
4768
|
+
"'k'": secondEscCharacterHandler('k'),
|
4769
|
+
fallthrough: ['vim-insert']
|
4770
|
+
};
|
4771
|
+
|
4541
4772
|
CodeMirror.keyMap['vim-replace'] = {
|
4542
4773
|
'Backspace': 'goCharLeft',
|
4543
4774
|
fallthrough: ['vim-insert']
|
@@ -4710,11 +4941,7 @@
|
|
4710
4941
|
// insert mode changes. Will conform to that behavior.
|
4711
4942
|
repeat = !vim.lastEditActionCommand ? 1 : repeat;
|
4712
4943
|
var changeObject = macroModeState.lastInsertModeChanges;
|
4713
|
-
// This isn't strictly necessary, but since lastInsertModeChanges is
|
4714
|
-
// supposed to be immutable during replay, this helps catch bugs.
|
4715
|
-
macroModeState.lastInsertModeChanges = {};
|
4716
4944
|
repeatInsertModeChanges(cm, changeObject.changes, repeat);
|
4717
|
-
macroModeState.lastInsertModeChanges = changeObject;
|
4718
4945
|
}
|
4719
4946
|
}
|
4720
4947
|
vim.inputState = vim.lastEditInputState;
|
@@ -4752,6 +4979,18 @@
|
|
4752
4979
|
}
|
4753
4980
|
return true;
|
4754
4981
|
}
|
4982
|
+
var curStart = cm.getCursor();
|
4983
|
+
var inVisualBlock = vimGlobalState.macroModeState.lastInsertModeChanges.inVisualBlock;
|
4984
|
+
if (inVisualBlock) {
|
4985
|
+
// Set up block selection again for repeating the changes.
|
4986
|
+
var vim = cm.state.vim;
|
4987
|
+
var block = vim.lastSelection.visualBlock;
|
4988
|
+
var curEnd = Pos(curStart.line + block.height-1, curStart.ch);
|
4989
|
+
cm.setCursor(curStart);
|
4990
|
+
selectBlock(cm, curEnd);
|
4991
|
+
repeat = cm.listSelections().length;
|
4992
|
+
cm.setCursor(curStart);
|
4993
|
+
}
|
4755
4994
|
for (var i = 0; i < repeat; i++) {
|
4756
4995
|
for (var j = 0; j < changes.length; j++) {
|
4757
4996
|
var change = changes[j];
|
@@ -4762,6 +5001,10 @@
|
|
4762
5001
|
cm.replaceRange(change, cur, cur);
|
4763
5002
|
}
|
4764
5003
|
}
|
5004
|
+
if (inVisualBlock) {
|
5005
|
+
curStart.line++;
|
5006
|
+
cm.setCursor(curStart);
|
5007
|
+
}
|
4765
5008
|
}
|
4766
5009
|
}
|
4767
5010
|
|