I use :copy
a fair bit. So like range :12,15 copy 20
will paste a block of text from 12 to 15 lines at 20th line. But when I want to paste a line at multiple places it doesn't work. For example :24 copy 12,22,25
it only pastes 24th line at 12th line. Is there a plugin or .vimrc setting that can help me achieve this behavior?
-
Welcome to Vi and Vim! I'm not aware of an existing solution that does this, but a command could feasibly by implemented. Interesting question! – D. Ben Knoble♦ Nov 9 '19 at 14:22
For example :24 copy 12,22,25 it only pastes 24th line at 12th line.
It is interpreted as a range, not as a list, of which copy
is able to take a first address only.
Is there a plugin or .vimrc setting that can help me achieve this behavior?
It's missing, probably, because it's rarely found useful. But you can always add such command yourself.
function! s:multicopy(line1, line2, ...) abort
" save the text to be copied
let l:text = getline(a:line1, a:line2)
" sort line numbers to prevent overlapping
let l:lines = reverse(sort(filter(map(copy(a:000),
\ {k, v -> trim(execute(v . '=', 'silent!'))}), '!empty(v:val)'), 'N'))
" now make all the copies
for l:line in l:lines
call append(l:line, l:text)
endfor
endfunction
command! -range -nargs=+ Copy call s:multicopy(<line1>, <line2>, <f-args>)
Note that normally Ex commands use a space as an argument separator, so you are expected to type
:24Copy 12 22 25
UPD.: Added support for an arbitrary :h :range
specification. Known bugs/features:
/pat/
and?pat?
always must be closed. That is,Copy /foo
is not supported, useCopy /foo/
instead.- With a range a last address is taken. That is,
Copy 10,20
is the same asCopy 20
, althoughcopy 10,20
is the same ascopy 10
(a range rarely makes sense for acopy
destination anyway). - No error messages (E16, E486 etc.) are given for bad arguments.
- Executing an arbitrary string may have some unexpected side-effects.
-
Clever! I came up with
command -range -nargs=1 Copy <line1>,<line2>yank | for target in split(<q-args>, ',') | execute target 'put' | endfor
as a first shot, but the overlapping was the problem I had – D. Ben Knoble♦ Nov 9 '19 at 14:31 -
@D.BenKnoble Yeah, I also thought about using
split(<q-args>, ',')
or evensplit(<q-args>, '[[:space:],;]')
to mimic the behaviour in the OP, but a normal separator should be preferred, IMO. – Matt Nov 9 '19 at 15:22