Emacs23に入れ替えたついでに、設定を見なおしてみました。
※追記
いろいろカスタマイズする方法を書いたんですが、もっと便利なjs2-mode (フォーク版)というのがあるのを知りました。そちらを使うほうが早くて簡単で高機能です。
(ちょっと古いけど日本語での紹介)
なのでこの下はもう読まなくてもいいんですが、いちおう残しておきます……。
js2-modeの不備を補うためにespressoを併用していたけれど…
js2-modeは大体すばらしいのですが、インデントがいただけません。たとえばコールバック関数を書くとき。
window.setTimeout(function(){ doSomething(); // インデントの基準が丸カッコの位置に… }, 1000);左にスペース空きすぎです。
やっぱり次のようになってほしいのです。
window.setTimeout(function(){ doSomething(); // インデントの基準は前の行 }, 1000);そこでポピュラーなのが、js2-modeとは別のJavaScript用メジャーモード「espresso-mode」を併用する方法。
元ネタはたぶんココだと思われます。
というわけでespresso-modeのサイトに行ってみたら、次のようなお知らせが。
「espresso-modeはGNU Emacsのバージョン23.2以降では js-mode という名前で本体同梱になったよ」(意訳)
えっ…!
espresso-modeは別途インストールの必要なし
今回インストールしたEmacsのバージョンは23.3.1。ということはjs-modeはバッチリ同梱されているはずです。そこで、espresso-modeを別途インストールするのではなく、同梱のjs-modeを利用する方向に切り替えてみましょう。
と言っても何も難しいことはなく、.emacsとかに書く「espresso」の部分を単純に「js」に置換すれば終了です。
(autoload 'js-mode "js")
(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
;; I like to indent case and labels to half of the tab width
(back-to-indentation)
(if (looking-at "case\\s-")
(setq indentation (+ indentation (/ js-indent-level 2))))
;; 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)
なお、元サイトからはついでにちょっぴり書き換えています。
・インデント幅を2に変更
・私の使わない行をコメントアウト
これを.emacsや.emacs.d/init.elなどに書けば、コールバックを渡すたびにイラッとすることもなくなります。
ついでにswitch文のcaseの位置や、変数宣言が複数行に渡る場合も快適に。
// BEFORE: var x = 0, y = 1; // 変数宣言の途中で改行すると、前行の頭がインデントの基準だった // AFTER: var x = 0, y = 1; // 前の行と変数名の位置が揃って気持ちいい
js2-mode 小ネタ2つ
備忘録ついでに js2-mode の小ネタを2つほど。- バイトコンパイルしましょう:
M-x byte-compile-file 【RET】(js2-mode.elのパスを入力)
- js2-mode.elはダウンロードページよりsvnのほうがちょっと新しい:
ダウンロードページにあるのは 2009/7/23(rev73) ですが、svnのほうは 2009/8/8(rev80)。ちょっとだけ新しいです。
svn使わなくても、Webブラウザでhttp://js2-mode.googlecode.com/svn/trunk/js2-mode.elにアクセスすればダウンロードできます。