理系学生日記

おまえはいつまで学生気分なのか

gitリポジトリの中のファイルをhelmインタフェースで検索する

Emacs バッファの中で、他のファイルに検索をかけて、検索結果一覧のバッファから直接ファイルの内容を更新するというタイプの拡張というのがいくつかあって、moccur-edit.el だったり、wrep.el だったりです。

しかし、こういうときの検索あるいは編集する対象のファイルというのは、そのときのコンテキストに依存します。そしてそのコンテキストの多くは「xx ディレクトリ配下の全ファイル」というよりは、「xx プロジェクトの全ファイル」だったりするでしょう。 そういう拡張ってあったよなー何だったかなーと思ってさがしていたら、helm-eg を見つけました。 見つけたというよりは、もともとロードしていたんだけれど、そういう使い方をできるということを知らなかった。

helm-ag

helm-eg はみんな大好き helm のインタフェースで The Silver Searcher という検索ツールを使用して検索結果一覧を出すというのが主な用途なのですが、The Silver Searcher (これをよく ag と呼びます) だけでなく、検索ツールとして grep だったり、ack だったりを使用することもできる、汎用の検索ツールとして使うことができます。

基本的には、grep とかと同じく「このディレクトリ以下のファイル」という検索になるんですが、今日見つけることができたのは helm-ag-project-root

現在バッファで開いているファイルの存在するディレクトリから親ディレクトリを辿って .git.hg 等の存在するフォルダを探し、そのフォルダ配下の全ファイルを検索対象にすることができます。

;;;###autoload
(defun helm-ag-project-root ()
  (interactive)
  (let ((rootdir (helm-ag--project-root)))
    (unless rootdir
      (error "Could not find the project root. Create a git, hg, or svn repository there first. "))
    (helm-ag rootdir)))

(defun helm-ag--project-root ()
  (cl-loop for dir in '(".git/" ".hg/" ".svn/" ".git")
           when (locate-dominating-file default-directory dir)
           return it))

これにキーバインドを設定しておけば、効率は一段とあがって良さそうです。

(global-set-key (kbd "M-p") 'helm-ag-project-root)

隠しファイルも検索対象にする

で、便利に使おうと思っていたら困った事象が、. から始まるいわゆる隠しファイル、隠しディレクトリが検索対象から外されてしまうことです。 これ、elisp を見ながら「そういう実装なんてないけどなー」と思っていたら、ag コマンドの仕様でした。 ag コマンドでは何も指定しないと隠しファイル/ディレクトリは対象外となってしまうため、--hidden オプションを追加する必要があります。

$ ag -h | grep -C 1 'Search hidden file'
  -G --file-search-regex  PATTERN Limit search to filenames matching PATTERN
     --hidden             Search hidden files (obeys .*ignore files)
  -i --ignore-case        Match case insensitively

elisp からオプションを設定することは可能なので、このような場合は、

(setq helm-ag-command-option "--hidden")

と設定すれば良いでしょう。