まず backspace、つまりコントロールコード \u0008 を考える。キーボードから “ifoa^Ho^[” と打つと:
- 入力テキストは “foa^Ho”
- 入力コマンドは “ifoa^Ho^[“
- undo ログは 3 つのアイテムを含んだクラスタ: “桁 0 へ ‘foa’ の挿入”, “桁 3 から後方に 1 文字削除”, “桁 2 へ ‘o’ の挿入”
また、キーボードから “i^H^H^[” と打った場合は:
- 入力テキストは “^H^H”
- 入力コマンドは “i^H^H^[“
- undo ログは “桁 0 から後方に 2 文字削除”
となる。なお vim の場合、^H と backspace を内部的に区別しているのだが wasavi ではそこまではしない。どちらも \u0008 として扱う。
追記: カーソルが 1 行 1 桁、つまりバッファの先頭にあった場合に上記ストロークを打った場合は、
- 入力テキストは “”
- 入力コマンドは “i^[“
- undo ログは生成されない
となる。この状態で . コマンドを実行するとカーソルが左に 1 文字移動するように見えるのは、つまり “i^[” の副作用だ。
次に delete。これに対応するコントロールコードは、wasavi においては ^_、つまり 0x7f だ。”d” の上にカーソルがある状態でキーボードから “i^_b^[” と打てば:
- 入力テキストは “^_b”
- 入力コマンドは “i^_b^[“
- undo ログは 2 つのアイテムを含んだクラスタ: “桁 0 から前方に 1 文字削除”, “桁 0 へ ‘b’ の挿入”
となる。考え方は backspace と同じ。
一方、特殊キーはどうか。input モードにおける特殊キーというのはつまり、カーソルを移動させるキー: 矢印キー、Home、End、PageUp、PageDn のことだ。そして input モード中のカーソル移動というのは、実はいったん command モードへ抜け、vi コマンドによりカーソルを移動させ、再度 input モードに入るという手順と意味は同じなのだ。したがって最初の input モードで入力した文字列と次の input モードで入力した文字列はそれぞれ独立したものとなる。これは undo ログも同じ。”ifoo” 左矢印 “bar^[” と入力した場合、左矢印キーを押した時点でまず
- 入力テキスト: “foo”
- 入力コマンド: “ifoo”
- undo ログ: “桁 0 から ‘foo’ を挿入”
という結果が生成されるが、直後に新しい input モードのセッションが開始する。undo ログはリスト構造であり、独立した 2 つのログが最終的に生成されるが、入力テキストと入力コマンドはそうではないため上書きされ、最後のセッションの結果が残る。つまり最終的に
- 入力テキスト: “bar”
- 入力コマンド: “ibar^[“
- undo ログ: 2 つのクラスタ
- “桁 0 へ ‘foo’ を挿入”
- “桁 2 へ ‘bar’ を挿入”
となる。undo ログが独立しているというのは、u を押すとまず bar が削除され、さらに u を押すと foo が削除されるということだ。なお、undo ログで桁位置も記録しているが、挿入系と削除系で意味合いが違う。前者は入力を開始した位置、後者は現在のカーソル位置だ。入力開始位置は input モードのセッション中は不変だが、backspace / delete で新規セッションが強制開始した場合は入力テキスト・コマンドと共に初期化する必要がある。