Michael Anhari

Python-backed Vim super snippets with UltiSnips

Typing on a laptop

I spent some of my day on Sunday converting my old snippets from my SnipMate, to the format expected by UltiSnips (a slighlty more robust snippet plugin). UltiSnips supports SnipMate out of the box, but I wanted my snippets in the UltiSnips form to make writing more advanced snippets a little bit easier.

This involved moving snippets from ~/.vim/snippets/ to ~/.vim/UltiSnips/, and converting them to a style that doesn't rely on significant whitespace.

" SnipMate format
snippet hm
  has_many :${0}

" UltiSnips format
snippet hm
has_many :${0}
endsnippet

Writing more advanced snippets with Python

UltiSnips supports Python interpolation which allows you to execute python code to transform inputs as you type them. To demonstrate what I mean here, let's take a look at the following snippet I patched up on Sunday:

snippet set
def set_${1:model}
  $1 = `!p snip.rv = ''.join([x.capitalize() for x in t[1].split('_')])`.find_by(params[:id])
end
endsnippet

And lets see it in action:

Example snippet expansion for setting an instance variable in a Rails controller. Note: new should really be show here. Oops.

Pretty great stuff. What's going on here:

  • !p houses an interpolated python expression
  • snip.rv assigns the value to be returned to vim from the snippet
  • ''.join([x.capitalize() for x in t[1].split('_')]) — converts advanced_charm to AdvancedCharm as I type.

Let's take a look at one more example. Quite often, I need to write a new feature spec using capybara/RSpec. I tend to name the files like so user_creates_an_article_spec.rb, and then end up adding the feature spec boilerplate:

require "rails_helper"

feature "User creates an article" do
  scenario "some text that varies here" do
    # Add expectation here
  end
end

Let's see how we can write a snippet that automate some of that process using python.

snippet feat
require "rails_helper"

feature "`!p snip.rv = snip.basename.replace("_", " ").replace(" spec", "").capitalize()`" do
  scenario "${0}" do
  end
end
endsnippet

Let's check this one out in action:

Example snippet expansion using UltiSnips to populate a scenario tag in RSpec.

This is pretty similar to the snippet before. All we are doing differently here is returning a different value via snip.rv. This time around we access the filename without the extension via snip.basename and perform some python functions to convert the filename into a capitalized description.

I've only scratched the surface here, but I hope you try out some python powered snippets too. Cheers!

Newsletter

I'm working on sending out a weekly newsletter. I'll make it as easy as possible to unsubscribe at any time.