コードリーディングにとっても便利な GNU GLOBAL と gtags.el (と anything-gtags.el) をつかおう

  • 64
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

はじめに

全国 1000 万人の emacs ユーザのみなさんこんにちは。

お題とは全く関係ないですが、今年のテキストエディタ界隈の検索トレンドを見てみました。

trend
リンクはこちら

Sublime Textが伸びていますね。
ちなみに Sublime Text 2 の拡張は Python で書くそうです。
全くの余談ですが Emacs ユーザのための Sublime Text 2 の紹介スライドがこちらです。
完全に蛇足ですが Sublime Text 2 の API リファレンスはこちらです。

さて

コードリーディングに便利なGNU GLOBALと、それを emacs から使うための gtags.el 、及びさらに便利に使うための anything-gtags.elについて書きたいと思います。

GNU GLOBAL

GNU GLOBAL はソースコードタグ付けシステムです。
C, C++, Yacc, Java, PHP, アセンブリに対応しているそうです。

GNU GLOBAL について調べようと思って「GLOBAL」で検索しても、
包丁の製造会社やおしゃれなアパレルサイトがヒットしがちなので気をつけましょう。

gtags.el

GNU GLOBAL に同梱されている、emacs から GLOBAL の機能を使うための elisp です。

が、最新の GNU GLOBAL に同梱の gtags.el は、
global-client というスクリプトに依存していたり(Windows だと動かない)、TRAMP とうまく動かなかったりしたので、
voins/gtags · GitHubを使います。

anything-gtags.el

るびきちさんお手製の、gtags.el を anything インタフェースで使えるようにする elisp です。

が、TRAMP 環境でちょっと困る部分があるので少し手を入れます。

使用イメージ

ニコ動に使用イメージの動画を上げてみました。
ちなみにタイマー公開機能を使いました。

http://www.nicovideo.jp/watch/sm19546665

やってみよう

GNU GLOBAL を導入する

Getting GLOBALにあるとおりですが、
make できる環境の方はソースを落として ./configure & make & make install してください。
Windows の方はここからバイナリを落として、パスの通った場所に置くのが楽です。

あとは global --version とかで動くのを確認しましょう。

gtags.el を導入する

先程も書きましたが、同梱の gtags.el ではなく、
voins/gtags · GitHubを使います。

M-x auto-install-from-url https://raw.github.com/voins/gtags/master/gtags.el

なりなんなりで入れましょう(適当)。

anything-gtags.el を導入する

auto-install-from-emacs-wiki で anything-gtags を探して入れましょう。

先程も書きましたが、TRAMP と一緒に使うとちょっと上手くないので、
以下のように編集します。

--- a/anything-gtags.el 2012-12-10 02:34:04.037695300 +0900
+++ b/anything-gtags.el 2012-12-10 02:33:27.235754100 +0900
@@ -225,7 +225,7 @@
          (gtags-select-buffer buffer)
          (anything-candidate-number-limit 9999)
          (bfn (with-current-buffer c-source-file buffer-file-name))
-         (pwd (with-current-buffer gtags-select-buffer (file-name-directory bfn)))
+         (pwd (with-current-buffer gtags-select-buffer (gtags-get-rootpath)))
          (basename (substring bfn (length pwd)))
          (lineno (with-current-buffer c-source-file
                    (save-restriction

.elsp なりなんなりを編集する

所々の設定を有効化するために以下を追記します。

(setq gtags-prefix-key "\C-c")
(require 'gtags)
(require 'anything-gtags)
;; キーバインド
(setq gtags-mode-hook
      '(lambda ()
         (define-key gtags-mode-map "\C-cs" 'gtags-find-symbol)
         (define-key gtags-mode-map "\C-cr" 'gtags-find-rtag)
         (define-key gtags-mode-map "\C-ct" 'gtags-find-tag)
         (define-key gtags-mode-map "\C-cf" 'gtags-parse-file)))
;; gtags-mode を使いたい mode の hook に追加する
(add-hook 'c-mode-common-hook
          '(lambda()
             (gtags-mode 1)))

これで gtags.el を使う準備が整いました。

もう少し便利にする

以上で基本的には終わりなのですが、
さらに便利に使えるようにする方法を紹介したいのでもう少しだけお付き合いください。

GTAGS を自動で更新する

GTAGS は自動では更新されませんので、なんとかして更新する必要があります。

例えば、crontab 等に登録してしまうのもひとつの手です。
毎分更新するようにしておけばそうそう困らないでしょう。

他には、保存するたびに GTAGS を更新するようにする手があります。

;; update GTAGS
(defun update-gtags (&optional prefix)
  (interactive "P")
  (let ((rootdir (gtags-get-rootpath))
        (args (if prefix "-v" "-iv")))
    (when rootdir
      (let* ((default-directory rootdir)
             (buffer (get-buffer-create "*update GTAGS*")))
        (save-excursion
          (set-buffer buffer)
          (erase-buffer)
          (let ((result (process-file "gtags" nil buffer nil args)))
            (if (= 0 result)
                (message "GTAGS successfully updated.")
              (message "update GTAGS error with exit status %d" result))))))))
(add-hook 'after-save-hook 'update-gtags)

こんな elisp をぺろりと .emacs あたりに追記しておくと、
保存するたびに gtags がインクリメンタル更新されます。

一応、interactive に呼べるようにしてあるので手動更新も可能です。
C-u M-x update-gtags という風に呼び出すと、インクリメンタルではなくフル更新します。

gtags の実行結果は *update GTAGS* というバッファに書かれます。

カレントバッファのメソッド一覧を見る

gtags-parse-file という関数で指定ファイルのメソッド定義一覧が見られるのですが、
いちいちファイル名を指定する必要があります。

また、TRAMP 環境でうまく動かない場合があります。

そのへんの問題を解決したのが以下の関数です。

(defun gtags-parse-file2 ()
  (interactive)
  (if (gtags-get-rootpath)
      (let*
          ((root (gtags-get-rootpath))
           (path (buffer-file-name))
           (gtags-path-style 'root)
           (gtags-rootdir root))
        (if (string-match (regexp-quote root) path)
            (gtags-goto-tag
             (replace-match "" t nil path)
             "f" nil)
          ;; delegate to gtags-parse-file
          (gtags-parse-file)))
    ;; delegate to gtags-parse-file
    (gtags-parse-file)))

これを gtags-parse-file の代わりに使うと、
カレントバッファのメソッド一覧を一発で出してくれます
(なんか上手くいかないときは gtags-parse-file を呼び出します)。

終わりに

GNU GLOBAL, gtags.el, anything-gtags.el について紹介してきました。
ソースコードリーディングには欠かせないツールだと思います。

拙い文章を最後までお読みいただき、ありがとうございました。

間違いや質問等がありましたらコメントにてお願いいたします。
他にももっと良いやり方があるよ!等のコメントもお待ちしております。

来年も Sublime Text 2 から目離せません。

この投稿は Emacs Advent Calendar 201211日目の記事です。