Diff
Nvim 的 :help
頁面,是使用 tree-sitter-vimdoc 解析器,從 來源 產生 的。
diff-mode 這個檔案描述了 diff 功能:顯示同一個檔案的兩到八個版本之間的差異。
若要開始以 diff 模式編輯,請執行 "nvim -d"。這會如常啟動 Nvim,並額外設定以檢視引數之間的差異。
nvim -d file1 file2 [file3 [file4]]
除了
-d 引數之外,
-R 也可用於唯讀模式。
第二個及後續的引數也可以是目錄名稱。Vim 接著會將第一個引數的檔案名稱附加到目錄名稱,以尋找檔案。
Diff 是目前的標籤頁面
tab-page 的局部設定。您無法在另一個標籤頁面中看到 diff。這使得能夠同時擁有多個 diff,每個 diff 都在自己的標籤頁面中。
發生的是,Nvim 會為每個檔案開啟一個視窗。這就像使用
-O 引數。這會使用垂直分割,但如果您偏好水平分割,請改用
-o 引數。
nvim -d -o file1 file2 [file3 [file4]]
如果您總是偏好水平分割,請在
'diffopt' 中包含 "horizontal"。
在每個編輯的檔案中,都會設定這些選項
這些選項是針對視窗局部設定的。當編輯另一個檔案時,它們會重設為全域值。當重新編輯檔案時,仍然可以從模式行覆寫這些選項。然而,當
'diff' 設定時,不會從模式行設定
'foldmethod' 和
'wrap'。請參閱
:diffoff
以取得還原選項的簡單方法。
顯示的差異實際上是緩衝區中的差異。因此,如果您在載入檔案後進行變更,這些變更將會包含在顯示的 diff 中。您可能需要不時執行 ":diffupdate",並非所有變更都會立即納入考量,尤其是在使用外部 diff 指令時。
在您的 vimrc 檔案中,您可以在 Vim 以 diff 模式啟動時執行一些特殊操作。您可以使用如下的結構
if &diff
setup for diff mode
else
setup for non-diff mode
endif
當已經在 Vim 中時,您可以使用三種方式啟動 diff 模式。
:diffp[atch]
{patchfile}
E816 :diffp :diffpatch 使用目前的緩衝區,使用在
{patchfile}
中找到的 diff 來修補它,並開啟一個結果的緩衝區。這會將選項設定為如同 "nvim -d"。
{patchfile}
可以是 "patch" 程式理解的任何格式,或是
'patchexpr' 可以處理的格式。請注意,
{patchfile}
應該只包含一個檔案的 diff,即目前檔案。如果
{patchfile}
也包含其他檔案的 diff,則結果是不可預測的。Vim 會將目錄變更為 /tmp,以避免目前目錄中的檔案意外被修補。但它可能仍然會導致建立各種 ".rej" 檔案。而且當存在絕對路徑名稱時,這些檔案仍然可能會被修補。
若要讓這些指令使用垂直分割,請在前面加上
:vertical。範例
:vert diffsplit main.c~
:vert diffpatch /tmp/diff
如果您總是偏好垂直分割,請在
'diffopt' 中包含 "vertical"。
由於選項值會與緩衝區一起記住,因此您可以暫時編輯另一個檔案,然後回到同一個檔案,並再次進入 diff 模式。
:diffo[ff]! 關閉目前視窗的 diff 模式,以及目前標籤頁面中所有設定了
'diff' 的視窗。只有在設定了
'diff' 的視窗中才會重設相關的選項,如果目前視窗沒有設定
'diff',則不會變更其中的任何選項。隱藏的緩衝區也會從 diff 的緩衝區清單中移除。
:diffoff
指令會將相關的選項重設為使用 :diffsplit
、:diffpatch
、:diffthis
或以 diff 模式啟動 Vim 時的值。當使用 :diffoff
兩次時,會還原最後儲存的值。否則,它們會設定為預設值。
效果是 diff 視窗顯示相同的文字,並以醒目提示差異。當捲動文字時,
'scrollbind' 選項會使其他視窗中的文字也跟著捲動。使用垂直分割時,文字應正確對齊。
當下列情況發生時,文字的對齊會出錯
摺疊在一個視窗中開啟,但在另一個視窗中未開啟
已對文字進行變更
在設定了
'diff' 選項的視窗中編輯的所有緩衝區都將加入 diff。隱藏的緩衝區也可以這樣做。它們必須先在視窗中編輯過,才能這樣做。若要擺脫隱藏的緩衝區,請使用
:diffoff!
。
:DiffOrig diff-original-file 由於
'diff' 是視窗局部選項,因此可以在一個視窗中以 diff 模式檢視相同的緩衝區,而在另一個視窗中則以「正常」模式檢視。也可以檢視您自從載入檔案後對緩衝區所做的變更。由於 Vim 不允許針對同一個檔案擁有兩個緩衝區,因此您需要另一個緩衝區。此指令很有用
command DiffOrig vert new | set buftype=nofile | read ++edit # | 0d_
\ | diffthis | wincmd p | diffthis
使用 ":DiffOrig" 以查看目前的緩衝區與其載入的檔案之間的差異。
無法將未載入的緩衝區用於 diff。但它適用於隱藏的緩衝區。您可以使用 ":hide" 關閉視窗,而不會卸載緩衝區。如果您不希望緩衝區繼續用於 diff,請在隱藏它之前執行 ":set nodiff"。
當您變更文字時,Vim 會嘗試保持差異更新。這主要處理插入和刪除的行。行內的變更和更複雜的變更不會導致差異更新。若要強制更新差異,請使用
:diffupdate
如果包含 !,Vim 將檢查檔案是否在外部變更,且需要重新載入。它會提示每個變更的檔案,就像使用
:checktime
一樣。
Vim 會顯示在一個視窗中遺失但在另一個視窗中存在的行的填補行。這些行是在另一個檔案中插入的,或是在此檔案中刪除的。從
'diffopt' 選項中移除 "filler" 將使 Vim 不會顯示這些填補行。
摺疊用於隱藏未變更的文字。請參閱
folding,以了解所有可以與摺疊搭配使用的指令。
可以使用
'diffopt' 選項設定摺疊中未包含的差異上方行的內容。例如,若要將內容設定為三行
:set diffopt=filler,context:3
diff 使用這些群組來醒目提示
hl-DiffAdd DiffAdd 已新增 (插入) 的行。這些行存在於此緩衝區中,但不存在於另一個緩衝區中。
hl-DiffChange DiffChange 已變更的行。
hl-DiffText DiffText 已變更行內的已變更文字。Vim 會找到第一個不同的字元,以及最後一個不同的字元 (從行尾搜尋)。之間的文字會醒目提示。這表示中間仍然相同的部份也會被醒目提示。
'diffopt' 旗標 "iwhite" 和 "icase" 會在這裡使用。
hl-DiffDelete DiffDelete 已刪除的行。也稱為填補行,因為它們實際上並不存在於此緩衝區中。
可以使用兩個指令跳到 diff:
[c[c 向後跳到上一個變更的起點。當使用計數時,執行多次。
]c]c 向前跳到下一個變更的起點。當使用計數時,執行多次。
如果沒有游標可移動到的變更,則會發生錯誤。
合併 有兩個指令可以將文字從一個緩衝區複製到另一個緩衝區。結果是緩衝區會在指定的範圍內相等。
:diffg :diffget :[range]diffg[et] [bufspec] 修改目前的緩衝區,以還原與另一個緩衝區的差異。如果指定了 [bufspec],則會使用該緩衝區。如果 [bufspec] 參照目前的緩衝區,則不會發生任何事。否則,這只有在 diff 模式中還有另一個緩衝區時才會生效。請參閱下方的 [range]。
:diffpu :diffput E793 :[range]diffpu[t] [bufspec] 修改另一個緩衝區,以撤銷與目前緩衝區的差異。就像 ":diffget" 一樣,但修改的是另一個緩衝區,而不是目前的緩衝區。當省略 [bufspec] 且差異模式中有一個以上的其他緩衝區,且設定了
'modifiable' 時,此操作將失敗。請參閱下方關於 [range] 的說明。
do [count]do 與沒有範圍的 ":diffget" 相同。"o" 代表 "obtain"("dg" 不能使用,因為它可能是 "dgg" 的開頭!)。
注意:這在可視模式下不起作用。如果您提供 [count],它會被用作 ":diffget" 的 [bufspec] 參數。
dp [count]dp 與沒有範圍的 ":diffput" 相同。
注意:這在可視模式下不起作用。如果您提供 [count],它會被用作 ":diffput" 的 [bufspec] 參數。
當未給定 [range] 時,會影響游標位置或其正上方的差異。當使用 [range] 時,Vim 會嘗試僅放入或取得指定的行。當存在已刪除的行時,這可能並非總是可行。
緩衝區的最後一行下方可能存在已刪除的行。當游標位於緩衝區的最後一行,且此行上方沒有差異時,":diffget" 和 "do" 命令將從另一個緩衝區取得行。
為了能夠在 [range] 中從另一個緩衝區取得這些行,允許使用最後一個行號加一。此命令會從另一個緩衝區取得所有差異。
:1,$+1diffget
請注意,已刪除的行會顯示,但不計為文字行。您無法將游標移入它們。若要使用另一個緩衝區的行來填滿已刪除的行,請在它們下方的行上使用 ":diffget"。
E787當即將修改的緩衝區是唯讀的,且由
FileChangedRO 觸發的自動命令變更緩衝區時,該命令將會失敗。自動命令不得變更緩衝區。
上述的 [bufspec] 引數可以是緩衝區編號、緩衝區名稱的模式或緩衝區名稱的一部分。範例:
:diffget 使用差異模式中的另一個緩衝區 :diffget 3 使用緩衝區 3 :diffget v2 使用符合 "v2" 且處於差異模式的緩衝區 (例如,"file.c.v2")
diff-slow diff_translations 對於非常長的行,差異語法高亮可能很慢,特別是因為它會嘗試比對所有不同的本地化類型。若要停用本地化並加速語法高亮,請將全域變數 g:diff_translations 設定為零。
let g:diff_translations = 0
設定此變數後,重新載入語法腳本。
set syntax=diff
可以設定
'diffexpr' 選項,以使用內部差異支援或標準的 "diff" 程式以外的東西來比較兩個檔案並找出差異。
"diff" 的輸出必須是正常的 "ed" 樣式差異或統一差異。內容差異將不起作用。對於統一差異,不能使用內容行。使用 "diff -u" 將不起作用,請使用 "diff -U0"。
此範例說明 Vim 預期的 "ed" 樣式差異格式:
1a2
> bbb
4d4
< 111
7c7
< GGG
---
> ggg
"1a2" 項目會附加 "bbb" 行。"4d4" 項目會刪除 "111" 行。"7c7" 項目會將 "GGG" 行替換為 "ggg"。
當
'diffexpr' 不為空時,Vim 會評估它以取得提及格式的差異檔案。這些變數會設定為所使用的檔案名稱:
v:fname_in 原始檔案 v:fname_new 同一個檔案的新版本 v:fname_out 將結果差異檔案寫入的位置
範例(這幾乎與
'diffexpr' 為空時相同)
set diffexpr=MyDiff()
function MyDiff()
let opt = ""
if &diffopt =~ "icase"
let opt = opt .. "-i "
endif
if &diffopt =~ "iwhite"
let opt = opt .. "-b "
endif
silent execute "!diff -a --binary " .. opt .. v:fname_in .. " " .. v:fname_new ..
\ " > " .. v:fname_out
redraw!
endfunction
使用 "-a" 引數來強制將檔案視為文字進行比較,以二進位檔形式比較沒有用處。"--binary" 引數會以二進位模式讀取檔案,以便
CTRL-Z
不會結束 DOS 上的文字。
redraw!
命令可能不需要,具體取決於執行 shell 命令是否在顯示器上顯示任何內容。
如果
'diffexpr' 表達式以 s: 或
<SID> 開頭,則它會被腳本 ID 取代 (
local-function)。範例:
set diffexpr=s:MyDiffExpr()
set diffexpr=<SID>SomeDiffExpr()
否則,表達式會在設定選項的腳本內容中評估,因此可以使用腳本本機項目。
E810 E97 Vim 會測試差異輸出是否正常。如果沒有,您會收到錯誤訊息。可能的原因:
無法執行 "diff" 程式。
"diff" 程式沒有產生正常的 "ed" 樣式差異 (請參閱上方)。
'shell' 和相關的選項未正確設定。請嘗試使用 ":!sort" 之類的命令,檢查篩選是否有效。
當
'patchexpr' 為空時,Vim 會像這樣呼叫 "patch" 程式:
patch -o outfile origfile < patchfile
這應該適用於大多數版本的 "patch" 程式。請注意,行中間的 CR 可能會導致問題,它會被視為換行符號。
如果預設值對您不起作用,請將
'patchexpr' 設定為將具有相同效果的表達式。這些變數會設定為所使用的檔案名稱:
v:fname_in 原始檔案 v:fname_diff 修補程式檔案 v:fname_out 修補後的結果檔案
範例(這與
'patchexpr' 為空時的作用相同)
set patchexpr=MyPatch()
function MyPatch()
:call system("patch -o " .. v:fname_out .. " " .. v:fname_in ..
\ " < " .. v:fname_diff)
endfunction
請確保使用 "patch" 程式不會產生不必要的副作用。例如,請注意額外產生的檔案,應將其刪除。它應該只修補檔案,而沒有其他作用。在評估
'patchexpr' 之前,Vim 會將目錄變更為 "/tmp" 或其他暫存目錄。這希望能避免目前目錄中的檔案被意外修補。Vim 也會刪除以 v:fname_in 開頭並以 ".rej" 和 ".orig" 結尾的檔案。
如果
'patchexpr' 表達式以 s: 或
<SID> 開頭,則它會被腳本 ID 取代 (
local-function)。範例:
set patchexpr=s:MyPatchExpr()
set patchexpr=<SID>SomePatchExpr()
否則,表達式會在設定選項的腳本內容中評估,因此可以使用腳本本機項目。