yasnippet のトリガーを変更して hippie-expand と連携するようにした

yasnippet を導入してみた - gan2 の Ruby 勉強日記ではたくさんのブクマを頂いたわけだけども
当の僕はといえば、実はあれ以来日に日に yasnippet の使用頻度が低下していき
遂には全く使わないようになってしまっていた。
というのは、「スペーストリガーいいよスペーストリガー!」とか言っていたくせに
スペーストリガーはスニペットのメンテナンスが面倒なことに気付いたからだった。

スペーストリガーをやめようと思った理由 (飛ばし読み可)

ちょっと考えれば分かることなのだけど
スペーストリガーだと意図しないところで補完が行われてしまう場合がある。
タブは押そうと思わなければ押さないキーなので
意図しないところで補完が行われることはそうそうないのだが
スペースの場合はそれが起こるのである。


何の気なしにスペースを打ったときに意図しない補完をされるとビックリする。
そして、その補完がされていい補完だったときはまだいいのだけどされて困る補完の場合がある。
例えば、「begin statement」と書こうとしたときに
「begin」の後のスペースで補完が起きると困るのである。
これで「あ!補完された!なんだよもうビックリしたなぁ!」で済めばまだいいのだが
補完された内容を削って書き直そうとすると
また「begin」の後ろでスペースを叩いたときに同じように補完される。
「あ、ああ…そうか(;゚д゚)」


ってなわけでスペーストリガーとうまく付き合っていくためには
補完が変なところで発動しないように考えてスニペットを編集しないといけないわけなのだけど
この設定作業はけっこう面倒である(´・ω・`)(体験談)
おそらくはうまい具合にスニペットを編集できていれば
まさに魔法の指のごとき打鍵でプログラムを書けるのだろうし、
実際僕はそういう状態を理想に掲げてスペーストリガーを使っていたのだけども
やっぱりというか何というか現実はそんなに甘くはなくて
スペースで強制的に補完されては「ひぃ!」と驚き
その度に設定をいじってはまた別の補完が起きて「もうやめて!」と叫び
そんなこんなを繰り返してストレスが溜まっていく日々は
夢見ていた理想とはかなり対照的なのであった。

スペースはやめて hippie-expand で使っているキーを採用

ってことで僕の発言に乗せられてスペーストリガーを採用していた方、ごめんなさい。
僕はもうスペーストリガーと別れようと思います。離別です。
代わりといってはなんですが、僕の考えた次の相方を紹介します。
それは普段から「hippie-expand」に使っている「C-o」です。
「hippie-expand」のところは「動的略語展開」とか
よく使っている補完機能に置き換えても OK です。
他のキーを使っている場合はたぶんそちらを使った方が幸せだと思います。
でも「C-o」はけっこう押しやすいのでお勧めです。

hippie-expand について

「hippie-expand」は「Emacs」に数多くある補完機能の一つ。
メリットは大きく分けて2つあって、
1つは標準で備わっているのですぐに試せること。
もう1つは「動的略語展開 (dabbrev)」などと違和感なく一緒に使えることである。
要は「補完機能のトリガーを1つにまとめちゃおうぜ」な機能。
「ac-mode」と似たようなものだ。
.emacs に以下のような設定を書き足せばすぐに使える。
「"\C-o"」のところは好みで変更するといいよ。

;;; hippie-expand
(global-set-key "\C-o" 'hippie-expand)
(setq hippie-expand-try-functions-list
      '(try-expand-dabbrev
        try-expand-dabbrev-all-buffers
        try-expand-dabbrev-from-kill
        try-complete-file-name-partially
        try-complete-file-name
        try-expand-all-abbrevs
        try-expand-list try-expand-line
        try-complete-lisp-symbol-partially
        try-complete-lisp-symbol))

「hippie-expand-try-functions-list」の中は優先順に並んでいるので
上の場合はディレクトリ構造のパスなどよりも動的略語展開が優先される。

yasnippet が hippie-expand から呼べるようになった

スペーストリガーによるストレス疲労でしばらくチェックしてなかった yasnippet だけど
0.4.4 だったバージョンは 0.5.5 になり 0.5.0 から hippie-expand に対応していたようだ。
yasnippet の ChangeLog
使い方は簡単で、上の「hippie-expand-try-functions-list」に
「yas/hippie-try-expand」を追加してやるだけで OK。
僕は yasnippet の補完が一番に優先されてほしいので一番上に追加した。

;;; hippie-expand
(global-set-key "\C-o" 'hippie-expand)
(setq hippie-expand-try-functions-list
      '(yas/hippie-try-expand
        try-expand-dabbrev
        try-expand-dabbrev-all-buffers
        try-expand-dabbrev-from-kill
        try-complete-file-name-partially
        try-complete-file-name
        try-expand-all-abbrevs
        try-expand-list try-expand-line
        try-complete-lisp-symbol-partially
        try-complete-lisp-symbol))


また、僕の環境で「yasnippet」を呼ぶのに「タブ」を使うとおかしくなっていた原因は
「hippie-expand」にあるらしいことも分かった。
Meadowのruby-modeでyasnippetが利かないのは - すばらしい新世界
なんか「Meadow」を「ネットインストーラ」でインストールすると
hippie-expand も自動的にインストールされてそいつが yasnippet とケンカするみたいだ。
でもこれも上の手順を踏むことで自動的に解決した。よかった。

さあ使うぞ!と、その前にちょっとだけ手直し

古いバージョンの yasnippet を既にインストールしていて
id:antipop さんの elisp を使っている場合はちょっとだけ手直しする必要がある。
yasnippetのスニペットをCodeReposで共有しよう! - antipopとかで紹介されてるやつね。


以前は「yas/root-directory」に渡すのは「文字列」だったのだけど

;; yasnippetのsnippetを置いてあるディレクトリ
(setq yas/root-directory (expand-file-name "~/dev/yasnippet/snippets"))

新しいバージョンでは「リスト」を渡さないといけなくなったようなので以下のように書き換える。

;; yasnippetのsnippetを置いてあるディレクトリ
(setq yas/root-directory (list (expand-file-name "~/dev/yasnippet/snippets")))

っていうか「yas/root-directory」が「リスト」を受けとるようになったってことは
id:antipop さんの拡張と同等の機能が本家に取り込まれたのかもしれない。
つまり、上のようなスクリプトをわざわざ .emacs に書かなくても
「yas/root-directory」にスニペットディレクトリをドカドカ追加するだけでよくなったのかもしれない。
ドキュメントもソースも読んでないからハッキリとは言えないけど。