brushing up, input mode #3

input モードの動作と「.」レジスタ、「.」コマンド、および undo ログとの整合性をとる作業。だいぶ良くなってきた。

次に、^W あたりを片付けよう。これは input モード中、カーソル位置の直前の単語を削除する。

  • input モードに入った入力開始行・桁位置までは、undo ログではなくて現在の入力文字列を操作する(undo ログは backspace/delete/escape などのキーが押されたときに生成されるので)。入力開始位置をさらにさかのぼる場合は、undo ログを生成する。単語の両端が入力開始位置の前、後に亘っている場合はどうするか?
  • ちなみに、^W が入力開始位置をさかのぼれるのは([cci]:set bs=2[/cci] した場合の)vim の機能であって vi や nvi では入力開始位置より前には戻れない。wasavi は戻れるようにする。つまり vim 互換にする
  • ^W の動きはコマンドモードで db した場合に似てるのだが、微妙に違う。たとえば ^W は 各行の 1 桁目で必ず止まるとか。これはなんで?

この辺に留意しつつ vim のソースを眺めてみる。

 * * *

たとえば [cci]ifoo^[[/cci] と打ち、続けて [cci]abar[/cci] 左矢印 [cci]^W^[[/cci] と打ったとき。つまり

foobar
^ ^カーソル位置
|
+挿入開始位置
という関係。ただし、^W を打つ前に左矢印キーを打っているのでそこで挿入開始位置は更新され(input モード中の矢印キーは、いうなれば [cci]^[i[/cci] と打つようなものである。挿入開始位置はその時点のカーソル位置に更新される)、

foobar
^カーソル位置、挿入開始位置
という関係になる。

  • 入力文字列: “^W”
  • 入力コマンド: “a^W^[“
  • undo ログ:
    1. 桁 0 へ ‘foo’ を挿入
    2. 桁 2 へ ‘bar’ を挿入
    3. 桁 0 から ‘fooba’ を削除

となる。つまりこのケースでは挿入開始位置と削除される単語の位置関係は、単語が完全に挿入開始位置の前方に位置しているということになる。すなわち、undo ログを生成する必要がある。

一方、[cci]ifoo^[[/cci] と打ち、続けて [cci]abar^W^[[/cci] と打った場合は、挿入開始位置との関係が変わる。

  • 入力文字列: “bar^W”
  • 入力コマンド: “abar^W^[“
  • undo ログ:
    1. 桁 0 へ ‘foo’ を挿入

vim では input モード中の単語削除を行うために、削除される領域の左端を走査するループを行うのだが、このループは挿入開始位置で必ず抜けるようだ。つまり、削除領域が挿入開始位置をまたぐことはない。単に領域全体が挿入開始位置より前方か後方かの 2 パターンで考えればいい。このケースでは削除領域は挿入開始位置より後方であり、現在の挿入文字列を操作だけで undo ログは生成しない。

この仕様が妥当なのかどうかは、よくわからない。この仕様だと途中で打った “bar” は undo ログから完全に失われる。もっとだだ長い単語だったら再利用したい場合もあるのではないだろうか? あるいは、[cci]:set bs=2[/cci] な vim で input モード中に挿入開始位置より前にも自由にカーソルを再配置できるというのは、つまりユーザに挿入開始位置を意識させないためのものであるはずだが、しかし単語削除時については挿入開始位置を意識させることを強いるのは変な話なのではないか?

^W が押されたときに必要ならそこまでに生成された挿入文字列から undo ログを生成し、挿入開始位置をカーソル位置に更新すれば、削除処理は常に undo ログを生成する backspace でまかなうこともできる。どちらがいいだろうか悩むところだ。ただし、この単純化した処理は ^U には適用できないので(^U は「挿入開始位置からカーソル位置までの入力文字列を取り消す」。暗黙的に挿入開始位置を参照するわけではない)、vim 互換の処理が完全に不要というわけではない。

vim では、このへんは edit.c でやっている。input モード中の backspace 処理は ins_bs() が担当している。この機能はコマンドモードで db した場合と確かに似ているのだが、処理は ins_bs() で完結している。

Leave a Reply

Your email address will not be published. Required fields are marked *