tags:

views:

80

answers:

5

Here is an example buffer in vim:

fooooo
bar
pippy

one
two
three

And here is what I would like to produce:

foooooone
bartwo
pippythree

Ideally by specifying the two ranges of line numbers, but a sequence of commands would also be great.

+2  A: 

In such cases, I usually record a macro like this: qq4j^y$4k$pjq. Here is what it does: starting at an item of the first list, it goes down to the second list, copies an item, goes back, then pastes the item at the end of the line. Lastly, it moves to the second item of the first list. Executing this macro three times (3@q) yields the desired result.

Don Reba
+1  A: 

Vim's registers have a mode associated with them: characterwise, linewise, and blockwise. This affects how the content of the register is put into the buffer when pasting the contents of a register. You can use this to your advantage for this problem.

Place your cursor at the start of the one line and select those lines using visual block mode:
Ctrl+v$jj
Delete the block:
x
Move your cursor to the end of the foo line and paste what you just deleted:
p

jamessan
This appears to only work when the first group all have the same line length, which was a misleading example. Thanks anyway.
Dave Tapley
+1  A: 

Since your first group all have the same line length, you could use block selection with <C>-v. Starting with the first character of your second block selected,

<C>-v } $ d { $ p

So you select the whole bottom section in "block" mode, move to the end of the line of the beginning of the first block, and paste.

Seth Johnson
A good observation, unfortunately this due to a misleading example, I've edited it accordingly. Thanks anyway.
Dave Tapley
+1  A: 

Ok, so start by yanking or removing the three lines you want to place at the end (e.g. 5G3dd). Then:

:let lines=split(@","\n")

This puts all those lines in a list of strings (e.g. ['one', 'two', 'three']).

Now select the lines you want to append to (e.g. 1GV2j). Then

:'<,'>s/$/\=remove(lines,0)

This replaces the end of each line (/$/) in the selected range ('<,'>) with the the next line unshifted off the front of the list of lines (\=remove(lines,0)).

If you find yourself doing this a lot, you may want to bind the above commands into a single command.

rampion
+2  A: 

Here's a vim script solution:

fun MergeLines(start1, start2, length)
    let end1 = a:start1 + a:length - 1
    let end2 = a:start2 + a:length - 1
    let starting_lines = getline(a:start1, end1)
    let ending_lines = getline(a:start2, end2)

    " Append each line in ending_lines to starting_lines.
    let i = 0
    while i < linecount
        let starting_lines[i] .= ending_lines[i]
        let i += 1
    endw

    " Set the new lines.
    call setline(a:start1, starting_lines)

    " Delete the old ones (there should be a function for this...).
    exe a:start2 . ',' . end2 . 'del'
endf

So to accomplish your example:

:call MergeLines(1, 4, 3)
meeselet