Skip to content

Commit bce6992

Browse files
binnymightyguava
authored andcommitted
[vim] changeCase for blockwise visual
1 parent ddd36cb commit bce6992

File tree

2 files changed

+79
-26
lines changed

2 files changed

+79
-26
lines changed

keymap/vim.js

Lines changed: 65 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,6 +2348,9 @@
23482348
}
23492349
}
23502350
cm.setCursor(curPosFinal);
2351+
if (vim.visualMode) {
2352+
exitVisualMode(cm);
2353+
}
23512354
},
23522355
undo: function(cm, actionArgs) {
23532356
cm.operation(function() {
@@ -2449,17 +2452,26 @@
24492452
repeatLastEdit(cm, vim, repeat, false /** repeatForInsert */);
24502453
},
24512454
changeCase: function(cm, actionArgs, vim) {
2452-
var selectedAreaRange = getSelectedAreaRange(cm, vim);
2453-
var selectionStart = selectedAreaRange[0];
2454-
var selectionEnd = selectedAreaRange[1];
2455+
var selectionStart = getSelectedAreaRange(cm, vim)[0];
2456+
var text = cm.getSelection();
2457+
var lastSelectionCurEnd;
2458+
var blockSelection;
2459+
if (vim.lastSelection) {
24552460
// save the curEnd marker to avoid its removal due to cm.replaceRange
2456-
var lastSelectionCurEnd = vim.lastSelection.curEndMark.find();
2461+
lastSelectionCurEnd = vim.lastSelection.curEndMark.find();
2462+
blockSelection = vim.lastSelection.visualBlock;
2463+
}
24572464
var toLower = actionArgs.toLower;
2458-
var text = cm.getRange(selectionStart, selectionEnd);
2459-
cm.replaceRange(toLower ? text.toLowerCase() : text.toUpperCase(), selectionStart, selectionEnd);
2465+
text = toLower ? text.toLowerCase() : text.toUpperCase();
2466+
cm.replaceSelections(vim.visualBlock || blockSelection ? text.split('\n') : [text]);
24602467
// restore the last selection curEnd marker
2461-
vim.lastSelection.curEndMark = cm.setBookmark(lastSelectionCurEnd);
2468+
if (lastSelectionCurEnd) {
2469+
vim.lastSelection.curEndMark = cm.setBookmark(lastSelectionCurEnd);
2470+
}
24622471
cm.setCursor(selectionStart);
2472+
if (vim.visualMode) {
2473+
exitVisualMode(cm);
2474+
}
24632475
}
24642476
};
24652477

@@ -2623,27 +2635,56 @@
26232635
return -1;
26242636
}
26252637
function getSelectedAreaRange(cm, vim) {
2626-
var selectionStart = cm.getCursor('anchor');
2627-
var selectionEnd = cm.getCursor('head');
26282638
var lastSelection = vim.lastSelection;
2629-
if (!vim.visualMode) {
2630-
var lastSelectionCurStart = vim.lastSelection.curStartMark.find();
2631-
var lastSelectionCurEnd = vim.lastSelection.curEndMark.find();
2632-
var line = lastSelectionCurEnd.line - lastSelectionCurStart.line;
2633-
var ch = line ? lastSelectionCurEnd.ch : lastSelectionCurEnd.ch - lastSelectionCurStart.ch;
2634-
selectionEnd = {line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch};
2635-
if (lastSelection.visualLine) {
2636-
return [{line: selectionStart.line, ch: 0}, {line: selectionEnd.line, ch: lineLength(cm, selectionEnd.line)}];
2639+
var getCurrentSelectedAreaRange = function() {
2640+
var selections = cm.listSelections();
2641+
var start = selections[0];
2642+
var end = selections[selections.length-1];
2643+
var selectionStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head;
2644+
var selectionEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor;
2645+
return [selectionStart, selectionEnd];
2646+
};
2647+
var getLastSelectedAreaRange = function() {
2648+
var start = lastSelection.curStartMark.find();
2649+
var end = lastSelection.curEndMark.find();
2650+
var selectionStart = cm.getCursor();
2651+
var selectionEnd = cm.getCursor();
2652+
if (lastSelection.visualBlock) {
2653+
var anchor = Pos(Math.min(start.line, end.line), Math.min(start.ch, end.ch));
2654+
var head = Pos(Math.max(start.line, end.line), Math.max(start.ch, end.ch));
2655+
var width = head.ch - anchor.ch;
2656+
var height = head.line - anchor.line;
2657+
selectionEnd = Pos(selectionStart.line + height, selectionStart.ch + width);
2658+
var endCh = cm.clipPos(selectionEnd).ch;
2659+
// We do not want selection crossing while selecting here.
2660+
// So, we cut down the selection.
2661+
while (endCh != selectionEnd.ch) {
2662+
if (endCh-1 == selectionStart.ch) {
2663+
break;
2664+
}
2665+
selectionEnd.line--;
2666+
endCh = cm.clipPos(selectionEnd).ch;
2667+
}
2668+
cm.setCursor(selectionStart);
2669+
selectBlock(cm, selectionEnd);
2670+
} else {
2671+
var line = end.line - start.line;
2672+
var ch = end.ch - start.ch;
2673+
selectionEnd = {line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch};
2674+
if (lastSelection.visualLine) {
2675+
selectionStart = Pos(selectionStart.line, 0);
2676+
selectionEnd = Pos(selectionEnd.line, lineLength(cm, selectionEnd.line));
2677+
}
2678+
cm.setSelection(selectionStart, selectionEnd);
26372679
}
2680+
return [selectionStart, selectionEnd];
2681+
};
2682+
if (!vim.visualMode) {
2683+
// In case of replaying the action.
2684+
return getLastSelectedAreaRange();
26382685
} else {
2639-
if (cursorIsBefore(selectionEnd, selectionStart)) {
2640-
var tmp = selectionStart;
2641-
selectionStart = selectionEnd;
2642-
selectionEnd = tmp;
2643-
}
2644-
exitVisualMode(cm);
2686+
return getCurrentSelectedAreaRange();
26452687
}
2646-
return [selectionStart, selectionEnd];
26472688
}
26482689
function updateLastSelection(cm, vim, selectionStart, selectionEnd) {
26492690
if (!selectionStart || !selectionEnd) {

test/vim_test.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,7 +1683,7 @@ testVim('reselect_visual', function(cm, vim, helpers) {
16831683
cm.setCursor(0, 0);
16841684
helpers.doKeys('g', 'v');
16851685
// here the fake cursor is at (1, 3)
1686-
helpers.assertCursorAt(2, 0);
1686+
helpers.assertCursorAt(1, 4);
16871687
eqPos(makeCursor(1, 0), cm.getCursor('anchor'));
16881688
helpers.doKeys('v');
16891689
cm.setCursor(2, 0);
@@ -1753,7 +1753,7 @@ testVim('o_visual_block', function(cm, vim, helpers) {
17531753
helpers.doKeys('o');
17541754
helpers.assertCursorAt(3, 1);
17551755
}, { value: 'abcd\nefgh\nijkl\nmnop'});
1756-
testVim('uppercase/lowercase_visual', function(cm, vim, helpers) {
1756+
testVim('changeCase_visual', function(cm, vim, helpers) {
17571757
cm.setCursor(0, 0);
17581758
helpers.doKeys('v', 'l', 'l');
17591759
helpers.doKeys('U');
@@ -1772,6 +1772,18 @@ testVim('uppercase/lowercase_visual', function(cm, vim, helpers) {
17721772
helpers.doKeys('V', 'U', 'j', '.');
17731773
eq('ABCDEF\nGHIJKL\nMnopq\nSHORT LINE\nLONG LINE OF TEXT', cm.getValue());
17741774
}, { value: 'abcdef\nghijkl\nmnopq\nshort line\nlong line of text'});
1775+
testVim('changeCase_visual_block', function(cm, vim, helpers) {
1776+
cm.setCursor(2, 1);
1777+
helpers.doKeys('<C-v>', 'k', 'k', 'h', 'U');
1778+
eq('ABcdef\nGHijkl\nMNopq\nfoo', cm.getValue());
1779+
cm.setCursor(0, 2);
1780+
helpers.doKeys('.');
1781+
eq('ABCDef\nGHIJkl\nMNOPq\nfoo', cm.getValue());
1782+
// check when last line is shorter.
1783+
cm.setCursor(2, 2);
1784+
helpers.doKeys('.');
1785+
eq('ABCDef\nGHIJkl\nMNOPq\nfoO', cm.getValue());
1786+
}, { value: 'abcdef\nghijkl\nmnopq\nfoo'});
17751787
testVim('visual_paste', function(cm, vim, helpers) {
17761788
cm.setCursor(0, 0);
17771789
helpers.doKeys('v', 'l', 'l', 'y', 'j', 'v', 'l', 'p');

0 commit comments

Comments
 (0)