Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to efficiently paste over multiple lines again and again with the same text in Vim?

Tags:

vim

Objective

Yank a line and use it to overwrite some of the lines following it.

Assumption

It is preferable in this case to manually select the lines to apply the substitution to. In other words, automated find and replace is not desired.

Analogy

Think of this process as creating a “stamp” from a line of text and going through a list of items—each item being a line of text following the “stamp” line—and deciding whether that line should be overridden using the contents of the “stamp” or not (in the former case, replacing the line with the “stamp”, of course).

This last step of triggering the replacement of the line under the cursor with the contents of the stamp, should be as easy as possible; preferably, as easy as pressing . (repeat last change) or @@ (execute the contents of macro register @).

Issue

The straightforward workflow is, of course, as follows.

  1. Position the cursor on the line to be copied (using movement commands).
  2. Enter line-wise Visual mode (via the V command).
  3. Copy selected text (using the y command).
  4. Manually position the cursor onto the line to be replaced (using movement commands).
  5. Enter Visual mode again to select the text to be replaced (using the V command).
  6. Paste over the selection (using the p command).

However, this approach does not work when the replacement has to be done multiple times. Specifically, replacing the text on step 6 overrides the (unnamed) register containing the line initially copied and intended to be used as a “stamp”.

What I have tried

I have tried using "_y to either yank or delete into the _ register, avoiding the loss of the contents of the stamp, but I am looking for something that ends up being quick and comfortable to type as I manually go through the list and apply replacements where I see fit.

What I would prefer not to use

I would rather not use macros or “remaps” for this, if I can help it.

Illustrative sample file

See the sample starting file below, followed by the desired final stage, for further clarity.

Sample file, starting condition

At this stage, I select the blueberry and make it my “stamp”.

blueberry

apple
banana
coconut
apple
banana
coconut
apple
banana
coconut

Sample file, desired final state

After having moved through the list, I have applied some replacements, “stamping” over some lines, making them the same as the “stamp” blueberry line.

blueberry

apple
banana
blueberry
apple
banana
coconut
apple
banana
blueberry
like image 738
Robottinosino Avatar asked Sep 22 '12 20:09

Robottinosino


People also ask

How do I paste a block of text in Vim?

Pasting over a block of text You can copy a block of text by pressing Ctrl-v (or Ctrl-q if you use Ctrl-v for paste), then moving the cursor to select, and pressing y to yank. Now you can move elsewhere and press p to paste the text after the cursor (or P to paste before).

How do I put multiple lines of text in Vim?

vim Inserting text Insert text into multiple lines at oncePress Ctrl + v to enter into visual block mode. Use ↑ / ↓ / j / k to select multiple lines. Press Shift + i and start typing what you want. After you press Esc , the text will be inserted into all the lines you selected.


2 Answers

To make your workflow work as expected, you need to paste from the previous yank register "0, rather than the default register.

So use Vy (or yy, which is the same) to yank the first line as before, then position the cursor over the line you want to replace, and do

V"0p

this replaces the current line with the previously yanked text, but doesn't overwrite the yanked text. I hope I understood you correctly!

EDIT 1: repeating using a macro

I was surprised that this operation isn't repeatable using ., but this is presumably due to the use of visual mode. To repeat the operation using a macro, do this:

qqV"0pq

The macro can then be repeated by pressing @q or @@.

EDIT 2: repeating using .

Here's an attempt at making it repeatable using . by not using visual mode. After yanking the stamp line and moving the cursor, do this:

"_S<c-r>0<delete>

which uses the insert mode <c-r> command to insert the contents of register 0. Note that the <delete> is necessary because the stamp line contained a carriage return. If it did not (i.e. yanking using y$ rather than yy) the <delete> could be omitted.

like image 102
Prince Goulash Avatar answered Oct 22 '22 10:10

Prince Goulash


I don't think you are going to reach your goal without at least a little bit of "remapping".

I've been using this one for a "long" time:

vnoremap <leader>p "_dP

p and P still work as usual and I simply hit ,p over a visual selection when I want to repeat the same paste later. You could also map a single function key to make the whole thing quicker.

Also, do you know about the c flag for substitutions?

:%s/coconut/blueberry/c

will ask for your confirmation for each match.

like image 38
romainl Avatar answered Oct 22 '22 09:10

romainl