LoginSignup
27
9

More than 5 years have passed since last update.

GNU GLOBALでgolangの関数呼び出し行にタグジャンプする

Posted at

godefで定義元には飛べますが、関数の呼び出し箇所にも飛べると便利です。
というわけで、golangでGLOBAL互換のタグを生成するツールをつくりました。
https://github.com/juntaki/gogtags

インストール方法

コマンド分はこれだけです。

$ go get github.com/juntaki/gogtags

生成されたタグの参照にはsqlite3対応のGNU GLOBALが必要です。--with-sqlite3のオプションを付けてビルドします。
https://www.gnu.org/software/global/

$ ./configure --with-sqlite3
$ make
$ sudo make install

使いかた

カレントディレクトリでタグ生成します。オプション-vをつけると解析したファイル名を出力します。

$ cd <target directory>
$ gogtags -v

gogtags_screenshot1.gif

生成されたタグを参照するときは普通の使い方でOKです。globalコマンドの出力を使うエディタの拡張は、GTAGSなどのファイル形式は変わっても影響ありません。(helm-gtagsは大丈夫でした)

gogtags_screenshot.gif

他の方法もある

GNU GLOBALの対応言語を大幅に増やすPygmentsパーサーを導入する」の方法があることは知っていました。が、使うにはいろいろ下準備が必要そうなのと、「抽象構文木(AST)をトラバースする #golang」、「ASTを取得する方法を調べる #golang」をみたら、golangだけで簡単にできそうなことが分かったので作ってみました。

Golang用のctags-compatibleの実装はすでにありました。GLOBALなのに世界的にはマイナーなのでしょうか。

参考:GNU GLOBALのフォーマット

フォーマットの説明はソースコードのコメントが一番詳しかったです。これはformat version 6の説明で、Standard formatがGTAGS用、Compact formatがGRTAGS用です。
データベースはデフォルトでBerkeley DBが選択され、最近のバージョンだとsqlite3が使えるようになっています。また、GSYMSは5.9から作られなくなっています(関数呼び出し以外のシンボルの情報もGRTAGSに含まれています)。

libutil/gtagsop.c
 * [Specification of format version 6]
 *
 * Standard format:
 *
 *  This format is the default format of GTAGS.
 *
 *         <file id> <tag name> <line number> <line image>
 *
 *                 * Separator is single blank.
 *
 *         [example]
 *         +------------------------------------
 *         |110 func 10 int func(int a)
 *         |110 func 30 func(int a1, int a2)
 *
 *         Line image might be compressed (GTAGS_COMPRESS).
 *         Tag name might be compressed (GTAGS_COMPNAME).
 *
 * Compact format:
 *
 *  This format is the default format of GRTAGS.
 *  It is used for GTAGS with the -c option.
 *
 *         <file id> <tag name> <line number>,...
 *
 *                 * Separator is single blank.
 *
 *         [example]
 *         +------------------------------------
 *         |110 func 10,30
 *
 *         Line numbers are sorted in a line.
 *     Each line number might be expressed as difference from the previous
 *     line number except for the head (GTAGS_COMPLINE).
 *           ex: 10,3,2 means '10 13 15'.
 *     In addition,successive line numbers are expressed as a range.
 *           ex: 10-3 means '10 11 12 13'.

gtagsで生成したsqlite3のフォーマットの解析

これをgtags --sqlite3してみます。

main.c,main2.c
     1  #include<stdio.h>
     2
     3  int a = 1;
     4
     5  int func1(){
     6    int a = 100;
     7    printf("%d", a);
     8    return 1;
     9  }
    10
    11  int main(){
    12    int a = 10;
    13    printf("%d", a);
    14    a = func1();
    15    return 0;
    16  }

仕様にはなかったですが、タグ名の文字列が@nで置換されています。また、行イメージの前後の空白は除去するようです。
GTAGSには関数の定義が含まれていて、datカラムがformat version6に従って格納されています。keyはタグ名でextraはファイルIDのようです。型は全部textでした。

GTAGS
juntaki@ubuntu ~/g/g/test> sqlite3 -header -column GTAGS "select * from db;"
key           dat                            extra
------------  -----------------------------  ----------
 __.COMPRESS   __.COMPRESS ddefine ttypedef
 __.COMPNAME   __.COMPNAME
 __.VERSION    __.VERSION 6
func1         1 @n 5 int @n(){               1
main          1 @n 11 int @n(){              1
func1         2 @n 5 int @n(){               2
main          2 @n 11 int @n(){              2

GRTAGSには関数呼び出しと変数の定義、参照が含まれています。

GRTAGS
sqlite> select * from db;
key              dat              extra
---------------  ---------------  ----------
 __.COMPACT       __.COMPACT
 __.COMPLINE      __.COMPLINE
 __.COMPNAME      __.COMPNAME
 __.VERSION       __.VERSION 6
a                1 @n 3,3-1,5-2   1
func1            1 @n 14          1
printf           1 @n 7,6         1
a                2 @n 3,3-1,5-2   2
func1            2 @n 14          2
printf           2 @n 7,6         2

ファイルIDからファイル名と、その逆のエントリがあります。
GPATHはバージョンが独立しているようです。

GPATH
juntaki@ubuntu ~/g/g/test> sqlite3 -header -column GPATH "select * from db;"
key          dat            extra
-----------  -------------  ----------
 __.VERSION   __.VERSION 2
./main.c     1
1            ./main.c
./main2.c    2
2            ./main2.c
 __.NEXTKEY  3
27
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
9