For a very long time vim has had only snippets plugins, which were using nasty regex hacks to get TextMate like snippets going…

Also related to the fact that vim for example does not move marks when you do any editing action. I.e. try putting a mark on a specific position in vim, then start deleting in front of the mark and the mark will still stay on the same column. Thus it’s not really trivial to track where the next position of the snippet should start when you want to jump to it.

The solution found in most snippets plugins for vim is to use a region like <**> and to search for it on your snippet expansion trigger key. Imaps, snippetsemu all do it that way. While snippetsEmu used to be the closest to TextMate behavior it was also the most buggy.

On a sidenote vim actually does movement of marks when you join two lines with mark_col_adjust, but I found it to be far from trivial to just make all editing operations, have that behavior on marks. Anyway, now there’s a new contender called snipMate. It actually no longer relies on that regex expansion described above and from what I can tell it’s pretty nifty.

I suggest you give it a try. Here’s a comment on how it works by the author:

    00:14 [  meese ] timebomb: well essentially, each snippet is stored
    as a string with each tab stop being specified by "${1}", "${2}", etc., 
    which are removed once the snippet is expanded. Before that, though, 
    the plugin stores the position of each "${1}" according to its position
    on the line in a list, and the count of "\n"'s before that to determine
    which line number it's on via some regexes; then it keeps track of 
    your position by updating the list each ti

On a side note the latest version properly honors expandtab options, however still reading the ts option, there’s a little fix below, but I bet Michael will incorporate it later today.

@@ -214,7 +214,7 @@
                let i += 1
            endw
            " expand tabs to spaces if 'expandtab' is set
-            if &et | let snippet = substitute(snippet, '\t', repeat(' ', &ts), 'g') | en
+            if &et | let snippet = substitute(snippet, '\t', repeat(' ', &sts), 'g') | en

            let snip = split(substitute(snippet, '$\d\|${\d.\{-}}', '', 'g'), "\n", 1)
            if afterCursor != '' | let snip[-1] .= afterCursor | en

Anyway, rock on. Happy vimming, I bet you’ll enjoy it.