Wednesday, August 13, 2008

Vim pr0n: A simple template engine

I frequently hang out in #vim on freenode. It's a funny place to be in sometimes. People come and go, asking all kinds of random questions, but occasionally someone will ask an interesting question that requires vimscript hacks. Its times like these where, if you listen closely, you can hear the collective *click* of all available nerds simultaneously pausing their pornography. This is closely followed by the furious stampeding of fingers over keyboards as said nerds race each other to hack and pastebin the solution.

A while ago, someone asked how to write a simple template engine, i.e. something like "when I create a new java file, how can I choose a code skeleton to prefill it with". I could practically hear the starter pistol fire. I cant remember if I won or not, but I wrote some dynamite hacks and kept them in my vimrc so that the next time someone asked I could pastebin them straight away and pretend I wrote them on the spot.

Anyway, a few days ago I revisited the code and cleaned it up a bit. Here it is:


 1 "define the Template command
 2 command! -complete=customlist,AvailableTemplates -n=1
 3     \ Template :call InsertTemplate('<args>')
 4
 5 function! InsertTemplate(name)
 6
 7     "read in the template
 8     execute 'read ~/.vim/templates/' . &filetype . '/' . a:name
 9
10     "if the cursor was previously on a blank line, delete it
11     if getline(line(".")-1) =~ '^\s*$'
12         exec line(".")-1 . 'd'
13     endif
14 endfunction
15
16 function! AvailableTemplates(lead, cmdline, cursorpos)
17     let templateDir = expand('~/.vim/templates/' . &filetype . '/')
18     let files = split(globpath(templateDir, a:lead . '*'), '\n')
19
20     "chop off the templateDir from each file
21     return map(files, 'strpart(v:val,strlen(templateDir))')
22 endfunction


The idea is that you store all your template files in:

~/.vim/templates/<filetype>/

So, for example, you might have three html templates and a java template:

~/.vim/templates/html/first.html
~/.vim/templates/html/second.html
~/.vim/templates/html/third.html
~/.vim/templates/java/foo.java

Then you edit an html file and apply a template with:

:Template first.html

You can also tab complete template names.

Limitations: No error handling. No clever variable expansion etc. Assumes you are working in *nix style os, but could easily be hacked for MF Windows.

2 comments:

  1. Replies
    1. I guess you'd really be doing something more like

      :r ~/.vim/templates/filetype/mytemplate.txt

      If you do that often, the repetition would get painful - which is probably what the dude in #vim was originally trying to solve.

      Delete