6

Not sure if this one is possible, but say I have a file with two blocks of text, in this case English words and their French translations. eg:

vivre
aimer
étudier

to live
to like
to study

Now I want to copy the second block and match them by position only, perhaps with a '-', eg:

vivre - to live
aimer - to like
étudier - to study

3 Answers 3

10

While doing yank/put while iterating through the rows works fine this can actually be done with a single yank/put thanks to blockwise Visual mode. That is the mode you enter by hitting Ctrl+V from Normal mode.

Since OP is flexible on the format and because some of this is probably new for a lot of folks I'll show a couple methods for joining the text using a Visual block.

Tabular

Personally I like this format which emulates a table; sections separated by a bit of whitespace and the rightmost section left-aligned on a single column...

vivre     to live
aimer     to like
étudier   to study

The feature that makes this possible is called "Virtual editing" which allows some interesting movement with the cursor.

...the cursor can be positioned where there is no actual character. This can be halfway into a tab or beyond the end of the line. Useful for selecting a rectangle in Visual mode and editing a table.

(Emphasis is mine...selecting a rectangle and editing a table is kind of what we'll be doing.)

In this case we'll set the option to "block" which allows virtual editing in blockwise Visual mode: :set ve=block. Then, with the cursor at the start of the first block (i.e. on the v in vivre)...

<C-V>}<BS>ll"adgvVjd"aP
  • <C-V> - Ctrl+V to enter blockwise Visual mode
  • }<BS> - move to the bottom right of the text block
  • ll - pick up a couple extra spaces as padding (this is where virtual editing comes into play)
  • "ad - delete the selected text into register a
  • gvV - reselect the previously selected visual block and switch to "linewise" mode
  • jd - add an extra line to the selection and then delete the selection
  • "aP - insert the first block of text before the second block

(At this point you may want to reset virtual edit to its default value: :set ve&)

Update: I golfed this down to two fewer characters by yanking instead of deleting and taking advantage of the fact that the last yank one does can be found in register 0: <C-V>}<BS>llygvVjd"0P. I also could have kept the delete and Put from register 2 since each delete "pushed" onto a stack of sorts: registers 1-9.

Dash-delimited

If you prefer the dash separation we can also use blockwise Visual mode and we don't even need virtual editing:

mt<C-V>}mb<BS>$A - <Esc>gvd'bjPkd't

Briefly, this will

  • Mark the beginning of the first block
  • Select the block with blockwise Visual mode, marking the following line in the process.
  • Append - to all lines
  • Reselect the block and delete the contained text
  • Go to the second block and Put/prepend the first block
  • Using the marks set earlier remove the (now empty) first block lines

The result:

vivre - to live
aimer - to like
étudier - to study

Reuse

If you're saying "But I want macros so I can reuse it" you can create a mapping instead. These are easier to keep in your vimrc, for one thing.

Using the second solution, for example, you'd just copy it straight in to the mapping:

:nnoremap <leader>X mt<C-V>}mb<BS>$A - <Esc>gvd'bjPkd't

(Use whatever keystrokes you want in place of <leader>X.)

2
  • 1
    This is awesome. I've used vi for years and never knew about gv; and it even works in visual studio vimfx! This should be the accepted answer.
    – Still.Tony
    May 1, 2018 at 1:06
  • 1
    Similar: <C-v>}<BS>lldgvVj"_dP using the blackhole register.
    – D. Ben Knoble
    Jan 5, 2022 at 14:19
6

Sure. A macro can do this without too much trouble. With your cursor on the first character of the first line (Anything in <> is a special key and not a litteral <key>):

qq"ay$:let @a .= ' - '<CR>4j"Ay$jjo<Ctrl+R>a<Esc>^6kq
  • qq: Starts a macro in register q.
  • "ay$: Yank to the end of line into the a register. (Not yy to avoid the newline)
  • :let @a .= ' - '<CR>: Append the text - to register a.
  • 4j"Ay$: Go down to the corresponding english text and append to regester a with A.
  • 2jo<Ctrl+R>a<Esc>: Print the contents of register a.
  • ^6k: Put the cursor back to the beginning to yank the next term.
  • q: End the macro

Then execute the macro with #@q where # is how many times you want to execute the macro (A.K.A. how many lines you have to copy). Any numbers in the macro may have to be adjusted for how many lines you need to skip over in your real text.

1
  • 2
    Vimgolf: qqA -<esc>}+dd'^pkJ+q2@qdd Apr 30, 2018 at 22:18
4

Assuming you're on a Linux or Unix system with the paste command available and your blocks are in two files:

vim file1
:%!paste - file2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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