0

Here's my use case. I have the following text:

This is a [hyperlink](http://someurl.com).

Now I want to replace the http://someurl.com text with a new URL in the default register (something I've copied from somewhere else).

Normally, I would move to the line, then probably do something like this:

f(    # move to the opening bracket   
vi(   # select the contents of the brackets
p     # paste from the default register

Is there any out-of-the box way to make this faster? What I'm looking for is an operation which pastes over a motion, such as "replace-in-whatever":

f(    # move to the opening bracket   
pi(   # paste *over* the contents of the brackets

I am guessing I'd need to manually create something for this, but before I look for plugins/commands, I wanted to check if there was a standard, idiomatic way (and also ideally one which supports pasting from any register if possible!).

Thanks in advance!

1 Answer 1

1

A custom operator that select and paste from any register:

nnoremap ,p :call <sid>opfunc_reg("<sid>select_and_paste")<cr>

" Apply current register to g@ . It's not allowed to set opfunc to s:func, i
" have to use a func argument.
"
" In function scope of normal map, v:register won't be changed by ex
" command (except :normal) ?
function! s:opfunc_reg(func)
  let &opfunc = a:func
  call feedkeys('"'. v:register .'g@')
endfunction

function! s:select_and_paste(type) abort

  " back up current register before visual selection
  let reg = v:register

  " visually select operator target.
  let vcmd = a:type ==# 'line' ? 'V' : (a:type ==# 'char' ? 'v' : "\<c-v>")
  silent exe printf('norm! `[%s`]', vcmd)

  " paste from current register
  exec 'norm! "' . reg . 'p'
endfunction

Don't use it

This operator is useless, because vi)p is 4 key strokes, ,pi) is also 4 key strokes (can be reduced to 3, which is still meaningless and crazy). One should get used to v{motion}p style operation.

I create it only because i'm leaning to create operator that support register.

update

If you use custom motion or text object, a lot of things could happen between g@ and opfunc, a single ex command is enough to reset v:register, to fix that, i have to use a global variable instead of v:register (not sure if it's the right way):

nnoremap ,p :let g:__opfunc_reg=v:register<cr>:set opfunc=<sid>select_and_paste<cr>g@

function! s:select_and_paste(type) abort

  " visually select operator target.
  let vcmd = a:type ==# 'line' ? 'V' : (a:type ==# 'char' ? 'v' : "\<c-v>")
  silent exe printf('norm! `[%s`]', vcmd)

  " paste from current register
  exec 'norm! "' . g:__opfunc_reg . 'p'
endfunction
5
  • The nested ternary could become a dict, and you could get with a default value. The paste could be exec 'put' reg
    – D. Ben Knoble
    Jun 1, 2019 at 14:19
  • @D.BenKnoble Not sure the meaning of default value here, :put is linewise, can't be used here.
    – dedowsdi
    Jun 1, 2019 at 14:26
  • Ah youre right. For the dict, something like get({'line': 'V', 'char': 'v'}, a:type, '<C-v>')
    – D. Ben Knoble
    Jun 1, 2019 at 14:35
  • @D.BenKnoble That's a little weird, i shall keep it in mind, it's the first time i see it. I was thinking you mean something like : {'line': 'V', 'char': 'v', 'block' : "\<c-v>"}[a:type].
    – dedowsdi
    Jun 1, 2019 at 14:42
  • i couldnt remember if block was available; i was just going off the ternary. I would definitely prefer your version if it works.
    – D. Ben Knoble
    Jun 1, 2019 at 14:47

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.