10

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
ib.
  • 27,830
  • 11
  • 80
  • 100
Robottinosino
  • 10,384
  • 17
  • 59
  • 97

6 Answers6

2

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.

Prince Goulash
  • 15,295
  • 2
  • 46
  • 47
  • Right, you did understand me correctly. And how can I conveniently repeat this opearation short of recording a macro? (e.g. qq ... and then @q or even @@) – Robottinosino Sep 22 '12 at 20:37
  • The attempt at making it work with **`.`** is **kick-ass**, but it doesn't really work (e.g. I need to `0` to go to the start of the line first, at that point I am probably better off using the macro, and it most definitely does not work for "stamp" lines with an indent). Having said that, the idea of using `.` was _exactly_ what I was hoping to get to... (of course I knew how to record a macro already, I even mentioned that in my Q) – Robottinosino Sep 22 '12 at 21:03
  • Assuming you haven't remapped it, you can use `Y`, rather than `yy` or `Vy` for yanking the initial line. (Many people remap `Y` to yank from the cursor to the end of the line, like `D` and `C`. But the default action for `Y` is to yank the entire line) – Trevor Powell Sep 22 '12 at 23:52
1

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.

romainl
  • 186,200
  • 21
  • 280
  • 313
  • The `c` flag for substitution is absolutely **awesome**. Thank you so much for teaching it to me! BTW: given that you have been using that mapping for a "long" time, it sounds like I am not the only one who found a need for multiple "stamping". I'll consider your advice... but I always prefer a temporary macro to a permanent remapping. – Robottinosino Sep 22 '12 at 21:34
  • How about a temporary mapping? `:vnoremap p "_dP`. I often have to replace long URLs with newer ones: `vi",p` is rather useful. – romainl Sep 22 '12 at 21:58
1

One can resort to Ex commands to achieve the said workflow.

For a single substitution, yank the “stamp” line (with yy, Vy, :y, or otherwise), then repeatedly use the combination of the :put and :delete commands:

:pu|-d_

Like any other Ex command, this one can be easily repeated with the @: shortcut (see :help @:) — unless another Ex command was issued in the meantime (in which case that command would be repeated instead).

Of course, you can also record the above Ex command as a macro and invoke it that way, too.

ib.
  • 27,830
  • 11
  • 80
  • 100
1

Many answers here outline the general keys or commands. I've turned them into my ReplaceWithRegister plugin, which also handles many corner cases, and allows quick repeat via the . command. I also use your described create stamp and replace technique often, and found my script indispensable. Should you not like it, the plugin page also has links to alternative plugins.

Ingo Karkat
  • 167,457
  • 16
  • 250
  • 324
1

A really easy solution: just put this script in your .vimrc, then toggle off the "buffer-overwriting" side-effect behavior of the delete key by typing ,, (two commas) to enter "no side effects" mode.

In this mode your workflow now works exactly as you described: yank whatever you like, then select, paste, and delete freely and repeatedly -- your buffer always remains intact. Then type ,, again if you wish to restore vim's normal buffer-altering behavior.

The script is the accepted answer here:

vim toggling buffer overwrite behavior when deleting

Community
  • 1
  • 1
Magnus
  • 10,736
  • 5
  • 44
  • 57
0

Starting with your cursor at the start of the line to be duplicated:

  1. y$ to yank the whole line (excluding the linefeed).
  2. j and k to advance to the next line to be replaced (repeating as needed)
  3. Replace the line with your yanked text
    • C<c-r>0<esc>0 (first time)
    • . (subsequent times)
  4. If there are more lines to be replaced, goto 2.

The cursor will remain in column zero after each step.

Trevor Powell
  • 1,154
  • 9
  • 20
  • You write "The cursor will remain in column zero after each step." - are you sure about that? It does not work on my machine. Having said that, I am thankful for your answer anyway.. – Robottinosino Sep 23 '12 at 00:52
  • @Robottinosino Which step moves the cursor horizontally for you? – Trevor Powell Sep 23 '12 at 01:38
  • I said that wrong: it's just that the cursor does not move automatically to the first column... – Robottinosino Sep 28 '12 at 23:55
  • That's true. You can use `+` and `-` instead of `j` and `k` if you prefer; those move the cursor to the first column of the next and previous line, respectively. Those keys are just a little further away from the home row than I usually like to go. :) – Trevor Powell Sep 29 '12 at 02:11