17

Goal: Select multiple words, one at a time, then replace them all.

visual studio feature select and replace

I'm new to Vim; I come from Visual Studio. I would like to achieve one important feature that helped me a lot in my productivity: Select multiple words, one at a time, and then replace them all.

I know there is a Vim way of replacing using:

:% s/target-word/replacement/gc

But as you can see it's still a lot to write compared to its counterpart in VS Code. Could someone help me with a vim script or a plugin to achieve this in the most similar way?

  • imagine that I already have selected the word with viw, for example.
  • then I want to have a single command to select the next match.
  • then start writing and see those changes written in real-time or after hitting Esc.

[Edit] Accepted answer

Thanks D. Ben Knoble; you provided to me the more convenient and practical answer. As the main goal is to change a word locally, the combination *cgn Is perfect.

As I'm changing the also the current word and * jumps me to the next match, what I add to go back to that word is Ctrl + N.

* Ctrl + N cgn then .

enter image description here

8
  • 2
    Welcome to Vi&Vim SE. If you're open to a little advice, seeing as you're new to vim and assuming you'd like to become as proficient as you can, be open to solutions that don't work exactly as you've laid it out but achieve the same thing..using "the Vim way". (I can't promise there will be a superior Vim way for this particular question so consider that general advice. Cheers.)
    – B Layer
    Commented Oct 27, 2020 at 20:05
  • 1
    @Sam also :grep -R match, depending on grepprg (I use ripgrep, so it’s really easy to do such a project wide search), :tselect if you have tags setup, :find if you know the file... there are many ways to search and navigate :)
    – D. Ben Knoble
    Commented Oct 27, 2020 at 22:10
  • 2
    I use registers a lot. Something like, while on the word, "ayiw to yank the word to register a, I mainly increment the number by a random number then do "byiw. Then I use %s/ (CTRL-ra)/(CTRL-rb)/gc where (CTRL-ra) puts register a into the search part of the replace. Then gc goes match by match and you can replace or not. Generally I replace all because I know I need to. If i need to check they changed I use :g// and expect no matches. Not a dev so maybe not what you're looking for.
    – Steve
    Commented Oct 27, 2020 at 23:50
  • 1
    A couple of notes: if you have a new question do not edit the original one; instead, ask a new one ([howto])—I've removed the edited-in new question, but you can get to it from the edit history if you like. Also, did you perhaps mean N (shift-n) instead of Ctrl-N?
    – D. Ben Knoble
    Commented Oct 28, 2020 at 13:17
  • 1
    @sam Hi. Exactly right. You can put the register directly with "a[pP] etc. Copying to a register in :g is useful as well eg :g/{pattern}/y A will append matches in register a. You have to clear the register first with qa` or `:let @a=''`` . learnvimscriptthehardway.stevelosh.com/chapters/12.html might help
    – Steve
    Commented Oct 28, 2020 at 23:50

4 Answers 4

24

I’m assuming all the things to change are the same. If not, I would probably proceed with either multiples of the steps below, or combine all the patterns into a single substitute pattern.

So, not really what you asked for, but:

*cgn

Breakdown:

  • *: start a search for the word under the cursor (g* if you don’t want the word boundaries)
  • cchange
  • gn the next match

So you put your cursor somewhere in a word, press *cgn, type the replacement, hit <esc>, and then hit . to change the next occurence.

If you already searched for the word, ignore the * and just cgn.

These are somewhat equivalent to

%substitute/\<<C-r>=expand('<cword>')<cr>\>/replacement/gc

and

%substitute//replacement/gc

If you want to do this with a visually-selected pattern, I would yank it, followed by

%substitute/<C-r>"//replacement/gc

(Add word boundaries \<\> as needed)


If you want to substitute in a narrower region, than the whole file (%), use ranges (and remember that in visual mode, : automatically populates the range '<,'>, which is also the range *, which is all the lines in the selection). These can be quite powerful, and a full overview is out-of-scope (:help [range]).


A slightly more advanced option: do a search (:grep, :vimgrep, &c.) or some other operation that fills the quickfix list (:cexpr, :make) and then

cdo substitute/pat/repl/flags

Or :cfdo %substitute if you know you want the whole of each file.

Don’t forget to :cfdo update or just :wall afterwards.


There do exist multi-cursor-emulation plugins for vim. I can’t recommend any, never having used them, but they are out there.

Really, though, learning how to use commands like :substitute, :global, ., operators like c, d, and all the other motions and such can be, in the long term, more efficient. It does require breaking some learned habits and thought-processes, however, and it’s not for everyone. Fear not. You can make vim whatever you want.

2
  • Thanks! this is what I was looking for, I like things to be simple and fast to type, the Linux mentality, this way I won't be needing any plugin. I'm aiming for the long term, thanks this really improves my productivity, first I was jumping with w and cw, then with :%s/match/replacement/gc, now for faster and local things I can use *cgn, thanks for the detailed answer!
    – Sam
    Commented Oct 28, 2020 at 1:31
  • 1
    The existence of multi-cursor plugins was exactly why I posted my initial comment. I was hoping you wouldn't end up with that as your choice. They are square pegs in round holes in terms of their fit in the Vim universe. Glad you found a solution that you like that follows "the Vim way" © ®. ;)
    – B Layer
    Commented Oct 28, 2020 at 14:16
4

One way would be to press * when your cursor is on the word you want to replace, phrase in this case, which will search for that word (very useful in general!) It will use \<phrase\> as the pattern: the \> are word boundaries (similar to \b in Perl-style regexps) so that it won't match phrases.

You can then use :%s//sentence/g; to replace phrase with sentence. If you omit the search pattern in :s then it will automatically use the current search pattern. I find that this is generally a more convenient way to do search previews than the /c flag: search for something: verify it matches what you want, and use :s//replace.


The current search pattern is stored in the @/ register, which is a variable you can read and write; for example if you want to use phrase without the word boundaries:

:echo @/
\<phrase\>

:let @/ = 'phrase'
:echo @/
phrase

:%s//sentence

This isn't exactly the live preview you asked for, which is something Vim doesn't really have right now. I find this is a reasonably efficient workflow. Generally speaking Vim isn't too good at these kind of live preview things and such; even the live search when you use / is actually fairly new and was added 3 years ago.

In NeoVim you can use :set inccommand=nosplit to show a preview in a split window, but this isn't in Vim yet. I can't really find an issue for it on the Vim tracker right now. I'm fairly sure I saw a plugin for this once, but I can't find that right now either 😅

4
  • Thinking alike :)
    – D. Ben Knoble
    Commented Oct 27, 2020 at 22:11
  • Thanks for your answer Martin, I knew about the star * operator to match the next word, but I didn't know that it was saved in the @ variable, interesting. I also didn't know I could use this to ignore the first parameter in :%s//replace. It's pretty great. I guess I would ask you, could you show me how to make a nmap or inoremap so we don't have to write the instruction :%s//replace? I would really appreciate it. I'll edit my question to put more context.
    – Sam
    Commented Oct 28, 2020 at 0:09
  • @Sam note that it is stored in the search register (:help quote/) which is accessible via @/--as are most registers. We already have a Q somewhere about mapping :%s//... if I can find it
    – D. Ben Knoble
    Commented Oct 28, 2020 at 13:20
  • 1
    Writing commands is kind of how Vim works @Sam, which is probably different from VSCode. You can use nnoremap <C-s> :%s// to map it to control+s, for example. Basically mappings just send the keys you'd type (although you can do some more advanced things as well). To automatically add the /g flag and put the cursor in the correct position you can use :nnoremap <C-s> :%s//g<Left><Left>. You can also add the * beforehand, if you'd like. Commented Oct 30, 2020 at 11:50
1

There are Vim plug-ins that emulate the "multiple cursors" feature from other editors such as Sublime or VS Code, for example, mg979/vim-visual-multi (successor to the now deprecated terryma/vim-multiple-cursors.)

But since these plug-ins need to use Vim highlighting features to emulate multiple selections and they typically need to re-implement many Vim native movements, they are often limited in what they can do and they can be a little buggy.

There are many other Vim plug-ins implementing search and replace features. While they might not be as visually straightforward as the "multiple cursors" feature, they often work better in Vim. Some examples are:

And many others. As it's often the case with Vim, there are tradeoffs with each choice, some will be better in specific situations, some will be more general. While you can get a lot done in terms of search and replace with built-in features of Vim, if you do consider adding external plug-ins, consider evaluating the ones in this list. A web search for "vim search and replace" will also point you at many more.

3
  • 1
    Thank you for your answer, acording to the repository terryma/vim-multiple-cursors. is deprecated, the new repository looks promising: github.com/mg979/vim-visual-multi, I'll check on it and I'll let you know. The other three in the list seem very powerful when it comes to seach in the whole project, but I guess is not the use case I'm looking for, I want something local, in the same file, and fast so I don't have to type too many comands, that's why I'm incline to use try a mapping solution as a configuration. Thanks again for all the references!
    – Sam
    Commented Oct 28, 2020 at 0:45
  • 1
    @Sam Oh wow I didn't realize that! I had fixed a bug in vim-multiple-cursors a few months ago... Anyways, glad you found the replacement and I hope it helps you! Don't miss the answers from Ben and Martin, often without any plugins you can get a lot done already... Cheers!
    – filbranden
    Commented Oct 28, 2020 at 20:19
  • 1
    @fibranden Thanks, yeah, sometimes the time comes and you know that you need a plugin, I just wanted to use all my options before doing it. I a nodejs developer I always consider if something can be done with plain javascript instead of adding yet another dependency to the node_modules... here I'm trying to apply the same with Vim. Thanks for everything!
    – Sam
    Commented Oct 28, 2020 at 20:31
0

You can watch in one minute.how is it work and what is shortcut for this.

https://youtube.com/shorts/dqQQ46w5tkI?si=ETMVFlMfUXCMq9Bw

1
  • 2
    Thank you for writing an answer. It is preferable to have the solution as text in the answer and a link to external content as an (optional) addition. Linked content can change or be removed altogether. You can take the tour and visit the help center to learn more about how this site works.
    – Friedrich
    Commented May 3 at 5:32

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.