Must-Have Vim JavaScript Setup

In this post I’ll cover the plugins and configuration I have found to be the best for editing and navigating Javascript projects with Vim.

Background

I have had around a year’s worth of experience at this point. I tried out various plugins, uninstalled some, tweaked others, and found a decent setup. There are probably some plugins out there that I am missing, so please let me know if I should investigate one. Primary stack has been Mongo, Angular, Express, Mongo. I’ll update if I find more good Vim JavaScript setup.

The Best Vim JavaScript Plugins

I use the following plugins on my current project. I listed them roughly based on importance, how much I use them, and how surprising they were.

vim-javascript

The biggest advantage of this plugin is how much better the default indentation is. I’m sure there are others, but indentation was unbearable before using it, and pretty good afterward.

vim-node

Although it has other utilities, I primarily use vim-node for gf on a relative require to go to that file. Following Vim conventions, gF opens that file in a split. This really aids in navigation, especially when paired with Ctags (discussed below.) It might not sound all that helpful, but when you have:

var UrlFinder = require('../../../server/util/other/urlFinder');

I can just type gF to view the file in a new split window to figure out what functions I might want to call on it. Much faster than other methods of getting there. Generally Vim would choke on the relative file path since I typically have my current working directory as the project root.

jsctags setup

I had not used Ctags much before, but have found them very useful on the project that I am working on. Ctags works by creating an index of tags, which are things that you want to be able to jump to. Vim supports Ctags-style tags.

The value is being able to jump to the definition of a function when your cursor is over it. So being able to say Ctrl+] and then jumping right to where the function is. I can easily get back with Ctrl+T (or perhaps Ctrl+O since that will take me out to the edit stack.)

This gets us closer to many IDEs, and avoids running the function name through grep/ack/ag and/or opening the file manually.

The core issue is that the current Exuberant Ctags JavaScript support is not very good. Often it would not be able to find a function declaration. There is an old Mozilla project, but it had one basic, but large issue with installation that cannot be solved by forking/patching (to my knowledge.) So I made a custom ZSH install function:

function install_jsctags {
  npm install jsctags
  # https://github.com/mozilla/doctorjs/issues/52
  gsed -i '51i tags: [],' ./node_modules/jsctags/jsctags/ctags/index.js
}

This is helpful because I sometimes switch node environments with nvm, or do an npm prune which removes it since it is not in the package.json file.

Then I can manually run something like:

$ jsctags -o tags server test admin

This takes a few seconds and then spit out Ctags-compatible output of processing the function names for the server, test, and admin directories to a tags file. Vim automatically reads the tags file. I don’t need to restart Vim, it just works after regenerating the file. So a little bit of setup, but I think the time savings is worth it. It would be nice to automate this so that the tags don’t get stale, but I usually only run it when I jumped to the wrong place or Vim couldn’t find the tag, which happens maybe once a week. So I am happy enough with how it works.

A Vim-alias would be something like:

nnoremap <leader>jt :! jsctags -o tags server test admin<CR>

html5-syntax.vim, html5.vim

html5-syntax.vim seems to handle HTML5 syntax highlighting. html5.vim seems to handle HTML5 autocomplete. So I installed them and I am happy with the indentation and syntax highlighting with HTML5 code, so this is about all I can ask for.

vim-less

We use less for having a higher level stylesheet language than CSS. vim-less is useful for working with these files to get good indentation.

Also, you’ll probably want the following in your ~/.vimrc:

autocmd BufNewFile,BufRead *.less set filetype=less
autocmd FileType less set omnifunc=csscomplete#CompleteCSS

The first line says to set the syntax type of .less files to use the less filetype. The second says to use the CSS autocomplete function for autocompletion. So if you are typing:

display:

and momentarily draw a blank on what options are possible, you can type Ctrl+X, O to see the list of standard options:

CSS Autocomplete

javascript-libraries-syntax.vim

This plugin has some syntax highlighting for common JavaScript libraries like Underscore (Lo-Dash), Angular, React, etc. This might be helpful for spotting incorrect function names:

Syntax Highlighting Shows An Error

There is a little configuration necessary, check out the plugin’s page for more details. Basically you’ll need something like this to get the full benefit, either in ~/.vimrc or by using some kind of local vimrc setup:

let g:used_javascript_libs = 'underscore,angularjs,jasmine,chai'

Musing: It might be nice if there was a way to automatically audit what manual configuration I need to do when installing a plugin to get the most out of it. I only found that I hadn’t set it up when I was writing up this post! :)

tern_for_vim

This was a bit hard to get properly set up (doubly so if you use nvm, since tern_for_vim wants a globally/system installed node executable…). And when I finally did get it working, it didn’t blow me away. However…

There are at least two useful Vim extensions that it provides:

:TernRename renames the variable under the cursor but only in this scope and then shows you a list of the changed references.

:TernRefs will just show you references to the variable under the cursor (similar to above, but with no rename.)

So I’d recommend this plugin just for the rudimentary refactoring support it provides. If you’re willing to go the extra mile it might be able to provide some more intellisense / autocomplete functionality.

Other Useful Non-JavaScript Specific Plugins

syntastic

Real-time syntax checking. Fantastic plugin, well documented and maintained, works well with no configuration. Works even better with some configuration. For JavaScript / HTML projects:

" use jshint
let g:syntastic_javascript_checkers = ['jshint']

" show any linting errors immediately
let g:syntastic_check_on_open = 1

I also found a handy gist to have Syntastic use my project’s .jshintrc.

There is a bit of munging I do to decrease spurious errors. Specifically, HTML Tidy is the worst when dealing with things it doesn’t understand (HTML5 custom elements / attributes, for example):

" Set up the arrays to ignore for later
if !exists('g:syntastic_html_tidy_ignore_errors')
    let g:syntastic_html_tidy_ignore_errors = []
endif

if !exists('g:syntastic_html_tidy_blocklevel_tags')
    let g:syntastic_html_tidy_blocklevel_tags = []
endif

" Try to use HTML5 Tidy for better checking?
let g:syntastic_html_tidy_exec = '/usr/local/bin/tidy5'
" AP: honestly can't remember if this helps or not
" installed with homebrew locally

" Ignore ionic tags in HTML syntax checking
" See http://stackoverflow.com/questions/30366621
" ignore errors about Ionic tags
let g:syntastic_html_tidy_ignore_errors += [
      \ "<ion-",
      \ "discarding unexpected </ion-"]

" Angular's attributes confuse HTML Tidy
let g:syntastic_html_tidy_ignore_errors += [
      \ " proprietary attribute \"ng-"]

" Angular UI-Router attributes confuse HTML Tidy
let g:syntastic_html_tidy_ignore_errors += [
      \ " proprietary attribute \"ui-sref"]

" Angular in particular often makes 'empty' blocks, so ignore
" this error. We might improve how we do this though.
" See also https://github.com/scrooloose/syntastic/wiki/HTML:---tidy
" specifically g:syntastic_html_tidy_empty_tags
let g:syntastic_html_tidy_ignore_errors += ["trimming empty "]

" Angular ignores
let g:syntastic_html_tidy_blocklevel_tags += [
      \ 'ng-include',
      \ 'ng-form'
      \ ]

" Angular UI-router ignores
let g:syntastic_html_tidy_ignore_errors += [
      \ " proprietary attribute \"ui-sref"]

Sometimes I get the following message on startup or loading JavaScript files: “syntastic: error: checker javascript/jshint: can’t parse version string (abnormal termination?)”. This error indicates that Syntastic can’t find the jshint executable. For me this means I need to exit vim and nvm use to load up the right node version. Then when I start Vim again, Syntastic can find jshint.

OK, enough about Syntastic for now.

vim-projectionist

If you’ve ever used Rails.vim, and loved the :A functionality to jump to the alternate file (typically the test file), but want to do that with arbitrary projects, then this is the plugin for you.

This has been extremely useful on my current project. We had a Rails-ish directory structure in an Express server, with unit tests in reasonable places. So something like the following in a projections.json file gives me quick access to the test file of the project file that I’m looking at (or vice versa):

{
    ...
    "server/models/*.js": {
        "type": "model",
        "alternate": "test/mocha/models/{}.spec.js"
    },
    "server/controllers/*.js": {
        "type": "controller",
        "alternate": "test/mocha/controllers/{}.spec.js"
    },
    ...
    "test/mocha/models/*.spec.js": {
        "type": "modeltest",
        "alternate": "server/models/{}.js"
    },
    "test/mocha/controllers/*.spec.js": {
        "type": "controllertest",
        "alternate": "server/controllers/{}.js"
    }
    ...
}

Can also open up a model file with :Emodel user and it does the right thing.All of the navigation commands also let you open the associated file in a new split or tab. Highly recommended.

Ultisnips

If you’re running a straight JavaScript project, there can be a lot of typing. Ultisnips is the most versatile text expander plugin for Vim. You can make new snippets for any file type. Here is my JavaScript Ultisnips configuration. A snippet of useful snippets:

snippet use
'use strict';
endsnippet

Type use<tab> and save a few keystrokes.

snippet clv
console.log('$1: ', ${1});
endsnippet

Handy for quick debugging. Basically log any variable while printing what it is, so you don’t need to type it twice.

snippet reqlo
_ = require('lodash')
endsnippet

snippet reqmonbb
BBPromise = require('bluebird'),
mongoose = BBPromise.promisifyAll(require('mongoose'))
endsnippet

Since we use these in 80% of our files, saves me quite a bit of time.

Just a few examples, there are other things that I constantly use in there. Basically if you have a pattern in your codebase, encode it in snippets and then always do the right thing in a consistent way with minimal typing / thinking.

Wrapping up

Prerequisites

Before you do anything else, get a Vim plugin manager. I use Pathogen. There are many other options.

More info

Here is my full configuration.

If you liked this post, check out my book on Writing With Vim, where I cover everything you need to know about writing prose in Vim.

Thanks for reading, hope this was helpful!

My First Experience With Node.js

Attention conservation notice: these were my rough notes as I played around with Node.js probably close to a year ago at this point. I have had more experience since then, but might be useful to see how I started.

Node.js seems interesting as a backend technology because of its highly scalable nature. Also, it seems to be gaining steam in terms of developer mindshare. It is somewhat interesting to write in the same language on the front end as the backend, but then you are writing in JavaScript everywhere.

I wanted to play around with Node a bit, so I got the latest version of Node and installed by doing the standard download, unpack, ./configure, make, sudo make install. (Running on Ubuntu for kicks today.)

I thought about what things I might want to make and generally Googled around a bit. I got some ideas and a general lay of the land.

Then I said, “well there must be a Hello World app that I can play around with.” The node.js site had an example, so I copied it into a new Vim buffer. I ran it from the command line with node hello.js. There was a useful console message that was printed (as expected), and then I fired up localhost:1337 and got the expected “Hello World” message. I thought, “pretty easy!”

After getting this feedback, I took a little closer look at the code that I copied. I wondered what would happen when I commented out the res.writeHead line, and then thought it might not be visible, so wondered what would happen if I changed the Hello World line, which would more immediately tell me if my server was looking at file changes or not. I changed the string to “Hello Worlds” and refreshing the page did not change the string. Terminating the server and starting it again worked though. I thought, “this is not sustainable in the long run” and hunted for something to automatically watch for file changes.

I am familiar with guard in Ruby-land, and could have used this somehow. But I figured this was probably a solved problem and wanted to stay in Node-land. A quick search showed that using supervisor is a decent way to go (for now at least.)

NPM modules seemed interesting, so I took a look at the highest-used projects on the NPM site. These are things that will be useful going forward.

I navigated to the Node.js official documentation, and started playing around with some of the functions. I wondered if console.error would print out red to the console. I was slightly disappointed to see that it did not (although this makes sense, wouldn’t want too much color logging.) I searched around for Node console color, and found some interesting git repos, but decided not to explore this much more.

Then I was thinking, CoffeeScript would be useful. I had played around with this for Kyle and I’s Generic Space Shooter demo. I copied my current file to another one with a .coffee extension, and converted to CoffeeScript. Then I realized that supervisor probably wasn’t going to cut it. I used coffee -w to watch the file for changes, but I got an exception when I changed the file. Hunted around a bit more and found nodemon which proved to be a better solution for reloading.

Kept scrolling down the main Node documentation. Noted the section on modules and such, and figured this was a good time to try to get code in another file imported. Thought I would have made things harder by using CoffeeScript, but it turned out to not be the case. As soon as I saw the export function, I was thinking there were some things going on that the documentation didn’t adequately explain. Probably scrolling a bit more would have helped, but I saw this post and it helped to understand a couple of cases and trade-offs.

My new module just exported a function that takes a parameter and logs the parameter to the node console. However, when I tested it in the server request, I got two messages where I expected one. I searched for “node http createserver called twice” and got a helpful StackOverflow post. I ran the debug statement suggested, and it was indeed getting the favicon as well as the normal hit.

Skimmed through the rest of the official documentation, and saw a lot of things that looked like other language base constructs. Tried to focus mostly on stable features. Called it a night.

Pros so far:

  • easy to install packages
  • well documented so far
  • quick feedback cycles
  • modules are not hard to use or create

Next project ideas:

  • Chat application (seems to be the next level up of hello world)
  • Playing around with Express and seeing what other frameworks are out there for building apps
  • Integrating with Backbone and/or persistence (I have a sample project in mind for this, Backbone + Pivotal Tracker)

Meta

I kind of like this format for exploring new technologies. Basically I just create a running “stream of consciousness” of what I am thinking about and working on. It helps me remember what I am doing, where I get stuck, and prevents me from getting bogged down on small details for too long.

Night Writing With The Neo

I like writing, and I often write at night. However, writing at night on a computer monitor increases exposure to bright light and blue light, which delay sleep onset and suppresses melatonin production, respectively. Even tablets have this drawback, which is why I try to avoid reading on them at night.

Alternatives

I looked for an alternative to writing on a standard computer monitor. I considered finding a Kindle-like screen that has e-ink technology. This seemed technically feasible, but difficult to set up and maintain as well as being expensive.

I briefly considered writing by hand, but this has the disadvantages of being slow and difficult to get into electronic form.

I also took a look at some electronic typewriters (yes, really!) I could type on a familiar keyboard layout and then scan the resulting copies and use OCR on them to get the text extracted to a digital format. This seemed cumbersome and error-prone, and lacked many of the simple editing tools that a modern word-processor would use.

What I really wanted was a few line LCD display. I remembered my parents had a small address book that ran off of a few batteries, and figured maybe I would have to make something like that. In a last ditch effort, I posted to Twitter:

Kyle replied that his wife had something that might fit the bill, and she responded with some more info:

The Neo

AlphaSmart Neo

After briefly looking into it, the Alphasmart Neo seemed like it fit the bill. It has been recently discontinued, but there are enough on eBay and Amazon at the moment that you can pick up one for under $40, delivered.

Key benefits include:

  • a few lines of text that are readable in low to medium light
  • no backlight
  • insane battery life (I have typed for many hours as of the time of writing, and it still registers > 95% battery life)
  • no-frills word processor for distraction-free writing
  • syncs with my computer to get or receive files
  • eight text files open at once, with more saved to device
  • quick to turn off and on

The Display

One thing that surprised me is that the font is not always monospaced. I was thinking it would always be monospace due to the display, and I typically write in monospace. However, the display itself is a grid of pixels, not a bunch of separated characters.

The font width also depends on which specific font you select. For example, there are monospaced fonts in the system font, but the smallest font has variable width only. There is a system font that has four lines visible but with monospaced, and you can use the variant that has the same height but variable width.

Overall I like a medium font the most. The smallest font was nice for a while, since I could see the most lines of text at once. But it can be hard to see depending on the lighting. I wouldn’t want to do much text editing in this processor. Mostly just for typing first drafts or getting things out of my head. Variable width is nice to get the most characters per line. The Neo reflows text in the paragraph when writing.

Sections

I guess there is support for sections, which is helpful for navigating around the document.

Editing Quirks

There are a couple of things that I would like to change about the AlphaWord applet. First is that the keyboard repeat rate is a bit slow, so trying to hold down the keys takes a long time and then I need to flutter them instead. As a result, navigating is harder than it needs to be.

Another quirk is that there is no easy way to kill backwards multiple characters or words. Typically this would be something like Ctrl-Backspace, Alt-Backspace, or Ctrl-W, depending on the program or platform. Instead, to delete multiple words, you need to select them and then press backspace. Further, after selecting some text, I cannot delete it by starting to type. It just unselects the text and starts writing at the place that the cursor was at.

Transferring data

You can pull files off of the Neo (and put them on, although this is less useful for me at this time.) However, the encoding is a bit messed up (I think it has Windows line endings.) I made a small script to convert the encodings and rename the files into something more command-line friendly. I probably could have done the same with bash and dos2unix or some variant, but it works.

But can it run Vim?

While there are some loadable applications and presumably some way of writing them, there doesn’t seem to be a Vim application. There is a similar-looking device called the QuickPAD PRO (image comparison) that runs various custom applications and has more screen space that might be more promising for something like this. I will probably try to pick one up if the opportunity presents itself.

Recommended

Overall, I recommend getting an AlphaSmart Neo if you do much night writing or want a quality portable writing device.

Refactoring JavaScript with Grasp

I happened upon an open source tool for refactoring JavaScript that has been useful. The tool is named Grasp, and it enables searching and replacing on the AST (abstract syntax tree) of your JavaScript code. This is powerful because instead of finding or replacing bits of text throughout your codebase, you can replace only identifiers, for instance. Or you could find matching blocks of code that are spread across lines, since we look at the entire syntax tree, not the text representation of it.

There is a fantastic blog post on the Grasp website. It provides several examples of common refactorings (rename variable, changing a function to accept an arguments hash instead of adding another parameter, etc.) It really does a great job of showing why standard tools like sed and grep fall short during refactoring. The examples are clear and provide good starting points for your own refactorings.

I’d love to see a Vim plugin/wrapper for Grasp. Especially if it could do simple JavaScript refactorings (extract method/function, rename variable, to name a few.) I feel a little safer using Grasp than I do with sed, which can corrupt my git repository if I foolishly invoke it incorrectly. My typically workflow is to run a command to search for the text that I want to replace, then run it inline, and then run git diff to see any potential replacement anomalies.

The Pain Will Continue Until Understanding Improves

I was on the swim team in high school, and we would do weightlifting a few days a week in the morning. In the weight room there was a sign that read: “The beatings will continue until morale improves.” At the time I thought “this is a typical meathead thing to say. Shouldn’t stopping the beatings improve morale? I mean how is this supposed to pump me up?”

The Beatings Will Continue Until Morale Improves

While knee deep in fixing a bug that seemed like it kept popping up, I realized that the bug kept popping up because my understanding of the tools I was using was flawed. Maybe it was caching or exactly how the database is doing queries or how DNS worked. Each time, I was banging my head against the wall and until I dug in and got a better understanding of the underlying problem, I was only able to band-aid on fixes.

Typically once I have the awareness to realize that I am lacking in knowledge about a topic, the knowledge itself is relatively easy to come by. But until then all sorts of pain will arise, including unstable or flaky performance, or avoidance of the technology (“ah, who needs that! Certainly not I, guy who doesn’t fully understand it.”)

When I realize this anti-pattern, my motto is: “The pain will continue until my understanding improves.” Basically I need to stop trying to hack around the problem and fiddle with the thing that I have to try to get it to work, and instead seek a deeper understanding of the abstractions that I am using by drilling down to the details. This might be most applicable when there is not someone else to turn to for easier answers, but is a good mentality to have to grow professionally.

A lot of life is like this, actually. The things that make us uncomfortable but are unavoidable need to be reckoned with.