ホーム » 技術 » viとvimと互換性

viとvimと互換性

viに初めて触れたのは1986年の頃だった。プログラミングの師匠に、Cでコードを書くならviが便利だと勧められたのだ。ところがそもそもviが動く環境がない。どうしたかというと、先輩の下宿に遊びに行くたびにPCを借り、プログラミングの手ほどきを受けるたびにviの使い方も習うという具合だった。自分で自由に使えるようになったのはPC-286v(これもPC-9800の互換PCだ)を買い、MS-DOSで動く互換viを手に入れた1988年だ。

メガネザルよりはるかに古いAT&Tのハンドブック

この頃は「MS-DOS SOFTWARE TOOLS」が出て、「MS-DOSを256倍使うための本」が出て、DOS環境をUnix化するのが(個人的な)ブームだった。SOFTWARE TOOLSのおかげで多くのコマンドがUnixぽくなった……が、問題はviだった。

この頃の自分にとってもっとも重要な事は、viがどの程度「本物」に近い動作をするか、ということだった。本物というのはもちろん、Bill Joyが作ったバージョンのviという意味だ。ただ、これを実際に使うことは非常に難しかった。1988年当時、Unixを触るには大学の計算機センターに行って端末の前に座るしかなかったのだ。何しろインターネットはまだ自由に使える時代ではなかったのだ。色々苦労してVAX11/785のアカウントを手に入れるのだが、それにしても徹夜でコードを書けるような環境ではない。そこで自宅のPCで、DOSで動く互換viを使うことになる。

当時の自分は、cursesのマニュアルを読みながらPC-9800のエスケープシーケンスでtermcapを作りメンテナンスするぐらいにviに凝っていた。脱線だが、termcapをチューンするとlessなんかも調子よく動く。ページバックするときに本当に逆スクロールさせるには、正しいエスケープシーケンスを登録しておかなければならないのだ。この延長で同じくcursesライブラリを使っていたNetHack用に98パッチを送る縁ができ、それがきっかけでdevteamに名前が載ることになるのだが、まあそれは別の話だ。viのキーバインドに慣れるためにrogueをやりすぎて、斜めにカーソルを動かそうとしたこともあった。

当時の互換viは、キーバインドをviっぽくしただけのなんちゃってviが多く、使っていると却ってストレスが溜まるエディタも多かった。たとえばviは「i」と「ESC」を交互に押すとカーソルは左へ1文字ずつずれていく(わかりますよね?)。ところがいい加減な実装だと、これが再現できていない。そんな事が重要か? と思うかもしれないが、viをタッチタイプで使っているとコマンドモードでのカーソルの移動が思った場所に行かないことが途方もないストレスになる。なのでごくごく些細な振る舞いも、どうしても見逃せない瑕疵に思えてしまうのだ。

もうひとつ例を挙げよう。「cw」などとしたときの振る舞いだ。互換viではこれを「dwi」っぽい動作で代替することがある(最後のスペースを削除しないので厳密には異なる)。最終的な結果は同じかもしれないが、画面の書き換えの様子は全然異なる。本物のviには「ボーレートが低い端末で画面書き換え工程を最小にするために、変更範囲を$で示す」という機能が備わっている。なので、具体的には以下のような差になって表れる。

viとvimの違い

これも一見つまらない機能に見えるが、慣れると手放せなくなってしまう。自分の場合、retypeするようなときは「元々何と書いてあったか」が表示されていた方が修正しやすく、とても便利だからだ。それなのに互換viのようにバッサリ消されてしまうと「あれ、なんて書こうと思ってたんだっけ」ということになってしまう。

時代はvim

さて、時代は変わって無料のUnixが世に出回ってきたころ。FreeBSDを使っていたときは何の問題もなかった。FreeBSDにはnviという非常に互換性の高いviが備わっていたので、文句のつけようがなかったのだ。だが仮想化ショック後、Linuxに乗り換えると事情が変わった。Linuxにnviはなく、vimを使わなければならないからだ。実はvimはMS-DOSの頃に触ったことがあり、やはり互換性の問題で使うのをあきらめた系のエディタだった。それから20年過ぎて他に選択肢がなくなってしまったので渋々使い始めたのだが、vimは大きく進化していた。vimのvi互換モードは、viを完璧に再現できているという。すばらしい!

.vimrcを書き始めるにあたって、まず最初にやるべきなのは

set compatible

と書くことだ。これでvi互換は保たれる。あとはお好みのオプションを好きなだけ書き加えればよい。

……さて、これで話はおしまいなのだが、これだけではツマラナイのでもう少し話を続けよう。vimがvi互換性を実現するために具体的にどんなことをしているのかを調べてみたい。

vimのvi互換性

set compatible は見た目はシンプルだが、その動作はかなり複雑だ。なにしろ1つのオプションを設定すると、69個のオプション設定に影響が及ぶ。これらは、vimによって拡張された機能の数々を、vi互換性のために無効にしたり、調整するために変更される。なので、自分にとっては「vimにおいて追加された、viとは互換性のない新機能」のリストに見える(わはは)。ざっと見てみると、たしかにvimのほうが合理的だなとか、新機能は便利だなと思われるものもなくはない。

たとえば expandtab というオプションがある。これは TAB を同等のスペースに置き換える機能だ。Python や YAML を書くときは重要と思うが、常にONにしておきたいワケではない(たぶんsyntax解釈と絡めると便利に使えるのだろうが、そういう機能も求めていないので使っていない)。

tildeop もちょっと魅力的だ。これはチルダコマンド(大文字と小文字を変換する機能がある)をオペレーターとして扱うというオプションだ。だが本物の動作に慣れすぎて、ちょっとONにするのが怖い(ONにしてしまうとチルダが即座に実行されなくなる)。

さて、これらは新機能という観点からの評価になるが、一方で「互換性の有無を指定するオプション」として cpoptions が気になる。こちらは52個ものオプション文字からなる。それらは、実に瑣末な振る舞いの違いを指定することができるようになっている。

たとえば「H」オプションは「空白のみを含む行の上で “I” を使ったとき、最後の空白の前から挿入する。このフラグが含まれていないと、最後の空白の後から挿入を開始する」とある。ぶっちゃけどうでもよさそうに見えるが、どうでもいいなら本物と同じ動作であってほしい、と思うわけだ。

cpoptionsで気になるのは p だろうか。これはLisp用インデントモードのとき、vi互換かvim拡張かを選べるオプションなのだが、「これが含まれないと、いくらか良いアルゴリズムが使われる」とマニュアルに書いてある。個人的にはこういう曖昧な表現は大好きだし、なんだかOFFにすべきかなと思えてくるのだが、最近 vi の Lisp モードなんて使ってないので、いちいち設定するまでもないかと思いとどまるのだった。

さて、vimの拡張で唯一利用しようと思ったのが cpoptions の「%」だ。これは % コマンド(対応するカッコにジャンプする)を拡張するもので、vimでは #if / #endif ペアや “/*” / “*/” ペアのような文字列もカッコとして扱ってくれるし、ダブルクォートで括られた文字列内のカッコを無視して「賢く」対応するカッコを探してくれるというのだ。これは確かに便利なので、これだけ利用したい。そういう場合は .vimrc にこんな風に書く。

set cpo-=%

逆に、もしも前述した「$」表示機能を利用したいという正統派vimmerの方がいらっしゃるなら、このように記述すればよい。

set cpo+=$

ところで

つらつら書いていてひとつ気づいたことがあるのだが、長いコンピュータ人生において自分が最初に触れたエディタはviだったんだなということに今さら思い至った。vi以前は、Turbo PascalについていたWordstar互換の簡易エディタか、それより以前だとMAIコンパイラとかPORTについていたラインエディタ、はたまたN-BASICのエディタとは呼べないようなエディットモードが原体験で、きちんと機能を持ったエディタはviが最初だったのだ。vzもMifesもこれより後の話なので、そりゃあviが好きに決まってるよなあと改めて思う次第だった。

参考リンク