還原
Nvim 的 :help
頁面,從 原始碼 使用 tree-sitter-vimdoc 解析器 產生。
還原與重做
:u[ndo]! 還原一個變更並將其從還原歷史中移除。
E5767:u[ndo]!
{N}
類似於 ":u[ndo]
{N}
",但會忘記目前還原分支中直到
{N}
的所有變更。您只能使用 ":undo!
{N}
" 在同一個還原分支中往回移動,而不能重做或切換到不同的還原分支。
CTRL-R CTRL-R 重做 [count] 個已還原的變更。
U U 還原在單行上的所有最新變更,也就是最新變更發生的那一行。
U 本身也算是一個變更,因此
U 會還原先前的
U。
最後的變更會被記住。您可以使用上面的還原和重做指令將文字恢復到每次變更之前的狀態。您也可以再次套用變更,回到還原之前的文字。
"U" 指令在還原/重做中被視為任何其他指令。因此 "u" 指令會還原 "U" 指令,而 'CTRL-R
' 指令則會再次重做它。當混用 "U"、"u" 和 'CTRL-R
' 時,您會注意到 "U" 指令會將一行的狀態恢復到先前 "U" 指令之前的狀態。這可能會令人困惑。請嘗試使用以習慣它。"U" 指令總是會將緩衝區標記為已變更。當 "U" 將緩衝區改回沒有變更的狀態時,它仍然被視為已變更。使用 "u" 來還原變更,直到緩衝區變成未變更。
還原和重做指令如何運作取決於
'cpoptions' 中的 'u' 旗標。有 Vim 方式(排除 'u')和 Vi 相容方式(包含 'u')。在 Vim 方式中,"uu" 會還原兩個變更。在 Vi 相容方式中,"uu" 不執行任何動作(還原一個還原)。
排除 'u',Vim 方式:您可以使用還原指令回到過去。然後可以使用重做指令再次前進。如果在還原指令之後進行新的變更,重做將不再可能。
包含 'u',Vi 相容方式:還原指令會還原先前的變更,也會還原先前的還原指令。重做指令會重複先前的還原指令。它不會重複變更指令,請使用 "." 來執行此操作。
範例 Vim 方式 Vi 相容方式
"uu" 還原兩次 無操作 "u
CTRL-R
" 無操作 還原兩次
理由:Nvi 使用 "." 指令而不是 CTRL-R
。不幸的是,這與 Vi 不相容。例如,在 Vi 中 "dwdwu." 會刪除兩個單字,而在 Nvi 中則不執行任何動作。
一個還原指令通常會還原一個輸入的指令,無論該指令產生多少個變更。這個可還原的變更序列形成一個還原區塊。因此,如果輸入的按鍵調用一個函數,函數中的所有指令都會一起還原。
如果您想要編寫一個不建立新的可還原變更,而是加入先前變更的函數或腳本,請使用此指令
當您需要在變更過程中提示使用者時,這最為有用。例如,在呼叫
getchar() 的函數中。請確保在此之前有相關的變更,而您必須將其合併。
這本身無法運作,因為下一個按鍵輸入會再次開始新的變更。但您可以執行以下操作
:undojoin | delete
在此之後,"u" 指令將還原刪除指令和先前的變更。
undo-break undo-close-block 若要執行相反操作,請對下一個變更使用新的還原區塊,在插入模式中請使用
CTRL-G
u。如果您想要將插入指令分成多部分來還原,這很有用。例如,針對每個句子。
i_CTRL-G_u
設定
'undolevels' 的值也會關閉還原區塊。即使新值等於舊值也是如此。請使用
g:undolevels
來明確讀取和寫入
'undolevels' 的全域值。
let &g:undolevels = &g:undolevels
請注意,類似的指定
let &undolevels=&undolevels
在本機選項已設定為不同值的情況下,不會保留
'undolevels' 的全域選項值。例如
" Start with different global and local values for 'undolevels'.
let &g:undolevels = 1000
let &l:undolevels = 2000
" This assignment changes the global option to 2000:
let &undolevels = &undolevels
上面我們只討論了一行的還原/重做。但也可以分支出去。當您還原一些變更,然後進行新的變更時,就會發生這種情況。已還原的變更會變成一個分支。您可以使用以下指令前往該分支。
:undol :undolist :undol[ist] 列出變更樹狀結構中的葉節點。範例
編號 變更時間 儲存時
88 88 2010/01/04 14:25:53 108 107 08/07 12:47:51 136 46 13:33:01 7 166 164 3 秒前
"編號" 列是變更編號。此編號會持續增加,可用來識別特定的可還原變更,請參閱
:undo。"變更" 列是從樹狀結構根目錄到此葉節點的變更數量。"時間" 列是進行此變更的日期和時間。四種可能格式為:N 秒前 HH:MM:SS 小時、分鐘、秒 MM/DD HH:MM:SS 相同,包含月份和日期 YYYY/MM/DD HH:MM:SS 相同,包含年份 "已儲存" 列會指定是否已將此變更寫入磁碟以及這是哪個檔案寫入。這可用於
: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" 會前往最新的文字狀態。
當時間移動顯示一次發生多個變更時,請不要感到驚訝。當在還原樹狀結構中移動,然後進行新的變更時,就會發生這種情況。
範例
按下 "x" 三次來刪除第一個單字
ne two three
e two three
two three
現在按下 "u" 三次來還原
e two three
ne two three
one two three
按下 "x" 三次來刪除第二個單字
one wo three
one o three
one three
現在使用 "g-" 三次來還原
one o three
one wo three
two three
您現在回到第一個還原分支,在刪除 "one" 之後。重複 "g-" 現在會將您帶回原始文字
e two three
ne two three
one two three
使用 ":later 1h" 跳轉到最後的變更
one three
並使用 ":earlier 1h" 再次回到開始狀態
one two three
請注意,重複使用 "u" 和 CTRL-R
不會將您帶到所有可能的文字狀態,而重複 "g-" 和 "g+" 會。
當卸載緩衝區時,Vim 通常會銷毀為該緩衝區建立的還原樹狀結構。透過設定
'undofile' 選項,Vim 會在您寫入檔案時自動儲存您的還原歷史,並在您再次編輯檔案時還原還原歷史。
在寫入檔案之後,但在 BufWritePost 自動指令之前,會檢查
'undofile' 選項。如果您想要控制要寫入還原資訊的檔案,可以使用 BufWritePre 自動指令
au BufWritePre /tmp/* setlocal noundofile
Vim 會將還原樹狀結構儲存在單獨的還原檔案中,每個編輯的檔案一個,使用簡單的方案將檔案系統路徑直接對應到還原檔案。Vim 會偵測還原檔案是否不再與其寫入的檔案同步(使用檔案內容的雜湊值),並在還原檔案寫入之後變更檔案時忽略它,以防止損毀。如果還原檔案的所有者與編輯檔案的所有者不同,也會忽略還原檔案,但還原檔案的所有者是目前使用者時除外。設定
'verbose' 以在開啟檔案時取得相關訊息。
還原檔案的位置由
'undodir' 選項控制,預設情況下,它們會儲存到應用程式資料夾中的專用目錄。
您也可以分別使用 ":wundo" 和 ":rundo" 來儲存和還原復原歷程:
:wundo :rundo :wundo[!]
{file}
將復原歷程寫入
{file}
。當
{file}
存在,且看起來不像復原檔(檔案開頭的魔術數字錯誤)時,此操作會失敗,除非加上了 !。如果檔案存在且看起來像復原檔,則會被覆寫。如果沒有復原歷程,則不會寫入任何內容。實作細節:覆寫會先刪除現有檔案,然後建立一個同名的新檔案。因此,無法在受寫保護的目錄中覆寫現有的復原檔。
:rundo {file}
從 {file}
讀取復原歷程。
您可以在自動指令中使用這些指令,明確指定歷程檔案的名稱。例如:
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' 選項,否則每次寫入都會產生兩個復原檔案。
請注意,在讀取/寫入檔案且
'undofile' 設定為開啟時,大多數錯誤會被靜默處理,除非設定了
'verbose'。使用 :wundo 和 :rundo 時,您會收到更多錯誤訊息,例如,當檔案無法讀取或寫入時。
注意:復原檔案永遠不會被 Vim 刪除。您需要自行刪除它們。
讀取現有的復原檔案可能會因為幾個原因而失敗:
E822 無法開啟,因為檔案權限不允許。
E823 檔案開頭的魔術數字不符。這通常表示它不是復原檔案。
E824 復原檔案的版本號碼表示它是由較新版本的 Vim 寫入的。您需要該較新版本才能開啟它。如果您想將復原資訊保留在檔案中,請不要寫入緩衝區。「檔案內容已變更,無法使用復原資訊」檔案文字與寫入復原檔案時的不同。這表示無法使用復原檔案,否則會損壞文字。當
'encoding' 與寫入復原檔案時的不同時,也會發生這種情況。
E825 復原檔案不包含有效內容,無法使用。「未讀取復原檔案,擁有者不同」復原檔案的所有者與文字檔案的所有者不同。為了安全起見,不會使用復原檔案。
寫入復原檔案可能會因為以下原因而失敗:
E828 無法建立要寫入的檔案。您可能沒有該目錄的寫入權限。「無法在
'undodir' 中的任何目錄中寫入復原檔案」無法使用
'undodir' 中的任何目錄。「不會以復原檔案覆寫,無法讀取」存在一個與要寫入的復原檔案同名的檔案,但無法讀取。您可能需要刪除或重新命名此檔案。「不會覆寫,這不是復原檔案」存在一個與要寫入的復原檔案同名的檔案,但它不是以正確的魔術數字開頭。您可能需要刪除或重新命名此檔案。「略過復原檔案寫入,沒有任何內容可復原」沒有要寫入的復原資訊,沒有任何變更或
'undolevels' 為負數。
E829 在寫入復原檔案時發生錯誤。您可能需要再試一次。
記住的變更次數由
'undolevels' 選項設定。如果它是零,則始終使用與 Vi 相容的方式。如果它是負數,則無法進行復原。如果您記憶體不足,請使用此選項。
clear-undo 當您將
'undolevels' 設定為 -1 時,復原資訊不會立即清除,這會在下一次變更時發生。若要強制清除復原資訊,您可以使用這些指令
:let old_undolevels = &l:undolevels
:setlocal undolevels=-1
:exe "normal a \<BS>\<Esc>"
:let &l:undolevels = old_undolevels
:unlet old_undolevels
請注意使用
&l:undolevels
來明確讀取
'undolevels' 的本機值,並使用
:setlocal
僅變更本機選項(它會優先於對應的全域選項值)。透過使用
&undolevels
儲存選項值是不可預測的;它會讀取本機值(如果已設定)或全域值(否則)。此外,如果已設定本機值,則透過
:set undolevels
變更選項將會同時變更全域和本機值,需要額外的工作來儲存和還原本機和全域值。
緩衝區的標記('a 到 'z)也會與文字一起儲存和還原。
當所有變更都被復原時,緩衝區將不被視為已變更。然後,可以使用 ":q" 而不是 ":q!" 退出 Vim。請注意,這是相對於上次寫入檔案而言。在 ":w" 後輸入 "u" 實際上會變更緩衝區,與寫入的內容相比,因此緩衝區被視為已變更。
當使用手動
摺疊 時,摺疊不會被儲存和還原。只有在摺疊範圍內完全變更的內容才會保持摺疊狀態,因為摺疊的第一行和最後一行不會變更。
編號暫存器也可用於復原刪除。每次刪除文字時,都會將其放入暫存器 "1。暫存器 "1 的內容會移至 "2,依此類推。暫存器 "9 的內容會遺失。您現在可以使用貼上指令取回最近刪除的文字:'"1P'。(此外,如果刪除的文字是上次刪除或複製操作的結果,則 'P' 或 'p' 也會起作用,因為這會貼上未命名暫存器的內容)。您可以使用 '"3P' 取回三次刪除前的文字。
redo-register 如果您想取回多個已刪除文字的部分,可以使用重複指令 "." 的特殊功能。它會增加使用的暫存器編號。因此,如果您先執行 '"1P',則後面的 "." 將產生 '"2P'。重複此操作將會插入所有編號暫存器。
範例:如果您使用 'dd....' 刪除了文字,則可以使用 '"1P....' 還原。
如果您不知道已刪除的文字在哪個暫存器中,可以使用 :display 指令。另一種方法是先用 '"1P' 嘗試第一個暫存器,如果不是您想要的,則執行 'u.'。這將移除第一個貼上的內容,並重複執行第二個暫存器的貼上指令。重複執行 'u.' 直到您得到想要的內容。