Solist Work Blog

Software engineer

Emacs Pinkyをhydraで解決する

Emacs Pinky 小指問題というものがあります。 EmacsではCtrlキーを酷使するので小指を痛めてしまうことを指します。 リチャード・ストールマンはまったく気にしていなかったので小指が強いのでしょう。 幸い私も指が太いからか、まったく小指は痛くないのですが、いつEmacs Pinky問題と遭遇するかわからないですし、Emacsが使えないと仕事に支障をきたす可能性が高いです。整体の先生は指を酷使するので指は消耗品であるとおっしゃっていました。指の使いすぎに気をつけても気をつけすぎることはないのです。予防的措置としてEmacs Pinky対策を考えます。

Emacs pinky 小指問題の歴史

Emacs Pinkyのページを見てもらえばわかりますが、先人達の苦労がうかがえます。 Ctrlキーになにやらくっつけて高くしておいて手のひらで押すのは斜め上を行く発想で好きですが、ラップトップでこれをやると外で使う時に美しくないですし、ラップトップの蓋が閉まらなくなるのでやろうとは思えません。1 フットスイッチにCtrlキーを割り当てて足で押すのも発想が斜め上を行っていて好きですが、ラップトップ派としてはノートパソコンのよさを台無しにしてしまうので避けたいところです。 Kinesisを使うのもラップトップ派として避けたいところではあります。 スマートスピーカーにコントロールと叫ぶとトリガーになってラップトップのxdotoolというソフトウェアを呼び出してCtrlキーを自動で押してもらうという方法もあるでしょうが、EmacsユーザーのCtrlキーの頻度を考えると一日中コントロールと叫ぶ必要があり、どういう結果になるかは言うまでもないことでしょう。

Ctrlキーを押す頻度を削減して小指を守る

Ctrlキーを押す回数を減らすことをまず考えます。

Dired画面

Dired(Emacs上で使うファイルマネージャ)では n と p で移動できるので今後一切Ctrl-n Ctrl-pを使わないようにする。 j を押すとDiredのバッファー内を検索してそこにジャンプできるのでこちらもオススメです。 Diredも人によってはそこそこ効果はあるかもしれません。

M-x projectile-switch-project

しかし、私はこの関数に Ctrl-x Ctrl-l ショートカットを割り当ててgitリポジトリを移動してファイルを直接呼び出しているので一日にDiredで削減できるCtrlキーの回数は数百回くらいでしょうか。まだまだ足りません。

Emacsでソースコードを読んでいる時間は計測したことはありませんが半分かそれ以上あるのではないでしょうか。 ソースコードを読んでいる時はCtrlキーなしですむような環境を作ればCtrlキーの削減は十分な量になると思います。 ソースコードリーディングしている間は小指を休ませることができるのもよいと思います。 私は小指が太い2のでEmacs Pinkyとは今まで無縁でしたが、 Ctrlキー押す回数が半分に減ればこれからも心配しなくてよさそうです。

Emacs Pinky hydraの説明

ソースコードを読んでいる時はCtrlキーを押さないで作業できるようにしましょう。 hydraを使って実現していくことにします。 hydraが発動するとそれ以降は全てのショートカットキーを奪ってカスタマイズできます。 hydraの発動が終わると元のEmacsに戻るので今までの操作体系を一切崩すことなくカスタマイズすることができます。 あなたのEmacs副作用を与えることなく新しい機能を付け加えることができるということです。副作用がないので気軽に試して取り入れていくことができます。3

設定は最後に書いておくとしてどのような操作体系になったか説明します。

jkキーを同時押し or Ctrl-'

このどちらかのキーでEmacs Pinky用のhydraが発動するようになっています。4

hydraが発動している状態

hydraが発動すると黄色い四角形の部分がでてきます。 hydra発動中はこの表示が続くのでわかりやすいです。 hydraが終了する条件は以下です。

黄色い四角形の中にある定義された赤いキー以外をタイプすること

つまり黄色い四角形の中のある赤い表示のキーをタイプしている間はいつまでたってもhydraは解除されません。 操作体系は以下のようになっています。

nをタイプすると下移動
pをタイプすると上移動
fをタイプすると右移動
bをタイプすると左移動
aをタイプすると行頭移動
eをタイプすると行末移動
vをタイプすると下に1ページ移動
Vをタイプすると上に1ページ移動
lをタイプするとリセンタリング
sをタイプすると検索するorリージョンが選択されていればそれを使って検索する
0をタイプするとポインタのあるウインドウを閉じる
xをタイプするとポインタのあるウインドウを閉じる
1をタイプすると他のウインドウを閉じる
2をタイプするとウインドウを上下に分ける
3をタイプするとウインドウを左右に分ける
oをタイプするとウインドウが1つの時はウインドウを上下に分けるorウインドウが2つ以上の時は他のウインドウに移動する
<をタイプすると先頭に移動
>をタイプすると末尾に移動
spaceをタイプするとマークがセットされる
gをタイプするとマークキャンセル
Sをタイプするとウィンドウを入れ替える
jをタイプするとgitの差分の次のhunkへ
kをタイプするとgitの差分の前のhunkへ
qをタイプするとバッファーを消す

おおむねEmacsのデフォルトからCtrlキーを省いた操作体系になっています。 hydra発動中は n を2回押すと下に二行移動し o を押すとウインドウが上下に分割され o をもう一度押すと別のウインドウにポインタが移動し 1 を押すとウインドウは一つに戻り s を押すと検索ができます。5 この操作体系はhydraが終了するまで継続するので、 Ctrlキーを全く押すことなくソースコードリーディングができるようになるのです。 これで劇的にCtrlキーを押す頻度を下げることができます。

ギリシア神話ヒュドラーの首はヘーラクレースが棍棒で叩き潰しても、傷口からすぐに2つの首が再生し、首を叩き潰せば首が増えていきます。 hydra発動中はヒュドラーの首をイメージした黄色い四角形のなかにある赤い表示のキーをタイプしてもヒュドラーは不死身です。 ヒュドラーを退治するためには首以外を攻撃する、すなわち黄色い四角形のなかにある赤い表示のキー以外をタイプするのです。 こういう洒落た名前をつけられるのもソフトウェアエンジニアの才能だと思います。

Emacs Pinky hydraの設定

M-x package-install hydra
M-x package-install key-chord
M-x package-install bind-key
M-x package-install swiper
M-x package-install diff-hl

jに割り当てられているdiff-hl-next-hunkとkに割り当てられているdiff-hl-previous-hunkを使う場合はdiff-hlの設定も必要です。詳しくは私のdotfilesを参考にしてください。 必要なパッケージをMELPAからインストールしておきます。 Emacs Pinky対策のhydraの設定は以下です。

(key-chord-define-global
 "jk"
 (defhydra hydra-pinky
   ()
   "pinky"
   ("n" next-line)
   ("p" previous-line)
   ("f" forward-char)
   ("b" backward-char)
   ("a" beginning-of-line)
   ("e" move-end-of-line)
   ("v" scroll-up-command)
   ("V" scroll-down-command)
   ("g" keyboard-quit)
   ("j" diff-hl-next-hunk)
   ("k" diff-hl-previous-hunk)
   ("o" other-window-or-split)
   ("r" avy-goto-word-1)
   ("l" recenter-top-bottom)
   ("s" swiper-isearch-region)
   ("S" window-swap-states)
   ("q" kill-buffer)
   ("w" clipboard-kill-ring-save)
   ("<" beginning-of-buffer)
   (">" end-of-buffer)
   ("SPC" set-mark-command)
   ("\C-m" dired-find-file)
   ("1" delete-other-windows)
   ("2" split-window-below)
   ("3" split-window-right)
   ("0" delete-window)
   ("x" delete-window)
   (";" counsel-switch-buffer)
   ("M-n" next-buffer)
   ("M-p" previous-buffer)))

;; key-chord
(setq key-chord-two-keys-delay 0.1)
(key-chord-mode 1)
(bind-key "C-'" 'hydra-pinky/body)

(defun other-window-or-split ()
  "If there is one window, open split window.
If there are two or more windows, it will go to another window."
  (interactive)
  (when (one-window-p)
	(split-window-vertically))
  (other-window 1))

(defun swiper-isearch-region ()
  "If region is selected, `swiper-isearch' with the keyword selected in region.
If the region isn't selected, `swiper-isearch'."
  (interactive)
  (if (not (use-region-p))
      (swiper-isearch)
    (swiper-isearch-thing-at-point)))

  1. 私はCtrlキーはAの横のCapslockキーの場所にしていて本来左Ctrlキーがある場所をCapslockにしているのでこの方法は使えないのです。

  2. 小指を酷使しすぎて鍛えられてこうなったのではなく生まれつき小指が太いのです。たぶん鍛えられて太くなった分も何割かはあるでしょうが…。

  3. 関数型プログラミングにおいて副作用をなるべく少なくプログラミングすることはよいこととされているのはこういうところから体感することができるでしょう。副作用を徹底的に排除したものは純粋関数型言語と呼ばれHaskellがその代表格です。私は非純粋動的型付けの関数型言語が最もmacroを柔軟に使ったメタプログラミングに向いていると思うのでLISPScheme関数型言語のなかではよいと思います。美しく書くこともできるし、泥臭く書いて急場を凌ぐこともできると思うからです。

  4. hydraが発動するのでhyキー同時押しも考えたのですが押しにくいのでjkキー同時押しにしているのです。ヒュドラーうみへび座のことでもあるのでumiをもじってuiキー同時押しも考えましたが、いかんせんjkキー同時押しはホームポジションの中心にあるキーなので押しやすいです。何かjkキー同時押しにしたそれらしい理由がほしいものです。

  5. hydra発動中に検索するにはSwiperがよいです。検索候補の選択は Ctrl-n Ctrl-p を使いますがhydraを発動させたまま検索することができます。私はSwiperが気に入ったので通常の Ctrl-s もSwiperです。またソースコードの関数定義ジャンプは M-. pop-stackは M-, ですが、プログラミング言語のモードによって呼ぶ関数が変わる事情から、まず M-. でジャンプさせて hydraを一旦終了し M-, で戻ってきたあとに再度jkキー同時押しでhydraを有効にしています。hydraを発動させたまま関数ジャンプをしたい場合は .キー ,キー で発動する関数を現在のモードで場合分けするEmacslispを各自書けばよいでしょう。

タグ一覧

お仕事のご相談などはこちらからどうぞ

お仕事の依頼はこちらからどうぞ