My typical day-to-day workflow in Vim involves having two vertical panes; production code on the left, and the tests on the right.

I frequently switch languages (and test frameworks), so I like to create a new mapping for running my test code each session. Let’s say I’m doing some Ruby project and I’m driving out a class in lib/importer.rb. The accompanying specs live in spec/lib/importer_spec.rb.

To create my mapping for running the specs, I would focus on the pane showing the specs, and enter the following:

:nnoremap -g :!rspec %<cr>

Note: I use hyphen/minus as my leader key.

This works, but only if the spec pane has focus when I hit -g. If the production pane has focus and I hit the mapping, rspec will try and run the production code, which doesn’t make sense.

To work around this, I can write the absolute path to the spec file:

:nnoremap -g :!rspec spec/lib/importer_spec.rb<cr>

This works, though it is a bit cumbersome to write.

While reading Practical Vim last night, I realised that in command mode you can use % expansion — you write % and then hit tab, and the percent is replaced with the absolute path to the file in the currently focused pane.

If I do this:

:!rspec %

…And then hit tab, I get this:

:!rspec spec/lib/importer_spec.rb

And that’s great! However, If I do this:

:nnoremap -g :!rspec %

…And then hit tab, I get this:

:nnoremap -g :!rspec %^I

I am a good person and I pay my taxes. Why is this happening to me?


The command completion by default isn't recognized in mappings (and recorded in macros). You can define an alternative key in the obscure 'wildcharm' option and use that. However, insertion of the current filename can be done in an easier and more straightforward way. Instead of completing %, just insert an equivalent Vimscript expression via <C-r>:

:nnoremap -g :!rspec <C-r>=expand('%')<cr><cr>

PS: To properly deal with all sorts of filenames, additionally use shellescape():

:nnoremap -g :!rspec <C-r>=shellescape(expand('%'), 1)<cr><cr>

PPS: I hope you're not actually manually typing in the mapping every time, but use a filetype plugin or :autocmd to define this automatically for the test buffers. I'd definitely recommend to automate it in that way.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.