anything.elのインターフェイスを使ってRのパッケージを管理するanything-c-source-R-pkg


Rは膨大なパッケージを持っていて、その数は今日現在で2238にのぼります。Rができてまだ15年そこそこだということ,統計解析に特化した言語だということを考えれば、いかにこの数がすごい数かということがわかると思います。
Rがここまで爆発的に普及した理由として非常に優れたパッケージ管理システムとドキュメントシステムがあります。
コマンドひとつでパッケージのインストールからアンインストール、アップデートからロードまで自在にできます。
それらパッケージで提供される関数には詳しいドキュメントがついていて、さらにはサンプルデータから実際に実行可能な実行例まで至れりつくせりのドキュメントがこれまた簡単なコマンドで閲覧や実行ができてしまいます。
ただ、ここまで増えてくると、困ったことも。パッケージを探すのがめんどくさいのです。ま、探せばいいんですけどね。探せば。
ただ2000もパッケージがあると,後発のパッケージはどうしても名前の文字数が多くなってきます。多くなってくるとくだらないtypoも増えてさらにイライラします。
といっても名前が重複することは当然できないのでこの傾向は悲しいかな、これからもっと続くわけです。
あーいやだ。こんなめんどくさいことはどうかしないといけません。

曖昧な記憶でどうにかしたい

要は曖昧な人間の記憶でもどうかしてくれればいいわけです。こんなときに便利なのがauto-complete-acr.el。とりあえず最初の何文字かを思いだせばぽんぽん補完してくれます。しかし、インストールされてないパッケージはauto-complete-acr.elでもお手あげです。auto-complete-acr.elは内部でbaseとロードされているパッケージなどから補完候補を生成するようになっているので、インストールされていないパッケージの関数を補完することができないのです。
というわけで、新しく書いてみました。今回はEmacserならば知らない人はいないであろうanything.elの力を借ります。

準備

まず、事前の準備。何をいまさらですが、anything.elが必要です。
EmacsWiki: anything.el
EmacsWiki: anything-config.el

それとESSが必要になります。
Emacs Speaks Statistics

次に今回書いたelispを.emacsにコピペしときます。スクリプトはgistにも置いてます。
gist: 327649

[cpp]
(defun anything-ess-marked-install (candidate)
(dolist (i (anything-marked-candidates))
(ess-execute (concat "install.packages("" i "")n") t)))

(defun anything-ess-marked-remove (candidate)
(dolist (i (anything-marked-candidates))
(ess-execute (concat "remove.packages("" i "")n") t)))

(setq anything-c-source-R-localpkg
‘((name . "R-local-packages")
(init . (lambda ()
;; this grabs the process name associated with the buffer
(setq anything-c-ess-local-process-name ess-local-process-name)
;; this grabs the buffer for later use
(setq anything-c-ess-buffer (current-buffer))))
(candidates . (lambda ()
(let (buf)
(condition-case nil
(with-temp-buffer
(progn
(setq buf (current-buffer))
(with-current-buffer anything-c-ess-buffer
(ess-command "writeLines(paste(”, sort(.packages(all.available=TRUE)), sep=”))n" buf))

(split-string (buffer-string) "n" t)))
(error nil)))))

(action
("load packages" . (lambda(obj-name)
(ess-execute (concat "library(" obj-name ")n") t )))
("remove packages" . (lambda(obj-name)
(ess-execute (concat "remove.packages("" obj-name "")n") t)))
("remove marked packages" . anything-ess-marked-remove))
(volatile)))

(setq anything-c-source-R-repospkg
‘((name . "R-repos-packages")
(init . (lambda ()
;; this grabs the process name associated with the buffer
(setq anything-c-ess-local-process-name ess-local-process-name)
;; this grabs the buffer for later use
(setq anything-c-ess-buffer (current-buffer))))
(candidates . (lambda ()
(let (buf)
(condition-case nil
(with-temp-buffer
(progn
(setq buf (current-buffer))
(with-current-buffer anything-c-ess-buffer
(ess-command "writeLines(paste(”, rownames(available.packages(contriburl=contrib.url("http://cran.md.tsukuba.ac.jp/"))), sep=”))n" buf))
(split-string (buffer-string) "n" t)))
(error nil)))))
[/cpp]

.emacsに設定を書いておきます。僕は次のように書いています。

[cpp]
(require ‘ess-site)

(require ‘anything-config)
(define-key global-map (kbd "C-;") ‘anything)

(setq anything-sources
‘(anything-c-source-buffers+
anything-c-source-imenu
anything-c-source-emacs-commands
anything-c-source-file-name-history
anything-c-source-locate
anything-c-source-man-pages
anything-c-source-occur
anything-c-source-recentf
anything-c-source-R-local
anything-c-source-R-help
anything-c-source-kill-ring
anything-c-source-R-localpkg
anything-c-source-R-repospkg
))

(setq anything-idle-delay 0.3)
(setq anything-input-idle-delay 0.2)

(define-key anything-map (kbd "C-p") ‘anything-previous-line)
(define-key anything-map (kbd "C-n") ‘anything-next-line)
(define-key anything-map (kbd "C-v") ‘anything-next-source)
(define-key anything-map (kbd "M-v") ‘anything-previous-source)
[/cpp]

使い方

M-x Rとしたら、ふつーにanythingバッファを開くだけです。
するとR-local-packagesとR-repos-packagesのふたつがでてくるはずです。 名前からだいたい推測がつくかもしれませんが、前者がすでにインストールしているパッケージのリスト、後者がインストールしていないパッケージのリストです。
R-local-packagesでは、デフォルトの動作はパッケージの読みこみになっています。
他にもアクションが設定されていて,アンインストールもできるようになってます。C-spaceで複数のパッケージを選択して一気に削除することもできます。
R-repos-packagesでは、デフォルトの動作はパッケージのインストールです。
こちらも複数のパッケージを選択することで複数のパッケージをインストールすることができます。

まとめっぽい何か

いかがだったでしょうか。そんなに長くないスクリプトですが、 効果は抜群だと思います。こういう便利な機能がさくっと書けるのもEmacsの良いところですよね。
ただ、ちょっと問題があって、どうやらproxy経由だとうまくいかないみたいです。いい解決方法あったら教えてください。
それと、上のスクリプトでは、筑波大のサーバからインストールするようにしてます。
サーバの設定を削ればサーバを選択するダイアログが開くようになるのでサーバは自分で選びたいという方はそっちの方がいいかもしれません。