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の書式もさっきまで知らなかったってひどい話。
見よう見まね。行儀がいい書き方かどうかは知らない。ひらすら定義しただけです。(なんだか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
- r の置換実装
- g と d と , をプレフィックスに
− ノーマルモードで日本語を挿入できないようにしたい
あんまり機能を増やすつもりはない。重くなると viper-modeと決別した理由がなくなるので。
こんなのでプラグインを名乗るのも、なんだかおこがましいですが、初めてなのでご容赦お願いします。
*1:Vimperatorは好きです