Coding with the Janus Vim Distro

I’m back on Vim, let me explain why and what my setup is.

Janus Vim Distro

The background is I’ve been happy, bordering on ecstasy, to use Vim for small projects, but found file management difficult for larger projects. I installed the incredibly useful Janus Vim distro a while back. There’s a one-liner curl script provided to install Janus.

The first useful thing about Janus is it ships with a selection of vital coding plugins. The most useful so far have been: NERDTree for file management; Ctrl-P for locating files (using IntelliJ-like matching, e.g. “PropertiesController.rb” could be found with “PCo” or “PrC”; “stars.html” could be found with “st.h”, and with its Most Recently Used algorithm, gives the same sense of magic); Ack for quick ack/grep-like searches; Syntastic, which automatically red-flags syntax errors when you open or save a file (ideally I’d like to run automatically every few seconds).

Janus also ships with a bunch of useful macros, as well as some handy customisations for those default plugins it ships with. All this is nicely documented in :help janus.

Another nice thing about Janus is it sets up a sane directory structure for you. If you’re not familiar, Vim’s default config distributes packages across role-based directories (like the way Linux distributes a package into /var/log, /etc, etc). This makes it difficult to add and remove a single package. Pathogen fixes this by letting you have a separate directory for each directory, and Janus ships with a Pathogen setup by default. Fortunately, most Vim packages are re-distributed in Pathogen form somewhere on the GitHub. And Janus provides a ~/.janus directory where you can drop them in. You can also customise your vim setup with ~/.vimrc.before and ~/.vimrc.after.

Command-Line/Terminal Vim (not MacVim)

Although the Janus README suggests using MacVim, I found it to be really slow switching tabs, at least while running with the Janus distro. So I’ve reverted back to regular shell Vim (which I installed via brew install vim). This is what I’m more used to anyway, as it has the advantage of fitting in with my regular workflow — I can just bring it up any time on the command-line — and it means I can use it as part of a multi-tab iTerm environment. So I can just cmd-left and cmd-right to drop into a running bash session. What I still need to work out is how to use the mouse with Vim running in iTerm2 (:set mouse=a isn’t working for some reason), which would give back the main benefit of MacVim.

Update: Yes, mouse now works in terminal mode! Now I can click on tabs and the expand/collapse/open items by clicking on the NERDTree. It just needed ttym to be set in the end; I’ve verified this works for the default TERM setting of “linux” (I think it’s default anyway). All you need is the following settings in your vim config (~/.vimrc.after in the case of Janus distro). I’ve only tested this in iTerm2.

set mouse=a
set ttym=xterm2

NERDTreeTabs

When I tried Janus some months ago, one thing bugged me. It was the main reason I scurried off to switch to RubyMine. That thing was NERDTree, the file hierarchy system. So close to being useful, falls stunningly short at the last mile.

What’s missing from NERDTree? It just doesn’t behave how one expects or wants a file tree to behave. You open a new tab, and NERDTree is gone! Imagine if web browsers removed the tab bar every time you open a new tab! Unnatural, unwanted. Yes, you can set up auto-commands to make it be there when you open a new tab, but even then, you end up with a different instance of the tree each time. So what got me back on Vim was finding this plugin:

NERDTreeTabs

Simply put, it gives the illusion that you’re using the same tree everywhere. So you switch tabs (or open a new tab) and the file tree is exactly the same as in the other tab. Really, a file hierarchy is essential for a large project, even if I use Ctrl-P most of the time to switch files. So this discovery was good enough to get me back on Vim. I mapped it to ,n (, is my leader) with map <Leader>n <plug>NERDTreeTabsToggle<CR>.

A couple of caveats. First, there’s still no way to keep the file tree in sync with the file you’re working on. It would be cool to have NERDTree highlight the current file, for example, like the kind of sync behaviour most IDEs provide. Second, I haven’t been able to open this automatically in Janus. So I have to manually close the NERDTree if it’s open. (Somehow, NERDTreeClose and NERDTreeTabsToggle have no effect in .vimrc.after; I’m not sure how to customise Janus here to fix this.)

Exuberant Tags

It’s also worth using Exuberant ctags for navigation. I installed it with brew install ctags. This lets you ctrl-] on a word to open up the corresponding file, and is also required for some of the default Janus plugins.

Wish Me A Pony

There are loads of Vi emulators out there now. Separate ones for Eclipse, IntelliJ, Cloud9, and Sublime. I’ve never had much luck with them. One of the great benefits of Vim and command-line in general is the muscle memory. Everything is supremely predictable and it just flows. My experience with these emulators is I’m always second-guessing what happens if I type anything. It’s not always clear whether I’m in command-line mode or not. And, they often require a lot of customisation to be usable.

My first wish is that someone would build a text editor/IDE with actual Vim inside it, not an emulator. It would ship with appropriate plugins to talk to its host IDE environment.

My second wish is that someone would use Chrome’s Native Client to build a Vim textarea plugin. Imagine if you could just call $(‘textarea’).vim() and every textarea becomes a Vim control. And not a Vim-in-JavaScript component. But — with the magic of Native Client — an actual Vim component. With such a component, people could build extensions for Vim enthusiasts to use Vim everywhere and cloud IDEs like Cloud9 could support the real-deal Vim.

Will Bespin really end up with multiple backends?

Google groups thread

Bespin has the idea of multiple backends attaching to the same client. Right now, Python is apparently “winning” while Java has fallen behind and PHP appears to have faded away.

The situation is very analogous to Shindig (http://incubator.apache.org/shindig/) which has a strong Java back-end, a PHP back-end that took a long time to get started in earnest and AFAICT from a quick glance has tapered off, and a number of non-starters.

I do wonder whether something like this is really viable – can you have a vibrant ecosystem of back-ends in different languages? Granted, there are hundreds of implementations of SMTP, FTP, and so on, in all the languages of the rainbow. Those are actual protocols based on strong standards. Likewise, Shindig had a fair crack at it because it’s based on the OpenSocial standard (but the diversity effort is probably hampered by the fact that most companies who want to be OpenSocial hosts tend to fall in the Java camp).

Bespin would need to formalise things and establish proper standards to support multiple backends. Nothing as onerous as the IETF standards, but still, they’d need to nail down all the subtle issues and edge cases in order to support multiple backends. Good for cleanliness perhaps, but at the expense of project velocity. Years ago, I asked SpringSource’s Rod Johnston about why one should use Spring over the upcoming EJB3, and one of his reasons – quite rightly – was that his code was available NOW while the committee-driven EJB standard and subsequent implementations were a long way off. In other words, Spring demonstrates that working, open, code is in many respects far more powerful than a standard. I can’t imagine Bespin will want to formally document its protocols; instead it will rely on code. But of course, if the code is a moving target, how easy will it be for different backends to keep up?

Also, how motivated will the second, third, and fourth guys be? It’s more fun being the first to see the concept become reality; less so to be building a port from one language to another. As with the previous point, though, I stand to be corrected; some people might enjoy the engineering challenge of building a parallel backend. (Maybe I’m being solipsistic here, as I’m personally 20x more motivated by user stories than implementation details.)

Java hosting is notoriously painful compared to the ease of cheap PHP hosting, so I can see the argument for both; companies will want to host Bespin on their own shiny enterprise Java servers, while rebellious little startups will want to do the same thing for a sliver of the cost on commodity iron.

Update: Ben Galbraith responds

Vim Macro for IDE-Like Behaviour

I find Vim easiest for browsing source and as I explore TiddlyWiki, I decided to use some fairly recent Vim features – vertical splitting and the explorer window. Combined, these give you the feeling you’re an 1988 edition of Eclipse. Just like a modern IDE, but navigation is ten times faster.

Here’s the macro – which assumes you just opened vim or have a single empty buffer:

map ]xx :Explore<cr>2jp<c-w>H20<c-w><

To switch files, navigate to the new file’s name in the explorer window, and hit “p” (the built-in command for “open this file in the previous location).

The macro:

  • Populates the current buffer with an explorer window
  • Jumps down two lines (to reach the second filename – the first name is often .svn)
  • Opens the file (“p”)
  • Places the explorer window on the left side (which also forces a re-orientation towards vertically split windows)
  • Resizes the explorer window to be 20 columns wide

While in the source window, you can still use commands like “:e filename” to open a new file (with tab completion) and ctrl-o/ctrl-i to jump back and forth.

The other helper is exuberant ctags, which I installed via Fink. I just run “ctags *.js” and then I can hyperlink from the file under my cursor using ctrl-], or visit any function using “:tag function-name”. (One remaining frustration is I can’t get it to hyperlink to OO methods established using the “abc.prototype.xyz = function() {…}” idiom, despite including the pattern in ~/.ctags.)