GNU GLOBAL on Emacsのタグ候補選択バッファで現在のファイル・行のエントリを示す

GNU GLOBALは内蔵grepでシンボルを全文検索できるが、候補選択バッファ(*GTAGS SELECT*)では現在のファイルを指し示してくれれば見易くてうれしい。もし、候補が現在行あるならば、そのエントリを指してほしい。

たとえば候補選択バッファの内容が以下であるような場合、

undef             969 /m/home/nobackup/compile/ruby19/array.c            if (rpl =
undef            1794 /m/home/nobackup/compile/ruby19/array.c           rb_ary_spl
undef            2451 /m/home/nobackup/compile/ruby19/array.c            return Qu
undef            2483 /m/home/nobackup/compile/ruby19/array.c            if (v !=
undef             696 /m/home/nobackup/compile/ruby19/bignum.c       #undef MASK_0
undef             697 /m/home/nobackup/compile/ruby19/bignum.c       #undef MASK_3
undef             698 /m/home/nobackup/compile/ruby19/bignum.c       #undef MASK_5
undef             145 /m/home/nobackup/compile/ruby19/blockinlining.c
undef             174 /m/home/nobackup/compile/ruby19/blockinlining.c
undef             199 /m/home/nobackup/compile/ruby19/blockinlining.c       if (va
undef             207 /m/home/nobackup/compile/ruby19/blockinlining.c     return Q
undef             245 /m/home/nobackup/compile/ruby19/blockinlining.c
undef             274 /m/home/nobackup/compile/ruby19/blockinlining.c
undef             318 /m/home/nobackup/compile/ruby19/blockinlining.c       if (va

ソースコードのポイントがbignum.cの10行目にある場合はbignum.cの最初のエントリ

undef             696 /m/home/nobackup/compile/ruby19/bignum.c       #undef MASK_0

を示してほしいし、bignum.cの698行目にある場合はその行のエントリ

undef             698 /m/home/nobackup/compile/ruby19/bignum.c       #undef MASK_5

を示してほしい。

ソースコードが多数にわたるプロジェクトの場合、そうしてくれないと本当に困る。いちいち現在のファイル名のエントリを手作業で探すなんて我慢できない。

この問題は、以下のコードで解決する。見やすいバージョンにも対応している。

(defun gtags-current-line ()
  (save-excursion
    (save-restriction
      (widen)
      (forward-char 1)
      (count-lines (point-min) (point)))))
  
(defadvice gtags-goto-tag (around show-current-position activate)
  "Point to the entry of current file/line."
  (let ((bfn buffer-file-name)
        (curline (gtags-current-line)))
    ad-do-it
    (when (and bfn (eq major-mode 'gtags-select-mode))
      (let ((path (if (looking-at "[^ \t]+[ \t]+[0-9]+[ \t]/[^ \t]+[ \t]")
                      bfn
                    (file-relative-name bfn))))
        (and (or (re-search-forward (format "%d[ \t]+%s" curline (regexp-quote path)) nil t)
                 (search-forward path nil t))
             (beginning-of-line))))))

追記

narrowing関連のバグを修正。