GNU GLOBALの対応言語を大幅に増やすPygmentsパーサーを導入する

[GNU GLOBAL](http://www.gnu.org/software/global/) 6.3.2 より、Pygments を利用したプラグインパーサー(以降 Pygmentsパーサー)が同梱されるようになりました。
これは Python で書かれたシンタックスハイライターである [Pygments](http://pygments.org/) を利用し、Pygments がサポートするたくさんの種類のプログラミング言語のタグ付けを可能にするものです。

具体的には、[GLOBAL-6.3.2 （2014年9月4日リリース）の新機能](http://www.tamacom.com/handbook/new.html#6.3.2) に GLOBAL の作者様が書かれているように 25種類、シンボルタグのみの検索ができるものも含めれば [150種類ぐらいの言語](https://github.com/yoshizow/global-pygments-plugin/blob/aebed6d2c77c01c82319aa6577c3b51c57e20ecc/sample.globalrc#L295-L448)に対応しているはずです。
個人的には、Ruby, Go, JavaScript などのタグ付けに利用しています。

そんなPygmentsパーサーですが、GLOBAL のプラグインパーサーの設定自体が少し難しい上、Pygmentsパーサーがいくつかのソフトウェアに依存していたりするため、導入方法がわかりにくいようです。そこで、Pygmentsパーサーの導入方法について解説したいと思います。

Exuberant Ctags の利用
======================

早速インストール…の前に、少し予備知識が必要です。

gtags の生成するタグには、定義タグとシンボルタグがあります。参照タグは少し特殊で、参照タグ専用のインデックスというのはありません。[^1]

Pygments だけではシンボルタグしか生成できません。シンボルタグだけでもタグジャンプはできますが、その場合 定義・参照もすべてシンボル扱いになります。

定義タグ、参照タグの区別ができたほうが便利です。そのため、Pygmentsパーサーでは [Exuberant Ctags](http://ctags.sourceforge.net/) がインストールされている場合には、Exuberant Ctags を利用して定義タグを生成します。
Pygments と ctags、両方の出力が組み合わさることにより、定義・参照・シンボルの全ての種類のタグジャンプが利用できるようになります。

![pygments-and-ctags.png](https://qiita-image-store.s3.amazonaws.com/0/8120/246c1755-f254-1b32-e7d5-55d5b74effe1.png)

なお、Exuberant Ctags がサポートしていない言語に関してはシンボルタグのみ生成されます。

[^1]: 参照タグはシンボルタグと定義タグから導出されます。シンボルタグのうち、同じ識別子が定義タグにも存在するものが参照タグになります。

インストール
============

Mac の場合
----------

Mac では Homebrew を利用するのが簡単です。

    $ brew install global --with-exuberant-ctags --with-pygments

これにより Python の Pygments パッケージや、Exuberant Ctags も自動的にインストールされます。

Unix系OS の場合
---------------

### 必要なもの

- Python 2.6 以降 (GLOBAL-6.3.3 以降のPygmentsパーサーでは 3.x も OK)
- [Pygments](http://pygments.org/) Python パッケージ (1.6 以降推奨)
- [Exuberant Ctags](http://ctags.sourceforge.net/) 5.5 以降

### インストール

Pygments パッケージをインストールします。

    $ sudo pip install Pygments

Exuberant Ctags をインストールします。

だいたいのディストリビューションではパッケージが用意されているのではないかと思います。
Ubuntu Linux の場合は以下のようにします。

    $ sudo apt-get install exuberant-ctags

GNU GLOBAL をインストールします。

    http://www.gnu.org/software/global/download.html から最新の global-x.x.x.tar.gz をダウンロード
    $ tar xf global-x.x.x.tar.gz
    $ cd global-x.x.x
    $ ./configure
    $ make
    $ sudo make install

なお `./configure` の実行の際、正しく python の実行ファイルが見つかれば

    checking for python... /usr/bin/python

というログが、また、正しく ctags の実行ファイルが見つかれば

    checking for exuberant ctags program... using /usr/bin/ctags

というログが出力されます。

動かしてみる
============

ラベルについて
--------------

GNU GLOBAL をインストールしたデフォルトの状態では、ビルトインパーサーが動作するようになっています。
ビルトインパーサーは C/C++, Java, PHP など限られた言語にのみ対応しています。

プラグインパーサーを利用するには、`gtags` 実行時に「ラベル」を指定し、使いたいパーサーを明示する必要があります。

    $ gtags --gtagslabel=pygments
    
    # 環境変数で指定することもできます
    $ export GTAGSLABEL=pygments
    $ gtags

ラベルとして指定できるのは、/usr/local/etc/gtags/gtags.conf[^2] に定義されている以下の項目です。

    default:\
            :tc=native:
    native:\
            :tc=gtags:tc=htags:
    user:\
            :tc=user-custom:tc=htags:
    ctags:\
            :tc=exuberant-ctags:tc=htags:
    pygments:\
            :tc=pygments-parser:tc=htags:

何も指定しないと、`default` が指定されたことになります。
Pygmentsパーサーを利用する場合はラベルに `pygments` を指定してください。
なお、このファイルで `tc=` というのは 他の定義をその場に読み込むというような意味です。

[^2]: パスは環境により読み替えてください。Mac の Homebrew では `/usr/local/etc/gtags/gtags.conf`、Linux では `/usr/local/share/gtags/gtags.conf` となることが多いです。

実行例
------

    $ cat hello.rb
    class Hello
      def hello
        puts message
      end
    
      def message; 'hello, world'; end
    end
    $ gtags --gtagslabel=pygments
    $ 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

定義タグと参照タグがそれぞれ検索できていることがわかります。


トラブルシューティング
======================

プラグインパーサーが呼ばれていることの確認
------------------------------------------

`gtags` に `--debug` オプションを与えることで、対象のファイルに対してプラグインパーサーが呼ばれているかどうかを確認することができます。

    $ gtags --debug
    .....
    File './hello.rb' is handled as follows:
    suffix:   |.rb|
    language: |Ruby|
    parser:   |parser|
    library:  |/usr/local/lib/gtags/pygments-parser.la|
    .....

拡張子 `.rb` の `hello.rb` が Ruby 言語と判断され、`pygments-parser` が呼ばれていることがわかります。

もしここで期待するプラグインパーサーが呼ばれていない場合は、

- インストールの手順が正しいか？
- 設定ファイルの内容が正しいか？

などを確認するとよいでしょう。

タグが生成されていることの確認
------------------------------

`gtags` に `-d` オプションとタグファイル名を与えることで、タグファイルの内容をダンプすることができます。

    $ gtags -d GTAGS
     __.COMPNAME     __.COMPNAME
     __.COMPRESS     __.COMPRESS ddefine ttypedef
     __.VERSION      __.VERSION 6
    Hello   1 @n 1 class @n
    hello   1 @n 2 def @n
    message 1 @n 6 def @n; 'hello, world'; end

    $ gtags -d GRTAGS
     __.COMPACT      __.COMPACT
     __.COMPLINE     __.COMPLINE
     __.COMPNAME     __.COMPNAME
     __.VERSION      __.VERSION 6
    Hello   1 @n 9
    h       1 @n 9-1
    hello   1 @n 10
    message 1 @n 3
    new     1 @n 9
    puts    1 @n 3

先頭の数行は管理データですが、それ以降は各行の先頭のフィールドがタグになっています。
`GTAGS` には定義タグが、`GRTAGS` にはシンボルタグが格納されています。

`GTAGS`、`GRTAGS` にそれぞれ期待するタグが生成されているかどうかを確認し、生成されていない場合は、

- (`GTAGS`に期待するタグが生成されていない場合) ctags がインストールされているか？
- Pygments が正しくインストールされているか？

などを確認するとよいでしょう。

Tips
====

ビルトインパーサーと併用する
----------------------------

Pygmentsパーサーは遅いので、ビルトインパーサーが対応しているファイルについてはビルトインパーサーで処理し、残りをPygmentsパーサーで処理するように設定しておくのがおすすめです。
また同時に、環境変数 `GTAGSLABEL` や `--gtagslabel` オプションを設定しなくてもPygmentsパーサーが機能するようにします。

設定ファイルを `~/.globalrc` という名前でコピーします。

    $ cp /usr/local/etc/gtags/gtags.conf ~/.globalrc    # gtags.conf の場所は環境により読み替えてください

`~/.globalrc` を編集します。

    default:\
            :tc=native:
    ↓
    default:\
            :tc=native:tc=pygments:

これにより、環境変数 GTAGSLABEL や `--gtagslabel` オプションを設定しなくてもPygmentsパーサーが機能するようになります。
さらに、ビルトインパーサーが処理できるファイルに対してはビルトインパーサーが優先的に利用されるようになります。


おわりに
========

正確さに欠ける、遅い、など欠点もありますが、1回設定すれば多くの言語に対応できるPygmentsパーサーは GNU GLOBAL ユーザーの方には便利に使って頂けるのではないかと思います。
使ってみてのフィードバックなど頂けると幸いです。