|
1411 | 1411 | if (operator) { |
1412 | 1412 | var inverted = false; |
1413 | 1413 | vim.lastMotion = null; |
| 1414 | + var lastSelection = vim.lastSelection; |
1414 | 1415 | operatorArgs.repeat = repeat; // Indent in visual mode needs this. |
1415 | 1416 | if (vim.visualMode) { |
1416 | 1417 | curStart = selectionStart; |
|
1437 | 1438 | curEnd.line = curStart.line + operatorArgs.selOffset.line; |
1438 | 1439 | if (operatorArgs.selOffset.line) {curEnd.ch = operatorArgs.selOffset.ch; } |
1439 | 1440 | else { curEnd.ch = curStart.ch + operatorArgs.selOffset.ch; } |
| 1441 | + // In case of blockwise visual |
| 1442 | + if (lastSelection && lastSelection.visualBlock) { |
| 1443 | + var block = lastSelection.visualBlock; |
| 1444 | + var width = block.width; |
| 1445 | + var height = block.height; |
| 1446 | + curEnd = Pos(curStart.line + height, curStart.ch + width); |
| 1447 | + // selectBlock creates a 'proper' rectangular block. |
| 1448 | + // We do not want that in all cases, so we manually set selections. |
| 1449 | + var selections = []; |
| 1450 | + for (var i = curStart.line; i < curEnd.line; i++) { |
| 1451 | + var anchor = Pos(i, curStart.ch); |
| 1452 | + var head = Pos(i, curEnd.ch); |
| 1453 | + var range = {anchor: anchor, head: head}; |
| 1454 | + selections.push(range); |
| 1455 | + } |
| 1456 | + cm.setSelections(selections); |
| 1457 | + var blockSelected = true; |
| 1458 | + } |
1440 | 1459 | } else if (vim.visualMode) { |
1441 | 1460 | var selOffset = Pos(); |
1442 | 1461 | selOffset.line = curEnd.line - curStart.line; |
|
1457 | 1476 | operatorArgs.registerName = registerName; |
1458 | 1477 | // Keep track of linewise as it affects how paste and change behave. |
1459 | 1478 | operatorArgs.linewise = linewise; |
1460 | | - if (!vim.visualBlock) { |
1461 | | - cm.extendSelection(curStart, curEnd); |
| 1479 | + if (!vim.visualBlock && !blockSelected) { |
| 1480 | + cm.setSelection(curStart, curEnd); |
1462 | 1481 | } |
1463 | 1482 | operators[operator](cm, operatorArgs, vim, curStart, |
1464 | 1483 | curEnd, curOriginal); |
|
1838 | 1857 | var curEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor; |
1839 | 1858 | var text = cm.getSelection(); |
1840 | 1859 | var replacement = new Array(selections.length).join('1').split('1'); |
| 1860 | + // save the selectionEnd mark |
| 1861 | + var selectionEnd = vim.marks['>'] ? vim.marks['>'].find() : cm.getCursor('head'); |
1841 | 1862 | vimGlobalState.registerController.pushText( |
1842 | 1863 | operatorArgs.registerName, 'change', text, |
1843 | 1864 | operatorArgs.linewise); |
|
1880 | 1901 | cm.replaceRange('', curStart, curEnd); |
1881 | 1902 | } |
1882 | 1903 | } |
| 1904 | + vim.marks['>'] = cm.setBookmark(selectionEnd); |
1883 | 1905 | actions.enterInsertMode(cm, {}, cm.state.vim); |
1884 | 1906 | }, |
1885 | 1907 | // delete is a javascript keyword. |
1886 | | - 'delete': function(cm, operatorArgs, vim, curStart, curEnd) { |
| 1908 | + 'delete': function(cm, operatorArgs, vim) { |
| 1909 | + var selections = cm.listSelections(); |
| 1910 | + var start = selections[0], end = selections[selections.length-1]; |
| 1911 | + var curStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head; |
| 1912 | + var curEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor; |
1887 | 1913 | // Save the '>' mark before cm.replaceRange clears it. |
1888 | | - var selectionEnd = vim.visualMode ? vim.marks['>'].find() : null; |
| 1914 | + var selectionEnd, selectionStart; |
| 1915 | + if (vim.visualMode) { |
| 1916 | + selectionEnd = vim.marks['>'].find(); |
| 1917 | + selectionStart = vim.marks['<'].find(); |
| 1918 | + } else if (vim.lastSelection) { |
| 1919 | + selectionEnd = vim.lastSelection.curStartMark.find(); |
| 1920 | + selectionStart = vim.lastSelection.curEndMark.find(); |
| 1921 | + } |
1889 | 1922 | var text = cm.getSelection(); |
| 1923 | + vimGlobalState.registerController.pushText( |
| 1924 | + operatorArgs.registerName, 'delete', text, |
| 1925 | + operatorArgs.linewise); |
| 1926 | + var replacement = new Array(selections.length).join('1').split('1'); |
1890 | 1927 | // If the ending line is past the last line, inclusive, instead of |
1891 | 1928 | // including the trailing \n, include the \n before the starting line |
1892 | 1929 | if (operatorArgs.linewise && |
1893 | | - curEnd.line > cm.lastLine() && curStart.line > cm.firstLine()) { |
| 1930 | + curEnd.line == cm.lastLine() && curStart.line == curEnd.line) { |
| 1931 | + var tmp = copyCursor(curEnd); |
1894 | 1932 | curStart.line--; |
1895 | 1933 | curStart.ch = lineLength(cm, curStart.line); |
1896 | | - } |
1897 | | - vimGlobalState.registerController.pushText( |
1898 | | - operatorArgs.registerName, 'delete', text, |
1899 | | - operatorArgs.linewise); |
1900 | | - if (vim.visualBlock) { |
1901 | | - var selections = cm.listSelections(); |
1902 | | - curStart = selections[0].anchor; |
1903 | | - var replacement = new Array(selections.length).join('1').split('1'); |
1904 | | - cm.replaceSelections(replacement); |
1905 | | - } else { |
| 1934 | + curEnd = tmp; |
1906 | 1935 | cm.replaceRange('', curStart, curEnd); |
| 1936 | + } else { |
| 1937 | + cm.replaceSelections(replacement); |
1907 | 1938 | } |
1908 | 1939 | // restore the saved bookmark |
1909 | 1940 | if (selectionEnd) { |
1910 | | - vim.marks['>'] = cm.setBookmark(selectionEnd); |
| 1941 | + var curStartMark = cm.setBookmark(selectionStart); |
| 1942 | + var curEndMark = cm.setBookmark(selectionEnd); |
| 1943 | + if (vim.visualMode) { |
| 1944 | + vim.marks['<'] = curStartMark; |
| 1945 | + vim.marks['>'] = curEndMark; |
| 1946 | + } else { |
| 1947 | + vim.lastSelection.curStartMark = curStartMark; |
| 1948 | + vim.lastSelection.curEndMark = curEndMark; |
| 1949 | + } |
1911 | 1950 | } |
1912 | 1951 | if (operatorArgs.linewise) { |
1913 | 1952 | cm.setCursor(motions.moveToFirstNonWhiteSpaceCharacter(cm)); |
|
2645 | 2684 | return [selectionStart, selectionEnd]; |
2646 | 2685 | }; |
2647 | 2686 | var getLastSelectedAreaRange = function() { |
2648 | | - var start = lastSelection.curStartMark.find(); |
2649 | | - var end = lastSelection.curEndMark.find(); |
2650 | 2687 | var selectionStart = cm.getCursor(); |
2651 | 2688 | 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; |
| 2689 | + var block = lastSelection.visualBlock; |
| 2690 | + if (block) { |
| 2691 | + var width = block.width; |
| 2692 | + var height = block.height; |
2657 | 2693 | 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; |
| 2694 | + var selections = []; |
| 2695 | + // selectBlock creates a 'proper' rectangular block. |
| 2696 | + // We do not want that in all cases, so we manually set selections. |
| 2697 | + for (var i = selectionStart.line; i < selectionEnd.line; i++) { |
| 2698 | + var anchor = Pos(i, selectionStart.ch); |
| 2699 | + var head = Pos(i, selectionEnd.ch); |
| 2700 | + var range = {anchor: anchor, head: head}; |
| 2701 | + selections.push(range); |
2667 | 2702 | } |
2668 | | - cm.setCursor(selectionStart); |
2669 | | - selectBlock(cm, selectionEnd); |
| 2703 | + cm.setSelections(selections); |
2670 | 2704 | } else { |
| 2705 | + var start = lastSelection.curStartMark.find(); |
| 2706 | + var end = lastSelection.curEndMark.find(); |
2671 | 2707 | var line = end.line - start.line; |
2672 | 2708 | var ch = end.ch - start.ch; |
2673 | 2709 | selectionEnd = {line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch}; |
|
2700 | 2736 | // This check ensures to set the cursor |
2701 | 2737 | // position where we left off in previous selection |
2702 | 2738 | var swap = getIndex(ranges, selectionStart) > -1; |
| 2739 | + if (vim.visualBlock) { |
| 2740 | + var height = Math.abs(selectionStart.line - selectionEnd.line)+1; |
| 2741 | + var width = Math.abs(selectionStart.ch - selectionEnd.ch); |
| 2742 | + var block = {height: height, width: width}; |
| 2743 | + } |
2703 | 2744 | // can't use selection state here because yank has already reset its cursor |
2704 | 2745 | // Also, Bookmarks make the visual selections robust to edit operations |
2705 | 2746 | vim.lastSelection = {'curStartMark': cm.setBookmark(swap ? selectionEnd : selectionStart), |
2706 | 2747 | 'curEndMark': cm.setBookmark(swap ? selectionStart : selectionEnd), |
2707 | 2748 | 'visualMode': vim.visualMode, |
2708 | 2749 | 'visualLine': vim.visualLine, |
2709 | | - 'visualBlock': vim.visualBlock}; |
| 2750 | + 'visualBlock': block}; |
2710 | 2751 | } |
2711 | 2752 |
|
2712 | 2753 | function exitVisualMode(cm) { |
|
0 commit comments