Raw Syntax

The stuff programs are made of

Learn Emacs: Editing Javascript

Permalink

One of my favorite things about emacs is its javascript modes. While there are a million options, I'm only going to talk about how I edit javascript with emacs.

Which Mode do I Use?

I use js2-mode. It provides syntax highlighting and underlines errors as you type. This mode doesn't come with emacs, it was built by Steve Yegge. However it is installable through the ELPA.

One problem I found with this mode is that it has some weird ideas about indentation. I personally prefer the indentation from the built-in js-mode in emacs. After some googling I came across a blogpost on fixing indentation in js2-mode. Starting with that I then made my own modifications and have a js2-mode that works exactly the way I want it (code below).

(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))
(add-to-list 'auto-mode-alist '("\\.json$" . js2-mode))
;; Use js-mode indentation in js2-mode, I don't like js2-mode's indentation
;;
;; thanks http://mihai.bazon.net/projects/editing-javascript-with-emacs-js2-mode
;; with my own modifications
;;
(defun my-js2-indent-function ()
(interactive)
(save-restriction
(widen)
(let* ((inhibit-point-motion-hooks t)
(parse-status (save-excursion (syntax-ppss (point-at-bol))))
(offset (- (current-column) (current-indentation)))
(indentation (js--proper-indentation parse-status))
node)
(save-excursion
(back-to-indentation)
;; consecutive declarations in a var statement are nice if
;; properly aligned, i.e:
;;
;; var foo = "bar",
;; bar = "foo";
(setq node (js2-node-at-point))
(when (and node
(= js2-NAME (js2-node-type node))
(= js2-VAR (js2-node-type (js2-node-parent node))))
(setq indentation ( 4 indentation))))
(indent-line-to indentation)
(when (> offset 0) (forward-char offset)))))
(defun my-indent-sexp ()
(interactive)
(save-restriction
(save-excursion
(widen)
(let* ((inhibit-point-motion-hooks t)
(parse-status (syntax-ppss (point)))
(beg (nth 1 parse-status))
(end-marker (make-marker))
(end (progn (goto-char beg) (forward-list) (point)))
(ovl (make-overlay beg end)))
(set-marker end-marker end)
(overlay-put ovl 'face 'highlight)
(goto-char beg)
(while (< (point) (marker-position end-marker))
;; don't reindent blank lines so we don't set the "buffer
;; modified" property for nothing
(beginning-of-line)
(unless (looking-at "\\s-*$")
(indent-according-to-mode))
(forward-line))
(run-with-timer 0.5 nil '(lambda(ovl)
(delete-overlay ovl)) ovl)))))
(defun my-js2-mode-hook ()
(require 'js)
(setq js-indent-level 2
indent-tabs-mode nil
c-basic-offset 2)
(c-toggle-auto-state 0)
(c-toggle-hungry-state 1)
(set (make-local-variable 'indent-line-function) 'my-js2-indent-function)
(define-key js2-mode-map [(meta control |)] 'cperl-lineup)
(define-key js2-mode-map [(meta control \;)]
'(lambda()
(interactive)
(insert "/* -----[ ")
(save-excursion
(insert " ]----- */"))
))
(define-key js2-mode-map [(return)] 'newline-and-indent)
(define-key js2-mode-map [(backspace)] 'c-electric-backspace)
(define-key js2-mode-map [(control d)] 'c-electric-delete-forward)
(define-key js2-mode-map [(control meta q)] 'my-indent-sexp)
(if (featurep 'js2-highlight-vars)
(js2-highlight-vars-mode))
(message "My JS2 hook"))
(add-hook 'js2-mode-hook 'my-js2-mode-hook)
view raw js2-mode.el hosted with ❤ by GitHub

Editing Javascript in HTML

In my experience I'm not always editing pure .js files. Sometimes I'm editing javascript inside a .haml, .erb, or .html file. The haml-mode I am using is supposed to have easy js-mode integration. However I tried to integrate js2-mode, and it was not simple. Furthermore, the built-in javascript highlighting seems to break on a regular basis. Troubleshooting that problem looked like it was going to take more time than I had. Instead I wrote some elisp to allow me to quickly create a javascript scratch buffer.

Javascript Scratch Buffer

I use this to write javascript and copy / paste between buffers until I'm happy with the code. It's a very simple solution to the problem. It creates a buffer named scratch-js with js2-mode. It's not unlike the elisp scratch buffer that comes up on emacs start up. I don't write javascript all the time, so this solution works pretty well for me.

(defun scratch-js ()
"Create or switch to a javascript mode scratch buffer"
(interactive)
(if (not (eq nil (get-buffer "scratch-js")))
(switch-to-buffer "scratch-js")
(set-buffer (get-buffer-create "scratch-js"))
(js2-mode)
(switch-to-buffer "scratch-js")))
view raw defuns.el hosted with ❤ by GitHub

This is admittedly a stopgap solution. I would prefer to have js2-mode integrated tightly with haml-mode. If anyone else has actually done this, I would love to see the code.

Comments