jkは上下移動だろjk (Emacs Advent Calendar jp: 2010)

Emacs Advent Calendar jp: 2010の23日目です。
昨日22日目はanything-gist, py-doc-popup, auto-complete-acr, ess-R-object-popupなどの作者@myuheさんでした。統合執筆環境 org-mode (Emacs Advent Calendar 22日目)

基本的なキーバインドも変えてみよう

このエントリでは移動用キーバインドやPrefixなど
「不便に感じてはいるけど、他への影響があるだろうから変更はしていない」
方が多いであろう、そんなキーバインドでも利便性を追求し変えてしまうことを提案します。

私は

  • C-nはいいとしてもC-pは指が疲れる
  • C-xが押し難い
  • C-uはめったに使わない

と思っていたのでこれらのキーバインドを全て変更しています。
使用感を合わせるためにanythingやauto-completeなど他の必須拡張機能での操作も併せて変更しています。
その設定をまとめたので、よければ試してみてください。

jkで上下移動

まず下記設定により、jkでカーソルを上下移動するように変更しています。

(global-set-key "\C-j" 'next-line)
(global-set-key "\C-k" 'previous-line)

元の C-j の newline-and-indent, eval-print-last-sexp や C-k の kill-line は下記のように変更しています。

(global-set-key "\C-m" 'newline-and-indent)
(add-hook 'lisp-interaction-mode-hook
          (function
           (lambda ()
	     (local-set-key "\C-c\C-j" 'eval-print-last-sexp)
             )))
(global-set-key "\C-n" 'kill-line)

これでC-pの割り当てが余分になりました。
私はどのOSでもCtrl-Spaceを日本語入力のトグルにしているので、余計になったC-pにはset-mark-commandを割り当てています。

(global-set-key "\C-p" 'set-mark-command)

他の機能もjkで上下移動

次にanythingやauto-completeの操作感も合わせています。(anythingのC-j,kの元の割り当てをよく使っている場合、それらは他の適当なキーに割り当ててください。)

(define-key anything-map "\C-j" 'anything-next-line)
(define-key anything-map "\C-k" 'anything-previous-line)
(setq ac-use-menu-map t)
(define-key ac-menu-map "\C-j" 'ac-next)
(define-key ac-menu-map "\C-k" 'ac-previous)

私はdiredをよく使うのでdiredもjkで上下移動するようにしています。

(add-hook 'dired-mode-hook
          (function
           (lambda ()
             (local-set-key "j" 'dired-next-line)
             (local-set-key "k" 'dired-previous-line)
             )))

Prefixキーも変える

次にC-x, C-uといったPrefixキーも下記の設定で変えています。

(global-set-key "\C-u" ctl-x-map)
(global-set-key "\C-x" universal-argument-map)

これでxとuの役割がswapされます。
Prefixを変更したこの状態で本来のCtrl-xのPrefixに続く入力を設定したい場合

(define-key ctl-x-map "\C-u" 'dired-jump)

などとします。ここではC-u2連打でdired-jumpするように設定しています。
(dired-jumpは本来C-x C-jに割り当てられています。)

コマンド入力時は通常のEmacsキーバインドにする

これまでjkで上下移動することで楽になると主張してきたのはバッファ内を移動することが多い場合であり、コマンド入力インタフェース(例えばeshellなど)の場合はこの限りではありません。
そのためコマンド入力インタフェース時には通常のEmacsキーバインドになるよう、さらに設定を行います。
私はeshellは使っていないのですが、ESSでRを使うので下記のように設定しています。

(add-hook 'inferior-ess-mode-hook
          (function
           (lambda ()
	     (local-set-key "\C-p" 'comint-previous-input)
	     (local-set-key "\C-n" 'comint-next-input)
	     (local-set-key "\C-r" 'comint-history-isearch-backward-regexp)
	     (local-set-key "\C-k" 'kill-line)
	     (local-set-key "\C-j" 'ess-smart-underscore)
             )))

蛇足かもしれませんがESSのヘルプの上下移動はjkで行うようにしています。

(add-hook 'ess-help-mode-hook
	  (function
	   (lambda ()
	     (local-set-key "j" 'ess-skip-to-next-section)
	     (local-set-key "k" 'ess-skip-to-previous-section)
	     )))

最後に

いかがでしたか。カーソル移動キーバインドを変更することは他のEmacsキーバインドを用いるソフトとの統一感がなくなるために抵抗を感じる方もいらっしゃるかもしれません。(特にkill-lineとか...でも上移動よりは使用頻度は少ないかと)
しかし設定

(global-set-key (kbd "C-;") 'anything)

を加えたりして、ホームポジションから一切動かずともバッファや、カーソルの移動ができるのを体感すると、なかなか気に入って頂けるのではないかと思っています。(コンソール内のEmacsでは使えませんが)

もし興味を持たれた方は、Emacs Advent Calendar 17日目の深町英太郎さんによる「Emacsのトラノマキ」の「元VimmerによるEmacsの再設計」もご覧下さい。

明日24日目はT-code使いであり、「便利なツールEmacsらくらく入門」の著者でもあられます@_ki_nuさんです。

最後の蛇足

私はCtrlをSpaceキーの位置にremapしています。