tail -f findings.out

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.

Tags: , ,
July 19, 2009 - 8:39 PM Comments (5)

Code navigation, completion and snippets in vim

In my last post on configuring vim as a (Python) IDE, there were two topics I forgot to cover and another I feel it necessary to amplify. The missing: viewing your code at a high level, and navigation therein; insertion of “code snippets” (i.e. completion of common code contructs). The short-shrifted: Types of code completion and how to set them up.

Code Navigation

There are a few simple steps to getting this all working, but it’s definitely worth it. You will end up with the ability to bring up a window showing all the classes and functions in your current file, and be able to jump to any of them.

First you need to install exuberant-ctags. It should be available in most repositories under that name. Then you need the vim taglist plugin (drop the plugin in ~/.vim/plugin and the readme in ~/.vim/doc). Go into ~/.vim/doc, open vim, and run “:helptags”. Now all should be installed and ready.

Before using it, let’s clean up the default configuration. Add this to your ~/.vimrc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
" Taglist variables
" Display function name in status bar:
let g:ctags_statusline=1
" Automatically start script
let generate_tags=1
" Displays taglist results in a vertical window:
let Tlist_Use_Horiz_Window=0
" Shorter commands to toggle Taglist display
nnoremap TT :TlistToggle<CR>
map <F4> :TlistToggle<CR>
" Various Taglist diplay config:
let Tlist_Use_Right_Window = 1
let Tlist_Compact_Format = 1
let Tlist_Exit_OnlyWindow = 1
let Tlist_GainFocus_On_ToggleOpen = 1
let Tlist_File_Fold_Auto_Close = 1

Once you close vim and reopen it (for best results, open a reasonably complex piece of code), you can press “TT” or <F4> to bring up a new window, displaying all classes and functions in the current file:

The options set above cause the window to appear vertically, on the right, and in a compact form, making display easy to configure. Additionally, the last three options cause the tag window to have focus when opened, as well as to close when the file being edited is closed. These make for a much more intuitive experience.

Code Completion

There are a number of possible goals here, as well as possible methods. I have tried out a few, and will share my results. First, consider the types of completion you might want. It is possible to provide matches for completion based on phrases in your current file, on entries in a dictionary of Python syntax, as well as to display contextual help for various matches.

For setting up completion based on current file contents (as well as other useful things like an English dictionary and filesystem locations!), check out this post over at The Geek Stuff.

For completion based on language constructs (in Python), pydiction is perfect. To make things easier, I also have installed the SuperTab plugin. This lets me perform all completions with <Tab>. In the following case, I typed “os.path.” then pressed <Tab>:

pydiction1

It’s faster than omni-completion, and includes a wider range of modules.

Code snippets

The name is somewhat worthlessly vague, but the purpose is definite: You start typing a common language construct, such as “def” or “for”, press <Tab>, and get a skeleton of that contruct. Not only that, but the skeleton matches the type of the file being edited, and you can tab through the skeleton’s fields!

[EDIT, 2009-07-19]: I’ve switched to snipMate for snippets in vim, and have been loving it. Check out this post for more. I’d recommend reading that and skipping the rest of this post.

To get this working, you need the snippetsEmu vim plugin. This was my first install of a Vimball based plugin, but it was simple to work with. Create a directory ~/.vim/after/ftplugin, if it does not exist. Download snippy_plugin.vba and snippy_bundles.vba there. Open each in vim and run “:source %”. All should now be installed.

In example.py, I typed “def” and pressed <Tab>. The result:

The same thing works for “for” loops, classes and many other constructs. The bundles .vba provides access to such constructs across a wide range of languages, e.g. Python, Ruby, HTML, PHP, even Djano-specific constructs.

Once you have pressed <Tab> and the skeleton is added, start typing to fill out the first field. Once done, press <Tab> again to move through the successive fields the skeleton provides. Once done, you will be within the construct created.

One thing to become accustomed to are the trigger words used by snippetsEmu. Most of the time they are perfectly intuitive, like “def”, but others might not be as you expect. Run “:help snippets” to view the documention.

Tags: , , , , ,
February 17, 2009 - 1:59 AM Comments (11)

Python and vim: Make your own IDE

I prefer to use vim for most of my systems administration and programming related editing tasks. Aside from the usual argument that it will be present on any *nix system worth its silicon that you log in to, I choose it because of the succinct and expressive power of its syntax. While I am still learning new commands and techniques all the time, and while it is true that the learning curve to be anything resembling proficient is rather steep, few editors can boast such a wide range of actions in so few commands.

Right of out the box, however, vim isn’t as suited to editing Python code as it could be. In fact, it’s rather annoying to write Python code with an uncustomized instance of vim. What follows is a description of how to put into place what I see as the most essential features of the editor one chooses to write code, especially Python code, in as manifested with vim. With the following changes, you can create a highly customized and powerful IDE, allowing you to increase your productivity without purchasing a commercial offering.

Before the good stuff, a few requirements. You need to make sure you have vim-full and vim-python installed. Some systems come with vim-minimal, which is lacking in many advanced features. These packages should be in most repositories. Aside from these package installs, configuration changes described are made in ~/.vimrc. A quick word on the syntax of this file. Double quotation marks denote a line as a comment. I make it a rule to place a comment line before every configuration line or block thereof, so I have some sense later of what the change was for. Regarding Python files, I eventually also began to collect the related customizations into a file “~/.vim/ftplugin/python.vim”. This is loaded whenever Python type files are opened, and allows me to isolate related configurations.

  • Syntax highlighting
    Having code displayed with proper highlighting of the logical components makes reading that code easier to read and understand. Any decent code editor allows for coloring particular to a number of languages, and vim is no exception. To get this working, simply add:

    1
    syntax on

    to your ~/.vimrc file. The actual colors will vary with your colorscheme. You can install new colorschemes (view hundreds here), as well as test out installed ones by typing

    1
    :colorscheme

    The various colorschemes will appear as you tab.

  • Line numbering
    Having line numbers displayed with code makes it easier to reference and move around in. It’s easy to add. In ~/.vimrc:

    1
    2
    3
    4
    # Turn on line numbers:
    set number
    # Toggle line numbers and fold column for easy copying:
    nnoremap <F2> :set nonumber!<CR>:set foldcolumn=0<CR>

    This will allow you to toggle line numbers (as well as the spaces for the fold column described below) on and off by pressing <F2>. This makes it easy to copy out code without numbers.

  • Proper indentation and formatting
    In Python more than almost all languages, indentation is essential, both to get right and to preserve. While most programmers add indentation to a wide variety of languages for greater readability, in Python getting this wrong means a syntax error. The following directive will allow vim to properly keep indentation in your Python files, without you having to touch <Tab>:

    1
    filetype plugin indent on

    Additionally, you need to download the latest version of this script, placing it in ~/.vim/indent/python.vim. This will make indentation much less of a chore, and more of a pleasure. Be sure to also check out this blog post, wherein Henry Prêcheur explains how to improve indentation for comments as well.

  • To improve the formatting and display of improper indentation, as well as special highlighting for things like string formatting, download the latest version of this script, and place it in ~/.vim/syntax/python.vim. Then add this to your configuration:

    1
    autocmd FileType python set complete+=k~/.vim/syntax/python.vim isk+=.,(
  • Shortcut complete syntax
    It can save time and your memory to be able to complete syntactic built-ins using a keyboard shortcut. [Edit: I had one method to get this working before, but it wasn't a good solution. For the right way to do this, check out this post.]
  • Access to documentation
    It is essential to be able to access built-in help quickly. This plugin allows you to view the built-in documentation for a given function by pressing “\pW” while over the word. This opens a new window, containing the related help documentation, if found.
  • Ability to run script being edited
    When debugging, I often need to make a small change, run the program, make another change, and so on. Having to write and close the file, then invoke it, is rather less than efficient. Simply add this to the ftplugin/python.vim file started above:

    1
    2
    " Execute file being edited with <Shift> + e:
    map <buffer> <S-e> :w<CR>:!/usr/bin/env python % <CR>

    Now you can press <Shift> + e to execute the Python file being edited. Once the code errors out or completes execution, output stays displayed until a key is pressed. Then you are returned to the code in the editor. Hard to imagine a shorter method.

  • Checker utilities and debugging
    pyflakes and pylint are two popular utilities for checking Python code for syntax errors, variable reference problems, and other signs of poor quality. If you haven’t tried them, install them both and see which you like best. Install the pyflakes and pylint packages for your system. For CentOS, you will need to add the EPEL repository to get access to these. Then add the functions listed here to your configuration. Now simply run “Pyflakes” and “Pylint” from within vim to view their output on your current file. Once you select the one you prefer, you could shorten access to it to a single keystroke, or even run it when you save your file.

    Once you have narrowed down the region you know a problem is present in, you will likely need to add some debugging statements and run the code repeatedly. Adding these functions into your .vimrc will allow you to add a PDB breakpoint with <F7> and remove all breakpoints with <Shift> + <F7>.

  • Code folding
    As soon as your scripts start to encompass more than a few functions, much less multiple classes, it’s time to start checking out code folding. This feature allows the display of a class, method, or function as a two lines, one with the definition line and another showing length:

    With a simple key command, you can display or hide the entire block. There are a number of built-in commands to create and work with folds. I prefer using this plugin to allow vim to automatically know how to fold Python code. Once that is loaded, newly opened Python files will have all their classes and functions already folded, making it much faster to review files. <Shift> + f toggles all folds, while f toggles the fold under the cursor.

  • Block navigation
    This script provides some advanced controls for selecting, navigating within, and acting upon blocks of code. You can jump to the top or bottom of a block, select it, even comment it out all with a few keystrokes.
  • Project navigation
    Nerdtree allows a window to be added to your vim display showing other files in your project. A “project” can either be the contents of your current directory, or you can define its members manually. This allows you to jump around your project, and open multiple files at once:

There are many, many more customizations possible concerning vim and Python. Check around the vim scripts pages if you have a particular itch to scratch. And if you know some good tricks that I didn’t list, please add them via comments!

Tags: , , , , ,
February 16, 2009 - 2:28 AM Comments (25)

Twitter links powered by Tweet This v1.6.1, a WordPress plugin for Twitter.