このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

[参照用 記事]

EmacsでJavaScriptソースを快適に読むために:js2-modeとエグズーベラントCtags

「横道にそれすぎ」に書いた事情で、EmacsでJavaScriptソースコードを読む環境を少し整えようかと。

次の2つのツールを導入してみよう、っと。

内容:

  1. より良いEmacs JavaScriptモード -- js2-mode
  2. 強烈なタグファイル作成ツール -- エグズーベラントCtags
  3. エグズーベラントCtagsを調べてみる
  4. EmacsでJavaScriptソースを読む

●より良いEmacs JavaScriptモード -- js2-mode

以前(2006年7月)、ひげぽんさんの記事で、「ecmascript-mode.el < javascript.el みたいだ」と書いてあったので、僕もjavascript.elを使っていたのですが、JavaScriptの構文解析があんまり精密でなくてイマイチ。例えば、/"[^"\\\n\r]*"/gという正規表現が出現すると、最後のダブルクォートを文字列のはじまりと認識してしまうのですよね。

js2-modeに切り替えましょう:

  1. js2-modeホームページのFeatured Downloadsから、js2-20080616a.el(今日の時点の最新バージョン)をダウンロード。
  2. js2-20080616a.elを、js2.elとして、Emacs(僕はMeadow3)のsite-lisp/の下にコピー。
  3. site-lisp/をDiredで開いて、 M-x byte-compile-file RET js2.el RET でコンパイル。js2.elcが出来ているのを確認。
  4. ~/.emacsを編集(すぐ下)。


;; js2-mode
(autoload 'js2-mode "js2" nil t)
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))

これで、(javascript.elがハイライティングに失敗していた)prototype-1.6.0.2.jsを見ると、ちゃんと構文解析できてます。ところどころに下線が現れますが、これはjs2.elが「ヤバイんじゃないの」と判断したところのようです。

it highlights syntax errors and underlines warnings



js2は、構文エラーをハイライト表示し、警告を下線表示します。

●強烈なタグファイル作成ツール -- エグズーベラントCtags

ソースコード中に出現する関数や大域変数の定義を効果的に参照するにはタグジャンプが便利。Emacsのタグジャンプについては、例えば次の説明を参照してください。

Emacsには、etagsというタグファイル作成ツールが付属してますが、機能的にイマイチ。特にJavaScriptに対してはうまく機能しません。エグズーベラントCtagsに置き換えましょう。

http://ctags.sourceforge.net/ から ctags-5.7.tar.gz や ec57w32.zip をダウンロードできますが、日本語対応版は http://hp.vector.co.jp/authors/VA025040/ctags/ctags_j.html から入手できます。日本語対応版では、--jcode=[ascii|sjis|euc|utf8] というオプションが使えます。日本語対応Win32バイナリは ec57j1w32bin.zip (ctags5.7J1 2007/09/10)。なお、http://hp.vector.co.jp/authors/VA025040/ctags/ には、エグズーベラントCtagsの日本語情報が色々あります。

既存のctags, etagsをエグズーベラントCtagsで置き換えてしまって問題ありません。エグズーベラントのctagsコマンドを、シンボリックリンク、ハードリンク、ファイルコピーなどでetagsという名前にしておけばetagsとして動作します(-e オプションでもOK)。起動したコマンドの実体が何であるか不安になったら、--version オプションで確認しましょう。

エグズーベラントCtagsの動作は、コマンドラインオプション以外に環境変数CTAGSと設定ファイルで制御できます。--verbose オプションで確認してみると、次の順序で設定を読むようです。

  1. /ctags.cnf (Windows版のみ)
  2. /etc/ctags.conf
  3. /usr/local/etc/ctags.conf
  4. ~/.ctags
  5. ~/ctags.cnf (Windows版のみ)
  6. ./.ctags
  7. ./ctags.cnf (Windows版のみ)
  8. $CTAGS

Windowsにおける ~/ は、環境変数HOMEから判断します。

ちなみにエグズーベラントって名前の由来は、エグズーベラントCtagsのFAQによると:

exuberantという単語の意味の1つが『究極に豊富に造られた』で、Exuberant Ctagsで生成したtagファイルと他のctagsで生成したものとを見比べてみれば、この名前がいかにふさわしいかがわかるはずです。

●エグズーベラントCtagsを調べてみる

次のようなJavaScriptのサンプルを作ってみました。


/* sample.js */

var g = 1;

function f1() {
return 0;
}

var f2 = function() {
return 0;
};

var foo = {};

foo.f3 = function() {
return 0;
};

var bar = {
C: 10, // constant
f4: function() {
return 0;
},
hello: "Hello"
};

function Baz(n) {
this.n = n;
}
Baz.prototype.f5 = function() {
return this.n;
};

次のコマンドでTAGSファイルを作ります。


ctags -e sample.js

できたTAGSファイルから判断するに、次の変数/関数は認識できているようです。


var g
function f1()
var f2 = function()
foo.f3 = function()
function Baz(n)
Baz.prototype.f5 = function()

残念ながら、bar.f4() が認識されてない。以前のsecondlifeさんの記事を参考に、次の内容を書いた ~/.ctags(Windowsなら ~/ctags.cnf でもよい)を作ります。


--regex-javascript=/^[ \t]*(['"]?)([A-Za-z0-9_.]+)\1[ \t]*[:=][ \t]*function[ \t]*\(/\2/I,inner/i

確かにこれで、funcName: funcion(...){...}スタイルの関数も認識するようです。

●EmacsでJavaScriptソースを読む

TAGSファイルを生成するには、ソースファイルのトップディレクトリで次コマンドを実行するのがよさそうです。


ctags --verbose -e --recurse --languages=javascript > ctags.log

--recurseオプションは、ディレクトリを再帰的にたどってファイルを探します。余計なファイルは読まないように--languages=javascriptオプションを付けました。念のため、--verboseオプションを先頭に付け、メッセージ出力をファイルに取ります。ctags.logに処理の経過が記録されます。(ctagsの挙動に慣れてしまえば、--verboseや出力のリダイレクトは不要です。)

目的のJavaScriptファイルをEmacsにロードし、関数定義などを参照したいときに次のキーコンビネーション(コマンド)を使います。

  • M-. (find-tag) : タグ(名前)の定義箇所を探す(タグジャンプ)。
  • M-* (pop-tag-mark) : 前にM-.を実行した場所に戻る。
  • C-u M-. : 次の定義箇所を探す。
  • C-u - M-. : 前に見つかった定義箇所に戻る。
  • C-x 4 . (find-tag-other-window) :タグ(名前)の定義箇所を探し別ウィンドウに表示する。
  • C-x 5 . (find-tag-other-frame) :タグ(名前)の定義箇所を探し別フレームに表示する。

C-u はコマンドfind-tagに引数0を与え、C-u - はfind-tagに引数-1を与えるプリフィックス・キーですが、ちょっとキーを押しにくいのが難点です(どうしてもイヤなら、当該コマンドをラップして別なキーにバインドし直しましょう)。

Emacsのタグ関連操作に関しては前述の「タグジャンプで関数の定義にジャンプ」、より詳しくは、オンライン「GNU Emacsマニュアル」の「20.13 タグテーブル」を参照してください。