Emacs and JavaScript in 2017
About an year ago, when it became clear that sooner or later I'll have to write ES6 code, I decided to give js2-mode another look (wow, how time flies!)
Steve Yegge no longer seems to maintain this majestic creation, but as it often happens in the open-source world, quality code finds new home and maintainers. The official fork today is located at https://github.com/mooz/js2-mode, and it's what you get if you install it from Melpa. However, I live on my own fork where I fix bugs as I find them. Eventually, my fixes get merged into the official repo.
On top of js2-mode
, Magnar Sveen of emacsrocks.com fame wrote js2-refactor, a collection of tools for working on JavaScript
code. It brings new powers at your fingertips — for example, you can select a piece of code and turn it into a
function; it figures out what are the variables needed by that piece of code, and turns them into arguments of the new
function; and replaces that piece of code with a call to the new function, which is inserted just outside the current
function. All that happens in a split second — an operation that would take many seconds to do manually. If you edit
JavaScript, and use Emacs, make sure to check js2-refactor
.
Before switching to js2-mode
+ js2-refactor
, I had some utilities for editing JS that worked with an external parser (based
on UglifyJS). I have ported these tools on top of js2-mode
and js2-refactor
, so we don't need
to call an external parser, and we get support for ES6. I wanted to briefly cover it in this post, and perhaps if more
people are interested I will submit a pull request to js2-refactor
.
js2r-highlights.el
These tools live in my fork of js2-refactor, on branch
highlights
. It could have been a separated package (maybe it will, someday), but it was more convenient
for me to work on the same codebase as js2-refactor
, as I found several bugs (fixes already merged into
the official repo).
If you load js2-refactor
from that branch, the following utilities are available:
-
js2r-highlight-thing-at-point
: with the cursor over a variable, it will highlight all occurrences of that variable in its defining scope. This is nice if you want to see quickly where is some variable used. It's, of course, smarter than a string search — it doesn't search for that name in strings or comments; in fact, it doesn't do any text search at all — instead, it uses the mighty power the parser to dig variable usage in the AST.For convenience, this function does what you'd expect also on names like
this
orsuper
. It also works on constants (strings or numbers), in which case it highlights occurrences in the whole buffer.While this mode is active, you can press
Ctrl-Enter
(js2r-highlight-rename
) to rename the variable. This duplicates a feature thatjs2-refactor
already had (renaming variables), but the way my function does it is a little different (it asks for the new name in the minibuffer; the operation is undoable in a single step; it also works on strings or numbers, or onthis
— which is sometimes convenient; and it tells you how many replacements were made). -
js2r-highlight-free-vars
: highlights “free variables” in the innermost function containing the cursor. Free variables are variables defined elsewhere (e.g. in some enclosing scope outside the current function). It's useful to know what are the free variables when you want to move a function around (for example a function with no free variables can be safely lifted to an upper scope). A short summary is displayed in the minibuffer (total free variable occurrences, and individually, their name and usage count). -
js2r-highlight-exits
: highlight exit points from the function surrounding the cursor. That is,return
orthrow
statements. This becomes really useful when you work with code containing huge functions (hundreds of lines). I commonly do that — the fact that a function is huge doesn't mean everything happens in a gigantic mess ofif
-s orfor
-s — the code is split into many subfunctions, which work together, sharing the environment, to achieve some goal. This kind of code is easier to write and understand, IMO, but you do need tools that enable you to reason about it, like, finding free variables, finding variable usage, or exit points.1
Keybindings
No keybindings are defined by default. My own preference is opinionated and based on years of usage and muscle memory — here's what I use, in my own Emacs config:
(define-key js2-refactor-mode-map (kbd "M-?") 'js2r-highlight-thing-at-point)
(define-key js2-refactor-mode-map (kbd "C-c f") 'js2r-highlight-free-vars)
(define-key js2-refactor-mode-map (kbd "C-c C-f") 'js2r-highlight-free-vars)
(define-key js2-refactor-mode-map (kbd "C-c C-x") 'js2r-highlight-exits)
However, when highlights are on, a minor mode will be active which does define a bunch of key bindings:
(,(kbd "C-<down>") . js2r-highlight-move-next)
(,(kbd "C-<up>") . js2r-highlight-move-prev)
(,(kbd "C-<return>") . js2r-highlight-rename)
(,(kbd "<escape>") . js2r-highlight-forgetit)
(,(kbd "C-g") . js2r-highlight-forgetit)
So, you can use Ctrl-Up
and Ctrl-Down
to jump to the previous or next highlighted area,
Ctrl-Enter
to rename variables (note this only makes sense if the mode was entered with
js2r-highlight-thing-at-point
), and Ctrl-G
or Esc
to quit this minor mode and
remove the highlights.
Conclusion
Emacs rocks. Steve rocks. Magnar rocks. Mooz rocks. And if you find my little highlights mode useful, means I rock a little too, so please drop me a line. ;-)