ctags-update 20170120.2313(in MELPA)
(auto) update TAGS in parent directory using exuberant-ctags

概要

Exuberant ctags は昔からある多言語に対応したタグファイル生成ツールです。

タグファイルを使えばM-.で関数定義・クラス定義などに
一発でジャンプすることができて便利です。

Emacs内部でも imenu などを使えば同じようなことができますが、
大きなプロジェクトになるとどうしても重くなってしまいます。

一方、タグファイルによる方法は高速ですが、
ファイルの内容と一致させる必要があります。

ファイルを保存したら、その都度タグファイルも更新する必要があります。

この欠点を克服するのが ctags-update.el です。

M-x ctags-auto-update-mode を有効にすると、
after-save-hookctags-update が登録され、
ファイル保存時に自動的にタグファイル更新を行ってくれます。

タグファイルが存在しないときは、
tags-table-listtags-file-name もチェックします。

インストール

パッケージシステムを初めて使う人は
以下の設定を ~/.emacs.d/init.el の
先頭に加えてください。

(package-initialize)
(setq package-archives
      '(("gnu" . "http://elpa.gnu.org/packages/")
        ("melpa" . "http://melpa.org/packages/")
        ("org" . "http://orgmode.org/elpa/")))

初めてctags-updateを使う方は
以下のコマンドを実行します。

M-x package-install ctags-update

アップグレードする方は、
以下のコマンドでアップグレードしてください。
そのためにはpackage-utilsパッケージが必要です。

M-x package-install package-utils (初めてアップグレードする場合のみ)
M-x package-utils-upgrade-by-name ctags-update

5分ごとに更新!

侮るなかれ!

このctags-update.elは賢くてよく作り込まれています。

auto-save-buffers-enhanced.el(レビュー)
real-auto-save.el(レビュー) でファイル自動保存をしていると
自動保存のたびにctagsが実行されて重くなるのでは?

という心配がありますが、大丈夫!

タグファイルのタイムスタンプを見て5分前よりも古い場合のみ
ctagsを実行してくれるように計らってくれます。

もちろんctagsは start-process による非同期実行なので
ctags実行中にEmacsが固まる心配もありません。

それにEmacsのタグジャンプ自体賢いので
タグファイルが多少古くてタグファイルで指し示されている行と
実際の行が異なる場合もずれずに正しくジャンプしてくれます。

よって、5分ごとに更新するという挙動は的を射ています。

おまけにWindows用のコードも記述されているので
Windowsでも安心して使えます。

手動でも呼べる

自動更新なのでいつもは放ったらかしでもタグファイルを更新してくれますが、
M-x ctags-update は手動でも呼べます。

手動で呼んだ場合、タイムスタンプのチェックをせずにタグファイルを更新します。

C-u M-x ctags-update は新しくタグファイルを作成します。

C-u C-u M-x ctags-update はタグファイル更新のシェルコマンドを
kill-ringに入れます。

実際にC-u C-uをつけて実行してみるとわかるように、
ctagsに適切なオプションが付けられています。

オプションは ctags-update-other-options で設定します。

cd /r/src/foo/ && ctags -R -e --fields=+iaSt --extra=+q −−c++−kinds=+p \\
--exclude='*.elc' --exclude='*.class' --exclude='.git' --exclude='.svn' \\
--exclude='SCCS' --exclude='RCS' --exclude='CVS' --exclude='EIFGEN' .

メカニズム

タグファイルのようにソースコード(本文)の内容に伴って
更新されるファイルを自動更新したい場合、
ctags-update.elのように自動更新に遅延をつけるといいです。

コードから抜粋します。

参考になれば幸いです。

(defun ctags-update(&optional args)
  (interactive "P")
  (let (tags-filename process)
    (when (or (and args (setq tags-filename
                              (expand-file-name
                               "TAGS" (read-directory-name "Generate new TAGS to directory:" ))))
              (and (not (get-process "update TAGS"));;if "update TAGS" process is not already running
                   ;; ここがキモ!
                   (or
                    ;; 手動で呼ばれたか
                    (called-interactively-p 'interactive)
                    ;; 更新時間のチェック!!!
                    (> (- (float-time (current-time)) ;現在時刻
                          ctags-update-last-update-time) ;最後に更新された時刻
                       ctags-update-delay-seconds)) ;300秒
                   (setq tags-filename (ctags-update-find-tags-file))
                   (not (and (buffer-file-name)
                             (string-equal (ctags-update-file-truename tags-filename)
                                           (ctags-update-file-truename (buffer-file-name)))
                             ))))
      ;; ここで更新時刻を設定
      (setq ctags-update-last-update-time (float-time (current-time)))
      本処理)))

(define-minor-mode ctags-auto-update-mode
  "auto update TAGS using `exuberant-ctags' in parent directory."
  :lighter ctags-update-lighter
  :keymap ctags-auto-update-mode-map
  ;; :global t
  :init-value nil
  :group 'ctags-update
  (if ctags-auto-update-mode
      (progn
        ;; バッファローカルなafter-save-hookに設定!!
        (add-hook 'after-save-hook 'ctags-update nil t)
        (run-hooks 'ctags-auto-update-mode-hook))
    (remove-hook 'after-save-hook 'ctags-update t)))

設定 150429051838.ctags-update.el(以下のコードと同一)

;;; 注意!exuberant-ctagsを指定する必要がある
;;; Emacs標準のctagsでは動作しない!!
(setq ctags-update-command "/usr/bin/ctags")
;;; 使う言語で有効にしよう
(add-hook 'c-mode-common-hook  'turn-on-ctags-auto-update-mode)
(add-hook 'emacs-lisp-mode-hook  'turn-on-ctags-auto-update-mode)

実行方法

$ wget http://rubikitch.com/f/150429051838.ctags-update.el
$ emacs -Q -f package-initialize -l 150429051838.ctags-update.el

本サイト内の関連パッケージ


本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。