むしろ日本語の長文は Vim で書く、Vim 使いの「ブイ」(仮名)です。第 5 回目のテーマは「アンドゥ」です。vi は一回のアンドゥ・リドゥしかできませんが、Vim の場合は無限アンドゥ・リドゥ [1] をサポートしています。それだけではなく、Vim には他のエディタでも例を見ない高度なアンドゥ機能があります。アンドゥはとても奥が深いのです。
1 アンドゥとリドゥ¶
vi は直前の操作を元に戻すアンドゥ機能があります。u
を一度押すとアンドゥになり、u
をもう一度押すと、アンドゥのアンドゥ = リドゥになります。ただし、このアンドゥは一度しかできません。最近のテキストエディタはメモリの許す限りの無限アンドゥが普通なので、この仕様はものすごく不便です。
具体的な例で説明します。
hogehoge
hogepiyopiyo
hogerahoge
hogerapiyopiyo
hogehoge
hogepiyopiyo
上記のテキストがあったとして、”hogehoge” と “hogerahoge” の行を下記のように “hogepiyo”, “hogerapiyo” と変更したいとします。
hogepiyo
hogepiyopiyo
hogerapiyo
hogerapiyopiyo
hogehoge
hogepiyopiyo
まず、”hogehoge” の行の “hoge|h|oge” にカーソルを移動します。||
はカーソル位置を表します。
hoge|h|oge
hogepiyopiyo
そして cwpiyo<ESC>
を入力 [2]、”hogehoge” の行を “hogepiyo”
に変更します。
hogepiy|o|
hogepiyopiyo
そして、”hogerahoge” の行へ移動し、”hogera|h|oge” の位置にカーソルを移動、.
を入力すれば編集作業は終了します。しかしあなたは間違えて、”hoger|a|hoge” の位置で .
を入力してしまいました。行が”hogerpiyo”
となってしまっています。
hogepiyo
hogepiyopiyo
hogerpiyo
hogerapiyopiyo
hogepiy|o|
hogepiyopiyo
しかも、それに気付いたのは二つ目の “hogehoge” を”hogepiyo” に変更した後でした。vi だと、二回目のアンドゥができないため、”hogerhoge” は手で修正しないといけません。しかしVim なら uu
を押すことで、両方の変更を元に戻すことができます。
hogepiyo
hogepiyopiyo
hogerahoge
hogerapiyopiyo
hogehoge
hogepiyopiyo
Vim では、u
を連続して押すと、アンドゥのアンドゥ( = リドゥ)ではなく、連続したアンドゥとなります。Vim のリドゥは u
ではなく、<C-r>
を用います [3]。
ちなみに、Vim のアンドゥ・リドゥはインサートモードの場合、<ESC>
で抜けるまでを 1 回の編集としてカウントしています。このため <ESC>
でインサートモードを抜けるほうがアンドゥを便利に使うことができます。ただしインサートモード中に <C-g>u
を入力すると、1 回の編集単位を区切ることができます。
2 時間によるアンドゥ¶
アンドゥ回数が多いと、アンドゥ操作は煩雑になります。「失敗して訳が分からなくなったので、ちょっと前の作業状態に戻りたい」と思ったことはないでしょうか。普通のエディタなら、バージョン管理システムを使用しないと無理ですが、Vim ならば標準で可能です。
:earlier {時間}{単位}
というコマンドを使うと、その時間の状態に戻ることができます。例えば、:earlier 10s
を実行すると、10 秒前の状態に戻ります。時間単位でリドゥするときは、:later {時間}{単位}
というコマンドを使用します。これは現在の状態から、その時間だけ後の作業状態に戻すという意味です。
Vim はアンドゥを時間単位で管理しているため、このような操作ができます。
3 アンドゥの永続化¶
Vim 7.3 以降にはアンドゥの永続化機能があります。アンドゥの永続化とは、アンドゥの履歴をファイルに保存し、Vim を一度終了したとしてもアンドゥやリドゥを行えるようにする機能です。
アンドゥの永続化を有効にするには、設定が必要となります。.vimrc に次の設定を追加しましょう。
set undofile
undofile
オプションをセットすることで、アンドゥ履歴をファイルに保存することができます。undodir
オプションにより、アンドゥファイルの保存場所を変更できます。ちなみに、アンドゥ履歴は暗号化されています。
4 アンドゥツリー¶
一度アンドゥをしてから別の変更を行うと、リドゥの履歴は消えてしまいます。これは、アンドゥ・リドゥの履歴が一方向なためです。
A -> B -> C
A -> B C
| -> D
例えば、図のように A から C という編集履歴があったとき、一度アンドゥをすると状態は B に戻ります。さらに別の変更をすると、状態は D になります。この状態でアンドゥ・リドゥをしても、A, B, D は辿ることができますが、C は辿ることができなくなります。
しかし、Vim 7.0 よりアンドゥ・リドゥの履歴がツリー化し、自在に編集履歴を移動できるようになりました。この機能は、バージョン管理システムでのブランチの切り替えによく似ています。
この機能の鍵となるのが、g-
と g+
のキーマッピングです。先ほどと同じ例で説明をします。
A(1) -> B(2, 4) C(3)
|--------> D(5)
内容は同じですが、編集の時間軸に従って番号を付けてみました。g-
,
g+
は時間軸方向に編集履歴を辿ります。現在、D の状態にいるとします。一度 g-
を入力すると、B に戻ります。もう一度 g-
を入力すると、A ではなく、C に戻ります。なぜなら、時間軸的には D の前は C だったからです。そこは u
と挙動が異なります。時間軸で編集履歴を戻ることにより、u
と <C-r>
では辿りつけなかった、C への参照が可能となります。
この編集履歴をビジュアルにグラフで表示してくれる gundo.vim というプラグインがあります。https://github.com/sjl/gundo.vim 興味があるなら、インストールしてみるとよいでしょう。
次回は「vi との互換性」について解説する予定です。
[1] | 実は、アンドゥ回数の最大数は “undolevel” オプションで制限されています。普通 “1000” です。100 回以上連続してアンドゥするのは通常考えられないため、この数で十分なはずです。 |
[2] | 普段 vi を使用している方は、Vim で cw を入力したときに末尾が “$” にならないのを不満に思っているかもしれません。そんなあなたは、次回の「vi との互換性」の記事を参照してください。 |
[3] | この挙動が気に入らない場合、cpoptions オプションを調整することで、undo の挙動を変更することができます。詳しくは次回解説予定です。 |