I’d like to merge two blocks of lines in Vim, i.e., take lines k through l and append them to lines m through n. If you prefer a pseudocode explanation: [line[k+i] + line[m+i] for i in range(min(l-k, n-m)+1)].
For example,
abc
def
...
123
45
...
should become
abc123
def45
Is there a nice way to do this without copying and pasting manually line by line?
You can certainly do all this with a single copy/paste (using block-mode selection), but I’m guessing that’s not what you want.
If you want to do this with just Ex commands
will transform
into
UPDATE: An answer with this many upvotes deserves a more thorough explanation.
In Vim, you can use the pipe character (
|) to chain multiple Ex commands, so the above is equivalent toMany Ex commands accept a range of lines as a prefix argument – in the above case the
5,8before thedeland the1,4before thes///specify which lines the commands operate on.deldeletes the given lines. It can take a register argument, but when one is not given, it dumps the lines to the unnamed register,@", just like deleting in normal mode does.let l=split(@")then splits the deleted lines into a list, using the default delimiter: whitespace. To work properly on input that had whitespace in the deleted lines, like:we’d need to specify a different delimiter, to prevent “work is” from being split into two list elements:
let l=split(@","\n").Finally, in the substitution
s/$/\=remove(l,0)/, we replace the end of each line ($) with the value of the expressionremove(l,0).remove(l,0)alters the listl, deleting and returning its first element. This lets us replace the deleted lines in the order in which we read them. We could instead replace the deleted lines in reverse order by usingremove(l,-1).