Faster Vim search/replace

Entering search patterns and replacement strings in Vim can sometimes be a pain, particularly if the search or replacement text is already available in a register or under the cursor. There are a few ways to make working with search and replace in Vim quicker and less cumbersome for some common operations, and thereby save a bit of error-prone typing.

Insert contents of a register

As in command mode or insert mode, you can insert the contents of any register by pressing Ctrl+R and then the register key. For example, to directly insert the contents of register a, you can type Ctrl+R and then a while typing a search pattern or replacement string.

Reference contents of a register

Similarly, if you want to use the contents of a register in a pattern or replacement but don’t want to directly insert it, you can instead reference the contents of register a with \=@a:

:s/search/\=@a/

Both of the above tips work for both the search and replacement patterns, and for special registers like " (default unnamed register) and / (last searched text) as well as the alphabetical ones.

Insert word under cursor

If you happen to be hovering over a word that you want to use as as a search or replacement string, as a special case of the above you can do so by typing Ctrl+R and then Ctrl+W for a normal word, or Ctrl+R and then Ctrl+A for a space-delimited word.

Empty search string

You can use the previous search as a search pattern or replacement string by including it from the special / register, in the same way as any other register above, by inserting it with Ctrl+R and then /, or representing it with \=@/. There’s a convenient shorthand for this however in just using an empty search string:

:s//replacement/

This will replace all occurences of the previous search string with replacement. It turns out to be a particularly convenient shorthand when searching for words by pressing * or #.

Typo correction in Bash

If you make a typo in a long command line in Bash, instead of typing it all out again, you can either recall it from your history, or use caret notation to repeat the command with an appropriate substitution. This looks like the following:

# sudo apache2ctl restrat
Action 'restrat' failed.
The Apache error log may have more information.
# ^strat^start
sudo apache2ctl restart

The string after the first caret is the text to match, and the one after the second string is the text with which it should be replaced. This provides a convenient method of not only quickly correcting typos, but to change small parts of the command line in general quickly:

$ touch filea.txt
$ ^filea^fileb
touch fileb.txt
$ ^fileb^filec
touch filec.txt

For the particular case of correcting small errors in long paths for cd calls, it’s helpful to use the cdspell option for Bash, which I discuss in my earlier article on smarter directory navigation.

Vim command window

The command line in Vim for ex commands can be edited with a few of the GNU Readline key combinations that may be familiar to Bash or Emacs users, so it’s reasonably easy to edit it, for example to type in complex search patterns and replacements.

However, if you want the full facility of Vim editing for your commands, it can be helpful to use Vim’s command line window, which will allow you to enter commands and edit previous ones with the usual normal and insert mode.

You can open the command line window from normal mode in one of four ways:

  • q: — Open with a command history from normal mode
  • q/ — Open with a search history from normal mode (to search forward)
  • q? — Open with a search history from normal mode (to search backward)
  • Ctrl+F — Open with a command history from command mode

Note that this doesn’t work while you’re recording macros, since pressing q stops the recording.

The window is always immediately above the status bar, and its height can be set via the cmdwinheight option.

Command line window

Once the command line window is opened with q:, you can browse through it and press Enter on any line to issue the same command again. You can also edit it beforehand, perhaps to fix a mistyped command. The window will close when this is done, but you can close it with Ctrl+W, C the same as any other window if you change your mind.

Vim command line window

Vim command line window

Note that you can’t move to another window while this one is open, nor can you load another buffer into it.

Search window

Similar to the above, if you open the command window with q/ or q?, it shows a history of your searches, and pressing enter on any line will issue the same again, in the appropriate direction.

Vim search window

Vim search window

For more information on how the command window works, check out :help command-line-window.

Vim search highlighting

Being able to search by regular expression is a pretty fundamental thing in a text editor. Vim takes it to the next level by making entering a search into a motion all on its own, and even a few weeks’ Vim experience and you’ll probably catch yourself using the search to navigate your buffers.

One of the things I most commonly see recommended in threads and discussions about useful Vim features includes turning on two kinds of search highlighting: first, highlighting the search result on which you’ll land as you type it, and secondly, once you’ve pressed Enter to run your search, highlighting all of the matches. You turn these on like this:

:set incsearch
:set hlsearch

This ends up being great for editing code in particular, because if you search for variable or function names, you can see at a glance where they’re declared, defined, or used in your code. Couple that with the quick forward and backward search that you can do with the * and # keys, and you have a very convenient way to flick through successive uses of an identifier.

The only snag, really, is that it doesn’t turn itself off, and it gets visually distracting when you’ve moved on from whatever task prompted the search, and because you might search to move around, you don’t always actually want the highlighting to stay there. Text editors following a Windows model would probably clear away the highlighting as soon as you close the search box, or insert some text. This isn’t the case with Vim, which can be good or bad, but most people I’ve spoken to about this feature seem to find it annoying.

Bram Moolenar, the author of Vim, addressed this very topic in a Google Tech Talk he gave about effective text editing. You can turn off the highlighting temporarily by typing:

:nohlsearch

This is different from :set nohlsearch in that it doesn’t permanently disable the highlighting. It’ll turn it on next time you search. I find this is kind of a pain to type, so I alias it to Ctrl+L in my .vimrc file, so that in addition to its default behaviour of clearing the screen it clears the search highlighting as well:

nnoremap <C-l> :nohlsearch<CR><C-l>

Additionally, I like to set leader keys to quickly turn the highlighting option on and off completely if for some particular project it’s just thoroughly unhelpful. In this example, typing \i and \h will toggle the incsearch and hlsearch settings on and off, respectively. I’m assuming you’re using the backslash key as your <leader> here.

nnoremap <leader>i :set incsearch!<CR>
nnoremap <leader>h :set hlsearch!<CR>

Finally, I find that while I’m in insert mode, I usually don’t want to see the highlighting, so I define events to turn the highlighting off temporarily in the current buffer while I’m inserting text:

autocmd InsertEnter * :setlocal nohlsearch
autocmd InsertLeave * :setlocal hlsearch

I find these shortcuts make the search highlighting behaviour much less annoying. Interestingly, according to Vim’s help, you can’t simply add an event hook to run :nohlsearch when you enter Insert mode (from :help nohlsearch):

This command doesn’t work in an autocommand, because the highlighting state is saved and restored when executing autocommands. Same thing for when invoking a user function.

You can work around this by setting the search pattern to empty instead, as suggested by this Stack Overflow answer, but I don’t really like doing that because I often like to recurse through more search results with n and N after leaving insert mode.