6

Is there a way to use a register or visual selection for search and replace? I have some longer sequence of words that are used repeatedly in my script. I want to replace them all but want to avoid typing a long sentence in a command line. If I can select them in visual mode or yank them in a buffer, and utilize it in replacement, it makes my life a lot easier.

i.e. Instead of doing something like,

:%s/Some really long word sequence that Id0n+wanna type /replacement sentence/g

I am imagining something like.

:%s/selected/replacement in a register/g

2 Answers 2

5

One possible solution is to use what I call register recall: on the :-command line, Ctrl-r followed by any of the registers (the named ones, like a or 3, or the others, such as - or ") will insert the contents of said register.

(This works in insert mode as well.)

So you could

  1. Yank the text
  2. Substitute with :%s/<C-r>"/replacement/g

It’s also interesting to note that this works on searches, too, so you could

  1. Yank the text
  2. Search: /<C-r>"
  3. Verify that you get the matches you want, or further refine the search pattern
  4. Substitute using the last pattern: :%s//replacement/g

A further refinement is to yank the replacement and do

:%s//<C-r>"/g
1
  • 1
    You could even search first, then visual select the replacement and yank it, then use the / register for find and the " register for replace expressions.
    – Spidey
    Aug 10, 2019 at 6:46
0

I use the following plugin to search for visually selected text:

function! VisualSelection()
    " Save register content and type.
    let old_reg     = getreg('"')
    let old_regmode = getregtype('"')

    " Calling this function has ended visual mode, so it must be started
    " again before the selection can be yanked into the unnamed register.
    normal! gvy
    let selection = @"

    " Restore register content and type.
    call setreg('"', old_reg, old_regmode)

    return selection
endfunction

function! Escaped(text)
    call inputsave()
    let result = escape(a:text, '\\/.*$^~[]')
    let result = substitute(result, "\n$", "", "")
    let result = substitute(result, "\n", '\\n', "g")
    call inputrestore()
    return result
endfunction

xnoremap <silent> <unique> * :<C-U><cr>/<C-R><C-R>=Escaped(VisualSelection())<cr><cr>
xnoremap <silent> <unique> # :<C-U><cr>?<C-R><C-R>=Escaped(VisualSelection())<cr><cr>

This overrides the default behavior of * and + which would extend the visual selection to the next occurrence of the word under the cursor.

For replacement you can define a third mapping which creates a substitute command for the whole buffer and prefills the search text with the visually selected text:

xnoremap <silent> <unique> g* :<C-U>%s/<C-R><C-R>=Escaped(VisualSelection()) . '/'<cr>
2
  • (1) that should probably be normal! gvy and (2) while this is great for visual searching, it does not directly answer the replace part. Maybe add a paragraph about the “last used search” so OP can do :%s//repl/g?
    – D. Ben Knoble
    Aug 9, 2019 at 17:16
  • @d.benknoble ad (1) That plugin is so old and I never cared to update it. Thanks for the hint. ad (2) I've added a third mapping that creates a prefilled substitute command. Aug 10, 2019 at 10:07

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.