これからEmacsでR使う人のための設定まとめ


Emacsはバッドノウハウだとか、古くさいエディタなんつーことをよく聞きます。でも、Rを使うにこれほど便利な道具はありません。
特に、Rでガリガリ計算させたい人にとってネットワーク越しで他のマシン使って計算させているうちにローカルのマシンで他の仕事させたいなんてことは、よくあること。そんなときにターミナルで起動できるEmacsを覚えておけば、快適にターミナル上でも書けますよね。Emacsってよくわからない、という理由だけでEmacs使わないというのは、もったいなさすぎな気がします。
ということで、今回はEmacsでRを使うに快適に使うための設定をまとめてみたいと思います。
ちと長いですが、これを読んでもらってEmacsの便利さを分かってもらえる人が増えればいいなーって思います。

まずはESS

これがないと始まりません。debian系使ってる人はaptで簡単に導入できるのでサクッと入れておきましょう。そうでない方は、
下のサイトからESSを落としてきて、ロードパスの通ったところに置いておきます。そしたら、.emacsに次のように書いておきましょう。
Emacs Speaks Statistics
[cpp](require ‘ess-site)[/cpp]
これだけでも、かなり便利に使えます。けどもう少し便利にしていきましょう。

anything.el

スクリプトを書いていると、この関数ってどういう風に使うのかなーソースコード見たいなーとか、自分が作ったオブジェクトがどうなってるのかなーとか、そう思うときがままあります。そんなときに便利な設定。これにはanything.elというelispを使って設定します。anything.elはこれ以外でもすごく便利なelispなので、今回の設定いらねーな人でも入れておくべきです。
今回の設定を簡単にしてもらうために必要なファイルをgithubに置いておきました。ここから、anythng.elとanything-config.elを同じくロードパスの通ったところに入れておきましょう。
myuhe’s auto-complete-acr.el at master – GitHub
そして、次のように.emacsに書いておきます。

[cpp]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;anything-c-source-R-helpの設定
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(setq anything-c-source-R-help
‘((name . "R objects / help")
(init . (lambda ()
;; this grabs the process name associated with the buffer
(setq anything-c-ess-local-process-name ess-local-process-name)))
(candidates . (lambda ()
(condition-case nil
(ess-get-object-list anything-c-ess-local-process-name)
(error nil))))
(action
("help" . ess-display-help-on-object)
("head (10)" . (lambda(obj-name)
(ess-execute (concat "head(" obj-name ", n = 10)n") nil (concat "R head: " obj-name))))
("head (100)" . (lambda(obj-name)
(ess-execute (concat "head(" obj-name ", n = 100)n") nil (concat "R head: " obj-name))))
("tail" . (lambda(obj-name)
(ess-execute (concat "tail(" obj-name ", n = 10)n") nil (concat "R tail: " obj-name))))
("str" . (lambda(obj-name)
(ess-execute (concat "str(" obj-name ")n") nil (concat "R str: " obj-name))))
("summary" . (lambda(obj-name)
(ess-execute (concat "summary(" obj-name ")n") nil (concat "R summary: " obj-name))))
("view source" . (lambda(obj-name)
(ess-execute (concat "print(" obj-name ")n") nil (concat "R object: " obj-name))))
("dput" . (lambda(obj-name)
(ess-execute (concat "dput(" obj-name ")n") nil (concat "R dput: " obj-name)))))
(volatile)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; anything-c-source-R-localの設定
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(setq anything-c-source-R-local
‘((name . "R local objects")
(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 "print(ls.str(), max.level=0)n" buf))
(split-string (buffer-string) "n" t)))
(error nil)))))
(display-to-real . (lambda (obj-name) (car (split-string obj-name " : " t))))
(action
("str" . (lambda(obj-name)
(ess-execute (concat "str(" obj-name ")n") nil (concat "R str: " obj-name))))
("summary" . (lambda(obj-name)
(ess-execute (concat "summary(" obj-name ")n") nil (concat "R summary: " obj-name))))
("head (10)" . (lambda(obj-name)
(ess-execute (concat "head(" obj-name ", n = 10)n") nil (concat "R head: " obj-name))))
("head (100)" . (lambda(obj-name)
(ess-execute (concat "head(" obj-name ", n = 100)n") nil (concat "R head: " obj-name))))
("tail" . (lambda(obj-name)
(ess-execute (concat "tail(" obj-name ", n = 10)n") nil (concat "R tail: " obj-name))))
("print" . (lambda(obj-name)
(ess-execute (concat "print(" obj-name ")n") nil (concat "R object: " obj-name))))
("dput" . (lambda(obj-name)
(ess-execute (concat "dput(" obj-name ")n") nil (concat "R dput: " obj-name)))))
(volatile)))

;; anything.elの設定
(require ‘anything-config)
(define-key global-map (kbd "C-x b") ‘anything)

(setq anything-sources
‘(anything-c-source-buffers
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
))
[/cpp]

使い方は、簡単。オブジェクトやパッケージを読み込んで、関数のヘルプ引きたいなーとか、オブジェクトの中身をサクッと見たいなーと思ったときに、C-x bを押してみましょう。そして、知りたい関数とかをタイプしていくと、anything.elが自動でいろいろな項目を絞り込んでくれるわけですが、その中に”R local object”と”R objects / help”というのがあります。”R local object”の方には、オブジェクトのデータ型や中身の情報が表示されていると思います。また、その中の一つを選択した状態でTABを押すと、さらに選択候補が表示されてhead()やsummary()を選択することができるようになります。
下のスクリーンショットは、ベクトルとデータフレームのデータ型を読み込んだ後でanything.elを呼び出した時のものですが、こんな感じでオブジェクトなり関数が候補としてでてくるわけです。
anything

auto-complete.el

Rでは、長たらしい関数名などがたまにあります。そんなのは、いちいちタイプするのはかなりめんどくさいので、auto-complete.elを入れて楽しましょう。
複数の言語を併用してたりするとfor文のシンタックスが違ったりするので、こんらんしたりします。そんなときに便利なのがyasnippet.el。こいつで登録したスニペットを一発で呼び出すことができます。これもauto-complete.elに統合させてさらに便利にさせていきます。
今回も同じく、githubからファイルを落としてきます。今度はauto-complete.el,auto-complete-acr.el,auto-complete-yasnippet.el,dropdown-list.el,yasnippet.el,それとsnippetディレクトリを丸ごと使います。
myuhe’s auto-complete-acr.el at master – GitHub

後は、次のように.emacsに書いておきましょう。
[cpp]
;;yasnippetの設定
(add-to-list ‘load-path "~/site-lisp/yasnippet");;site-lispにロードパスを通してる場合
(require ‘yasnippet) ;; not yasnippet-bundle
(yas/initialize)
(yas/load-directory "~/site-lisp/snippets")
;;auto-completeの設定
(require ‘auto-complete)
(require ‘auto-complete-yasnippet)
(require ‘auto-complete-acr)
[/cpp]

後は、ガツガツ書いていくだけ。次のスクリーンショットは、M-x R してforとタイプしたときのもの。候補で赤くなっているものはsnippet.elで補完できるもの。それ以外は、auto-complete.elかauto-complete-acr.elで補完できる候補をあらわしています。
yasnippet1
んで、forを選択した段階でリターンかC-mするとスニペットが展開されます。
yasnippet2

まとめ

今回はESSの詳しい使い方についてはあまり詳しく説明しませんでしたが、ESS自体も部分実行やインデント、ジャンプ機能さらには引数アドバイス機能とか便利な機能がたくさんあります。使い込んだころには、手放せない道具となっていることでしょう。
enjoy R!!

参考リンク

ESS – RjpWiki
yasnippetがすごい!!!!1112345! – antipop
EmacsWiki: Anything Sources
ESS on Emacsで快適に補完できるauto-complete-acr.el0.2リリースしました