Emacsにviっぽいノーマルモードを持たせるハックと、なんとなく実装

たまにはこっちのブログでプログラムの話をしたい。そう、僕はEmacsでもhjklで移動したい。


EmacsenがよくVimmerにバカにされるのは、小指を酷使する非人道的なキーバインドのせいじゃないでしょうか! 鋼鉄の小指を持つEmacsenでも、小指の限界がコーディングの限界だと恥ずかしいですよね!
僕も子供の頃のフライボールをキャッチしそこねて左手の小指を骨折してしまって、今でも少し変形してしまっています。あんまり酷使するとすぐヘタれます。
で、自分はEmacs上においてvimっぽいキーバインドを再現するviper-modeを愛用していたんですが、これすっごく重い。


じゃあもうviper-mode捨ててVim使えよ!と言われても仕方ないんですけど、かといってそこまで「Vimという環境」が好きなわけでもない。いろんな人に怒られそう!*1
なんとなくEmacsを使い続けてきたので、愛着がわいてしまってるんですね。anythingとか、anythingとか。fuzzyfinderなにそれ


viper-modeが重いのは、viの再現のためにviエミュレーションをelispで実装しているのが理由だと思われます。viper-cmd.el.gzなんかをみると、ご丁寧に一個ずつ定義してある。
僕としては完璧な再現なんて必要なくて、ぶっちゃけノーマルモード、インサートモードの分離ができればそれでいい。
自分で用意したマイナーモードのkeymapにノーマルモードとしてのキーバインドアサインしてしまえば、十分満足な 俺俺 emacsになるわけです。


で、実践

;;ノーマルモードとインサートモードのマップ
(defvar hoge-normal-map (make-keymap))
(defvar hoge-insert-map (make-keymap))

;;easy-mmodeでminor-modeを作る
(easy-mmode-define-minor-mode hoge-normal-mode
      "normal-mode mapping mode"
      nil
      " hoge[normal]"
      hoge-normal-map
 )
(easy-mmode-define-minor-mode hoge-insert-mode
      "insert-mode mapping mode"
      nil
      " hoge[insert]"
      hoge-insert-map
 )

;;toggle用の関数
(defun hoge-insert ()
  (interactive)
  (hoge-normal-mode 0)
  (hoge-insert-mode 1)
   )
  )
(defun hoge-normal ()
  (interactive)
  (hoge-normal-mode 1)
  (hoge-insert-mode 0)
  )
(define-key hoge-normal-map "i" 'hoge-insert)
(define-key hoge-insert-map "\C-z" 'hoge-normal)

これで 編集モードとノーマルモード(の雛形)が分離できました。あとは ひたすらそれぞれのキーマップに定義していくだけです。
ということで、vls.elというマイナーモードを書いてみました。自分にとって初elispです。1年ちょっとEmacsつかってるのに、prognもdefunもifの書式もさっきまで知らなかったってひどい話。


gist: 418084 - GitHub


見よう見まね。行儀がいい書き方かどうかは知らない。ひらすら定義しただけです。(なんだかanythingの存在が前提になってるような...)

使い方

パスが通った場所に置き ~/.emacs.d/init.el あるいは ~/.emacs.el で
(require 'vls)
(global-set-key "\C-cv" 'vls) ;; Ctrc-c v で起動
;;(global-vls-mode) ;;定義したけど副作用が大きいので推奨しない

vi標準の挙動に倣って h j k l o p i g(gg) G d(dd) a o v x あたりをマップしました。他は適当。
vimらしくない定義は自分の趣味。初期化してるあたりは非常に見苦しいですが、ASCIIのマップをどうにか取ってくると、もっと簡潔に書けそうな気がします。


IMEパッチが入ったCocoaEmacs23.2で動かしていますが、mac-change-language-to-us を使わなければ問題ないと思います。使うとノーマルモードに戻るときにIMEが自動でオフになっていい感じ。

TODO

ノーマルモードで日本語を挿入できないようにしたい

あんまり機能を増やすつもりはない。重くなると viper-modeと決別した理由がなくなるので。

こんなのでプラグインを名乗るのも、なんだかおこがましいですが、初めてなのでご容赦お願いします。

*1:Vimperatorは好きです