anythingでgitリポジトリ内のファイルを列挙するなんていうのはやり尽くされている気がするけれど, きちんとやっているものは意外と少なかったので, フルスクラッチで書いた.
特徴
- 現在開いているファイルと同一のgitリポジトリ内のファイルを列挙する
- サブモジュール内のファイルも列挙できる
- 列挙し直さなくていい場合は前に列挙した結果を使い回す
- ファイルの列挙のための
git
コマンドの呼出しは非同期にやる git
コマンドのエラー処理をきちんとしている
配布場所とインストール
インストールするには(helmではなく)anythingを入れた上で, anything-git-files.elをロードパスの通ったところに置く. el-getを使っている場合は以下のレシピを書いてel-get-install RET anything-git-files RET
するのが簡単.
(:name anything-git-files :type github :pkgname "tarao/anything-git-files-el" :depends anything)
設定と使い方
設定ファイルで
(require 'anything-git-files)
とすると, M-x anything-git-files
でgitリポジトリ内のファイルを列挙できるようになる. デフォルトでは, 現在のリポジトリとそのサブモジュールについてそれぞれ, 変更のあったファイル, リポジトリで管理していないファイル, リポジトリ内の全ファイルを列挙する.
列挙に使う情報源を変更したい場合(anythingの他の情報源と組み合わせたい場合など)には, anything-git-files:modified-source
, anything-git-files:untracked-source
, anything-git-files:all-source
を情報源として指定する. サブモジュールについてはanything-git-files:submodule-sources
関数を(anything-git-files:submodule-sources '(modified untracked all))
のように呼び出すと, 情報源のリストが返ってくる.
これらの情報源を使う場合は, gitリポジトリにいないとエラーになるので, 適宜anything-git-files:git-p
関数でgitリポジトリにいるかどうかチェックするとよい.
gitリポジトリ情報源と他の情報源を組み合わせた関数の例:
(defun tarao/anything-for-files () (interactive) (require 'anything-config) (require 'anything-git-files) (let* ((git-source (and (anything-git-files:git-p) `(anything-git-files:modified-source anything-git-files:untracked-source anything-git-files:all-source ,@(anything-git-files:submodule-sources 'all)))) (other-source '(anything-c-source-recentf anything-c-source-bookmarks anything-c-source-files-in-current-dir+ anything-c-source-locate)) (sources `(anything-c-source-buffers+ anything-c-source-ffap-line anything-c-source-ffap-guesser ,@git-source ,@other-source))) (anything-other-buffer sources "*anything for files*")))
参考にしたやり方
最初のうちはid:yaotti作, id:shiba_yu36改のものをさらに改良したanything-git-project.elを使っていた. しばらく使ってみて, たまにgitコマンドがエラーになったときの挙動がおかしいような気がしたり, id:mechairoiのanything-git-ls-files.elがサブモジュール内のファイルも列挙できてうらやましくなったりした.
そこでanything-git-project.elを手直ししながらanything-git-ls-files.elの機能を取り込もうと思って実装の詳細を見てみたところ, どちらも毎回git ls-files
していて非効率なのが気になった. まず, どちらの実装でもcandidates-in-buffer
しているので, git ls-files
の結果をどこかのバッファに保持している. 本来はgit status
の出力に変化がない限りgit ls-files
しなおす必要はなく, 前に出力した内容を使い回せる. git status
の結果のハッシュ値をリポジトリルートに関連づけて覚えておくことで, ファイルを実際に列挙する回数は大幅に減らすことができる.
細かいところとしては, vc-git.elのvc-git-command
関数を使えばエラー処理なども適切にやってくれるし, --no-pager
も自動的につけてくれるので, git
コマンドはすべてvc-git-command
経由でやるのがよい.
この辺りのことをanything-git-project.elに組込もうとすると, いちから書いた方が早そうだったので, フルスクラッチで実装した.
追記
現状は 済(8f19c87)secure-hash
関数を使っているのでEmacs 24以降でしか動かないはず. SHA-1をとっているだけなので, secure-hash
がなければsha1
関数を使うようにすれば古いEmacsでも動くと思うのでそのうち直す.
追記(2013-05-02T16:17+0000)
git ls-files
を非同期に実行するバージョンをこつこつと開発していたのが安定してきたのでマージした.