2

I have the current file (current location being [n])

The [p]hilosophical chicken saw the street
The red dog saw the street
The red dog crossed the street
The apple was red
The red dog crossed the street
The red dog was sleeping

I want to change the next 4 lines that contain red dog to philosophical chicken

This is a situation I routinely run into and end up using the mouse.


What is the quickest way to do this with minimal keystrokes?

I have attempted so far

  • Counted the lines by pushing Ctrl+g, counting the next lines and doing :2,5s:red dog:philosophical chicken:g
    • Lot of time, thinking and typing
  • Macro -> qu /red dog Enter c2W philosophical chicken Esc /red dog Enter q 2@u
    • Once complete, about as fast as using substitute (:s)
  • 2yW j P 2dE - Yank two words (ignoring punctuation), go down 1 line, paste before the cursor and delete two words
    • Quickly completes one line, but now my buffer contains red dog, so I have to go back and recapture the buffer.
  • Highlight philosophical chicken with mouse in terminal, hit Ctrl+Shift+C, j 2cW + Ctrl+Shift+V, Esc - Copy text, go down one line, change two words and enter Insert mode and paste, Esc escapes insert mode
    • Mouse in vim? :(
  • c2W philosophical chicken Esc ?red dog Enter .N.N. - Change two words, type "philosophical chicken" escape, reverse search for "red dog", do last action (change 2 words to philosophical chicken), repeat
    • Have to type two full words again

So far using the mouse, copying and pasting with change has been the fastest way for me. This cannot be the right way.

How should I be doing this?

Ideally, I'd like to yank 2 words, navigate to red dog and replace 2 words with the yanked buffer.

1
  • 1
    you can use "0p or "0P (that is zero, not the letter o) to paste last yanked text...
    – Sundeep
    Sep 8, 2016 at 2:56

5 Answers 5

2

Optimising what @MattObert said:

  • y3iw
  • /red dogEnter
  • c3iwCtrl-r0Esc
  • n. etc.

In detail:

  • y3iw yanks philosophical chicken; this is marginally better than y2W because the latter includes a trailing space; the iw part also makes sure the yank still works when you start with the cursor in the middle of the first word, rather than at the beginning
  • /red dogEnter finds the first red dog
  • c3iw deletes red dog (again, without the trailing space) and switches to insert mode
  • Ctrl-r0 pastes from register 0 (cf. :h i_CTRL-R and :h quote0)
  • Esc switches to normal mode
  • n. finds the next red dog and re-plays the last operation (i.e. replaces it with philosophical chicken)
  • repeat n. as needed.

The first trick is that yanks are automatically saved to register 0. The second trick is you can paste registers in insert mode with Ctrl-r.

Other things that would help you:

  • turn on line numbers: :setlocal relativenumber! number! (run it again to turn it off)
  • same thing as a macro: nnoremap <silent> <Leader>, :setlocal relativenumber! number!<CR>
  • use line offsets relative to the cursor line: :.,+6 s/.../.../
  • replace with confirmation: :%s/red dog/philosophical chicken/gc

Take a look at Drew Neil's Vimcasts for other similar tricks. Also consider posting Vim-related questions to the Vi site.

7
  • might add that paste registers with Ctrl-r works in command line also
    – Sundeep
    Sep 8, 2016 at 5:55
  • c2W won't delete trailing space.. y2E can be used to yank without trailing space
    – Sundeep
    Sep 8, 2016 at 5:56
  • @spasic There's a difference if you have philosophical chicken followed by a comma (philosophical chicken,), which is not uncommon. y2E yanks the comma, y3iw (or y2e) doesn't. But y3iw is still better than y2e because it also works when you start with the cursor in the middle of the first word, rather than at the beginning. Sep 8, 2016 at 6:01
  • agree but am nitpicking... OP requires Word variants not word... in question it is mentioned ignoring punctuation and see comment on Matt Obert's answer.. would also agree about y3iW instead of y2E
    – Sundeep
    Sep 8, 2016 at 6:10
  • @spasic Feel free to downvote my post if you think it doesn't answer the OP's question appropriately. shrug Sep 8, 2016 at 6:17
1

There's certainly more than one way to do this. But I think the simplest way would be to search for red dog:

/red dog

then change two words:

c2w

This will put you into insert mode, and you can just type:

philosophical chicken

Then hit the Esc key to switch back to command mode, and type:

n.n.

until you have replaced all instances of red dog with philosophical chicken. (n will search forward to the next instance of red dog, and . will repeat the previous command.)

Less thinking, not too much typing, and you don't even need to use buffers. (Although buffers are cool!)

Maybe I misunderstood the question, but this approach seems super simple and I wonder why everyone else is overthinking it.

EDIT:

After reading the question more closely, I see that a variation on this is one of the options above, but OP has rejected it because "Have to type two full words again". Sorry about that. But this would still be my preferred method.

3
  • 1
    This is how I would go about it to. Not to much thinking required. Sep 8, 2016 at 4:56
  • 1
    I do this when it's quick to type but try replacing (for example) database passwords that can look like this -> ]Xqysmw#IUeO"g@bp9y}BCj<-@|?X.3 The point is the content of the words shouldn't suddenly make copying with the mouse faster.
    – Miati
    Sep 8, 2016 at 5:13
  • 1
    We have edit history, tagging on "Edit" with some extra information makes your post less readable. Think about all future readers, you should integrate your changes to make your answer a consistent whole that is easy to read and understand. Tagging on your thoughts this way doesn't achieve that.
    – Anthon
    Sep 8, 2016 at 5:15
0

I would normally use the first approach.  But, if you don't like that, I would suggest a minor modification of the third approach.

  1. "a2yW, to yank "philosophical chicken" into buffer A.
  2. Move to "red dog" by the method of your choice; e.g., j or /red dog.
  3. 2dW and "aP (or "aP and 2dE) to paste "philosophical chicken" from buffer A and delete "red dog".
  4. Repeat steps 2 and 3 (since buffer A still contains "philosophical chicken").  If you searched for "red dog" before, just use n to repeat the search.  If you used j before, use 2Bj (or 2B2j to move from line 3 to line 5, etc.)
0

I discovered this post

RESOLUTION: For my immediate need, I used 12yl to yank 12 characters and "_cw^r0 to replace a word. I was then able to use the . command to repeat the replacement throughout the file. – plong

Making the sequence

y2W /red dog Enter "_c2W^r0 Esc n.n.

1
  • 1
    this will leave extra spaces as W behaves differently with y and c.. and since you are pasting from 0 reg, no need to clear to black hole reg.. so this might be optimal: y2E/red dog<CR>c2W^r0<Esc>
    – Sundeep
    Sep 8, 2016 at 5:51
0

First, I'd yank philosophical chicken, as this is shorter than re-typing. Then, I would employ either one of my plugins:

Alterative A

With my ChangeGlobally plugin, gc{motion} replaces red dog with typed text (here: pasted register), and re-applies this to all / [count] following occurrences as well.

"ay2ejgc2e<C-R>a<Esc>

Alterative B

This is more suited to editing, not pasting, though. For few (or not subsequent) occurrences, I would prefer my ReplaceWithRegister plugin, which lets you override text with a register via gr{motion}. For your example, I use +w to move to the next occurrence; one could also use search / n.

y2ejgr2e+w.2+w.+w.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .