ex コマンド最後のテスト、@ コマンド。
@ コマンドは、指定のレジスタに格納されている文字列を ex コマンドとみなし、実行する。vi コマンドにも @ があり、vi コマンド版 @ は ex コマンドを含むことができるのでつまり上位互換ということになっている。ex コマンド版の @ はレジスタの内容をあくまで ex コマンドとして実行する。
[addresses]@register
レジスタが省略されたか、文字 @ が指定された場合は、最後に実行されたレジスタ名が用いられる。レジスタの実行がまだ 1 度も行われていない場合は、エラーになる。
addresses で指定された範囲の各行について、まず現在行( . )にセットされ、そしてその時点で @ コマンドが実行されたかのように、名前付きレジスタの内容が ex コマンドとして実行される。ex コマンドパーサは、行指向で保存されたレジスタの各行と、文字指向で保存されたレジスタの最終行以外の行は、末尾に改行がついたものとして扱う。
処理の間にエラーが発生した場合、または addresses で指定された行がそれを現在行としてセットする段階で存在しなかった場合、または addresses として複数行が指定されかつバッファの内容が(たとえば ex コマンド edit によって)置き換えられた場合、エラーとなり、エラーメッセージが表示され、このコマンドの実行は打ち切られる。
* * *
最後の段落以外は、特に問題はない。最後の段落は実はよくわからない。たとえば現在行の次の行を削除するような ex コマンド(+1d とか)を、複数行を対象に、@ コマンドで実行したとする。すると、仕様で言っているような addresses には含まれているが、レジスタの内容を実行する段階では存在しない行というのが確かに生まれる。仕様では、そういう行を見つけたら即エラーにすると言っている。それはどうなのか? その動作は global コマンドとも異なっている(global コマンドはマッチした行を覚えておくフェーズと、それらの各行に対してコマンドをは実行するフェーズで構成される。第 2 フェーズのループ内では、第 1 フェーズにおいて覚えておいた行が存在しなくてもエラーにせず、次の行へスキップする)。
また、レジスタに格納されている ex コマンドが明示的に addresses を含んでいる場合、@ コマンドに対する addresses とどう折り合いをつけるかは仕様では示されていない。置き換えるのか、マージするのか、レジスタのそれを優先するのか?
vim はこの点について、@ コマンドに付随するアドレスは addresses ではなく実質的に address であるという仕様にしているようだ。これはちょっと特殊で、コマンド自体は複数行の範囲を受け付けるが、実行はその先頭行のみに対して行われる。先頭行を現在行に設定しレジスタの内容を実行する、それで終わり。ヘルプを読む限りでは将来的には複数行に対応するかもねということになっているが、posix による定義が曖昧なのが解決しない限り対応は難しそうだ。
ということで、wasavi でもそれに従う。