前回に引き続き Emacs + ag (The Silver Searcher) ネタです。howm で ag を使えるようにしてみました。
howm (一人お手軽 Wiki もどき)というメモ書きツール、今どれだけ使っている人がいるでしょう?一時期話題になり、雑誌などでも特集が組まれるほど盛り上がっていましたが、ここ数年サポートすら行なわれているのか分からないような状況です。ブログなどでも取り上げられることはほとんどありません。Emacs のパッケージリポジトリに登録されるでもなく、野良アプリとしてですが、今でもダウンロードはできるようになっていますが。
しかし私にとってメモ書きツールとして今でも無くてはならない存在です。howm のいい所は特定のフォーマットを規定している訳ではなく、単なるテキストファイルを扱う「マイナーモード」なので、他のメジャーモードと組み合わせて使うことができる点です。単なるテキストファイルなので、例え howm の使用を止めても今までのメモが無駄になることもありません。ドキュメントにも書かれているように、いつでも宗旨変えをすることができます。といいつつ、org-mode + howm の組合せで私は約10年もメモを書き溜めています。
howm にはデフォルトで elisp による検索と外部コマンドの grep を使って検索する機能があります。メモが少ないうちは elisp 検索で事足りますが、そのうち grep を使うようになり、更に grep でも遅く感じるようになる、というのが howm ユーザが通る道です。そこで ag の登場です。
ag を使う上で問題になることが
ここ で少しだけ述べられています。ag は検索対象ファイルが唯一つだけだった場合、出力結果にファイル名を表示してくれないのです。これさえ何とかなれば使えそうです。
何だそんなことか、という気がしました。実はこれ、昔の grep にも同じ問題がありました。なので当時 Emacs から grep を呼び出す場合何をやっていたかというと、検索対象に常に /dev/null を追加して、強制的に二つ以上のファイル検索になるようにしていたのです。(ちなみに今の grep には -H というオプションがあり、これは必要ありません。) しかしこれがまた Windows では問題になり、使う grep によっては、そんなファイルないよエラーが出たりしたものです。
基本的に同じ方法を使ってみようと思いますが、grep でやっていたように何がなんでも常に /dev/null を追加するというのも芸が無いので、ファイルが一つだけだった場合のみ追加するという風にしてみます。
howm のソースコードを見てみると grep にハードコードされているわけではなく、変数設定で他のコマンドも使えるようになっています。この辺は設計者様に感謝です。
今回も Emacs24.4 から使えるようになった nadvice.el を使いました。旧来の defadvice を使った方法も載せておきますので、古い Emacs を使っている場合はコメントアウトされている方のコードを使ってください。
私の環境は以下の通りです。
- Windows10 Pro x64
- NTEmacs 24.5.1
- ag on Cygwin64
ag にはパスを通しておいてください。また Windows 環境では Cygwin 意外の ag では使えないと思います( /dev/null を認識しないので)。
以下、設定コードです。先頭の howm-process-coding-system の設定は Windows を前提としたものなので、Mac や Linux では削除してください。たぶんそれ意外はそのまま使えると思います。
- (setq howm-process-coding-system '(utf-8-dos . cp932-unix))
- (setq howm-view-use-grep t)
- (setq howm-view-grep-command "ag")
- (setq howm-view-grep-option "--nocolor --nogroup")
- (setq howm-view-grep-extended-option nil)
- (setq howm-view-grep-fixed-option "-F")
- (setq howm-view-grep-expr-option nil)
- (setq howm-view-grep-file-stdin-option nil)
- ;; 検索対象が単一ファイルだった場合、/dev/null を追加する
- ;; nadvice を使った実装 (Emacs 24.4 からの機能)
- (defun add-devnull (args)
- (let ((str (car args)) ;; 検索文字列
- (files (nth 1 args))) ;; ファイルリスト
- (when (= 1 (length files)) ;; 単一ファイル?
- (if (file-regular-p (car files)) ;; 通常ファイル?
- ;; 単一の通常ファイルが指定された場合に /dev/null を追加
- (setq files (append files '("/dev/null"))))
- )
- (list str files)))
- (advice-add 'howm-real-grep-single :filter-args #'add-devnull)
- ;; 検索対象が単一ファイルだった場合、/dev/null を追加する
- ;; (defadvice howm-real-grep-single (before single-file-modifier activate)
- ;; "If argument parameter specifies single file, then add /dev/null."
- ;; (let ((arg-files (ad-get-arg 1))) ;; 第二引数
- ;; (when (= 1 (length arg-files)) ;; 単一ファイル?
- ;; (if (file-regular-p (car arg-files)) ;; 通常ファイル?(ディレクトリでなく)
- ;; (progn
- ;; (setq arg-files (append arg-files '("/dev/null"))) ;; /dev/null を追加
- ;; (ad-set-arg 1 arg-files) ;; 元の関数に引数をセット
- ;; ))))
- ;; )
-