From 44194bd09c173d20c32c7aae7f3ed97254cee164 Mon Sep 17 00:00:00 2001 From: Julian Prein Date: Wed, 15 Feb 2023 16:38:16 +0100 Subject: [PATCH] vim:keys: Expand visual selection on [jk] Add two vmaps that call ExpandVisualSelection() for the appropriate direction. That expands the selection over all directly following lines in the given direction that contain the current selection at the same position. Example: ``` - TODO: ... - TODO: ... - TODO: ... ``` In visual block one can select `TODO: ` on the first line and then call `ExpandVisualSelection(1)` which results in a block selection that spans over all other TODOs as well. --- .config/vim/vimrc.d/40-keys.vim | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/.config/vim/vimrc.d/40-keys.vim b/.config/vim/vimrc.d/40-keys.vim index 652a716..4e746c2 100644 --- a/.config/vim/vimrc.d/40-keys.vim +++ b/.config/vim/vimrc.d/40-keys.vim @@ -287,3 +287,57 @@ nnoremap gUl vnoremap gU nnoremap gul vnoremap gu + +" Expand visual selection over all directly following lines in the given +" direction that contain the current selection at the same position. +" +" Example: +" ``` +" - TODO: ... +" - TODO: ... +" - TODO: ... +" ``` +" +" In visual block one can select `TODO: ` on the first line and then call +" `ExpandVisualSelection(1)` which results in a block selection that spans over +" all other TODOs as well. +function! ExpandVisualSelection(direction) + let l:sel = escape(GetVisualSelection(), '\') + normal gv + + " Move the cursor onto the side of the selection that points in the + " direction of the expansion. + let l:swap_ends = 0 + if ( + \ (getpos('.') == getpos("'>") && a:direction < 0) || + \ (getpos('.') == getpos("'<") && a:direction > 0) + \) + normal o + let l:swap_ends = 1 + endif + + if (a:direction < 0) + " Because of the greedy nature of search(), we cannot use the same + " regex/approach as when searching forwards, as it will only ever match + " the preceding line. + while ( + \ (line('.') - 1) && + \ match(getline(line('.') - 1), '\%'.col("'<").'c'.l:sel) != -1 + \) + call cursor(line('.') - 1, col("'<")) + endwhile + elseif (a:direction > 0) + let l:pat = '\v%#(.*\n.*%' . col("'<") . 'c\V' . l:sel . '\)\*' + call search(l:pat, 'e') + else + " TODO: expand in both directions + endif + + " Reset cursor column + if (l:swap_ends && mode() == "\") + normal O + endif +endfunction + +vmap j :call ExpandVisualSelection(1) +vmap k :call ExpandVisualSelection(-1)