動機
Vim歴がもうすぐ7年になろうとする私ですが、そもそもVimを使い始めた理由は当時のエディタの中でアンドゥ(元に戻す)の機能が最も優れていたのがVimだったからです。
しかし、Vimのアンドゥ機能は十分に理解されているとは言い切れないと思っています。そこでこの記事ではVimのアンドゥ機能について解説を加えていきます。
本編
Vimのアンドゥ機能の基本
Vimではアンドゥをu、リドゥをCtrl+rで行います(どちらもノーマルモードでの話)。
Vimはアンドゥの履歴をツリー状にかつ無制限に保存できます。特に「ツリー状」のアンドゥ機能(アンドゥツリーとも言われます)を持つエディタはなかなか珍しいのではないかと思います。
アンドゥ機能がツリー状であることとモーダル形式の編集が合わさることでVimの強力な優位性が生まれます。モードに入ってから出るまでが一つのアンドゥ単位であるため、論理的に意味のある編集(インサートモードで特定の文字列を入力する・c2wなどで文字列の変更を行うなど)を繰り返すことであたかも各編集がGitにおけるコミットであるかのように扱うことができます。
アンドゥツリー間の移動がブランチのチェックアウトと似ている点が重要で、プラグインを使ってアンドゥツリーを可視化することでGitに近い操作性で過去の編集を取り戻すことができます。
具体例
class Foo
def bar
puts 'bar'
end
end
以上のファイルが与えられているとします。ここで、メソッド名を変更します。
class Foo
def baz
puts 'bar'
end
end
しかし、この変更はあまり良くないとわかったため、uで操作をアンドゥしoriginalに戻ります。
その後、今度はクラス名を変更します。
class Hoge
def bar
puts 'bar'
end
end
ここで、modified2からmodified1に戻るにはどうすればいいのでしょうか?
Vimの標準機能でやる場合、:undolistでアンドゥの一覧を取得しundo nでn番のアンドゥ履歴を復元できます。しかし、これはあまり直感的ではありません。
私はundotreeというプラグインを使っています(レポジトリのURL)。これはアンドゥツリーをビジュアルに表示するツールです。jとkのようなVim標準の操作で履歴間を移動し、差分のプレビューを見ながら目的の履歴を復元できます。
これはundotreeプラグインでmodified1の状態に復元したところです。どこが変更されたのかも含め、わかりやすく表示されています。
実際に試してみるとわかるのですが、FooをHogeに変更した、これをu一つで戻れるだけでもかなり便利です。さらにツリーの機能により、「さっきのあの状態」に戻れるという安心感を得ることができます。
アンドゥの永続化
ここまででも便利なアンドゥ機能ですが、なんとVimを閉じたあともアンドゥを保存しておけるという機能があります。
設定は簡単で、
if has("persistent_undo")
set undodir=~/.undodir
set undofile
endif
こんな感じのコードを.vimrcに記述するだけです(~/.undodirの箇所を好みの場所に書き換えてください)。
タイムトラベル
Vimには履歴を順に行ったり来たりする機能だけではなく、履歴を時間指定する機能まであります。機能の性質上例示が難しいのですが、:earlier 1dで1日前の状態に戻れるようです。
小ネタ:インサートモードの途中で履歴を分けたい場合
通常、インサートモードでの文字列の追加は全て一つのアンドゥ単位として扱われます。しかし、長文を入力するときなど、途中でアンドゥの区切りを入れたくなるときがあります。そういったときはCtrl+g uをインサートモード内で使います。
まとめ
Vimのアンドゥ機能についてざっとまとめてみました。機能として必要十分であり、プラグインの支援を得ることでとても強力なものになりえます。普段Vimを使っている方もそうでない方も、色々と試してみることをおすすめします。
参考文献
:h undo.txt
:h usr_32.txt