vim-jp/issues — Issue #148: vi 互換モードで、an Empty region に対するコマンドがエラーになった時の "." コマンドの動作が不正
Author: hdk1983
Created: 2012-01-26 14:07:35+00:00
State: open

vi 互換モードで、an Empty region に対するコマンドがエラーになった時の . (ピリオド) コマンドの動作が不正です。An Empty region に対する操作がエラーになる、cpoptions E がセットされている時に発生します。
不正というのは、コマンドがエラーになっているにも関わらず、次の . コマンドでエラーになったコマンドが再実行されたり、. コマンドの処理中にエラーが発生しているにも関わらず、. コマンドの処理が中止されません。

再現手順 (1):
まず簡単な例を示します。
1. vim -u NONE で vim を起動する
2. :set cpoptions+=E
3. hoge という文字列を入力する (ahoge[ESC])
4. 行頭で an empty region に対するエラーになる操作を行う (0c0, 0y0, 0d0 など)
5. . (ピリオド)でコマンドを再実行する
期待される結果:
3 のコマンドが再実行され、以下のような表示になる:

hhogeoge

実際の動作:
4 で失敗したはずのコマンドが再実行される。

再現手順 (2):
ちょっと複雑な例を示します。
1. vim -u NONE で vim を起動する
2. :set cpoptions+=E$
3. foo という文字列を入力する (afoo[ESC])
4. c0 を使って hogeo という文字列にする。c0 の後にバックスペース等を使わず確実に h を入力する (c0hoge[ESC])
5. 行頭で . (ピリオド) コマンドを実行する (0.)
ビープ音が鳴り何も起きない
6. 行末に移動し . (ピリオド) コマンドを実行する ($.)
期待される結果:
4 のコマンドが再実行される。内容は変化しない。
実際の動作:
c0 だけを入力したのと同じ状態になる。以下のような表示になる:

hog$o

実は、5 の時に Vim は h をカーソル移動として実行しようとして失敗し、ここで . (ピリオド) コマンドの実行が中止されています。

再現手順 (3):
ちょっと極端な例を示します。
1. vim -u NONE で vim を起動する
2. :set cpoptions+=E
3. hoge という文字列を入力する (ahoge[ESC])
4. 次のような操作を (間違えてバックスペース等を入力しないように) 行い、文字列を変更する: c0:q![RET][ESC]
画面は以下のようになり、行頭の e のところにカーソルが来る:

:q!
e

5. . (ピリオド)でコマンドを再実行する
期待される結果:
4 のコマンドの再実行には失敗するので、何も起きない。
実際の動作:
4 のコマンドの再実行に失敗しているにも関わらず後ろの入力である :q! が引き続き処理され、vim が終了する。

vim-tiny で vi 互換モードをよく使っているのですが、癖で c0 という操作をよく使っているようで、見つかりました。. コマンドで入力モードに入ったままになるというのは、traditional vi ではありえない動作なので、結構気になります。
パッチを作ってみたのですが、これで問題ないかどうかの自信はありません。修正内容も、とりあえず気になるところだけ直したので、他にも (例えば互換モードでなくても) . コマンドの問題が起きるパターンがあるかも知れません。
https://code.google.com/r/hdk1983-vim/source/detail?r=f8fd62f7777cf2d0cc1fdd47fbc465e230520877

互換モードユーザーは少ないかも知れませんが、vim はいろんな Linux ディストリビューションで vi の代わりの標準コマンドとして採用されていて、触る機会が多いので、このような互換モードのバグも適切に修正されると嬉しいです。