2011-05-23

Emacs23でjs2-modeを使うのにもうespressoは不要

EmacsでJavaScriptを書くのに欠かせないjs2-mode
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つほど。
  1. バイトコンパイルしましょう:
    M-x byte-compile-file 【RET】(js2-mode.elのパスを入力)
  2. 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にアクセスすればダウンロードできます。

0 件のコメント:

コメントを投稿