I am a programmer who runs a small software-as-a-service business. I mainly write Ruby, Haml, Coffeescript and Bash.
I switched to Vim from an IDE in 2001. I knew the learning curve would be vertiginous but I’m an optimist and I thought it would pay off in the end. For the first few days I felt hamstrung while my Eclipse-using colleagues laughed at my fumbling efforts. Eventually I got the hang of it and was able to get half a day’s work done while they waited for Eclipse to launch.
Having decided to switch, I narrowed the choices down to Vim and Emacs. Both sounded powerful and worthwhile though Emacs also had its Lisp appeal. But my overriding concern was to minimise typing strain and on that basis Vim’s modal editing triumphed over Emacs’ chords. Also just-a-text-editor seemed neater to me than includes-a-text-editor.
These days I use Vim for everything plain text or software-related, which is pretty much everything. But not email; it’s always seemed too much hassle to get Vim working with Apple Mail. Recently I’ve started hoping that someone will figure out how to embed Neovim within Mail.
I’m on OS X and I use MacVim, currently 7.4.969 via Homebrew. I don’t follow the day to day commits to Vim or MacVim and I only upgrade every few months. Occasionally I might run into a specific bug, and I’ll modify the Homebrew recipe to re-build Vim with a patch from the mailing list, but that’s unusual.
I prefer the GUI version to the terminal version because the GUI fires focus events. I use FocusLost to avoid typing
:w every time I switch away and FocusGained to pulse the cursorline and have vim-gitgutter automatically update all the visible buffers when I switch back to MacVim.
It’s good to see text editors in general flourishing at the moment, and the consequent cross-pollination of ideas.
One day I’d like to write a kind of Coffeescript for Vimscript, perhaps a bit like riml, but I’m not sure when I’ll ever have the time.
I started from nothing and I’ve slowly built it up over time. I try to keep it as lean as possible and I never copy-paste stuff I don’t understand. As and when I change my config I try it for a few weeks before deciding whether to keep the change or drop it. Usually I drop it.
I’m not a fan of “distributions”, those large bundles of plugins and configuration. They might provide a short term benefit but I believe they hinder learning how unadorned Vim works, and they can easily bloat Vim. Vim’s got enough to wrap one’s head around without having to learn heaps of plugins at the same time.
I really value how easily one can read plugin source code on places like GitHub and BitBucket. It’s impossible on vim.org where all the code is hidden away inside zip files.
Alongside Pathogen to manage Vim’s path, I use my own plugin “manager”, voom, to install, update and uninstall plugins. It’s a 100 line bash script. I looked at the plugin managers out there and they’re all hundreds if not thousands of lines of Vimscript. At the end of the day all I want to do is download some files to disk and maybe make some symlinks. If you use Vimscript you’re going to end up calling out to bash to do that, with the added fragility of Vim’s
system(), so why not cut out the middleman and just do it in bash? To my mind that’s the simplest thing that works.
I believe the biggest problem afflicting Vim plugin development is the lack of a way to express dependencies. Every other language has a dependency mechanism for its libraries. Vim doesn’t and as a result every plugin has to reimplement (and debug) the same utility functions over and over again.
For example it would be great to have a plugin which simply provides an easy-to-use DSL over Vim’s clunky signs commands, and avoids the gotchas when handling signs. Instead every plugin which uses signs has to re-implement the same functionality.
To make this happen we need a standard way to express dependencies. JSON would make a good format: Vim reads it natively as of v7.4.1154 (and it’s easy to parse in Vimscript for earlier versions). Once the dependency file has been agreed, plugin authors could add it to their plugins and plugin managers could start to use it.
Anyway, you can see the plugins I use here.
Vim users navigate their buffers and files all the time. You want this to be as efficient and intuitive as possible. Efficiency is objective but intuitive-ness is subjective, which is why there are so many plugins in this area. Personally I like bufexplorer for buffers though it would be nice to drop the old winmanager integration and incorporate git-status information. I invoke it all the time so I [map
To open files I either use filebeagle if the file is near the current buffer’s file or a fuzzy finder. I think fuzzy finders are great; I have tried several though I haven’t really settled on one. Originally I used PeepOpen but I can’t get it installed on El Capitan. I would use selecta if it worked with MacVim. Currently I used probe which does the job nicely. I keep meaning to try out Unite which seems like it could replace bufexplorer, filebeagle and probe…but with 4,000 lines of instructions I never feel I have enough time available to get to grips with it properly.
I don’t use tabs; more accurately the only time I use a second tab is for reading the help docs.
I’ve also tried several alignment plugins. You need to give them three pieces of information: which lines to align, what character(s) to align on, and what alignment you want. Each plugin has a different way to specify these three things and lion is the only I can use without having to check the docs each time.
Colorscheme-wise I use solarized-dark. I find dark backgrounds easier on the eyes, and while I have no idea what to make of solarized’s colour-science stuff, I do like its colours.
For a long time I used airline for my status line. But I like keeping things minimal and I was trying to configure it not to display various of its bits and bobs and it took me ages to figure out. I realised it was crazy to install a huge statusline manager and then spend time figuring out its custom syntax in order to turn off most of its output.
So I spent 10 minutes deciding what I did and did not want to see in my statusline, e.g. not the current line because I can look at the line number in the margin. And then I spent 10 minutes reading
:help statusline. And then I uninstalled airline and spent 30 minutes or so implementing exactly what I wanted and fiddling with the colours. Very satisfying!
I like the file path: the filename stands out while the the relative path is there if you need it. I haven’t see this two-colour innovation anywhere else and I trust it will lead to fame and fortune. I use the window number for jumping around (see below).
Everything else is fairly standard I think. I use the default leader key. I’ve never wanted to change it, though I saw a suggestion somewhere to use the space bar instead which sounded like a promising idea.
I like mappings which augment, rather than replace, Vim’s built-in commands. For example:
" Use | and _ to split windows (while preserving original behaviour of [count]bar and [count]_). nnoremap <expr><silent> <Bar> v:count == 0 ? "<C-W>v<C-W><Right>" : ":<C-U>normal! 0".v:count."<Bar><CR>" nnoremap <expr><silent> _ v:count == 0 ? "<C-W>s<C-W><Down>" : ":<C-U>normal! ".v:count."_<CR>"
I turn off Vim’s backups and swapfiles because they solve problems I don’t have and introduce new ones I don’t need.
I used to think that one day I’d properly analyse how I use Vim, along the lines of Seth Brown’s Vim Croquet or Drew Neil’s Vimprint, to discover ways I could squeeze out a little more efficiency. Now I think it couldn’t possibly be worth the time.
When I started I read the 7 Habits Of Effective Text Editing and the first few chapters of Vim’s manual. After that I used
:helpgrep to look up anything I didn’t know, which was just about everything.
I looked up and learned what every key on the keyboard did in normal mode, and then tried to use each one where appropriate.
Early on I found an excellent reference card which I stuck to my monitor. I crossed off each line as I learned it, which kept alive the hope of ever being able to use Vim well.
More recently Drew Neil’s Vimcasts were excellent.
These days for Vimscript I turn to Steve Losh’s Learn Vimscript the Hard Way and, of course, I look on GitHub at how people have already solved whatever problem I’m stuck on.
I just learned how to implement custom completion, which turned out to be easy. I’ve been typing a lot of German recently and I wanted to be able to auto-complete accented letters instead of learning a few digraphs.
Neovim-wise I recently looked at its job control mechanism so vim-gitgutter can run its diffs asynchronously. Vim itself has just added async capability in v7.4.1274 though it’s not clear how stable the API is yet.
Geoffrey Grosenbach, of PeepCode (now Pluralsight), asked me to write a plugin for PeepOpen, a desktop app for switching between files in text editors. I had previously volunteered to write a PeepCode screencast on Vim, so when he built PeepOpen he asked me to provide a plugin.
I had never written a Vim plugin before and it took me hours to write those 30 lines of Vimscript. The part I found confusing was linking up functions, commands, and maps. Even today I find this part of Vim unintuitive.
Once Vim was able to talk to PeepOpen, Geoffrey asked me to write something to automatically change Vim’s working directory to the project root. This is vim-rooter. Having Vim change directory automatically isn’t everybody’s cup of tea – but I like it and it helps when working on two projects in the same session, e.g. a Rails app and a gem dependency.
Six years ago I read a blog post entitled Cyclomatic Complexity in Vim: First Steps. In it Gary Bernhardt, who later went on to make the Destroy All Software screencasts, got Vim to highlight the complexity of each function in the margin (a.k.a. SignColumn). I had never seen Vim do anything like it and I wanted to do something similar myself…but I couldn’t think of anything suitable.
Three years later I read a blog post entitled GitGutter. JD Isaacks had written a Sublime Text plugin to show git-diff markers in the margin. I thought it was interesting, though not very useful, and looked for a Vim version to try. I couldn’t find one; and I realised this was the excuse I’d been looking for to try doing something with the SignColumn.
I wrote the first version in a day or two. It was the simplest thing that worked: a proof of concept really. It didn’t have any realtime updating and it was slow, but it made me happy because I had finally got the SignColumn doing something. And to my great surprise I found it useful after all.
After that it was mainly a question of speeding it up. So instead of processing all buffers when it ran, I made it process only the visible ones. I measured and found Vim was taking 7ms to place each sign. On a file with 142 signs, that meant Vim freezing for 1s every time the plugin ran – even if the diff hadn’t changed. So instead of throwing away all the signs and adding them from scratch each time, I diffed the diff and “upserted” the signs, which made a big difference. After that I kept re-profiling and concentrating on the worst remaining hotspot, and eventually it got to the point where it seemed more or less instant to me.
The part of the code which has churned the most is the function which calls out to
git-diff. Initially there was no realtime diffing so I could just call
git diff FILE. Realtime diffing meant sending the contents of the buffer, without saving it, to
git-diff. So I passed the buffer’s contents as the second argument to
system()…but it turned out that didn’t work with repos which automatically adjust line endings. So now I pass two files to
git-diff: a temp file holding the buffer’s contents and a temp file for the file in the index (
git show :file > tmpfile).
Then it became apparent that using new temp files each time, even if they are never loaded into vim, makes the buffer numbers sky-rocket; after a day I would find my buffer numbers were in the thousands. So I started reusing temp files…but then it turned out you have to preserve the real file’s extension or git’s line ending conversion goes awry.
Also I found that writing the buffer’s contents to a temp file resets various marks, so I had to restore those afterwards. And then Windows requires a random extra pair of parentheses around everything. And so on.
And then there were a number of unexpected problems with
grep. I use
grep if it’s available to filter
git-diff’s output for the hunk information because it’s more efficient than piping lots of unnecessary data back for Vimscript to filter. But it turns out some people have
grep always return colourful output, which breaks things. So then I passed the
--color=never flag to
grep, but some
greps don’t support it. So then I auto-detected whether or not
--color=never but that slowed down Vim’s startup. Et cetera.
Initially there were no tests. But after I found a couple of gotchas with Vim’s signs “API”, I realised I had to write tests to avoid re-introducing bugs I’d already fixed. I’d never written Vimscript tests and, as far as I knew, there was no de-facto standard way to test. I looked at half a dozen testing plugins but none clicked with me. I eventually decided to follow Christian Wellenbrock’s approach in targets.vim: just use bash. My tests have many disadvantages, e.g. you can’t easily run a single test, but on the plus side, they work. I don’t know if I’d do it the same way again.
Overall the biggest surprise for me is how useful I find vim-gitgutter: both the diff markers and the hunk staging. I used to
git add -p all the time and now I never do: I stage all hunks with vim-gitgutter.
In Vim you’re constantly moving between windows. When I have fewer than four or five open, I use tab and shift-tab to cycle between them to the one I want.
" Use tab and shift-tab to cycle through windows. nnoremap <Tab> <C-W>w nnoremap <S-Tab> <C-W>W
With more windows, I find it quicker to jump directly to the one I want. My status line shows each window’s number so I can type
\7 to jump straight to window 7.
" Source: http://stackoverflow.com/a/6404246/151007 let i = 1 " If I have more than 9 windows open I have bigger problems :) while i <= 9 execute 'nnoremap <Leader>'.i.' :'.i.'wincmd w<CR>' let i = i + 1 endwhile
It’s not rocket science but it saves me lots of time. Which is the whole point of Vim.
I recently used Vim over ssh on my phone to fix a production bug while I was away from my computer. With a low-bandwidth connection I was very glad of Vim’s succinct keystrokes – which, I believe, were originally motivated by having to edit text over 300 baud modems. It felt like an apt use of Vim.