Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

In vim, when I have a vertical block selected (such as a single column of text), I would like to be able to repeatedly put (paste) whatever is in the current register. For example, if I had something like:

username0 password0 personal_info0
username1 password1 personal_info1
username9 password9 personal_info9

and I select the column of text between username. and password. (i.e. the column of spaces between the two), I would like to be able to put (paste) there. This works fine in one sense: I can put something, but if the selection is longer than the register, the rest of the selection is just replaced by nothing. Instead, I'd like it to do something like repeat the register down the selection. Is there any way to do this short of using a regex?

share|improve this question
up vote 3 down vote accepted

If the new column is going to have the same value on each line (i.e. your initial yank was on a single line), then is probably just easier to visually block select the space between the username and password column and type A (or I) to start appending (inserting). When you return to normal mode (Esc), Vim will append the text to the rest of the original selection, too.

If you really need to do a repeating pattern, then you could use a function and mapping like this:

:function! PutRegFilledToRange() range
:  let l:fill = ''
:  let l:lines = getreg()
:  let l:lineStart = 0
:  let l:linesLen = strlen(l:lines)
:  let l:lineIndex = 0
:  let l:linesNeeded = a:lastline - a:firstline + 1
:  while l:lineIndex < l:linesNeeded 
:    let l:lineEnd = matchend(l:lines, "\n\\|$", l:lineStart)
:    let l:line = strpart(l:lines, l:lineStart, l:lineEnd - l:lineStart)
:    if l:lines[l:lineEnd - 1] != "\n" 
:      let l:line = l:line . "\n"
:    endif
:    let l:fill = l:fill . l:line
:    let l:lineStart = l:lineEnd < l:linesLen ? l:lineEnd : 0
:    let l:lineIndex = l:lineIndex + 1
:  endwhile
:  normal gv
:  " This probably does not make much sense in any mode
:  " other than block modes, but we will try to cope.
:  if mode() == "\<C-V>" || mode() == "\<C-S>"
:    let l:newMode = "\<C-V>"
:  elseif mode() == 'v' || mode() == 's'
:    let l:newMode = 'v'
:  else
:    let l:newMode = 'V'
:  endif
:  let l:origReg = getreg('')
:  let l:origRegType = getregtype('')
:  try
:    call setreg('', l:fill, l:newMode)
:    execute 'normal ' . v:count1 . 'p'
:  finally
:    call setreg('', l:origReg, l:origRegType)
:  endtry
:vmap _f :call PutRegFilledToRange()<CR>

Put in your .vimrc, or some other file (and run :source /path/to/file). Or paste it directly into a Vim session.

To use it:

  • C-V{motion}y: visually block select and yank the text you want to use to repeatedly put
  • {motion}C-V{motion}: select the block you want to replace
  • _f: fill the selected block with repeated lines of the current register ("a_f fills block with lines from register a)
share|improve this answer
Amazing. Does exactly what I needed. Thanks!!! – G Gordon Worley III Feb 25 '10 at 15:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .