helm-perldocを使ってインストール済みモジュールのドキュメントを参照する(carton対応も)

インストール済みのモジュールたちから、perldocを引くためのリストを作る - すぎゃーんメモ を書いた後 id:syohexさんと相談させていただいた結果、きれいにモジュール一覧を取得する方法を確立していただき。

これでhelm-perldoc がインストール済みのモジュール・podをすべて取得して参照できるようになりました。ありがとうございます。

helm-perldoc:setup

このコマンドが非同期でモジュール一覧を取得してくれる。
既にモジュールのリストが取得されていれば何もせずにスルーするので、cperl-modeでファイルを開くたびにhookで実行させておけばよい。

(defun my-cperl-mode-hook ()
  (helm-perldoc:setup)
  (flymake-mode t))
(add-hook 'cperl-mode-hook 'my-cperl-mode-hook)

helm-perldoc:perl5lib で取得対象パスを追加

helm-perldoc:setupでモジュール一覧を取得するけれど、普通に実行すると その環境のPerlにインストールしているもののみが対象になり、例えばcarton install~/myproject/local/以下にインストールされているものは取得されない。

そこで、そういうときのためにhelm-perldoc:perl5libという変数が用意されていて、これを指定してからhelm-perldoc:setupを呼ぶことで そのpath以下のモジュールたちも取得し、ドキュメントを引けるようになる。
helm-perldoc:modulesnilにするかprefix-argを指定してやればhelm-perldoc:setupは再びモジュール一覧を取得しなおしてくれる。

(setq helm-perldoc:perl5lib "~/myproject/local/lib/perl5")
(let ((current-prefix-arg t))
  (helm-perldoc:setup))

これで、~/myproject/local/以下にインストールされたモジュールもhelm-perldocで引けるようになる。便利。

projectileを使って自動で helm-perldoc:perl5lib を追加

carton環境のプロジェクト下のファイルをそれほど使わないのであれば上記の操作を一回やれば済むのでそれほど面倒ではないけれど、
例えば複数のプロジェクトでcartonを使っていて それぞれの環境でしか入れていないモジュールのドキュメントを参照したい、となるとそれぞれのlocalディレクトリをhelm-perldoc:perl5libに追加する必要が出てくる。
いちいち手動で変更するのも面倒だし、起動時の設定ファイルに書いたりするのもイヤだ。
…というわけで、「ファイルを開いたときに、そのファイルがcarton環境下であり、且つ まだhelm-perldoc:perl5libにその環境用のpathが設定されていなければ自動で追加する」ということをしてみる。

projectile でルート検出

Projectile は、特定のファイルを検索してプロジェクトの起点を判別してくれる。
デフォルトではcpanfileは判別ファイルとして含まれていないので、

(custom-set-variables
 '(projectile-project-root-files
   '(".projectile"        ; projectile project marker
     "Gemfile"            ; Bundler file
     "package.json"       ; npm package file
     "cpanfile"           ; CPAN dependencies for Perl applications
     ".git"               ; Git VCS root dir
     )))

のように変更しておく。順番的に".git"とかより先に"cpanfile"を書いておかないとgit管理下のisucon/perlみたいなプロジェクトでperlプロジェクトとしてより先にgitプロジェクトとして認識されてしまうので注意。

initファイルの記述

で、carton環境のプロジェクトか否かは(projectile-verify-file "cpanfile")で判別できるので、その際は(projectile-expand-root "local/lib/perl5")で得られるpathがhelm-perldoc:perl5libに追加されているべき、ということになる。
もし現在のhelm-perldoc:perl5libにそれが含まれていないようであれば追加してsetupしなおす、ということで

(defun my-cperl-mode-hook ()
  (let ((perl5libs (split-string (or helm-perldoc:perl5lib "") path-separator t))
        (local-lib (projectile-expand-root "local/lib/perl5")))
    (when (and (projectile-verify-file "cpanfile")
               (not (member local-lib perl5libs)))
      (setq helm-perldoc:perl5lib
            (if perl5libs
                (mapconcat 'identity (cons local-lib perl5libs) path-separator)
              local-lib))
      (message "helm-perldoc:perl5lib is updated. (%s)" helm-perldoc:perl5lib)
      (setq helm-perldoc:modules nil)))
  (helm-perldoc:setup)
  (flymake-mode t))
(add-hook 'cperl-mode-hook 'my-cperl-mode-hook)

このように起動時の設定ファイルに書いておくと、あとは何もしなくても開いたPerlファイルが属するプロジェクトでインストールされているモジュールは自動で取得されドキュメントを参照できるようになる。嬉しい!

今後?

2014.3.12現在 上記のようなものはhelm-perldocの標準機能を追加することでもう少し簡潔にできるようにしようか?という話もしているので、これからまた変わっていくかも