3

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
2

Use vim-visual-multi. Create cursors at different places using \\c and press p.

| improve this answer | |
1

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:

  1. /pat/ and ?pat? always must be closed. That is, Copy /foo is not supported, use Copy /foo/ instead.
  2. With a range a last address is taken. That is, Copy 10,20 is the same as Copy 20, although copy 10,20 is the same as copy 10 (a range rarely makes sense for a copy destination anyway).
  3. No error messages (E16, E486 etc.) are given for bad arguments.
  4. Executing an arbitrary string may have some unexpected side-effects.
| improve this answer | |
  • 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 even split(<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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.