5

Sometimes I have a bunch of lines, where there's a column clearly indicating some commonality between them, which in general doesn't go far beyond that column; this is an example, I think general enough:

...
what  1: and then
who   2: there's
when  3: some other
where 4: text
ok?   5: on these lines
...

I want to insert the characterwise text from a register (say the text is text from some register,) in those five lines, right after the space which follows the :, so that the result looks like this:

...
what  1: text from some register,and then
who   2: text from some register,there's
when  3: text from some register,some other
where 4: text from some register,text
ok?   5: text from some register,on these lines
...

If I with the cursor on the second a in the file I hit Ctrl-V4jP, the letters a, t, s, t, o are deleted, just like :h v_p describes.

0

6 Answers 6

4

I tend to like using :normal with a range for this kind of edit.

Using :normal with a range is often similar to using a macro, but it can be more convenient in cases when:

  • You want a single modification per line. (A macro can be more flexible in selecting what to modify.)
  • You can express the whole command using only alpha-numeric characters (no need to enter special keys such as a sequence involving Ctrl or the Esc key.)
  • You don't need visual feedback while coming up with the sequence of commands (since you're writing them in the Ex command-line, instead of recording them while seeing what they do, which is how macros work.)
  • There's at most one insertion (mostly so that you don't need to issue an Esc at the end of the insertion; ending a :normal with an insertion will implicitly issue an Esc at the end of the command execution.)

In this case, you can simply forward to the first : in a line (with f:), then move another character right (with l), so you're on the space after the colon, and then use p to put the contents of the default register.

Putting it all together:

:%normal f:lp

This will execute this command for every line in the buffer. You can use a more specific range if you desire to do so. You can even use a Visual selection to decide which lines to act upon and then simply use:

:'<,'>normal f:lp

Note that when you press : from Visual mode, Vim will automatically add the :'<,'> part, so you only need to type the normal f:lp then.

One advantage of this approach using :normal over a Visual Block selection is that this approach will work regardless of whether the : characters are all aligned to the same column or not. As long as there's uniformity of being the first : character and always followed by a single space, this approach will work.

1
  • 1
    Accepting this because of the last paragraph which gives invaluable insight into possible uses of visual mode, even though in the case that the :s are all in the same column my self answer seems to be a far easier way.
    – Enlico
    Nov 27, 2020 at 6:30
3

Would it be possible to try it with a macro?

  1. Perform your yank command as you first describe (0y$).
  2. Move the cursor to the first period where you want to "put" the yanked line.
  3. Press q and then another key to store the macro (e.g. push q again)
  4. Press P and then j for the macro keys.
  5. Press q again to stop the macro recording.
  6. For the rest of the lines, when over the ., press @q to execute the macro. You can also press 3@q I believe to execute it three times in succession.

Hope that helps!

1
  • I know of macros, but they don't go in muscle memory (the faulty approach I described in my question goes there, except at most for the 3, which you need time to work out), and muscle memory is important for such a basic task. I've used macros, but for pretty complicated things. +1 nonetheless.
    – Enlico
    Nov 23, 2020 at 15:58
2

This is a good point to highlight a shortcoming of P (or the equivalent p) in Visual Block mode (more generally, in Visual mode.) It replaces the selected text, so it's not a great fit for this use case.

While you can work around it, perhaps a more straightforward alternative would be to use Visual-block Insert and then use Ctrl+R to insert the contents of the default register, from Insert mode. (See :help i_CTRL-R for more details.)

Putting it all together:

  1. Place the cursor on the a of and in the first line, then use Ctrl+V, 4, j to create a Visual Block selection on the proper column, spanning all lines where the contents should be inserted.
  2. Use I to start Visual-block Insert at the start of every line in the block.
  3. Use Ctrl+R, " to insert the contents of the default register, from Insert mode.
  4. Optionally, add another space after the comma, or insert more text if you'd like.
  5. Leave Visual-block Insert by pressing Esc. At that moment, that same insertion will be replicated to every line in the block.

One advantage of this approach is that you get to insert more text around the default register, which is useful in your particular example since it allows to easily add a trailing space after the comma, without having to modify the default register first to add that space.

2

Wow, actually it's easier than I thought!

:h v_p reads

The previously selected text is put in the unnamed register.

therefore probably the best way to do what I want is Ctrl-V3jpp, where the latter p puts back what the former p deleted, right at the place it is needed.¹


(¹) Ctrl-V3jPp is not equivalent because P and p in block-visual mode are not equivalent anymore.

1

Would you try this?

:%s/: \zs/\=@+

If you want space after the comma set your clipboard register before running the above command:

:let @+='text from some register, '
1
  • 1
    Very nice! Also good is to use Ctrl+R + on the replacement side, to get the contents of the register. That makes it even easier to prepend or append more text around it (e.g. add a trailing space.)
    – filbranden
    Dec 24, 2020 at 17:12
0

Easiest way to do it is to:

  1. Move to the first letter of the word you want to change.
  2. Go in visual block mode (ctrl-v).
  3. Then j to select all the lines.
  4. Then hit $, once the selection is made.
  5. Hit c type your new word and finally hit <Esc>.

Explanation:

  • `ctrl-v: enter visual block mode.
  • j: move down 1 line.
  • $: move to end of line.
  • c: (small "c") change (in this case, it acts like changeword.)
  • <Esc>: return to normal mode.

NB: This works for words at the end of lines. If all the words are in the middle of a line, use cw instead.

1
  • 1
    Even in the original formulation of the question I had written that the text (text, not just one word) I wanted to put was from another file; furthermore toward the end I wrote that the first step I attempted was to yank the text from the second file. This should apparent that I don't want to type my new text manually, but I want to put it from a register. The updated question should make all of this more apparent.
    – Enlico
    Nov 26, 2020 at 14:39

Your Answer

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

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