普段 GNU GLOBAL (gtags) には大変お世話になっています。
http://www.gnu.org/software/global/global.html
これがなければ、ソースコードの読解や不具合調査など、あらゆるプログラミング活動に支障が出るほど。
そんな GNU GLOBAL ですが、対応言語が少ないことが悩みの種でした。
プラグインパーザーを使って Exuberant Ctags (http://ctags.sourceforge.net/) と連携させれば対応言語は増えますが、ctags は定義元の情報しかインデックス化しないため、GLOBAL の特徴である参照元へのジャンプができなくなってしまいます。
個人的には参照元やシンボルへのジャンプもよく使うので、ctags プラグインパーザーでは物足りないと感じていました。
GLOBAL に新規に対応言語を追加するには(何らかの言語で)パーザーを書かなければならず、かなり骨が折れる作業です。
ちゃんとしたパーザーを書くのは面倒ですが、ソースコードから識別子を抜き出すくらいなら正規表現ベースの実装でも実現でき、(シンボルタグのみの対応にはなりますが)比較的容易に対応言語を増やせるのではないかと考えました。
正規表現でうまく識別子を抜き出すにはどうすればいいのかと思い、Pygments (http://pygments.org/) のソースを眺めていました。
眺めているうちに、あれ、これそのまま使えばいいんじゃね? と思い至りました。
Pygments はライブラリとして呼べて、トークンを取り出すモジュールがあります。また、広範なプログラミング言語に対応しています。GitHub のシンタックスハイライティングにも使われています。
そんなわけで、Pygments を利用して GLOBAL のためのタグ情報を抜き出すプラグインパーザーを作りました。
Pygments Plug-in Parser for GNU GLOBAL
https://github.com/yoshizow/global-pygments-plugin
インストール方法は README.md を見てください。
実行には python 2.6 以降と Pygments パッケージが必要です。
global-pygments-plugin をインストール済みで、~/.globalrc に global-pygments-plugin を使うように設定を書いたら、あとはいつもどおり gtags を実行するのみです。
1 2 3 4 5 6 7 8 9 10 11 12 |
$ cat hello.rb class Hello def hello puts message end def message; 'hello, world'; end end $ gtags $ global -sx message hello.rb message 3 hello.rb puts message message 6 hello.rb def message; 'hello, world'; end |
参照元である 3 行目の message が出力されているのがわかります。また、6 行目の message は本来は定義元タグですが、Pygments の出力からは区別が付かないのでシンボルタグとして出力されています。
さらに、ctags が存在する場合は ctags も呼んで、定義元のタグを収集するようにしました。これにより、定義元と参照元の区別がつくようになります。
もちろん、ctags が対応している言語に対してのみ有効です。
1 2 3 4 5 |
$ gtags $ global -x message hello.rb message 6 hello.rb def message; 'hello, world'; end $ global -rx message hello.rb message 3 hello.rb puts message |
message が定義元と参照元に分けられているのがわかります。
さて、このツールでどれくらいの言語に対応できたことになるでしょうか。
Pygments の対応言語は http://pygments.org/languages/ に一覧があります(Pygments 開発版も含まれる)。また、手元で pygmentize -L lexers
を実行すれば手元の Pygments の対応度合いがわかります。
中にはうまく動作しないものもあります。例えば Pygments 1.6 の CoffeeScript lexer はトークンの区切り方がおかしく、シンタックスハイライトとしては読みやすいのかもしれませんが、タグジャンプには使えないデータを返してきます。
ですが CoffeeScript の例はレアケースで、だいたいの言語ではだいたいうまく識別子を抜き出せているようです。
このツールの欠点は遅いことです。gtags のビルトインパーザーや ctags に比べるとだいぶ遅いです。原因としては
- シンボルタグの数は通常 定義元タグの数よりかなり多い
- Pygments は識別子と関係ないトークンまで詳細に解析する (シンタックスハイライターだから…)
- 同じ処理を書いても C より Python のほうが多くの場合遅い
といったところかと思います。
これは Pygments を無理やり使っている以上、仕方のない部分かと思います。
gtags -i
(incremental) などのオプションを活用したり、夜間に実行するなど工夫が必要でしょう。
ありがとうございます!滅茶苦茶助かります。
同じ民族の優秀な人が非常に大きい仕事をしてくれて非常に誇らしい。(私は関係ないけど)
ありがとうございます!
早速使わせていただきます!