faux の Vim キーバインド対応

github.com

faux で Vim キーバインドを使えるように対応を行った時に調べた CodeMirror (v5) のキーバインド拡張についてのメモです。

CodeMirror のキーバインドの拡張

https://codemirror.net/doc/manual.html#option_extraKeys

キーバインドの簡単な拡張方法として、extraKeys オプションを利用する方法があります。

ただし、この方法でキーバインドを追加した場合は KeyMap の設定に関わらず常に有効な設定となります。

今回は KeyMap 毎に別のキーバインドを追加したいので、この方法は利用できません。

KeyMap 毎の拡張方法を調べたのですが残念ながら見つけられず、諦めて各々の KeyMap 設定に直接追加する方法で拡張を行いました。

KeyMap 設定は、CodeMirror.keyMap オブジェクトにそれぞれ格納されており、標準の KeyMap であれば CodeMirror.keyMap.basicEmacs であれば CodeMirror.keyMap.emacs となります。

例えば Emacs であれば、以下のように任意のキーバインドを追加できます。

CodeMirror.keyMap.emacs['Ctrl-X Ctrl-C'] = function() { alert('bye!') };

しかし Vim はモードがある為か事情が異なり、この方法では追加できません。ただしその代わりに API が存在します。

Vim キーバインドの拡張

VIM Mode API

CodeMirror.Vim オブジェクトを通じて API を利用する形となります。

キーバインドの追加には、map または mapCommand を利用します。

map

map(lhs: string, rhs: string, ?context: string)

map はキーとコマンドのマッピング設定を行えます。

あるキーから別のキーやコマンドへ、または、あるコマンドから別のコマンドやキーへとマッピングすることができます。

例: gonextline コマンドで j を押した時と同じ動作をする

CodeMirror.Vim.map(':gonextline', 'j');

mapCommand

mapCommand(keys: string, type: string, name: string, ?args: object, ?extra: object)

mapCommand はキーに対応するコマンドのマッピング設定を行えます。

type に motion / operator / action などを指定し、name で実行するコマンド名を指定します。

新しいコマンドが必要な時は、defineMotion / defineOperator / defineAction で定義できます。

例:キー ZQ で bye とメッセージを表示する

CodeMirror.Vim.defineAction('end', function() { alert('bye'); });
CodeMirror.Vim.mapCommand('ZQ', 'action', 'end', {});