Emacsのivy.elとquelpa.elでのニッチな不具合について(quelpa-melpa-recipe-stores)
Emacsを便利にしたい!という理由で様々なパッケージを入れています。
しかし、インストールするパッケージのelispソースコードをほとんど見ていない私はまた首を傾げる事態に遭遇してしまいました。とほほ
環境 : Emacs 25.3.1
Ivy
IvyはEmacsにおける補完機能(completion)用パッケージです。Emacsで補完といえばHelmが有名ですが、こちらはよりシンプルでminibuffer内に候補が表示されます。
M-x ivy-mode
などでグローバルマイナーモードであるivy-mode
を有効にすると、completing-read-function
にivy-completing-read
が設定されます。これによって、minibufferでの補完にivyの補完が用いられます。つまり、標準の入力補完completing-read-default
(minibufferでTABを押すと*Completions*バッファが出てくるやつ)とはおさらばということです。やったね。
ちなみに、このivy-mode
によるcompleting-read-function
の変更だけでも便利ですが、同レポジトリにあるcounsel.elやswiper.elには、Emacsのデフォルトの関数のラッパー(counsel-mode
で有効化)や便利な関数があるので利用するとさらに便利です。counsel-M-x
は(インストールされていれば)smex、amxに対応しているので嬉しいですね。MELPAからpackage.elでインストールする際は、counselをインストールすれば依存でswiperとivyもインストールしてくれます。
quelpa
quelpaはEmacsにおけるパッケージの管理ツールです。標準のpackage.elのラッパーとして働き、またquelpa-use-packageでuse-packageと統合できるため便利です。(最近githubからframagitにレポジトリを移したようです)
ただし、quelpaは基本的にMELPAのみを対象としているため、パッケージをインストールする際、依存パッケージがMELPAに登録されていない場合エラーとなります。例えば、magitはlet-alist-1.0.5を必要とするが、Emacs25.3.1で標準に入っているものはlet-alist-1.0.4であり、また、MELPAのレシピにはないためインストールに失敗します。
追記 2018-08-29
インストールに失敗しますと書きましたが、これは自分が(setq package-archives nil)
としていたためです。package-archives
をいじらなければ、普通にインストールできました。つまり、以下は(setq package-archives nil)
としている際に起こる不具合の説明です。相当ニッチになってしまいました。
追記終わり
エラーを回避するにはquelpa-melpa-recipe-stores
(もともとMELPAのレシピのディレクトリのみ)に必要なレシピファイルを置いたディレクトリを追加すればよい。そうすればquelpaはレシピを見てパッケージを取得できます。もしくは、.emacsの中で完結させたい場合は
(add-to-list 'quelpa-melpa-recipe-stores '((let-alist :fetcher url :url "http://git.savannah.gnu.org/cgit/emacs.git/plain/lisp/emacs-lisp/let-alist.el" :version original)))
を追加すればよい。(これはquelpaの作者のconfig fileを参考にしました)
これでmagitパッケージをインストールできました。ちゃんちゃん。と言いたいところですが、この方法だととある不具合が生じます。M-x quelpa
でエラーを吐かれてしまい使用できません。
追記 2019-01-26
現在最新版のivyでは以下のエラーは起こりません。いつの間にか直ったようです。
追記終わり
不具合の原因、解決策
quelpaだけの不具合ならquelpaだけ紹介すればいいのにIvyを先に紹介している。まあつまり原因はIvyにありました。(弱い人なので原因究明にとにかく時間がかかりました...)
実は、ivy-completing-read
とcompleting-read-default
では仕様が少し違いました。
手っ取り早くサンプルを示します。*scratch*バッファなどで試せます。(上からそれぞれの末尾でC-j)
(ivy-mode -1) ; ivy-modeを無効化 (completing-read-default "select: " '("a" "b" (c C))) ; => TABで3つの候補が出る (ivy-completing-read "select: " '("a" "b" (c C))) ; => error
上のようにcompleting-read-default
では第2引数(collection)にリストを与え、その要素がリストの場合でもエラーとならず、そのリストのcarが候補として補完されます。しかし、ivy-completing-read
では補完を作れずエラーとなってしまいます。
おそらくivy-completing-read
ではcollectionに与えるリストの要素にリストと文字列が混在する使用法を想定していません。edebugを使ってみましたが、condを使っての場合分け、もしくはsortの関数が問題のようでした。
解決方法としてはivy-completing-read-handlers-alist
に、補完にivy-completing-read
を用いないようにしたい関数と別の補完関数のconsを追加することです。
(add-to-list 'ivy-completing-read-handlers-alist '(quelpa . completing-read-default)) (add-to-list 'ivy-completing-read-handlers-alist '(quelpa-expand-recipe . completing-read-default))
こうすればivy-modeが有効でもM-x quelpa
とM-x quelpa-expand-recipe
は補完にcompleting-read-default
が使われ、エラーは起こりません。しかし、Ivyの縦に並ぶ補完はとても便利であるため、使えないのは悲しいですね。
まとめ
実を言うとM-x quelpa
を実行する機会はないです。インストールしたいなら.emacsに記述して評価する(eval)し、またM-x quelpa
だとquelpa-melpa-recipe-stores
にあるレシピしか選択できません。C-u M-x quelpa
とするとアップデートされるという機能がありますが、M-x quelpa-upgrade
ならMelpaのレシピに限られず、quelpaでインストールしたパッケージ全てをアップデートしてくれます。
追記 2018-08-29
嘘です。C-u M-x quelpa
が便利なので、使えた方がいいと思います。また、el-getを知ったら、quelpa-melpa-recipe-stores
にリストを追加するのではなく、ディレクトリを追加してそこに自分でrecipeファイルを書いて置いておくのもいいのかもしれないと思いました。それと、M-x quelpa-upgrade
はあまりオススメしません。C-u M-x quelpa
で一つずつアップデートするのがいいと思います。
追記終わり
結局は、どうしてM-x quelpa
でエラーが発生するんだろう?という疑問を解決できた。ので嬉しい。というお話でした。
ivyとquelpaを使用しているかつquelpa-melpa-recipe-stores
にディレクトリではなくリストを追加しているユーザに対する記事でした。とてもニッチですね。
Ivyの改良について
githubのレポジトリなんだしIssueを送ったらどうかと一度思いましたが、そうなったら多分自分でコードを書いてプルリクエストしてねと言われそうなので弱い私は上の方法で満足しました。ivy.el読んだけど直すのは結構面倒くさそうです。
追記 2019-01-26
久々に試したら直っててびっくりしました。
上にあげたエラーが出ていたコード例も現在は普通にivyの補完が出てきます。
直してくださった方に感謝。
追記終わり