Promise and Generator #5

ex の executor はかなり書き換えたわけだが、一方で vi コマンドの executor というのも一応ある。これは ex ほど大規模ではなくて、単に vi コマンドの文字列をキー入力キューに挿入するだけだ。この機能は [cci].[/cci] コマンド及び [cci]@[/cci] コマンドが利用している。つまりいわゆるマクロ機能に相当する。

今回コマンドの実行が非同期になったことで難しくなったのは、マクロの実行が完了したタイミングが取れないということで


executeViCommand('2w');
doSomethingAfterExecute();

ということができない。そこで、キー入力の最後に特別な擬似キー [cci]*macro-end*[/cci] を付加するようにした。なぜマクロ完了のタイミングが重要なのかといえば、カウントというものがあるからだ。[cci].[/cci] の場合は実行する vi コマンド列がカウントを内包しているのであんまり関係ないのだが、[cci]@[/cci] の場合はそうではない。

そういうわけでこのマクロ実行完了を表す擬似キーを使う。対応するコマンドハンドラ内でカウントを見て、必要なら再度コマンド列をキー入力キューに充填したりすればいい。ところでそのハンドラは normal モードにしか存在しないので、マクロ実行完了時のモードもまた normal モードじゃいけない。つまり他のモードの場合は [cci]escape[/cci] キーを再充填するなどの処置も必要。

それから、[cci]@[/cci] コマンドというのは指定したレジスタの内容を vi コマンドとして実行する機能なのだが。そうすると今回施した修正の元、たとえば [cci]@a[/cci] という文字列がレジスタ [cci]a[/cci] に格納されている状態で [cci]@a[/cci] を実行すると実質的な再帰が起こってしまう。ちなみに vim 7.4 (2013 Aug 10, compiled Nov 24 2016 16:44:48) で試したところ、固まってしまった(固まらない時もある。よくわからない)。

というわけで、[cci]@[/cci] コマンドのもとで vi コマンドを実行している際は同じレジスタを使った [cci]@[/cci] コマンドを入れ子で使えないようにした。入れ子でなければいいので、@a が @b を呼び、それが @c を呼び…ということはできる。

Leave a Reply

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