Light at the end of the carpal tunnel: snippets in vim with snipMate

vim_logoI’ve tried a number of snippet plugins for vim, many claiming more and less feature parity with the beloved TextMate. I started using snipMate today, and it is by far my favorite. If you haven’t seen TextMate-like snippets in action, check out this short video. If you weren’t a fan of snippets before, you should be now. They allow you to type a small piece of text that serves to remind you of the purpose and, once triggered, have it be replaced with blocks of text and code of all sorts.

So why choose snipMate for snippets? The main features:

 
  • Easy to use
  • Well documented
  • Lots of snippets out of the box
  • Simple to define your own snippets
  • Easy to convert current TextMate snippets for snipMate use
  • Marks aren’t added into the buffer, so if you change your mind and escape in the middle of finishing the snippet, you don’t have ugly “{<foo>}” placeholders in your code
  • Variables are updated dynamically, so different parts of a snippet related to what you’re typing change as you type
  • <Shift-Tab> goes backwards in the tabbed fields

Many of the other snippet plugins lack one or many of these characteristics, which are all quite valuable.

Setup

  • Download the latest zip file into your ~/.vim directory and unzip it. This will place the plugin files, snippet files, and help files into the right places.
  • Open a new instance of vim and run “:helptags ~/.vim/doc”. This will load snipMate’s help files for vim to access.
  • The next time you open/restart vim you’ll be ready to go.

Conflicts

There’s one fly in this tabular ointment. <Tab> is a popular fellow, so snipMate’s use of it will likely conflict with other completion plugins. Perhaps your language-based code completion (see this post if you haven’t set this up before). In my case, all was good until I opened a Python file, wherein <Tab> after “class”, for example, brought up the word completion pop-up, not the desired snippet.

To get around this, I changed the trigger for code completion to <CTRL+n>, so both sets of functionality can be used. I find snippets more valuable than language completion, so I’d rather it be closer at hand.

Use and examples

To use a snippet, you simply type the appropriate term representing it and press <Tab>. The snippet is then placed at your current location. In many cases, you need to fill out part of the snippet to make it valid code. In these cases, you can simply tab through the locations you need or might want to edit, typing as you go. Once you tab past the last one, you are done.

.html file example, after typing “doct”, <Tab>, “html”, <Tab>, “head”, <Tab>:

HTML file snippets

Then you just type in the title, the rest is complete and indented already. A .py file example, after typing “cl”, <Tab>:

Python snippet example

Roll your own

What really sold me on snipMate was how easy it was to define custom snippets. In some other snippet plugins I tried, the snippets were in a wretched format:

1
2
exec "Snippet get def get_".st."name".et."(self):<CR>return self._".st."name".et."<CR>".st.et
exec "Snippet set def set_".st."name".et."(self, ".st."value".et."):

Not exactly easy on the eye. snipMate, however, is much more flexible. One place to start adding your own is in ~/.vim/snippets/_.snippets. This file is for snippets to be loaded for all filetypes. Here are a few useful ones I added to illustrate:

1
2
3
4
5
6
7
8
snippet date
    `strftime("%Y-%m-%d")`
snippet datetime
    `strftime("%Y-%m-%d %T %Z")`
# My name and email
snippet myinfo
    Author: `g:BASH_AuthorName`
    Email: `g:BASH_Email`

Tabs and newlines can be used without escaping, and you have full access to vimscript. It gets even better once you need to be able to type in certain parts of the snippet:

1
2
3
4
snippet def
    def ${1:fname}(${2:`indent('.') ? 'self' : ''`}):
        """${3:docstring for $1}"""
        ${4:pass}

Each “${NUM}” represents a tab stop. In this example, typing “def” then <Tab> would bring up the snippet, with the cursor placed right after def, ready to be filled in. And the string after “${NUM:” acts as a reminding placeholder. In addition, “$NUM” can be used to refer to the content of previous entries, which allows dependent parts of a snippet to be updated as you type! After “def” and <Tab>, I only typed the function name once:

Example of variable synchronization

Multiple filetypes

One issue I ran into early on was wanting more than one filetype’s snippets available for a single file. In my case, I was editing a file with a .php extension, but it had a lot of HTML in it as well. Since the filetype is determined from the extension, I only had the snippets for PHP. To fix this, I added a file ~/.vim/ftdetect/php.vim, containing:

1
au BufRead,BufNewFile *.php set filetype=php.html

When a file with an extension matching a filename in ftdetect is opened, its filetype can be changed to whatever is desired via a directive like the one above. The dot separating the filetypes allows for multiple formats to be made available at once.

Useful customizations

I’ve been adding more snippets as I’ve needed them. Additions to ~/.vim/snippets/python.snippets:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
snippet sb
    #!/usr/bin/env python
snippet sba
    #!/usr/bin/env python
    """${1}
    """

snippet docs
    """
    File: `Filename('$1.py', 'foo.py')`
    Author: `g:BASH_AuthorName`
    Date: `strftime("%Y-%m-%d %T %Z")`

    Description: ${1}
    """

# Debugging
snippet pdb
    import pdb; pdb.set_trace()

snippet pudb
    import pudb; pudb.set_trace()

And to ~/.vim/snippets/html.snippets:

1
2
3
4
snippet img
    <img src="${1}" alt="${2:Helpful description}" />${3}
snippet p
    <p>${1}</p>

Aside from this, I also changed the names of several of the trigger words. If a needed snippet’s name isn’t intuitive to you, change it! The longer it takes you to recall the shortcut, the closer you are to typing the full form. To customize the terms, open the file appropriate to the language you are working inside of ~/.vim/snippets. Just search for the old term, replace it, save, and the next time you open vim your new trigger will be in place.

Be Sociable, Share!

Post to Twitter Post to Delicious Post to Digg Post to Reddit

This entry was posted in vim and tagged , , . Bookmark the permalink.

9 Responses to Light at the end of the carpal tunnel: snippets in vim with snipMate

  1. Pingback: Code navigation, completion and snippets in vim | tail -f findings.out

  2. i try to find this info from 2 days, finally you help me thank you a lot :) for sharing :)

  3. dogstar says:

    how to make the python_pydiction.vim and snipMate.vim work together with tab?
    i just modify the python_pydiction.vim,use S-Tab trigger.then Tab for snipMate. any other way?

  4. @dogstar Yep, or any other shortcut as long as it’s different. I myself use Tab for snipMate and CTRL-Tab for pydiction, seems to work well enough.

  5. fladd says:

    It seems that there are some limitations in snipmate.

    Try to add more than one argument to the __init__ of a class (with the cl keyword).

    All arguments will just be appended, leading to:
    self.arg1, arg2, arg3 = arg1, arg2, arg3

    I will look into XPTemplate to see if this can be done there

  6. Pingback: Zeneffy >> Zen & Efficace

  7. Justin says:

    Can you explain how you edited pydiction to use ctrl tab? It seems easy, but it’s not working for me.

    Thanks!

  8. Justin says:

    Never mind…I’m an idiot. It’s just C-Tab and not Ctrl-Tab. Oops. :)

  9. Have you ever considered writing an e-book or guest authoring on other blogs? I have a blog centered on the same topics you discuss and would love to have you share some stories/information. I know my viewers would appreciate your work. If you’re even remotely interested, feel free to shoot me an email.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>