Vi and Vim Asked on August 31, 2021
This is mainly for working on multiple files in vifm (log1.txt
, log2.txt
, etc.) so lines can be assumed to be sorted, though this should work in normal vim/nvim.
Let’s say we have this:
test 1
test 2
test 3
test 4
test 5
testing 1
testing 2
testing 3
another
I’m on the line with test 3
(normal mode) and want to select everything from test 1
to test 5
. I can choose to select every consecutive line (up & down) with the same starting substring test
(with a space).
May be I’m on test 3
and want to select every consecutive line with the starting substring test
(without a space), which is test 1
till testing 3
but not another
.
In such cases, I want to visually select all consecutive lines with the same <count>
characters. I can set this to 3,5,10,etc. I know the lines I want to select typically work with 5 starting characters so I can set that as a constant. However, I don’t know beforehand what those 5 characters would be.
How can I make a macro/binding to do such selection?
If you want a command that does that based on the length of the prefix, here's one:
function! Prefix(count)
if a:count == 0
return
endif
let prefix = strcharpart(getline('.'), 0, a:count)
let pat = 'V^'.escape(prefix, '')
echom "pat = [".pat."]"
let start = line('.')
let end = start
let last = line('$')
while start > 1 && match(getline(start-1), pat) == 0
let start -= 1
endwhile
while end > 1 && match(getline(end+1), pat) == 0
let end += 1
endwhile
execute printf('normal! %dGV%dG', start, end)
endfunction
command! -bar -count=0 Prefix call Prefix(<count>)
You call it as :Prefix 4
to use the first four characters (match both test
and testing
), or :5Prefix
to use the first five (match only test
followed by a space.) You can pass the length of the prefix either before or after the command itself.
It works by assembling a pattern based on the first n characters of the line, then iterating through the lines that precede and follow the current one, as long as the pattern still matches. Then finally it visually select the range with the matching lines.
Answered by filbranden on August 31, 2021
Here's a seemingly working solution, but I'm not sure it's very robust. It selects down from the current line (not above).
function! SelectFirstWordBlock(all) abort
let curpos = getpos('.')
let curline = curpos[1]
let nextline = curline + 1
let firstword = split(trim(getline('.')), 'W+')[0]
while (a:all == 1 && split(trim(getline(nextline)), 'W+')[0] =~ firstword)
let nextline += 1
endwhile
while (a:all == 0 && split(trim(getline(nextline)), 'W+')[0] ==# firstword)
let nextline += 1
endwhile
normal V
call cursor(nextline - 1, 0)
endfunction
nnoremap <leader>V :silent! call SelectFirstWordBlock('1')<cr>
nnoremap <leader><c-v> :silent! call SelectFirstWordBlock('0')<cr>
The first mapping matches with a space (test X
and not testx
), whereas the second matches without it.
Answered by Biggybi on August 31, 2021
The only idea that comes to my mind is to use /
to search for another
:
V
: select the first line/
: search the first non-matching line (another
)k
: up a lineAnswered by Biggybi on August 31, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP