$shibayu36->blog;

株式会社はてなでエンジニアをしています。プログラミングや読書のことなどについて書いています。

anything-git-project.elを少し手直ししてみた

 id:yaottiさんが作っているanything-git-project.el(プロジェクト内のファイルを絞り込んで操作するanything-git-project.el - yaotti's diary)ですが、gitでproject管理している人にとってはすごく便利です。
 ただ、一つだけ不満がありました。

  • 現在のディレクトリからの相対パスが出てしまう
    • ../../とかあんまり見たくない

 そこでちょっとだけ手直ししてみました。

chomp

 elisp触ってるとchompが欲しいけど無い、みたいな状況に出会います。そこで以下の関数をユーティリティとして定義しておくと良いと思います。今回の手直しではこれを使ってるので、適当にどこかで定義しておいてください。

(defun chomp (str)
  (replace-regexp-in-string "[\n\r]+$" "" str))

変更したもの

(defun anything-git-project-project-dir ()
  (chomp
   (shell-command-to-string "git rev-parse --show-toplevel")))

(defun anything-c-sources-git-project-for ()
  (loop for elt in
        '(("Modified files (%s)" . "--modified")
          ("Untracked files (%s)" . "--others --exclude-standard")
          ("All controlled files in this project (%s)" . ""))
        collect
        `((name . ,(format (car elt) (anything-git-project-project-dir)))
          (init . (lambda ()
                    (unless (and ,(string= (cdr elt) "") ;update candidate buffer every time except for that of all project files
                                 (anything-candidate-buffer))
                      (with-current-buffer
                          (anything-candidate-buffer 'global)
                        (insert
                         (shell-command-to-string
                          ,(format "git ls-files --full-name $(git rev-parse --show-cdup) %s"
                                   (cdr elt))))))))
          (candidates-in-buffer)
          (display-to-real . (lambda (name)
                               (format "%s/%s"
                                       (anything-git-project-project-dir) name)))
          (type . file))))

(defun anything-git-project ()
  (interactive)
  (let* ((sources (anything-c-sources-git-project-for)))
    (anything-other-buffer sources
                           (format "*Anything git project in %s*"
                                   (anything-git-project-project-dir)))))

 これを使えば以下のように../とかの相対パスではなく、project rootからの相対パスで表示され、移動することができます。以下のような感じ
f:id:shiba_yu36:20121222132735p:plain

いくつかの技術的tips

gitでprojectのrootディレクトリを取得する

これは簡単で

git rev-parse --show-toplevel

を実行すれば良いです。最後に改行文字が入ってくるので注意。

gitで管理されているファイルをrootからの相対パスで取得する

これも簡単で

git ls-files --fullname

としてやれば取得できます。

更に今回はどのディレクトリにいても全ファイル必要なので

git ls-files --full-name $(git rev-parse --show-cdup)

としてあげます。

show-cdupは現在のディレクトリからrootディレクトリまでの相対パスをくれます。../../みたいなやつ。

anything上で見えているものと実行するものを変える

 今回現在のディレクトリからの相対パスではなく、project rootからの相対パスを表示するようにしたため、anythingのtype fileでそのまま実行しようとすると違うファイルが選択されてしまいます。そこでanythingのdisplay-to-realを利用して、絶対パスへの書き換えを行なってあげます。
 以下の部分が該当しているところ。anything-git-project-project-dirが現在のproject root dirを返してくれるので、それにrootからの相対パスを足してあげて返します。これでちゃんとしたファイルが選択できるようになりました。

(display-to-real . (lambda (name)
                    (format "%s/%s" (anything-git-project-project-dir) name)))

最後に

 今回の変更をするにあたり、anything周りのことはEmacsテクニックバイブルが参考になりました。

Emacsテクニックバイブル ?作業効率をカイゼンする200の技?

Emacsテクニックバイブル ?作業効率をカイゼンする200の技?

 elisp周りまだぜんぜんわかってないので、Emacs Lispテクニックバイブルも買いたいなー。

Emacs Lispテクニックバイブル

Emacs Lispテクニックバイブル