• 作成:

Emacsでhelp-fns+の代わりとしてhelpfulを使ってみたら代わり以上に良かった

help-fns+の消失

Emacsにhelp-fns+.elというパッケージがあります.

これはまあ色々とコマンドを提供しているのですが,私が主に使っていたのはdescribe-keymapでした.

Emacsの普通のdescribe-variableで例えばhelpful-mode-mapのようなキーマップを参照すると,

悲しい
悲しい

のようにキーコードが数字で表示されてしまいます.これでは一部の変人以外は何がなんだかわかりませんね.

describe-keymapで呼び出すとキーコードではなくEmacsのkbd関数引数風の文字列で表示してくれるため,私にも読める画面になりました.

しかしこのパッケージはmelpaから削除されてしまっています.

Update on MELPA removing EmacsWiki packages: They are no longer available on MELPA as of 2018-01-24. Help-fns+ and dired+ (among others) are no longer available on MELPA. : emacsによると,melpaがEmacsWikiからのホスティングを拒否して,help-fns+の作者がEmacsWikiからの移動を拒否したから削除されたようですね.

これはもう2年ぐらい前の話なのですけれど,私はelpaをgit commitするという狂った管理方法を使っていたため,この影響を受けませんでした.

しかし最近leaf管理に移行しました.私の.emacs.dをelpaをgit管理下に入れる気の狂った管理方法からleafに移行させました - ncaq

なのでmelpaにないパッケージを使うのが今更面倒になったわけです.

helpful

代替を探して見つけたのがWilfred/helpful: A better Emacs help bufferでした.

READMEにも

This project has been heavily influenced by:

help+.el, help-fns+.el, help-mode+.elDave Williams' demo of Lucid's Energize

と書いてありますね.

私はこれを

(leaf helpful
  :ensure t
  :require t
  :bind
  ([remap describe-function] . helpful-callable)
  ([remap describe-key]      . helpful-key)
  ([remap describe-variable] . helpful-variable)
  :defvar helpful-mode-map
  :config (ncaq-set-key helpful-mode-map))

として既存のdescribe系関数を置き換えるように設定しています.

また

(leaf elisp-slime-nav
    :ensure t
    :bind (:elisp-slime-nav-mode-map ("C-c C-d" . helpful-at-point))
    :hook emacs-lisp-mode-hook help-mode-hook)

elisp-slime-nav-describe-elisp-thing-at-pointの代わりに使うように設定しました.

これで

読める
読める

のように読める表記で表示してくれます.

しかしDvorakを使ってる都合上define-keyでnilを設定しまくっているのでnilだらけで汚いですね…nilにするのではなく取り除く関数は何処かにあるのでしょうか…

ところでこのhelpful,単にキーコードを読める化してくれるだけではなく,色々と便利な機能が付いていました.

便利
便利

その変数や関数の定義元やソースコード(C言語でもOK)の抜粋を見せてくれたり,ボタンを押すことでサクッと代入が出来たり,逆にキーコードに戻してくれたりなど.

こんな便利なものがあるとは知りませんでした.これまで使ってなくて損していましたね.

フォーカスを移さないで欲しかったのが解決しました

このhelpful-at-point, elisp-slime-nav-describe-elisp-thing-at-pointと違ってフォーカスをヘルプを開いたウィンドウに移してしまいます.

Emacs Lispを書いていてサクッと定義を知りたくて呼び出したら後はコーディングに戻りたいため,フォーカスを移すのは余計な動作に感じます.

解決策を探して,helpful-switch-buffer-functionに関数を設定してあげれば挙動が変わることがわかりました.

そう言えば似たような問題を解決した経験があると思ってinit.elを見てみたら以下の関数が見つかりました.

(defun pop-to-buffer-without-switch (buffer-or-name &optional action norecord)
    "本当にwithout switchしているわけではなく前のウィンドウにフォーカスを戻すだけ"
    (pop-to-buffer buffer-or-name action norecord)
    (other-window -1))

強引すぎる…

しかしこの関数を設定してあげてもエラーで動かないんですよね.

cl--assertion-failed: Assertion failed: (not (null helpful--sym))

というエラーが出てきます.

バッファを切り替えてしまっているので

(cl-assert (not (null helpful--sym)))

に失敗するようです.

ウィンドウ作ってからupdateしているからですね.

かと言ってアップデート後にadviceをかけても…いやhelpful-at-pointにadviceをかければ良いのか.

:advice (:after helpful-at-point other-window-backward)

を付け加えてみましょう.

解決しました.

でも流石に強引すぎる方法だからあまり嬉しくはないですね…

最終的にはこう.

(leaf helpful
  :ensure t
  :require t
  :bind
  ([remap describe-function] . helpful-callable)
  ([remap describe-key]      . helpful-key)
  ([remap describe-variable] . helpful-variable)
  :defvar helpful-mode-map
  :advice (:after helpful-at-point other-window-backward)
  :config (ncaq-set-key helpful-mode-map))