How to efficiently paste over multiple lines again and again with the same text in Vim? - 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.
Position the cursor on the line to be copied (using movement commands).
Enter line-wise Visual mode (via the V command).
Copy selected text (using the y command).
Manually position the cursor onto the line to be replaced (using movement commands).
Enter Visual mode again to select the text to be replaced (using the V command).
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

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.

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.

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.

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

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.

Starting with your cursor at the start of the line to be duplicated:
y$ to yank the whole line (excluding the linefeed).
j and k to advance to the next line to be replaced (repeating as needed)
Replace the line with your yanked text
C<c-r>0<esc>0 (first time)
. (subsequent times)
If there are more lines to be replaced, goto 2.
The cursor will remain in column zero after each step.

Related

How to repeat a navigation command in Vim

The . key can be used to repeat the last insert command. However, we might do some navigation that is not part of the insert, but we want it repeated.
Imagine commenting out lines like so:
// line of text
// line of text
line of text
line of text
The insert command is to put the two forward slashes and a space. That can be repeated using the . key. The navigation would be to navigate down one line and then left some number of characters. That part is not captured by the . key command.
How can we achieve this functionality? I read that it was not available in Vi some years ago, but I'm wondering if it exists now in the latest version of Vim.
Press qX, where X is any of the writable registers (typically: pick any lowercase letter).
Do whatever actions you want to record.
Press q again to stop recording.
Press #X (where X is the same register) to play it back (count times, if used with a count).
Press ## to replay the most recently used macro (count times).
I read that it was not available in Vi some years ago, but I'm wondering if it exists now in the latest version of Vim.
If the Vim docs are to be believed, Vi did not support recording (steps 1-3), but did support #. Then you would have to manually yank the characters into the target register with "Xy<motion> or some other register-writing command. That also works under Vim, but I can't recommend it because it is much more error prone.
Another approach would be "block select then edit" approach:
ctrl + v - block select
then go down j or down-arrow
shift + i will put you in insert mode. Make the change here where you want it to be reflected on all the other lines you've selected.
esc twice will show/repeat that change you made on the line one.
If you have a big range of similar lines and want to put // at the beginning of it, you can do something like:
:15,25norm! I//<space>
You can also use visual area (vip selects an entire paragraph)
:'<,'>norm! I//<space>
using a pattern
:g/TODO/norm! I//<space>

Vim command to paste over highlighted word

I've only recently learned about use v command to mark a section I want to copy or cut. This is great!
But I'd like to use the v command to make the section I want to replace.
For example:
$another_obj->method_in_obj
$self->method_actually_in_obj
I want to mark "another_obj" and overwrite "self" with "another_obj". Basically I want to tell vim that, I want to take these 4 characters (self) and turn them into these 11 characters (another_obj) and have vim adjust my line accordingly.
So the final should be:
$another_obj->method_in_obj
$another_obj->method_actually_in_obj
Thanks!
#Kent has outlined the basic approach: You yank the source word, then paste over the selected replacement. The downside is that you can do that only once, because that action overrides the original yanked text! To avoid that, you need to specify the black-hole register.
I do this so often, I wrote a plugin to simplify and allow maximum speed: ReplaceWithRegister.
This plugin offers a two-in-one gr command that replaces text covered by a {motion} / text object, entire line(s) or the current selection with the contents of a register; the old text is deleted into the black-hole register, i.e. it's gone. It transparently handles many corner cases and allows for a quick repeat via the standard . command. Should you not like it, its page has links to alternatives.
cursor on [a]nother, pressing yw
then j cursor is on [s]elf, press:vawp

Pasting inside delimiters without using visual selection

In Vim, let's say I want to replace the contents of one String with the content of another.
Original input
var1 = "January"
var2 = "February"
Desired output
var1 = "January"
var2 = "January"
What I would usually do is:
Move cursor to line 1
y i " (yank inner quotes)
Move cursor to the destination quote in line 2
v i " p (visual select inner quotes, paste)
While this works well, I generally try to avoid visual mode when possible, so I am not completely satisfied with my step 4 (v i " p).
Is there any way to specify a "destination paste area" without using Visual mode? I suspect it might be something chained to g, but I can't think of anything.
There are many ways of doing this however using visual mode is the easiest.
Use the black hole register to delete the content then paste. e.g. "_di"P
Do ci"<c-r>0. <c-r> inserts the contents of a register
Simply paste and then move over a character and delete the old text. e.g pldt"
However visual mode still has my vote. I find that the concerns most people have is that using visual mode + paste is that the default register is swap with the selected text and it doesn't repeat well. Good news everybody! The 0 register always stores the last yank. The bad news is visual mode still doesn't repeat well. Take a look at this vimcast episode, Pasting from Visual mode, for more information. It mentions a few plugin that help with this.
I need this so often, I wrote a plugin to simplify and allow maximum speed: ReplaceWithRegister.
This plugin offers a two-in-one gr command that replaces text covered by a {motion} / text object, entire line(s) or the current selection with the contents of a register; the old text is deleted into the black-hole register, i.e. it's gone. It transparently handles many corner cases and allows for a quick repeat via the standard . command. Should you not like it, its page has links to alternatives.
It's not particularly pretty, but here goes:
Go to line one and yi"
Move to line two
Type "_di"hp
That deletes what's in the quotes, but sends the deleted text to a black hole register. Then it moves the cursor back one, and pastes what you yanked from line one.
All in all, you can start on the first line and type yi"j"_di"hp. Why is it that people find vim intimidating? ;)
Alternatively, yank the first line as normal, then drop to line two and type ci"<Ctrl+p> and select the previously yanked text from the menu.
Excerpt from my .vimrc:
" Delete to 'black hole' register
nnoremap <leader>d "_d
vnoremap <leader>d "_d
So, you just need to \di"P as your last step (assuming you use \ as a <leader>).
There is a plugin that addresses this problem precisely. It was presumably born out of the same feeling you're feeling, namely that Visual mode often feels less than ideal to advanced Vim users.
operator-replace – Operator to replace text with register content
With operator-replace installed the replacing goes like this.
Yank the word inside the quotes.
yi"
Move to the target line
j
Replace inside the quotes with the yanked text. (I've set up gr as the replace operator: :map gr <Plug>(operator-replace). Pick your own mapping.)
gri"
Check it out! This is part of the truly excellent textobj/operator frameworks. I couldn't work without them.

Is there some pattern behind the many VIM commands?

I have to add a VIM personality to an IDE. I never used VIM for more than the most basic edits and i'm now overwhelmed by the complexity of the command structure.
Is there any overall structure for the combination of counts moves and insert/delete commands?
I just can't see the wood for the trees.
Well, there is obviously a finger position pattern behind h, j, k, l.
The fact that ^ goes to the beginning of a line and $ goes to the end is patterned on common regular expression syntax.
Ctrl-F and Ctrl-B page forward and back, and that's fairly intuitive.
i inserts (before) and a appends (after the cursor). Similarly,
I inserts at the beginning of the line, and A appends at the very end.
> and < indent and outdent, respectively. That's also kind of intuitive.
But on the whole, many of the other commands are on whatever keys were left – it's hard to find an intuitive mapping between the letters of the alphabet and an editor's commands.
Repeat counts are always entered before a command, and mostly repeat the command that many times, but in some cases do something clever but analogous.
I think the secret to not going crazy over vi is to start out with only a small handful of commands. I have a lot of colleagues who don't know to do anything other than
move the cursor around using the arrow keys (you don't have to use h, j, k, l);
insert with i, delete with Del (you don't have to use x);
delete a line with dd
get out of input mode with Esc
get out of vi with :x (exit) or q! (quit, and throw away my changes!)
Because I'm much smarter, the additional commands I know and use are:
go to the top of the file with gg, the bottom with G.
I can go to a specified line number with (line-number)G.
copy a line with y (yank), paste it with p
change a word with cw, the rest of the line with C
delete a word with dw, the rest of the line with D
I sometimes use . to repeat the last command, or u (undo) if I messed up.
When you have occasion to use other commands, you can teach them to yourself one by one as needed.
This is a good article for explaining the VIM philosophy.
I think the characteristic that better defines VIM in respect to other editors is its wide array of motion commands. The first thing to learn to fully use VIM is hitting the arrow keys as little as possible, and think at the text in terms of "blocks" like "a sentence" "a tag" "a word" "a group of brackets".
Say you have function foo($bar, $fooz) you can change the parameters by simply positioning your cursor anywhere inside the brackets and pressing ci) (mnemonic: change inner bracket). The same pattern applies to other commands: yank (y), delete (d) and so on.
I know this doesn't explain the whole "VIM philosophy" but combining normal mode commands with the vast amount of motion modifiers is what really made me see the light.
There are plenty of nice and interesting tutorials. One example is
http://blog.interlinked.org/tutorials/vim_tutorial.html
But the broad structure that most of them would give you is
There are two main modes for editing - Command mode and insert mode. You can move from insert mode to command mode using the key.
You can execute commands in the command mode by typing a single key or a sequence of keys.
Commands can help you achieve a wide variety of things
deletion of lines - dd
yanking (copying of lines ) - yy
pasting lines below the current line - p
pasting lines above the current line - P ( and so on)
Most commands in the command mode can be pre-fixed by a "count" to indicate the number of times the command has to be executed. For example, 3dd would delete three lines.
One set of commands in the command mode lets you move to the insert mode. That is explained below.
There are different ways of entering the insert mode from the command mode. Prominent among them are (i-insert at cursor, I-insert at beginning of line, o-insert a line below, O-insert a line above, a-append, A-append at end of line.
The quick reference at
http://www.andy-roberts.net/misc/vim/vim.pdf
Will help you understand the relevance of "count"

How to repeat a command with substitution in Vim?

In Unix the ^ allows you to repeat a command with some text substituted for new text. For example:
csh% grep "stuff" file1 >> Results
grep "stuff" file1
csh% ^file1^file2^
grep "stuff" file2
csh%
Is there a Vim equivalent? There are a lot of times I find myself editing minor things on the command line over and over again.
Specifically for subsitutions: use & to repeat your last substitution on the current line from normal mode.
To repeat for all lines, type :%&
q: to enter the command-line window (:help cmdwin).
You can edit and reuse previously entered ex-style commands in this window.
Once you hit :, you can type a couple characters and up-arrow, and it will character-match what you typed. e.g. type :set and it will climb back through your "sets". This also works for search - just type / and up-arrow. And /abc up-arrow will feed you matching search strings counterchronologically.
There are 2 ways.
You simply hit the . key to perform an exact replay of the very last command (other than movement). For example, I type cw then hello to change a word to "hello". After moving my cursor to a different word, I hit . to do it again.
For more advanced commands like a replace, after you have performed the substition, simply hit the : key then the ↑ up arrow key, and it fills your command line with the same command.
To repeat the previous substition on all lines with all of the same flags you can use the mapping g&.
If you have made a substitution in either normal mode :s/A/B/g (the current line) or visual mode :'<,>'s/A/B/g (lines included in the current selection) and you want to repeat that last substitution, you can:
Move to another line (normal mode) and simply press &, or if you like, :-&-<CR> (looks like :&), to affect the current line without highlighting, or
Highlight a range (visual mode) and press :-&-<CR> (looks like :'<,'>&) to affect the range of lines in the selection.
With my limited knowledge of Vim, this solves several problems. For one, the last visual substitution :'<,'>s/A/B/g is available as the last command (:-<UP>) from both normal and visual mode, but always produces an error from normal mode. (It still refers to the last selection from visual mode - not to the empty selection at the cursor like I assumed - and my example substitution exhausts every match in one pass.) Meanwhile, the last normal mode substitution starts with :s, not :'<,'>s, so you would need to modify it to use in visual mode. Finally, & is available directly from normal mode and so it accepts repetitions and other alternatives to selections, like 2& for the next two lines, and as user ruohola said, g& for the entire file.
In both versions, pressing : then & works as if you had pressed : and then retyped s/A/B/, so the mode you were in last time is irrelevant and only the current cursor line or selection determines the line(s) to be affected. (Note that the trailing flags like g are cleared too, but come next in this syntax too, as in :&g/: '<,'>&g. This is a mixed blessing in my opinion, as you can/must re-specify flags here, and standalone & doesn't seem to take flags at all. I must be missing something.)
I welcome suggestions and corrections. Most of this comes from experimentation just now so I'm sure there's a lot more to it, but hopefully it helps anyway.
Take a look at this: http://vim.wikia.com/wiki/Using_command-line_history for explanation.

Resources