js2-mode setup recommendation

Update @ 2013 March: cleaned up deprecated recommendations

js2-mode is a JavaScript mode for Emacs with JavaScript parser built-in which allows syntax error detection on the fly and JavaScript refactoring (js2-refactor.el). If you are going to use js2-mode, either install the mooz fork or install the GNU ELPA version available via M-x list-packages:

How to install the mooz fork of js2-mode

The original old js2-mode had a problem of enforcing an unpopular indentation style, did not play well with idle-highlight-mode, and was not a derived mode of prog-mode. The mooz fork fixed them and then those changes were incorporated back to the original js2-mode. I don’t know which of the two the GNU ELPA one is based on but it also has those changes.

My setup recommendation for js2-mode

0. Enabling js2-mode or js2-minor-mode

If you want all js files to be open in js2-mode instead of the Emacs built-in js-mode (formerly known as espresso-mode), add this line:

(add-to-list 'auto-mode-alist (cons (rx ".js" eos) 'js2-mode))

Instead of using js2-mode as a JavaScript major mode, you could keep using the built-in js-mode and use that with js2-minor-mode to enable js2-mode’s syntax checking:

(add-hook 'js-mode-hook 'js2-minor-mode)

Latest release note from original js2-mode (as of 2013 March) says

This is the first major new release for js2-mode in three years. It incorporates several sets of changes:

* changes and fixes from Mooz’s github fork
* changes suggested by Stefan Monnier and the emacs maintainers
changes I made to allow js2 to be used as a minor mode

js2-mode is really best for its linting; its major-mode facilities are a bit weak. So I’ve added js2-minor-mode, with instructions in the file for how to enable it. You can use it in conjunction with your favorite JavaScript major mode (such as the one that is now bundled with Emacs 24), and get the best of both worlds.

Work is continuing on js2-mode by various contributors, but there is currently not a “canonical” version that I’m aware of — that is, the GitHub forks are not(?) directly contributing back to the ELPA version, nor vice-versa. So I will periodically (perhaps every 6 months) hand-merge them and upload the results here after it’s been tested by enough dogfooders.

This latest version is also the head SVN revision if you want to grab the source that way. The internal elisp version number, `js2-mode-version’, is 20120726.

1. Run prog-mode-hook in js2-mode. (deprecated recommendation that now only applies to old js2-mode)

For some reason, old js2-mode is not a derived mode of prog-mode when it should be. prog-mode is available from Emacs 24 on. Here’s an excerpt from Emacs 24 NEWS:

`prog-mode’ is a new major mode from which programming modes
should be derived.

`prog-mode-hook’ can be used to enable features for programming
modes, e.g. (add-hook ‘prog-mode-hook ‘flyspell-prog-mode) to enable
on-the-fly spell checking for comments and strings.

To ensure that prog-mode-hook runs in js2-mode, add:

;; add buffer-local indicator for whether prog-mode-hook has run.
(defun my-set-pmh-ran ()
  (set (make-local-variable 'my-pmh-ran) t))

(add-hook 'prog-mode-hook 'my-set-pmh-ran)

(add-hook 'js2-mode-hook 'my-run-pmh-if-not-ran)
(defun my-run-pmh-if-not-ran ()
  (unless (bound-and-true-p my-pmh-ran)
    (run-hooks 'prog-mode-hook)))

The reason I’ve added the check to see whether prog-mode-hook is run is that you don’t want to end up running prog-mode-hook twice when you upgrade to the latest version of js2-mode.

2. Turn off js2 mirror mode and use autopair mode instead.

3. Make js2-mode use spaces instead of tabs if that’s what you prefer. (deprecated recommendation that now only applies to old js2-mode)

(add-hook 'js2-mode-hook 'my-disable-indent-tabs-mode)
(defun my-disable-indent-tabs-mode ()
  (set-variable 'indent-tabs-mode nil))

(Update: It seems TAB now inserts spaces even when indent-tabs-mode is on.)

4. Etc

(eval-after-load "js2-mode"
  '(progn
     (setq js2-missing-semi-one-line-override t)
     (setq-default js2-basic-offset 2) ; 2 spaces for indentation (if you prefer 2 spaces instead of default 4 spaces for tab)

     ;; add from jslint global variable declarations to js2-mode globals list
     ;; modified from one in http://www.emacswiki.org/emacs/Js2Mode
     (defun my-add-jslint-declarations ()
       (when (> (buffer-size) 0)
         (let ((btext (replace-regexp-in-string
                       (rx ":" (* " ") "true") " "
                       (replace-regexp-in-string
                        (rx (+ (char "\n\t\r "))) " "
                        ;; only scans first 1000 characters
                        (save-restriction (widen) (buffer-substring-no-properties (point-min) (min (1+ 1000) (point-max)))) t t))))
           (mapc (apply-partially 'add-to-list 'js2-additional-externs)
                 (split-string
                  (if (string-match (rx "/*" (* " ") "global" (* " ") (group (*? nonl)) (* " ") "*/") btext)
                      (match-string-no-properties 1 btext) "")
                  (rx (* " ") "," (* " ")) t))
           )))
     (add-hook 'js2-post-parse-callbacks 'my-add-jslint-declarations)))

js2-parse-global-vars-decls makes js2-mode recognize JsLint global variables directives such as:

/*global console, jQuery, $, _, Backbone */

5. M-x customize-group RET js2-mode

This entry was posted in Emacs and tagged , . Bookmark the permalink.

3 Responses to js2-mode setup recommendation

  1. Pingback: Install and use the mooz fork of js2-mode | Yoo Box

  2. Pingback: using autopair mode in js2-mode | Yoo Box

  3. base698 says:

    Any idea how to define a custom key to redefine C-x C-e in js2-mode? I’m trying to run another command which sends to the repl.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s