0

How do I duplicate a word in my buffer?

Answers should take care to point out side effects such as modified registers and discuss tradeoffs of avoiding such effects vs simplicity.

2
  • Could you elaborate on what you mean by duplicate word? An example of before and after would help to make it more concrete? I would like also better understand the limitation you have with the recent register (do you want to keep the value of the ", * register of the value of all the registers? Commented May 26 at 13:01
  • Do you still have something open in your question? How can we help you further? Otherwise maybe could you accept one of the answers using the v button next to the arrow voting buttons. It allow the question to rest :-) Commented May 28 at 8:23

4 Answers 4

3

Actually it's possible to change the current line without changing any registers. To do so, we need to use setline(), getline() and expand(<cword>).

Here is a quick proof of concept. I should have computed the byte index in the current line that corresponds to the start of the current word. It's perfectly possible, but this is not what matters here.

You can start from:

nnoremap <silent> µ :<c-u>call setline('.', substitute(getline('.'), '$', expand('<cword>'), ''))<cr>

If you compare :registers state after and before executing the mapping, you'll see nothing has changed. Note that one of the tricks is that I don't :call setline() interactively from the command line in order to leave @: unchanged. In the same idea, calling from a function won't change anything either.

Should we do it? Nahhh! yawp is perfect. The convoluted approach would only make sense in plugins where we don't want to touch end-user registers.

2
  • 1
    Nice. It bears mentioning that calling Ex commands from a mapping does not change ":. That's the one thing I missed in my answer - even though I mentioned :help ": where this is explicitly documented.
    – Friedrich
    Commented Jun 26 at 10:55
  • 1
    Yes indeed. That's because it's not explicitly called by us from the command line. mappings, abbreviations... won't appear. Also If not not mistaken, marks are not altered, the cursor doesn't move, and so on. Commented Jun 26 at 12:39
3

Here's a convoluted technique that is a few less keystrokes than Luc Hermitte's answer.

Technically, it does change one register: the expression register "=), but that's not really a problem in practice, as whatever was in there before would be overwritten the next time you use it anyway.* As you are performing an edit, it also updates the change and undo lists, and alters the '[, '], and '. marks.

With your cursor on the start of the word, type:

"='Ctrl-RCtrl-W'EnterP

Like in Friedrich's :substitute command, this uses <C-R><C-W> to enter the word under the cursor into the command line, but instead of using it as a replacement, it instead enters it into the expression register to put it directly into the buffer.

*: It is possible to access the expression register without affecting its contents, by using getreg(), but there can't be too many situations where you'd actually want to do so.

0
2

It's not possible in Vim to change the buffer without changing a register.
I stand corrected: see Luc's answer.

Let's explore some options to turn foo into foofoo, always assuming the cursor is on the word:

  • The obvious solution yawP — will change the unnamed register ". Specifying a register won't help because we would change that register instead.
  • Use an Ex command like :s/<C-R><C-W>/&&/ — looks promising until we remember that this changes the : register that holds the last Ex command, see :help ":. So much for clever solutions writing a user command that restores the unnamed register after copying the word. Note: you can, however, define a mapping that calls a command as this will not change ":. This is exploited by Luc's answer.
  • Heck, let's just type it out as afoo<Esc> — even this is flawed because it will change the last inserted text register, see :help "..
  • Use the clipboard using various settings of the 'mouse' option — will disqualify as well because it will change any of "+, "* or "..

The only option to leave your precious registers untouched would be to change the file with another editor (or another instance of Vim) and let Vim pick up the changes. This is decidedly not "in Vim".

It's not entirely obvious where you're going with your "don't change registers" approach. After all, they're called registers, not constants so it's probably time to get used to the fact that they change all the time.

For all practical purposes, one of the approaches outlined above should be good enough.

1

Standard Solution

To duplicate you could copy and paste:

  1. yiw copy the current word and move at the start of the word
  2. P paste before the cursor

If you don't want to override the default register you can use another register (e.g. z):

  1. "zyiw copy the current word in the z register and move at the start of the word
  2. "zP past the content of the z register before the cursor

Related Plugin

If you need to juggle with the registers you could be interested by the following plugins:

yoink

The yoink maintains an history of all text that have been yank (copy).

At the time of pasting (e.g. using the p or P key command), rigth after you paste you can use the Ctrl+n key to select one of the previously yank (copy) text (the Ctrl+p key to select one of the next yank text).

2
  • I'm not sure to understand your comment. Could you elaborate more? The black hole can be use to yank (cut) but not really to paste or more precisely it is always empty. Commented May 26 at 14:10
  • Thanks! English is not my native language ;-) I'm so glad you check my answers :-) Commented May 26 at 16:47

Your Answer

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

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