Here is a list of some intermediate to advanced Vim tips I’ve found interesting. Let’s recap.

1. Repeat the last Ex command

In Vim there are 3 command line mode prompts:

  • Ex command prompt: :something
  • Search prompt: /something
  • Expression prompt (from insert mode type <C-r>= ): =1+1<cr>

Let’s say we run a spec from the Ex command prompt with:

:!rspec spec/models/code_spec.rb

We can repeat the last Ex command by typing @: from normal mode.

2. Sort properties in CSS

If we want to order the lines in the CSS selector alphabetically, we just select the lines and type :sort while in visual mode and then we have them sorted.

h4 {
  font-size: 11px;
  margin: 15px;
  background: red;
}

3. Select yanked and pasted text

We can select the original yanked text with gv . And, select last pasted text with gb . gb is a custom mapping that we add to vimrc file and I find it extremely  useful when doing extract method refactoring, a cut-paste and then we need to fix indentation. With gb we easily select the pasted text and we fix the indentation with  <  or >.

" select last paste in visual mode
nnoremap <expr> gb '`[' . strpart(getregtype(), 0, 1) . '`]'

4. Paste text while in insert mode

Say we’re in insert mode and we want to paste yanked text without leaving the insert mode. We can do that with  <C-r>0. If yanked text contains new line characters, <C-r><C-p>0 will take care of fixing indentation issues.

5. Delete in insert mode

To delete a character, word or line while in Insert mode, Vim Command Line mode or Shell Command Line  we have the following shortcuts available:

<C-h> " delete back one character (backspace)
<C-w> " delete back one word
<C-u> " delete back to start of line
<C-k> " delete forward to end of line

6. Run normal mode commands across a range

We have the following javascript lines and we forgot to append ;  to each of them:

var element = $(this)
var tabName = element.data('tab')
var report = element.data('report')

We can visually select all 3 lines and then run command :normal A;  that will execute A; (append ;) for each line. Alternatively, we can run same on the whole content of the file with  :%normal A;.

7. Repeat last change on multiple lines

What if we did a single modification on the first line of the above snippet appending ; at the end of the line with A;. We can repeat that command by selecting the lines 2-3 and running the dot command over visual selection with :'<,'> normal .

8. Replace in multiple files

Replacing in multiple files is not a straight forward action in Vim. To search & replace in multiple files, first we need to create a list of files in which we’ll execute a command. We do that by using the :args command. For example, lets load all javascript files that start with the “ext” string:

:args app/assets/javascripts/ext*.js

We can see which files are loaded in the arguments list by running the :args command. Having the arguments list prepared, we can execute search & replace with:

:argdo %s/From/To/g

Once changes have been made in the files, we can save all the files in arguments list with:

:argdo update

9. Search and replace in multiple files

Previous tip works OK if we know the files where we want to run the replace command. But, most of the time we want to search for a text in files and then run the replace command only in those files. We can do that by using vimgrep command to find a pattern in files. vimgrep command creates quicklist with files matching the pattern which list we can see by opening it with :copen command. If we want quicklist to be useful, we need to convert it to arguments list by using the :Qargs mapping which we have in our vimrc file:

command! -nargs=0 -bar Qargs execute 'args' QuickfixFilenames()

" populate the argument list with each of the files named in the quickfix list
function! QuickfixFilenames()
  let buffer_numbers = {}
  for quickfix_item in getqflist()
    let buffer_numbers[quickfix_item['bufnr']] = bufname(quickfix_item['bufnr'])
  endfor
  return join(map(values(buffer_numbers), 'fnameescape(v:val)'))
endfunction

Finally, here’s an example of what needs to be run to do search & replace in files:

:vimgrep /CurrencyNumberHelper/ app/models/*.rb
:Qargs
:argdo %s/CurrencyNumberHelper/CurrencyHelper/g
:argdo update

An easier option as pointed by buztard in the comments, is to use ack-grep to create the arguments:

:args `ack-grep -l CurrencyNumberHelper`
# or, if you're using Ack plugin, then just :Ack CurrencyNumberHelper
:argdo %s/CurrencyNumberHelper/CurrencyHelper/g
:argdo update

And, even more easier, if you’re on a newer version of Vim, you can simply use cdo and cfdo as pointed out by Thiago A. in the comments:

:Ack CurrencyNumberHelper
:cfdo s/CurrencyNumberHelper/CurrencyHelper/g | update

10. Edit already recorded macro

While recording a macro it’s easy to do mistakes. And when that happens, it’s easier to edit the already recorded macro than to re-record it. Lets say we have recorded new macro in register a . We can print the content of the macro in the current buffer using :put a and then edit the macro in Vim. Once macro is changed, we can select it and then yank it to register a with "ay . Then we are ready to execute the new macro from register a with @a .

11. Execute macro in multiple files

We have already recorded a macro and we want to run it in few files. First we build arguments list with the files, for example let’s load all models from a Rails app:

:args app/models/*.rb

Then we run the macro (that is recorded in register a) with:

:argdo normal @a

In the end we save all the buffers with:

:argdo update

12. Vi mode on command line

Bash shell provides two modes for command line editing: emacs and vi . Emacs editing mode is the default one, and we can change it to vi mode using:

set -o vi

Then while on command line, we can press ESC to go to vi editing mode and use vi’s single line editing capabilities. While in vi editing mode on the command line, we can press v that will popup editor where we can edit and save buffer that will be executed on command line. Awesome, huh? :)

If we need to go back to emacs mode, type:

set -o emacs

Here’s a cheatsheet of what Vi commands we can run in bash shell vi mode.

Looking for more Vim tips? Checkout my vimfiles on Github.