3

How do I replace a visual selection with some register content without overwriting the unnamed ("") register by the visual selection?

The question

https://stackoverflow.com/questions/3837772/vim-replace-selection-with-default-buffer-without-overwriting-the-buffer

is basically the same, however the answer xnoremap p "_dP provided there doesn't work properly if applied to a selection that includes the last character of the line (not even the end of line character $). Furthermore, with this solution, the paste register is hardcoded (to the unnamed one).

I found a partial solution using c, namely "_c<C-R>"<Esc>. This still has the problem that the paste register is hard coded. Furthermore, I don't know how to use this in a vimscript function.

(My main goal is to write a command that takes a motion and then replaces everything between the current cursor position to the motion target by a given register. I currently have this:

noremap s :set opfunc=SensibleSubstitute<CR>g@
function! SensibleSubstitute(type)
    normal `[v`]
    normal "_c<C-R>"
endfunction

but the <C-R>" is not recognized and just inserted verbally. Furthermore I don't know how to use the selected register if the user for example types "asiw)

(PS: the accepted answer here has the same problems with selections at the end of hte line)

1

2 Answers 2

2

There are a lot of weird workarounds, but I do have an answer.

but the <C-R>" is not recognized and just inserted verbally.

If you want ctrl-r, you'll need "\<C-r>". (Note: Specifically with double quotes, not single. Try :echo "\<C-r>" and :echo '\<C-r>') Which unfortunately means you'll need the whole thing to be a rather convoluted exec command:

exec 'normal "_c'."\<C-r>".'"'

Furthermore I don't know how to use the selected register if the user for example types "asiw

You can get this in the v:register variable. Unfortunately, it's not quite that simple in your example. Try this for example:

noremap s :set opfunc=SensibleSubstitute<CR>g@
function! SensibleSubstitute(type)
  echo v:register
endfunction

Try something like "asiw. This always prints " instead of a. Why is that? Because of your remapping, you're effectively running

"a:set opfunc=SensibleSubstitute<CR>g@

When you really want to run

:set opfunc=SensibleSubstitute<CR>"ag@

So you'll have to use an <expr> mapping.

Putting this all together, this should work for you (though I haven't tested it a whole lot):

noremap <expr> s ":set opfunc=SensibleSubstitute\<CR>".'"'.v:register."g@"
function! SensibleSubstitute(type)
  normal `[v`]
  exec 'normal "_c'."\<C-r>".v:register
endfunction
2
  • I find that exec’s look a little prettier when the string is generated with printf instead of string concatenation, but YMMV.
    – D. Ben Knoble
    Dec 19, 2018 at 18:45
  • Doesn't work, I think the v:register get's consumed by entering the visual mode. I got it to work by storing v:register at the beginning of the function
    – Bananach
    Dec 19, 2018 at 22:18
2

Finally! After years of us all dealing with Vim's bizarre (and undocumented (UPDATE: OK, OK, half-documented)) default behaviour of replacing the unnamed register even when you are pasting from it, P was introduced in version 8.2.4242 (apparently). I am running v.9 so I have this already!

Shift+P

Or rather, P instead of p.

NB: P only works if you use it the first time and every time.

IF you haven't yet upgraded to >= v.8.2.4242, or you have forgotten and just this second put/pasted with p, never fear! You can still access your latest "put" text in register 0:

Shift+",0,p

"0p

You can follow a p with "0p as many times as you like, as long as you don't "put" any other text in the meantime. If you do, you will then find your original paste text in register 1 ("1) etc.

If your Vim does support P, you can also map p to P in your .vimrc file so you never forget:

xnoremap p P

Evidently I am in the fine company of many other Vim users (cf. other questions around SE on this topic) in never having found the default behaviour useful. Presumably it is handy if you want to replace a single instance of some text but also re-insert the replaced text later on. I suppose someone might want to do that, but it's pretty hard to imagine the use case. Maybe if you needed to bump something down a list, but keep the other stuff around it the same.

It must either be something Bram really likes, or just die-hard compatibility with the original vi (which Bram and team have always been happy to depart from in order to make Vim more 'Improved').

UPDATE 2: OK, two weeks on from writing this, I finally needed to replace and move a word in some code today and realised this would be appropriate. First time in 20 years!

1
  • 2
    FWIW, the behavior has been documented for 13 years under :help v_p. Also, vi didn't have an equivalent of Vim's visual mode to begin with so vi compatibility can't be the reason. I must say that the provided explanation makes sense to me even if it is a situation I rarely find myself in.
    – romainl
    Feb 3 at 6:48

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.