vim-jp / vimdoc-ja / undo

undo - Vim日本語ドキュメント

メインヘルプファイルに戻る English | 日本語 | 編集
undo.txt      For Vim バージョン 9.1.  Last change: 2024 Nov 09


                  VIMリファレンスマニュアル    by Bram Moolenaar


undo と redo                                            undo-redo

基本的なことは 02.5 で説明されています。

1. undo と redo のコマンド      undo-commands
2. Undo の二つの方式            undo-two-ways
3. Undo ブロック                undo-blocks
4. Undo ブランチ                undo-branches
5. Undo の永続化                undo-persistence
6. 備考                         undo-remarks

==============================================================================
1. undo と redo のコマンド                              undo-commands

<Undo>          or                                      undo <Undo> u
u                       [count] 個の変更を元に戻す。

                                                        :u :un :undo
:u[ndo]                 一つの変更を元に戻す。

                                                                E830
:u[ndo] {N}             変更番号 {N} の直後にジャンプする。{N} の意味について
                        は undo-branches を参照。

                                                        CTRL-R
CTRL-R                  undo された変更を [count] 個やり直す (redoする)。

                                                        :red :redo redo
:red[o]                 undo された変更を一つやり直す。

                                                        U
U                       最近変更された行の、一つの行の中でのすべての最近の変更
                        を元に戻す。U 自体も変更としてカウントされます。つま
                        り U によってその前の U を元に戻すことができます。

変更は記録されます。上記の undo コマンドや redo コマンドを使うと、それぞれの変
更が加えられる前のテキストに戻したり、変更を元に戻した後でその変更を再び加える
ことができます。

"U" コマンドは他のコマンドと同様に undo/redo の対象となります。つまり、"u" コ
マンドで "U" コマンドを undo したり、'CTRL-R' コマンドでそれを redo したりでき
ます。"U" と "u" と 'CTRL-R' を混ぜて使うと、"U" コマンドが直前の "U" コマンド
以前の状態を復元することに気づくでしょう。この動作はわかりにくいかもしれません
が、練習して慣れてください。
"U" コマンドはバッファを変更有りの状態にします。つまり、"U" コマンドで変更が加
えられる前のテキストに戻しても、それは変更有りの状態として認識されます。"u" を
使って変更無しの状態まで undo してください。

==============================================================================
2. undo の二つの方式                                    undo-two-ways

undo コマンドと redo コマンドの動作は 'cpoptions' の 'u' フラグに依存していま
す。Vim 方式 ('u' がない場合) と Vi 互換方式 ('u' がある場合) があります。Vim
方式では "uu" は二つの変更を undo します。Vi 互換方式では "uu" は何もしません
(undo を undo する)。

'u' がない場合。Vim 方式:
undo コマンドで過去に戻れます。そして、redo コマンドで再び先に進むことができま
す。undo コマンドを実行した後で新しい変更を加えると、redo はできなくなります。

'u' がある場合。Vi 互換方式:
undo コマンドは直前の変更と undo コマンドを undo します。redo コマンドは直前の
undo コマンドを繰り返します。変更コマンドが繰り返されるわけではないので、そう
したい場合は "." を使ってください。

例              Vim 方式                Vi 互換方式
"uu"            2回 undo                変更なし
"u CTRL-R"      変更なし                2回 undo

理由:       Nvi では CTRL-R の代わりに "." コマンドを使います。あいにくこれは
            Vi 互換ではありません。例えば、"dwdwu." は Vi では二つの単語が削除
            されますが、Nvi では何も変更されません。

==============================================================================
3. Undo ブロック                                        undo-blocks

undo コマンドは普通は一つのコマンドを undo します。そのコマンドがいくつの変更
を加えるかは関係ありません。この undo 可能な変更の組が undo ブロックです。例え
ば、キーの入力によって関数が呼ばれた場合、その関数内のすべてのコマンドは一緒に
undo されます。

関数やスクリプトを作るとき、undo 可能な変更を新しく追加するのではなく、その変
更を直前の変更につなげたい場合は、次のコマンドを使ってください:

                                                :undoj :undojoin E790
:undoj[oin]             以降の変更を直前の undo ブロックにつなげる。
                        警告: 注意して使ってください。ユーザーが適切に変更を
                        undo するのを妨げてしまうかもしれません。undo や redo
                        の後でこのコマンドを使わないでください。

これは特に変更の途中でプロンプトを表示するような場合に便利です。例えば関数の中
で getchar() を呼び出すなど。変更をつなげてしかるべき関連性のある変更がそこ
にあることがわかっている場合に使ってください。

このコマンドは単独では機能しません。なぜなら、次のキー入力によって再び新しい変
更が開始されるからです。しかし例えば次のように使うことはできます:

        :undojoin | delete

この後で "u" コマンドを実行すると delete コマンドとその直前の変更が undo され
ます。
                                        undo-break undo-close-block
反対の動作、つまり次の変更で新しい undo ブロックを使うには、挿入モードで
CTRL-G u を使います。挿入コマンドを部分ごと (例えば文単位) に undo できるよう
にしたい場合に便利です。 i_CTRL-G_u

'undolevels' の値を設定したときも undo のブロックが閉じられます。新しい値と古
い値が同じでもそうなります。g:undolevels を使用して、'undolevels' のグローバ
ル値のみを明示的に読み書きします。Vim9 script では:
        &g:undolevels = &g:undolevels
旧来のスクリプトでは:
        let &g:undolevels = &g:undolevels

Note 同様に見える代入 let &undolevels=&undolevels は、ローカルオプションが別
の値に設定されている場合、グローバルオプションの 'undolevels' 値を保持しないこ
とに注意してください。例えば:
        " 'undolevels' に異なるグローバル値とローカル値を使用して開始する。
        let &g:undolevels = 1000
        let &l:undolevels = 2000
        " この代入により、グローバルオプションが 2000 に変更される。
        let &undolevels = &undolevels

==============================================================================
4. Undo ブランチ                                undo-branches undo-tree

ここまでは一線上の undo/redo について説明してきました。しかし、それを枝分かれ
させることもできます。枝分かれは、変更を undo してから新しい変更を加えることで
起こります。undo された変更は枝 (ブランチ) になります。以下のコマンドで枝に移
動できます。

ユーザーマニュアルに説明があります: usr_32.txt.

                                                        :undol :undolist
:undol[ist]             変更木 (tree) の、葉 (leaf) を一覧表示する。例:
                           number changes  when               saved
                               88      88  2010/01/04 14:25:53
                              108     107  08/07 12:47:51
                              136      46  13:33:01             7
                              166     164  3 seconds ago

                        "number" 列は変更番号です。この番号は連続的に増えてい
                        き、undo 可能な変更の識別番号として使えます。 :undo
                        参照。
                        "changes" 列は木のルートから葉までの変更の数です。
                        "when" 列は変更が加えられた日付と時刻です。日時の表記
                        は 4 種類あります:
                            N seconds ago        秒前
                            HH:MM:SS             時:分:秒
                            MM/DD HH:MM:SS       月/日 時:分:秒
                            YYYY/MM/DD HH:MM:SS  年/月/日 時:分:秒
                        "saved" 列は変更がディスクに保存されたかどうか、そして
                        それがどの書き込みだったかを示します。この番号は
                        :later コマンドと :earlier コマンドで使用できま
                        す。
                        詳細を取得するには undotree() 関数を使います。

                                                        g-
g-                      古いテキスト状態に移動する。カウント指定で繰り返し回数
                        を指定できます。
                                                        :ea :earlier
:ea[rlier] {count}      {count} 回前の古いテキスト状態に移動する。
:ea[rlier] {N}s         {N} 秒前の古いテキスト状態に移動する。
:ea[rlier] {N}m         {N} 分前の古いテキスト状態に移動する。
:ea[rlier] {N}h         {N} 時間前の古いテキスト状態に移動する。
:ea[rlier] {N}d         {N} 日前の古いテキスト状態に移動する。

:ea[rlier] {N}f         {N} 回前のファイルを保存したときのテキスト状態に移動す
                        る。
                        最後の保存から何か変更が加えられていたとき、":earlier
                        1f" は保存時の状態に移動します。変更がない場合は一つ前
                        の保存時の状態に移動します。
                        最初にファイルを保存した直後か、ファイルをまだ保存して
                        いないときは、":earlier 1f" は最初の変更の前に移動しま
                        す。

                                                        g+
g+                      新しいテキスト状態に移動する。カウント指定で繰り返し回
                        数を指定できます。
                                                        :lat :later
:lat[er] {count}        {count} 回後の新しいテキスト状態に移動する。
:lat[er] {N}s           {N} 秒後の新しいテキスト状態に移動する。
:lat[er] {N}m           {N} 分後の新しいテキスト状態に移動する。
:lat[er] {N}h           {N} 時間後の新しいテキスト状態に移動する。
:lat[er] {N}d           {N} 日後の新しいテキスト状態に移動する。

:lat[er] {N}f           {N} 回後のファイルを保存したときのテキスト状態に移動す
                        る。
                        最後に保存した状態にいるときは、":later 1f" は一番新し
                        いテキスト状態に移動します。


Note: テキスト状態は、'undolevels' により undo 情報がクリアされると、到達不可
能になります。

時間を移動すると一度に複数の変更が現れることもあります。これは undo ツリーを移
動して新しい変更を加えたときに起こります。



次のテキストがあります:
        one two three

"x" を 3 回押して最初の単語を削除します:
        ne two three
        e two three
         two three

"u" を 3 回押してそれを undo します:
        e two three
        ne two three
        one two three

"x" を 3 回押して二番目の単語を削除します:
        one wo three
        one o three
        one  three

"g-" を 3 回押してそれを undo します:
        one o three
        one wo three
         two three

最初の undo ブランチ ("one" を削除した後) に戻りました。さらに "g-" を押してい
くと元のテキストに戻ります:
        e two three
        ne two three
        one two three

":later 1h" を実行すると最後の変更にジャンプします:
        one  three

":earlier 1h" を実行すると最初に戻ります:
        one two three


Note: "u" と CTRL-R では "g-" と "g+" のようにすべてのテキスト状態に移動するこ
とはできません。

==============================================================================
5. Undo の永続化 (Undo persistence)     undo-persistence persistent-undo

バッファがアンロードされるとき、通常はバッファの undo ツリーは廃棄されます。
'undofile' オプションを設定することで、ファイルを書き込んだときに自動的に undo
履歴が保存され、後でファイルを開いたときに undo 履歴が復元されます。

'undofile' オプションはファイルを書き込んだ後、BufWritePost 自動コマンドの前に
参照されます。undo 情報の保存をファイルごとに制御したい場合は BufWritePre 自動
コマンドを使います:
        au BufWritePre /tmp/* setlocal noundofile

undo ツリーは undo ファイルとして分けて保存されます。undo ファイルは編集ファイ
ルごとに作られます。保存場所の決定にはファイルシステムのパスをそのまま使用した
簡単な方法が使われます。Vim は編集ファイルと undo ファイルの同期がとれているか
どうかを確認し (ファイルの中身のハッシュ値で判断)、undo ファイルが書き込まれた
後で編集ファイルが変更されていたときは、データの損失を防ぐため、undo ファイル
を無視します。開いているファイルと undo ファイルの所有者が違うときも undo ファ
イルは無視されます。ただし、undo ファイルの所有者が現在のユーザーである時を除
きます。ファイルを開いたときにこの事についてのメッセージを表示させるには
'verbose' を設定してください。

通常、undo ファイルは編集ファイルと同じディレクトリに保存されます。この動作は
'undodir' オプションで変更できます。

ファイルが暗号化されているときは、undo ファイル内のテキストも暗号化されます。
ファイルと同じ暗号化メソッドとキーが使用されます。 encryption

Note テキストプロパティは undo ファイルには保存されません。バッファがロードさ
れている限りテキストプロパティを復元できますが、undo ファイルから復元すること
はできません。 理論的根拠: 関連するテキストプロパティタイプを以前と全く同じ方
法で定義する必要がありますが、これは保証できません。

":wundo" と ":rundo" を使うことで undo 履歴の保存と復元を手動で実行することも
できます。
                                                        :wundo :rundo
:wundo[!] {file}
                undo 履歴を {file} に保存する。
                {file} が存在し、それが undo ファイルでないなら (ファイル先頭
                のマジックナンバーが違うなら)、コマンドは失敗します。それでも
                保存したい場合は ! を付けてください。
                {file} が存在し、それが undo ファイルなら上書きされます。undo
                履歴がない場合は何も書き込まれません。
                実装詳細: 上書きは、最初にそのファイルを削除して、同じ名前の
                ファイルを新しく作成することで実行されます。そのため、書き込み
                制限のかかったディレクトリ内の undo ファイルは上書きできませ
                ん。

:rundo {file}   {file} から undo 履歴を読み込む。

自動コマンドを使うことで undo ファイルの名前を明示的に指定することができます。
例:

        au BufReadPost * call ReadUndo()
        au BufWritePost * call WriteUndo()
        func ReadUndo()
          if filereadable(expand('%:h') .. '/UNDO/' .. expand('%:t'))
            rundo %:h/UNDO/%:t
          endif
        endfunc
        func WriteUndo()
          let dirname = expand('%:h') .. '/UNDO'
          if !isdirectory(dirname)
            call mkdir(dirname)
          endif
          wundo %:h/UNDO/%:t
        endfunc

これを使うときは 'undofile' をオフにしておく必要があります。そうしないと二つの
undo ファイルが作成されてしまいます。

undofile() 関数を使うと、Vim が使用する undo ファイルの名前を取得できます。

Note'undofile' が設定された状態でファイルを読み書きするとき、ほとんどのエ
ラーは表示されません ('verbose' が設定されていなければ)。:wundo と :rundo を使
うときはより多くのエラーメッセージが表示されます。例えばファイルが読めない、書
き込めないとき。

Note: Vim は undo ファイルを削除しません。自分で削除する必要があります。

undo ファイルの読み込みが失敗する原因はいくつかあります:
E822  パーミッションの設定によりファイルを開けない。
E823  ファイル先頭のマジックナンバーが違う。普通はそのファイルが undo ファイ
        ルでないことを意味します。
E824  undo ファイルのバージョン番号が、それが Vim の新しいバージョンで書き込
        まれたことを示している。新しいバージョンで開く必要があります。undo
        ファイルの情報を維持したいならそのバッファを保存してはいけません。
"ファイルが変更されています。undo 情報を使用できません"
("File contents changed, cannot use undo info")
        ファイルのテキストが undo ファイルを保存したときから変わっています。テ
        キストが壊れてしまうため、その undo ファイルは使用できません。これは
        'encoding' の設定が undo ファイル保存時と違う場合にも起こります。
E825  undo ファイルの中身が不正なので使用できません。
E826  undo ファイルが暗号化されていて、復号に失敗しました。
E827  undo ファイルが暗号化されていて、使用中の Vim が暗号化をサポートしてい
        ません。他の Vim でファイルを開いてください。
E832  undo ファイルが暗号化されていて、'key' が設定されておらず、テキスト
        ファイルは暗号化されていません。これはテキストファイルが暗号化を使用し
        て保存された後で、暗号化を使用しないで上書きされた場合に起こります。
        おそらく undo ファイルを削除する必要があります。
"undo ファイルを読み込めません。所有者が違います"
("Not reading undo file, owner differs")
        undo ファイルの所有者とテキストファイルの所有者が違います。安全のため
        undo ファイルは使用されません。

undo ファイルの書き込みは次のような理由で失敗することがあります:
E828  書き込みのためのファイルを作成できません。おそらくディレクトリの書き込
        み権限がありません。
"'undodir' で指定されたディレクトリに undo ファイルを保存できません"
("Cannot write undo file in any directory in 'undodir'")
        'undodir' で指定されたディレクトリの中に使用可能なものがありません。
"undo ファイルを上書きしません。読み込み不可です"
("Will not overwrite with undo file, cannot read")
        undo ファイルと同じ名前のファイルが存在し、それが読み込みできない状態
        になっています。そのファイルを削除するか名前を変更する必要があります。
"上書きしません。undo ファイルではありません"
("Will not overwrite, this is not an undo file")
        undo ファイルと同じ名前のファイルが存在し、そのファイルの先頭に正しい
        マジックナンバーがありません。そのファイルを削除するか名前を変更する必
        要があります。
"undo ファイルの書き込みをスキップします。undo がありません"
("Skipping undo file write, noting to undo")
        保存する undo 情報がありません。何も変更されていないか 'undolevels' が
        マイナス値です。
E829  undo ファイルの保存中にエラーが発生しました。もう一度試してみてくださ
        い。

==============================================================================
6. 備考                                                 undo-remarks

記録される変更の数は 'undolevels' オプションで設定できます。ゼロに設定すると、
Vi 互換方式の動作になります。マイナスの値に設定すると undo は使用できなくなり
ます。メモリが足りない場合に設定してください。

                                                        clear-undo
'undolevels' を -1 に設定しても、undo 情報はすぐにはクリアされません。次の変更
が加えられたときにクリアされます。強制的に undo 情報をクリアしたいときは次のコ
マンドを使ってください:
        :let old_undolevels = &l:undolevels
        :setlocal undolevels=-1
        :exe "normal a \<BS>\<Esc>"
        :let &l:undolevels = old_undolevels
        :unlet old_undolevels

Note &l:undolevels を使用して 'undolevels' のローカル値を明示的に読み取り、
:setlocal を使用してローカルオプションのみを変更します (対応するグローバルオ
プション値より優先されます)。&undolevels を使用してオプション値を保存するこ
とは予測できません。ローカル値 (設定されている場合) またはグローバル値 (ローカ
ル値が設定されていない場合) のいずれかを読み取ります。また、ローカル値が設定さ
れている場合、:set undolevels でオプションを変更すると、グローバル値とローカ
ル値の両方が変更され、両方の値を保存および復元するための追加の作業が必要になり
ます。

バッファのマーク ('a から 'z) はテキストと同様に記録、復元されます。

すべての変更を undo したとき、バッファは変更ありとはみなされません。その状態か
らは ":q" (":q!" ではなく) で Vim を終了できます。Note これはいつファイルを保
存したかに関係します。":w" の後で "u" を実行すると、保存したときから見てバッファ
は変更された状態なので、バッファは変更ありと認識されます。

マニュアル設定の折り畳み (folding) を使っているとき、折り畳みは記録も復元も
されません。変更が折り畳みの中だけで行われた場合のみ (折り畳みの最初と最後の行
が変わらないので) 折り畳みは維持されます。

番号レジスタを使って削除を元に戻すこともできます。テキストを削除すると、それは
"1 レジスタに記録されます。元々 "1 にあったものは "2 にシフトされ、他の番号レ
ジスタも同様にシフトされます。"9 レジスタの内容は失われます。そして、プットコ
マンド '"1P' を使って削除されたテキストを元に戻すことができます。(削除やコピー
の操作をした後ならテキストは無名レジスタに入っているので 'P' や 'p' でも元に戻
せます)。三回前に削除されたテキストなら '"3P' で戻せます。

                                                redo-register
数回に分けて削除されたテキストを戻したい場合は、"." コマンドの特殊な機能が役に
立ちます。"." コマンドは使用されたレジスタの番号を増加させます。例えば、'"1P'
を実行した後で "." を押すと '"2P' が実行されます。さらに "." を押していくとす
べての番号レジスタが挿入されます。

例:             'dd....' でテキストを削除したら '"1P....' で元に戻せる。

削除されたテキストがどのレジスタに記録されているかわからないときは :display コ
マンドで確認できます。あるいは、'"1P' を実行してみて、もしそれが違うものなら
'u.' を実行します。'u.' は最初にプットされたテキストを削除し、二番目のレジスタ
を使ってプットコマンドを実行します。目的のものが出るまで 'u.' を繰り返してくだ
さい。

 vim:tw=78:ts=8:noet:ft=help:norl: