Vim is fairly extensible. Unlike Emacs or Eclipse, it’s just an editor, not a platform. It is, however, quite featureful and includes its own slightly eccentric domain language as well as bindings into a few others. Note: this isn’t a HOWTO, it’s just a few things to consider before jumping in.
1. Vim Script
Here is a neat lineage: the Unix line editor
ed evolved into the more advanced
ex which was used as the basis for the command mode in
vi and extended into the roughly Turing-complete mini-language of Vim. And development continues; in his latest release, Bram Moolenaar has added native support for floating point numbers.
Vim Script supports many regular programming concepts: loops, lists, dictionaries, exceptions, etc. But the language is unconventional. Here’s some code showing the hoops one must jump through to map a bit of functionality to a key:
function! s:doSomething() " stuff endfunction command DoSomething :call <SID>doSomething() nmap k :DoSomething
- A trailing
s:in the function definition and the
<SID>in the command declaration are a thin but tenable form of namespace management. They’ll expand to a unique name at read time so that similarly named functions in other files are not clobbered.
functioncould be replaced equivalently with
func, etc. This follows for all Vim commands. As long as a token can uniquely complete into a keyword, it is valid.
As in many other languages, statements can be wrapped using a
\ character. Unlike in those languages, in Vim Script it must appear at the beginning of the succeeding line:
if some_exceedingly_long_expression || \ a_second_expression echo 'Success' endif
2. Alternative plugin languages
It isn’t widely known that Vim has interfaces into several popular scripting languages: Python, Ruby, Perl, Scheme, and Tcl. These are more powerful than Vim Script but have certain practicality drawbacks in context.
- Debugging is difficult. Foreign code is interpreted by what is essentially one giant eval. If you misplace a close parenthesis or an
endkeyword, you will have to track it down yourself.
- Integration with Vim is slight. The calling interface is in a table below. The bindings just tunnel most editor interactions through
Vim::command(or equivalent) as unstructured string arguments.
- Many Vim installations don’t include external language support by default. It’s an easy fix for a user running a
rpm-based Linux distribution, but will require a recompile on Windows, something a Windows user is not wont to do. OS X is hit-or-miss.
Point (3) is particularly unfortunate if you’re making an extension you intend to distribute. I wrote perhaps the largest and most popular Ruby-based plugin for Vim available, yet the majority of people who contact me about it are only looking for installation help.
This is what it looks like to interact with Vim from Ruby:
# Setting options inside the editor is pretty # straightforward. VIM::set_option "noinsertmode" VIM::set_option "hlsearch" # ...unless you want to set an option local to a buffer. # There's no API call for this, so we must ascend one # layer of abstraction: VIM::command "setlocal nowrap" VIM::command "setlocal spell" VIM::command "setlocal foldcolumn=0"
If we’re going to do an odd call in multiple places, it makes sense to add some glue to confine code acrobatics:
def VIM::has_syntax? # All return values from `evaluate` are strings, and # "0" evaluates to true in ruby. VIM::evaluate('has("syntax")') != "0" end
See below the partial interfaces for a few languages. Obviously there’s room for improvement in the API:
For some strange reason, the Scheme interface also offers the highly situational
(beep), and the Tcl interface,
::vim::beep. These do what you expect.
Interesting sidenote: these extension languages have access to window handles within Vim, providing equality semantics and therefore deterministic window management. Vim Script doesn’t seem to support this, so using an alternative language appears to offer an (inelegant) superset of functionality.
3. Choosing a language
This can be summarized like so:
- Great integrated
- Lots of other plugins you can crib from.
- The language is awkward.
Other (Perl, Python, Ruby, Tcl, Scheme)
- Strong languages.
- Experience carries over into other pursuits.
- Debugging is hard.
- Interface to Vim is slight.
- May require the user to install language libraries.
- Syntax highlighting in a
.vimfile is easily confused.
- Neglected by both plugin writers and Vim developers.
Using Vim Script means giving up the good stuff: closures, object-orientation, higher-order functions, reflection, and metaprogramming. So despite the extra work, selecting an alternative language is recommended for non-trivial extensions. Perhaps support within Vim will improve as more plugin writers follow this route.
Thanks to Jesse Funaro and Chris Gaal for their comments and suggestions.