hydra 20170803.1319(in MELPA)
Make bindings that stick around.

概要

hydra.el は、連続して操作するときにプレフィクスキーを
キャンセルさせるためのelispです。

日本人の間では smartrep.el が有名ですが、
hydra.elも同様の機能を提供します。

http://sheephead.homelinux.org/2011/12/19/6930/ ←smartrep.el作者のページ

hydraとは大蛇、日本でいえば「やまたのおろち」のようなものですが、
省略されたプレフィクスキー以降のキーを「頭」に例えています。

それではsmartrepとhydraの両者を比較してみましょう。

その結果は…

インストール

パッケージシステムを初めて使う人は
以下の設定を ~/.emacs.d/init.el の
先頭に加えてください。

(package-initialize)
(setq package-archives
      '(("gnu" . "http://elpa.gnu.org/packages/")
        ("melpa" . "http://melpa.org/packages/")
        ("org" . "http://orgmode.org/elpa/")))

初めてhydraを使う方は
以下のコマンドを実行します。

M-x package-install hydra

アップグレードする方は、
以下のコマンドでアップグレードしてください。
そのためにはpackage-utilsパッケージが必要です。

M-x package-install package-utils (初めてアップグレードする場合のみ)
M-x package-utils-upgrade-by-name hydra

文字の大きさを調整する例 150125084412.smartrep.hydra.el(以下のコードと同一)

;;; smartrepの場合
(require 'smartrep)
(smartrep-define-key global-map "<f2>"
  '(("g" . text-scale-increase)
    ("l" . text-scale-decrease)))
;;; smartrep管轄外のコマンドも定義できる
(global-set-key (kbd "<f2> f") 'find-file)

;;; hydra-createはautoloadされているのでrequire不要
(global-set-key (kbd "<f3>") nil)
(hydra-create "<f3>"
  '(("g" text-scale-increase "zoom in")
    ("l" text-scale-decrease "zoom out")))
;;; hydra管轄外のコマンドも定義できる
(global-set-key (kbd "<f3> f") 'find-file)

スクリーンショット

<f2>(<f3>) gglを押した場合で比較しましょう。

20150125090523.png
Fig1: smartrepはモードラインに発動中と表示

20150125090543.png
Fig2: hydraはエコーエリアに使えるキーを表示

org-modeの例 150125085254.hydra.org.1.el(以下のコードと同一)

org-modeで前後の見出し行に移動するのに
C-c C-n C-c C-n C-c C-p ... はかったるいので
C-c C-n C-n C-p と操作できるようにします。

smartrep/hydra両者の記述を比較します。

(require 'org)
;; smartrepの場合
(require 'smartrep)
(smartrep-define-key org-mode-map "C-c"
  '(("C-n" . outline-next-visible-heading)
    ("C-p" . outline-previous-visible-heading)))
;; hydraの場合
(hydra-create "C-c"
  '(("C-n" outline-next-visible-heading "NextHead")
    ("C-p" outline-previous-visible-heading "PrevHead"))
  org-mode-map)

同じプレフィクスキーで別のグループを定義… 150125090750.hydra.same.el(以下のコードと同一)

(require 'smartrep)
(smartrep-define-key global-map "<f2>"
  '(("g" . text-scale-increase)
    ("l" . text-scale-decrease)))
(smartrep-define-key global-map "<f2>"
  '(("+" . text-scale-increase)
    ("-" . text-scale-decrease)))
;;; まだhydraではできない…
(hydra-create "<f2>"
  '(("g" text-scale-increase "zoom in")
    ("l" text-scale-decrease "zoom out")))
(hydra-create "<f2>"
  '(("+" text-scale-increase "zoom in")
    ("-" text-scale-decrease "zoom out")))

<f2> {g,l} と <f2> {+,-} というふうに
共通のプレフィクスキー<f2>を使って別のsmartrepを作成することはできます。

しかし、現段階でのhydraはこれができません。

<f2> gを押したら後に定義された{+,-}の方を見てしまいます。

ああ残念…

結論

smartrepではmode-lineのsmartrep発動中と表示するだけです。

対してhydraでは使える「頭」を表示してくれるので、
次に使えるキーが明確にわかります。

その点ではhydraの方が優れていると思います。

しかし、先程検証したように共通のプレフィクスキーで
複数のhydraを作ることができない欠点があります。

また、smartrepは smartrep-read-event-loop という関数を使えば、
プレフィクスキーとは無関係にsmartrepを発動させられる強味があります。

現時点ではsmartrepが優位ですが、
キーを表示してくれる方がありがたいという方は
hydraを使ってみてもいいでしょう。

とはいえhydra.elは開発されてからたった5日なので、
欠点は克服される可能性があります。


本日もお読みいただき、ありがとうございました。参考になれば嬉しいです。