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)

More efficient HTML editing in vim

When I’m writing HTML and CSS, being forced to type out repetitive and fixed syntax, as well as remembering the particularities of the syntax and its formatting, makes me rather unhappy. Not to mention less productive. Let’s fix that.

HTML highlighting and snippets

Place html.vim in ~/.vim/syntax. Then in a file ending in .html, start a tag, e.g. <script, and press <Tab>:

Now the skeleton of the tag will be added for you, and your cursor placed in the first place you will likely need to edit. You navigate through these editable areas with <Tab>, adding your particulars. When at the last one, simply tab again to be placed after the tag. This makes properly adding tags much easier, especially for less familiar tags that are only occasionally needed. Here’s another example with a tag that is often needed and quite tedious:

The <{}> indicate places you can navigate to with tab. Once you are in one and tab past, those characters are removed. You can also add javascript.vim in ~/.vim/syntax, and the previous script will load this in appropriately.

This script also provides color highlighting for matching filetypes. When in a file ending in .html, type “:help html.vim” to see more information.

Closing tags

It’s also useful to be able to trigger close tags, if you started typing them manually. I find this most troublesome when editing HTML and XML. To add this capability, download the latest version of this script in ~/.vim/ftplugin/html.vim.

Then when you have started a tag and wish to close it (in files ending in .html), press <Ctrl> + <_> (that’s an underscore, so Shift + -). This will insert the close tag matching the closest previous open tag under the cursor:

Formatting

The following directives in your ~/.vimrc will make proper formatting automatic for CSS and HTML files:

1
2
3
4
5
6
7
8
" for CSS, also have things in braces indented:
autocmd FileType css set smartindent
" for HTML, generally format text, but if a long line has been created
" leave it alone when editing:
autocmd FileType html set formatoptions+=tl
" for both CSS and HTML, use genuine tab characters for
" indentation, to make files a few bytes smaller:
autocmd FileType html,css set noexpandtab tabstop=2

Watch your sppellinng

While writing HTML code involves plenty of code, you also end up writing text that others might just see. Don’t let mistakes in spelling slip by any more than you would let syntax errors. Add this to your ~/.vimrc to be able to toggle display of spelling errors with <F7>:

1
2
" F7 to toggle spell-checking
map <silent> <F7> :set nospell!<CR>:set nospell?<CR>

This post explains more advanced commands, such as bringing up suggestions, as well as customizing the formatting.

Tidy up

Being able to clean up your HTML code with a single command, making it more standards compliant and easier to read, is a great boon. To get this working for vim, first install tidy, an HTML syntax checker and reformatted. On Ubuntu, it’s available in the repository as “tidy”.

After that’s installed, add the following lines to your ~/.vimrc:

1
2
setlocal makeprg=tidy\ -quiet\ -errors\ %
setlocal errorformat=line\ %l\ column\ %v\ -\ %m

Now when in files ending in .html, type “:make”. All the errors Tidy found will be shown a list. Then press Enter to be taken back into the file, with the cursor on the first error, which is described at the bottom of the window:

Press “:cn” to move to the next error found, and “:cp” for the previous. As you encounter each error, you can fix it and move on. Once done, save the file, and run “:make” again to verify everything is fixed.

Tags: , , , , ,
May 9, 2009 - 4:15 PM No Comments

vim for Bash scripting: A happier union

Two factors recently caused me to look less than positively toward writing Bash scripts. First, I have started actively using Python more, and performing tasks in it that I would have previously written in Bash. Second, I came across a number of Python-specific, and more general purpose programming related, improvements to my vim experience. Relatively, writting Bash scripts just got worse.

Luckily, another awesome post at The Geek Stuff shook me from my unproductive stupor. After installing the bash-Support plugin the post describes how to install and use, Bash scripting is easier and slightly more pleasurable.

  • The first handy feature to notice is that any new file ending in .sh will include a header with things like name, purpose, etc. By customizing its template, you can create consistent, helpful headers for all your new scripts.
  • The trigger completion ability to quickly create functions and other bash constructs is something I had gotten quite accustomed to when writing Python, so it’s good to have that in place.
  • Another essential addition is the built-in help. Simply place your cursor over a Bash built-in command you need information on and press “Leader (default ‘\’) hh”. A window will open with man-page assistance.
  • Quick formatted comments, custom snippets and more make bash-Support simply essential for writing Bash scripts.

There are definitely cases where a programming task can be more quickly accomplished in a Bash script as compared to one written in Python. It takes a certain length of code or task for the increased (and welcome) verbosity of Python to be “worth it”. But don’t languish when those times arise, try out the bash-Support plugin!

Tags: , , , ,
March 1, 2009 - 9:23 PM No Comments

We’re not in CONNEBRASKACTICUTAH anymore: Adventures with sed

Today I encountered one of those tasks (actually quite common…) that seems fairly straightforward, but ends up collecting complexities and nuances frenetically, devouring 10 times its alloted time. I had two separate datastores that contained information about the same sort of entity, people. One of those sources contained more records with an additional datum of interest, each person’s location. So my seemingly simple and beneficial task: Create a regular method by which the location information for records in one source is added to the other.

As it turns out, the format for the US state in one source was different than that in the other. Certain country names also differed. So my script had to take this into account and perform conversions on the fly. Thus the particular task of converting US state abbreviations in one instance to long names in all capital letters. Being lothe to type more than is necessary, I created a short Python script to generate sed commands, each converting a state abbreviation to its full name equivalent in all capitals. It just iterated through a dictionary of state names (happily created by Constantinos Michael), and created the sed fragments based on a pre-defined pattern. The sed commands came out like:

1
2
sed -i 's/AK/ALASKA/' $STATE_DUMP
sed -i 's/AL/ALABAMA/' $STATE_DUMP

$STATE_DUMP being the text file I had from one source with the additional location information. Once I ran it, I examined the results file. I was surprised to see some new state names:

1
2
3
4
5
6
7
DISTRHODE ISLANDCT OF COLUMBIOWASHINGTON
VIRGIN ISLANDSRGINIA
MARYLANOREGONTH DAKOTA
MISSOURHODE ISLAND
NEVIRGIN ISLANDSRGINIADA
NEW YOREGONK
NOREGONTH CAROLINA

What happened here!? It turns out to be a simple lack of forethought. Once the first conversions had occurred, the file began to fill with combinations of capital letters that could have and did match the initial pattern of subsequent conversions! So once “AK” was replaced with “ALASKA”, then the match for “AL” would be seen in word “ALASKA” itself, creating the monster that is “ALABAMASKA”! And so on, creating such unique and interesting names.

The solution I chose was simple: Change the dictionary to provide full names in all lower case letters. Then after the conversions occurred, I changed them to the proper case via a function in the backend database of the target source. The trouble could have likely been avoided by mapping out the formats and conversion beforehand, and applying some consideration.

Divigation: I initially thought I had to convert the states to initial caps only once they were in the target source. I discovered all caps was sufficient before completing this feature, but even starting it allowed me to realize how complex it would be! I first tried:

1
2
3
UPDATE target_table SET state_name TO
concat(upper(substring(state_name, 1)),
substring(state_name FROM 2));

That worked for “Pennsylvania” and the like, but failed for cases like “North dakota”. I would have had to alter the pattern to apply to each consecutive group of words set off by spaces. Luckily I didn’t have to.

Tags: , , , ,
February 20, 2009 - 7:05 PM Comments (2)

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)

« Older Entries

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