4

I search a way to paste/merge 2 block of text

apple
pear
banana

tomato
beans
potato

like this

apple tomato
pear beans
banana potato

The lines have different length but same number of lines of course. I don't want different number of spaces like in visual block paste, and I search a way without using macro.

It's something we can easily do in sublime text, but I can't find an easy way to do it in vim.

Thx

  • 1
    I don't have time for a full answer, but try using visual block mode (<C-v>) – D. Ben Knoble Feb 10 at 22:09
3

This would be very easy with a macro, but you've stated don't want to use one, so here's a few alternative methods. I think they're all more complicated than a simple macro-based solution, but they show off some interesting features of Vim that readers might want to use in other scenarios.

Using :normal edits

:5,7norm!d$4kA ^R"

 5,7                # On lines 5 through 7
    norm!           # run normal mode commands that
         d$         # delete to the end of the line,
           4k       # move up 4 lines,
             A      # append a space, and
               ^R   # insert the contents of (note that this is a literal CTRL-R:
                    #                         to insert it type <C-V><C-R>
                 "  # the unnamed register   (i.e. the text we deleted)

Using :move and :join

:5m.|-1j|+1

 5m.         # Move line 5 below this line
    |        # and then
     -1j     # join the two lines
        |    # and then
         +1  # move down a line

This will append the 5th line to the current line. You can then repeat it twice to complete the edits by typing:

2@:

(Thanks to D. Ben Knoble in the comments for the suggestion to use :join.)

You could also perform the join with the normal mode command J:

:5m.|norm!kJj

 5m.           # Move line 5 below this line
    |          # and then
     norm!     # run normal mode commands that
          k    # move up a line,
           J   # join the line below, and
            j  # move down a line

Using :substitute

:1,3s/$/\= ' '.getline(line('.') + 4)

 1,3                                   # On lines 1 through 3
    s/                                 # substitute
      $                                # the end of the line
       /                               # with
        \=                             # the result of the expression
           ' '                         # a space
              .                        # followed by
               getline(             )  # the contents of the line
                       line('.') + 4   # four lines below this one.

This leaves the original second block of lines in place. You can then remove them with the command:

:4,7d
| improve this answer | |
  • Will :join not work for the move variant? – D. Ben Knoble Feb 11 at 13:45
  • @D.BenKnoble Yes! Much nicer. – Rich Feb 11 at 14:17
2

I am going to suggest using Ctrl + v (<C-v>) to make a block.

It sounds as if putting the second block after the first doesn't do what you want. However, if you put the first block in front of the second block, it should work.

To move the first paragraph to before the second paragraph you can do:

vip<C-v>$x"_d)P

vip              # Visually select the first [Inner] Paragraph (cursor inside first block)
   <C-v>$        # Change to Visual Block mode and select all the way to end of line
         x       # Cut the first paragraph into default register
          "_d)   # Delete paragraph into black hole register to remove leftover empty lines
              P  # Prepend the first paragraph (line-wise) before second paragraph

However, that doesn't leave any space between items. For example:

apple

tomato

turns into

appletomato

One way to fix this is to append a space to every item in the first block

vip:s/$/ <enter>

vip              # select the first paragraph
   :             # enter command mode
    s            # substitute command
     /$          # replace End of line...
       / /       # with a space (the second '/' here is optional)
         <enter> # press enter to complete the substitution command

Altogether:

vip:s/$/ <enter>vip<C-v>$x"_d)P

Original answer: (similar in idea to above solution, but not as generic). See more explanations in an earlier revision.

Vjj:s/$/ /<enter>C^v2k$x4jPgg4dd
^---------------^       ^^ ^---^
Put a space @ end       *1    *3
                 ^-----^  ^
                 Cut top  2
*1 - Go down
*2 - Paste
*3 - Cleanup

Freebee alternative

A completely different solution that would require macros because it only does the move one line at a time. It jumps between top and bottom blocks and combines them.

One iteration is:

)jD<C-o>pkJj

)j           # Move down to the second paragraph and onto first line
  D          # Delete the top line of the second paragraph
   <C-o>     # Jump back to the top paragraph (Ctrl+o)
        pk   # Put line from bottom below and move back to top line
          J  # Join the two lines (white space is taken care of, leaves a single space)
           j # Move down a line, ready to do it again

This moves

     Run once:           Repeat            Repeat
apple    =>  apple tomato  =>  apple tomato  =>  apple tomato
pear         pear              pear beans        pear beans
banana       banana            banana            banana potato

tomato       beans             potato
beans        potato
potato

To create and use this as a macro do qt)jD<C-o>pkJjq and 2@t. (create and use a macro in register t)

| improve this answer | |
  • I wrote my set of answers essentially for fun, but this seems like it's the correct answer, given (or indeed ignoring!) the constraints. – Rich Feb 11 at 14:39

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.