快速修正(Quickfix)
Nvim 的 :help
頁面,從 原始碼 使用 tree-sitter-vimdoc 解析器產生。
Vim 有一種特殊模式可以加速編輯-編譯-編輯的循環。這是受到 Amiga 上 Manx 的 Aztec C 編譯器的快速修正選項的啟發。其想法是將編譯器的錯誤訊息儲存在一個檔案中,並使用 Vim 一個接一個地跳到錯誤。您可以檢查每個問題並修正它,而無需記住所有錯誤訊息。
在 Vim 中,快速修正命令更廣泛地用於在檔案中尋找位置列表。例如,
:vimgrep 尋找模式匹配。您可以使用
getqflist() 函數在腳本中使用這些位置。因此,您可以做的不僅僅是編輯/編譯/修正的循環!
如果您的錯誤訊息在檔案中,您可以使用以下命令啟動 Vim
vim -q filename
在 Vim 內部,執行命令並處理輸出的簡單方法是使用
:make 命令(見下文)。
位置列表(location-list) E776 位置列表是一個視窗本地的快速修正列表。您會在
:lvimgrep
、
:lgrep
、
:lhelpgrep
、
:lmake
等命令後得到一個位置列表,這些命令會建立位置列表而不是像對應的
:vimgrep
、
:grep
、
:helpgrep
、
:make
一樣建立快速修正列表。
location-list-file-window位置列表與一個視窗相關聯,每個視窗都可以有單獨的位置列表。一個位置列表只能與一個視窗相關聯。位置列表獨立於快速修正列表。
當分割一個具有位置列表的視窗時,新視窗會得到位置列表的副本。當不再有任何對位置列表的參考時,該位置列表將被銷毀。
可以使用以下快速修正命令。位置列表命令與快速修正命令類似,只是將快速修正命令中的 'c' 字首替換為 'l'。
:cc :cc[!] [nr] 顯示錯誤 [nr]。如果省略 [nr],則會再次顯示相同的 :[nr]cc[!] 錯誤。當跳轉到另一個緩衝區、目前緩衝區已變更、該緩衝區只有一個視窗且
'hidden' 和
'autowrite' 都關閉時,不使用 [!] 則無法運作。當使用 [!] 跳轉到另一個緩衝區時,目前緩衝區的任何變更都會遺失,除非設定了
'hidden' 或該緩衝區有另一個視窗。當跳轉到緩衝區時,會遵守
'switchbuf' 設定。在快速修正視窗中使用時,可以使用行號,包括 "." 代表目前行和 "$" 代表最後一行。
:ll :ll[!] [nr] 與 ":cc" 相同,只是使用目前視窗的位置列表代替快速修正列表。
:lne :lnext ]l :[count]lne[xt][!] 與 ":cnext" 相同,只是使用目前視窗的位置列表代替快速修正列表。
:cabo :cabove :[count]cabo[ve] 跳到目前緩衝區中目前行以上的第 [count] 個錯誤。如果省略 [count],則使用 1。如果沒有錯誤,則會顯示錯誤訊息。假設快速修正列表中的項目按其緩衝區編號和行號排序。如果同一行有多個錯誤,則只使用第一個項目。如果 [count] 超過目前行以上項目數,則會選擇檔案中的第一個錯誤。
:lab :labove :[count]lab[ove] 與 ":cabove" 相同,只是使用目前視窗的位置列表代替快速修正列表。
:cbel :cbelow :[count]cbel[ow] 跳到目前緩衝區中目前行以下的第 [count] 個錯誤。如果省略 [count],則使用 1。如果沒有錯誤,則會顯示錯誤訊息。假設快速修正列表中的項目按其緩衝區編號和行號排序。如果同一行有多個錯誤,則只使用第一個項目。如果 [count] 超過目前行以下項目數,則會選擇檔案中的最後一個錯誤。
:lbel :lbelow :[count]lbel[ow] 與 ":cbelow" 相同,只是使用目前視窗的位置列表代替快速修正列表。
:cbe :cbefore :[count]cbe[fore] 跳到目前緩衝區中目前游標位置之前的第 [count] 個錯誤。如果省略 [count],則使用 1。如果沒有錯誤,則會顯示錯誤訊息。假設快速修正列表中的項目按其緩衝區、行和欄號排序。如果 [count] 超過目前位置之前項目數,則會選擇檔案中的第一個錯誤。
:lbe :lbefore :[count]lbe[fore] 與 ":cbefore" 相同,只是使用目前視窗的位置列表代替快速修正列表。
:caf :cafter :[count]caf[ter] 跳到目前緩衝區中目前游標位置之後的第 [count] 個錯誤。如果省略 [count],則使用 1。如果沒有錯誤,則會顯示錯誤訊息。假設快速修正列表中的項目按其緩衝區、行和欄號排序。如果 [count] 超過目前位置之後項目數,則會選擇檔案中的最後一個錯誤。
:laf :lafter :[count]laf[ter] 與 ":cafter" 相同,只是使用目前視窗的位置列表代替快速修正列表。
:lrewind :lr [L :lr[ewind][!] [nr] 與 ":crewind" 相同,只是使用目前視窗的位置列表代替快速修正列表。
:llast :lla ]L :lla[st][!] [nr] 與 ":clast" 相同,但使用目前視窗的位置列表,而不是快速修復列表。
:cq :cquit :cq[uit][!] :{N}cq[uit][!] :cq[uit][!]
{N}
以錯誤代碼
{N}
結束 Vim。
{N}
預設為 1。當 Vim 從另一個程式呼叫時很有用:例如,編譯器不會再次編譯相同的文件,
git commit
將中止提交過程,
fc
(像是 bash 和 zsh 的內建 shell 命令)將不會執行該命令等等。
{N}
也可以是零,在這種情況下,Vim 會正常退出。
警告:所有檔案的變更都會遺失。它的作用類似於 ":qall!"
:qall,除了 Nvim 會以非零或 [count] 退出。
:lf :lfi :lfile :lf[ile][!] [errorfile] 與 ":cfile" 相同,但使用目前視窗的位置列表,而不是快速修復列表。您不能使用 -q 命令列選項來設定位置列表。
:lg[etfile] [errorfile]
:lg :lge :lgetfile 與 ":cgetfile" 相同,但使用目前視窗的位置列表,而不是快速修復列表。
:laddf :laddfile :laddf[ile] [errorfile] 與 ":caddfile" 相同,但使用目前視窗的位置列表,而不是快速修復列表。
:cb :cbuffer E681 :[range]cb[uffer][!] [bufnr] 從目前緩衝區讀取錯誤列表。當給定 [bufnr] 時,它必須是已載入緩衝區的編號。然後將使用該緩衝區,而不是目前的緩衝區。可以指定要使用的行範圍。否則,將使用緩衝區中的所有行。有關 [!],請參閱
:cc。
:lb :lbuffer :[range]lb[uffer][!] [bufnr] 與 ":cbuffer" 相同,但使用目前視窗的位置列表,而不是快速修復列表。
:cgetb :cgetbuffer :[range]cgetb[uffer] [bufnr] 從目前緩衝區讀取錯誤列表。與 ":cbuffer" 相同,但不跳至第一個錯誤。
:lgetb :lgetbuffer :[range]lgetb[uffer] [bufnr] 與 ":cgetbuffer" 相同,但使用目前視窗的位置列表,而不是快速修復列表。
:cad :cadd :caddbuffer :[range]cad[dbuffer] [bufnr] 從目前緩衝區讀取錯誤列表,並將錯誤新增至目前的快速修復列表。如果沒有快速修復列表,則會建立一個新的列表。否則,與 ":cbuffer" 相同。
:laddb :laddbuffer :[range]laddb[uffer] [bufnr] 與 ":caddbuffer" 相同,但使用目前視窗的位置列表,而不是快速修復列表。
:cex :cexpr E777 :cex[pr][!]
{expr}
使用
{expr}
的結果建立快速修復列表,並跳至第一個錯誤。如果
{expr}
是字串,則字串中以換行符號終止的每一行都會使用
'errorformat' 的全域值進行處理,並將結果新增至快速修復列表。如果
{expr}
是列表,則會處理列表中每個字串項目,並將其新增至快速修復列表。會忽略列表中非字串的項目。有關 [!],請參閱
:cc。範例
:cexpr system('grep -n xyz *')
:cexpr getline(1, '$')
:cadde :caddexpr :cadde[xpr]
{expr}
評估
{expr}
並將結果行新增至目前的快速修復列表。如果沒有快速修復列表,則會建立一個新的列表。目前的游標位置不會變更。有關更多資訊,請參閱
:cexpr。範例
:g/mypattern/caddexpr expand("%") .. ":" .. line(".") .. ":" .. getline(".")
:cl :clist :cl[ist] [from] [, [to]] 列出所有有效的
quickfix-valid 錯誤。如果給定數字 [from] 和/或 [to],則會列出對應的錯誤範圍。負數從最後一個錯誤向後計算,-1 是最後一個錯誤。
:filter 命令可用於僅顯示符合提供的模式的快速修復項目。該模式會與項目的檔案名稱、模組名稱、模式和文字進行比對。
:cl[ist] +{count} 列出目前和接下來 {count}
個有效的錯誤。這類似於 ":clist from from+count",其中 "from" 是目前的錯誤位置。
:cl[ist]! [from] [, [to]] 列出所有錯誤。
:cl[ist]! +{count} 列出目前和接下來
{count}
個錯誤行。這對於查看目前行之後無法識別的行很有用。例如,如果 ":clist" 顯示
8384 testje.java:252: error: cannot find symbol
然後使用 ":cl! +3" 顯示原因
8384 testje.java:252: error: cannot find symbol
8385: ZexitCode = Fmainx();
8386: ^
8387: symbol: method Fmainx()
:lli[st] [from] [, [to]]
:lli :llist 與 ":clist" 相同,但使用目前視窗的位置列表,而不是快速修復列表。
:lli[st]! [from] [, [to]] 列出目前視窗位置列表中的所有項目。
如果您插入或刪除行,由於使用了隱藏的標記,大多數情況下仍然可以找到正確的錯誤位置。有時,當標記因某種原因被刪除時,會顯示訊息「行已變更」,以警告您錯誤位置可能不正確。如果您退出 Vim 並重新啟動,則標記會遺失,且錯誤位置可能不再正確。
QuickFixCmdPost 範例 當
'encoding' 與地區設定不同時,錯誤訊息的編碼可能與 Vim 使用的編碼不同。若要轉換訊息,您可以使用此程式碼
function QfMakeConv()
let qflist = getqflist()
for i in qflist
let i.text = iconv(i.text, "cp936", "utf-8")
endfor
call setqflist(qflist)
endfunction
au QuickfixCmdPost make call QfMakeConv()
另一個選項是使用
'makeencoding'。
quickfix-title 每個快速修復和位置列表都有標題。預設情況下,標題設定為建立列表的命令。
getqflist() 和
getloclist() 函數可用於分別取得快速修復和位置列表的標題。
setqflist() 和
setloclist() 函數可用於分別修改快速修復和位置列表的標題。範例
call setqflist([], 'a', {'title' : 'Cmd output'})
echo getqflist({'title' : 1})
call setloclist(3, [], 'a', {'title' : 'Cmd output'})
echo getloclist(3, {'title' : 1})
quickfix-index 當您使用任何快速修復命令(例如
:cc、
:cnext、
:cprev 等)跳至快速修復/位置列表項目時,該項目會成為目前選取的項目。可以使用 getqflist()/getloclist() 函數取得快速修復/位置列表中目前選取項目的索引。範例
echo getqflist({'idx' : 0}).idx
echo getqflist({'id' : qfid, 'idx' : 0}).idx
echo getloclist(2, {'idx' : 0}).idx
對於新的快速修復列表,會選取第一個項目,且索引為 1。可以使用 setqflist() 函數將任何快速修復/位置列表中的任何項目設定為目前選取的項目。範例
call setqflist([], 'a', {'idx' : 12})
call setqflist([], 'a', {'id' : qfid, 'idx' : 7})
call setloclist(1, [], 'a', {'idx' : 7})
quickfix-context 任何 Vim 類型都可以作為上下文與快速修正或位置列表相關聯。
setqflist() 和
setloclist() 函數可用於將上下文分別與快速修正和位置列表相關聯。
getqflist() 和
getloclist() 函數可用於分別檢索快速修正和位置列表的上下文。這對於處理多個快速修正/位置列表的 Vim 外掛非常有用。範例
let somectx = {'name' : 'Vim', 'type' : 'Editor'}
call setqflist([], 'a', {'context' : somectx})
echo getqflist({'context' : 1})
let newctx = ['red', 'green', 'blue']
call setloclist(2, [], 'a', {'id' : qfid, 'context' : newctx})
echo getloclist(2, {'id' : qfid, 'context' : 1})
快速修正解析 您可以使用
'errorformat' 解析行列表,而無需使用
getqflist() 函數建立或修改快速修正列表。範例
echo getqflist({'lines' : ["F1:10:Line10", "F2:20:Line20"]})
echo getqflist({'lines' : systemlist('grep -Hn quickfix *')})
這會返回一個字典,其中 "items" 鍵包含從行解析的快速修正條目列表。以下展示如何使用自訂的
'errorformat' 來解析行,而無需修改
'errorformat' 選項
echo getqflist({'efm' : '%f#%l#%m', 'lines' : ['F1#10#Line']})
在快速修正或位置列表中的所有緩衝區中執行命令:
:cdo:cdo[!]
{cmd}
在快速修正列表中的每個有效條目中執行
{cmd}
。它的工作方式如下
:cfirst
:{cmd}
:cnext
:{cmd}
etc.
當目前檔案無法
放棄 且未出現 [!] 時,命令會失敗。當前往下一個條目失敗時,執行會停止。最後一個緩衝區(或發生錯誤的地方)會變成目前的緩衝區。
{cmd}
可以包含 '|' 來串聯多個命令。
僅使用快速修正列表中的有效條目。可以使用範圍來選取條目,例如
:10,$cdo cmd
跳過條目 1 到 9。
:cfdo :cfdo[!]
{cmd}
在快速修正列表中的每個檔案中執行
{cmd}
。它的工作方式如下
:cfirst
:{cmd}
:cnfile
:{cmd}
etc.
否則其工作方式與 :cdo
相同。
:ldo :ld[o][!]
{cmd}
在目前視窗的位置列表中的每個有效條目中執行
{cmd}
。它的工作方式如下
:lfirst
:{cmd}
:lnext
:{cmd}
etc.
僅使用位置列表中的有效條目。否則其工作方式與 :cdo
相同。
:lfdo :lfdo[!]
{cmd}
在目前視窗的位置列表中的每個檔案中執行
{cmd}
。它的工作方式如下
:lfirst
:{cmd}
:lnfile
:{cmd}
etc.
否則其工作方式與 :ldo
相同。
篩選快速修正或位置列表:
cfilter-plugin :Cfilter :Lfilter 如果您的快速修正列表中有太多條目,您可以使用 cfilter 外掛程式來減少條目數量。使用以下方式載入外掛程式
packadd cfilter
然後您可以使用以下命令來篩選快速修正/位置列表
:Cfilter[!] /{pat}/
:Lfilter[!] /{pat}/
:Cfilter 命令會從目前快速修正列表中與
{pat}
相符的條目建立新的快速修正列表。
{pat}
是 Vim
正規表示式 模式。檔案名稱和條目的文字都會與
{pat}
比對。如果提供了可選的 !,則會使用與
{pat}
不符的條目。模式可以選擇性地使用以下其中一個字元括起來:'、"、/。如果模式為空,則會使用上次使用的搜尋模式。
這些命令不會修改目前的快速修正/位置列表,因此您可以使用
:colder/|:lolder| 命令返回未篩選的列表。
當提供 [height] 時,視窗會變為該高度(如果有空間)。當省略 [height] 時,視窗會設為十行高。
如果已經有快速修正視窗,則會使其成為目前的視窗。無法開啟第二個快速修正視窗。如果提供 [height],則現有視窗會調整為該大小。
快速修正緩衝區 視窗會包含一個特殊的緩衝區,其中
'buftype' 等於 "quickfix"。請勿變更此設定!視窗會設定 w:quickfix_title 變數,該變數會指出產生快速修正列表的命令。如果
'statusline' 的值經過適當調整,則可以使用此變數來組合自訂狀態列。每當此緩衝區被快速修正命令或函數修改時,
b:changedtick 變數就會遞增。您可以使用 getqflist() 和 getloclist() 函數,透過傳遞 "qfbufnr" 項目來取得此緩衝區的編號。對於位置列表,當移除位置列表時,此緩衝區會被清除。
:lop :lopen :lop[en] [height] 開啟一個視窗以顯示目前視窗的位置列表。僅當目前視窗存在位置列表時才有效。您可以一次開啟多個位置視窗。否則,其行為與 ":copen" 相同。
:cw :cwindow :cw[indow] [height] 當有已辨識的錯誤時,開啟快速修正視窗。如果視窗已開啟且沒有已辨識的錯誤,則關閉視窗。
:lw :lwindow :lw[indow] [height] 與 ":cwindow" 相同,但使用顯示目前視窗位置列表的視窗。
:cbo :cbottom :cbo[ttom] 將游標放在快速修正視窗的最後一行,並捲動使其可見。當由非同步回呼新增錯誤時,這很有用。如果有很多更新要避免大量重繪,請僅偶爾呼叫它。
在快速修正視窗中,每一行都是一個錯誤。行號等於錯誤編號。目前的條目會以 QuickFixLine 反白顯示。您可以變更其外觀,例如
:hi QuickFixLine ctermbg=Yellow guibg=Yellow
您可以使用 ":.cc" 跳至游標下的錯誤。按下
<Enter>
鍵或在行上按兩下滑鼠會產生相同的效果。包含錯誤的檔案會在快速修正視窗上方的視窗中開啟。如果該檔案已經有一個視窗,則會改用該視窗。如果所使用視窗中的緩衝區已變更,且錯誤位於另一個檔案中,則跳至錯誤會失敗。您必須先確定視窗包含可以放棄的緩衝區。
當您從快速修正視窗中選取檔案時,會使用以下步驟來尋找用於編輯檔案的視窗
1. 如果目前的索引標籤頁面中存在顯示所選檔案的視窗(從快速修正視窗之前的視窗開始),則會使用該視窗。2. 如果上述步驟失敗,且如果
'switchbuf' 包含 "usetab",且任何一個索引標籤頁面中存在顯示所選檔案的視窗(從第一個索引標籤頁面開始),則會使用該視窗。3. 如果上述步驟失敗,則會使用目前索引標籤頁面中顯示
'buftype' 未設定的緩衝區的視窗(從快速修正視窗之前的視窗開始)。4. 如果上述步驟失敗,且如果
'switchbuf' 包含 "uselast",則會使用先前存取的視窗。5. 如果上述步驟失敗,則會使用快速修正視窗之前的視窗。如果沒有先前的視窗,則會使用快速修正視窗之後的視窗。6. 如果上述步驟失敗,則會使用快速修正視窗上方新的水平分割視窗。
填寫快速修正視窗後,會觸發兩個自動命令事件。首先,
'filetype' 選項會設定為 "qf",這會觸發 FileType 事件(另請參閱
qf.vim)。然後會觸發 BufReadPost 事件,使用 "quickfix" 作為緩衝區名稱。這可以用於對列出的錯誤執行一些動作。範例
au BufReadPost quickfix setlocal modifiable
\ | silent exe 'g/^/s//\=line(".") .. " "/'
\ | setlocal nomodifiable
這會在每行前面加上行號。請注意 ":s" 命令的取代字串中使用 "\=",這用於評估運算式。也會觸發 BufWinEnter 事件,同樣使用 "quickfix" 作為緩衝區名稱。
注意: 當新增至現有的快速修正列表時,不會觸發自動命令。
注意:在快速修復視窗中進行變更不會影響錯誤列表。
'modifiable' 選項已關閉以避免進行變更。如果您還是刪除或插入行,文字與錯誤編號之間的關係將會錯亂。如果您真的想這樣做,您可以將快速修復視窗的內容寫入檔案,並使用 ":cfile" 來解析並將其用作新的錯誤列表。
位置列表視窗 位置列表視窗會顯示位置列表中的條目。當您開啟位置列表視窗時,它會在目前視窗下方建立,並顯示目前視窗的位置列表。位置列表視窗與快速修復視窗類似,但您可以同時開啟多個位置列表視窗。當您在此視窗中使用位置列表命令時,將會使用顯示的位置列表。
當您從位置列表視窗中選取檔案時,會使用以下步驟來尋找編輯該檔案的視窗
1. 如果目前索引標籤頁中存在與位置列表相關聯的非快速修復視窗,則會使用該視窗。2. 如果上述步驟失敗,且該檔案已在目前索引標籤頁中的另一個視窗中開啟,則會使用該視窗。3. 如果上述步驟失敗,且
'switchbuf' 包含 "usetab",且該檔案在任何一個索引標籤頁的視窗中開啟,則會使用該視窗。4. 如果上述步驟失敗,則會使用目前索引標籤頁中顯示
'buftype' 未設定的緩衝區的視窗。5. 如果上述步驟失敗,則會在新的視窗中編輯該檔案。
在上述所有情況下,如果尚未設定選取視窗的位置列表,則會將其設定為位置列表視窗中顯示的位置列表。
getqflist 範例 getqflist() 和
getloclist() 函式可用於取得快速修復和位置列表的各種屬性。以下是一些使用這些函式的範例
" get the title of the current quickfix list
:echo getqflist({'title' : 0}).title
" get the identifier of the current quickfix list
:let qfid = getqflist({'id' : 0}).id
" get the identifier of the fourth quickfix list in the stack
:let qfid = getqflist({'nr' : 4, 'id' : 0}).id
" check whether a quickfix list with a specific identifier exists
:if getqflist({'id' : qfid}).id == qfid
" get the index of the current quickfix list in the stack
:let qfnum = getqflist({'nr' : 0}).nr
" get the items of a quickfix list specified by an identifier
:echo getqflist({'id' : qfid, 'items' : 0}).items
" get the number of entries in a quickfix list specified by an id
:echo getqflist({'id' : qfid, 'size' : 0}).size
" get the context of the third quickfix list in the stack
:echo getqflist({'nr' : 3, 'context' : 0}).context
" get the number of quickfix lists in the stack
:echo getqflist({'nr' : '$'}).nr
" get the number of times the current quickfix list is changed
:echo getqflist({'changedtick' : 0}).changedtick
" get the current entry in a quickfix list specified by an identifier
:echo getqflist({'id' : qfid, 'idx' : 0}).idx
" get all the quickfix list attributes using an identifier
:echo getqflist({'id' : qfid, 'all' : 0})
" parse text from a List of lines and return a quickfix list
:let myList = ["a.java:10:L10", "b.java:20:L20"]
:echo getqflist({'lines' : myList}).items
" parse text using a custom 'efm' and return a quickfix list
:echo getqflist({'lines' : ['a.c#10#Line 10'], 'efm':'%f#%l#%m'}).items
" get the quickfix list window id
:echo getqflist({'winid' : 0}).winid
" get the quickfix list window buffer number
:echo getqflist({'qfbufnr' : 0}).qfbufnr
" get the context of the current location list
:echo getloclist(0, {'context' : 0}).context
" get the location list window id of the third window
:echo getloclist(3, {'winid' : 0}).winid
" get the location list window buffer number of the third window
:echo getloclist(3, {'qfbufnr' : 0}).qfbufnr
" get the file window id of a location list window (winnr: 4)
:echo getloclist(4, {'filewinid' : 0}).filewinid
setqflist 範例 setqflist() 和
setloclist() 函式可用於設定快速修復和位置列表的各種屬性。以下是一些使用這些函式的範例
" create an empty quickfix list with a title and a context
:let t = 'Search results'
:let c = {'cmd' : 'grep'}
:call setqflist([], ' ', {'title' : t, 'context' : c})
" set the title of the current quickfix list
:call setqflist([], 'a', {'title' : 'Mytitle'})
" change the current entry in the list specified by an identifier
:call setqflist([], 'a', {'id' : qfid, 'idx' : 10})
" set the context of a quickfix list specified by an identifier
:call setqflist([], 'a', {'id' : qfid, 'context' : {'val' : 100}})
" create a new quickfix list from a command output
:call setqflist([], ' ', {'lines' : systemlist('grep -Hn main *.c')})
" parse text using a custom efm and add to a particular quickfix list
:call setqflist([], 'a', {'id' : qfid,
\ 'lines' : ["a.c#10#L10", "b.c#20#L20"], 'efm':'%f#%l#%m'})
" add items to the quickfix list specified by an identifier
:let newItems = [{'filename' : 'a.txt', 'lnum' : 10, 'text' : "Apple"},
\ {'filename' : 'b.txt', 'lnum' : 20, 'text' : "Orange"}]
:call setqflist([], 'a', {'id' : qfid, 'items' : newItems})
" empty a quickfix list specified by an identifier
:call setqflist([], 'r', {'id' : qfid, 'items' : []})
" free all the quickfix lists in the stack
:call setqflist([], 'f')
" set the title of the fourth quickfix list
:call setqflist([], 'a', {'nr' : 4, 'title' : 'SomeTitle'})
" create a new quickfix list at the end of the stack
:call setqflist([], ' ', {'nr' : '$',
\ 'lines' : systemlist('grep -Hn class *.java')})
" create a new location list from a command output
:call setloclist(0, [], ' ', {'lines' : systemlist('grep -Hn main *.c')})
" replace the location list entries for the third window
:call setloclist(3, [], 'r', {'items' : newItems})
到目前為止,都假設只有一個錯誤列表。實際上,會記住最後使用的十個列表。當開始新的列表時,會自動保留先前的列表。可以使用兩個命令來存取較舊的錯誤列表。它們會將現有的錯誤列表之一設定為目前的列表。
:colder :col E380 :col[der] [count] 前往較舊的錯誤列表。當給定 [count] 時,執行此操作 [count] 次。當已經在最舊的錯誤列表時,會顯示錯誤訊息。
:lolder :lol :lol[der] [count] 與
:colder
相同,但使用目前視窗的位置列表,而不是快速修復列表。
:cnewer :cnew E381 :cnew[er] [count] 前往較新的錯誤列表。當給定 [count] 時,執行此操作 [count] 次。當已經在最新的錯誤列表時,會顯示錯誤訊息。
:lnewer :lnew :lnew[er] [count] 與
:cnewer
相同,但使用目前視窗的位置列表,而不是快速修復列表。
:chistory :chi :[count]chi[story] 顯示錯誤列表的列表。目前的列表會以 ">" 標記。輸出看起來像這樣
error list 1 of 3; 43 errors :make
> error list 2 of 3; 0 errors :helpgrep tag
error list 3 of 3; 15 errors :grep ex_help *.c
當給定 [count] 時,則將 count'th 快速修復列表設為目前的列表。範例
" Make the 4th quickfix list current
:4chistory
當新增新的錯誤列表時,它會變成目前的列表。
當使用 ":colder" 且使用 ":make" 或 ":grep" 新增新的錯誤列表時,會覆寫一個較新的列表。如果您使用 ":grep"
grep 瀏覽,這會特別有用。如果您想要保留較新的錯誤列表,請先使用 ":cnewer 99"。
若要取得快速修復和位置列表堆疊中的列表數,您可以使用
getqflist() 和
getloclist() 函式,並將列表編號設定為特殊值 '$'。範例
echo getqflist({'nr' : '$'}).nr
echo getloclist(3, {'nr' : '$'}).nr
若要取得堆疊中目前列表的編號
echo getqflist({'nr' : 0}).nr
:lmak :lmake :lmak[e][!] [arguments] 與 ":make" 相同,但會使用目前視窗的位置列表,而不是快速修復列表。
":make" 命令會執行
'makeprg' 選項給定的命令。這是藉由將命令傳遞給
'shell' 選項給定的 Shell 來完成的。這幾乎與輸入以下內容相同
":!{makeprg} [arguments] {shellpipe}
{errorfile}
"。
{makeprg}
是
'makeprg' 選項給定的字串。可以使用任何命令,而不僅限於 "make"。字元 '%' 和 '#' 會像在命令列上一樣展開。您可以使用 "%<" 來插入不含副檔名的目前檔案名稱,或使用 "#<" 來插入不含副檔名的替代檔案名稱,例如
:set makeprg=make\ #<.o
[arguments] 是在 ":make" 後輸入的任何內容。
{shellpipe}
是
'shellpipe' 選項。
{errorfile}
是
'makeef' 選項,並將 ## 取代為使其唯一。
如果命令需要在其引數後加上一些額外字元,則可以使用佔位符 "$*" 來表示
{makeprg}
中的引數列表。然後,所有引數都會取代 $*。範例
:set makeprg=latex\ \\\\nonstopmode\ \\\\input\\{$*}
或更簡單
:let &mp = 'latex \\nonstopmode \\input\{$*}'
"$*" 可以多次給定,例如
:set makeprg=gcc\ -o\ $*\ $*
'shellpipe' 選項在 Win32 上預設為 "2>&1| tee"。這表示編譯器的輸出會儲存到檔案中,而不會直接顯示在螢幕上。對於 Unix,會使用 "| tee"。編譯器輸出會同時顯示在螢幕上並儲存到檔案中。根據使用的 Shell,預設會使用 "|& tee" 或 "2>&1| tee",因此會包含 stderr 輸出。
如果
'shellpipe' 為空,則會省略
{errorfile}
部分。這對於自行寫入錯誤檔案的編譯器很有用。
'encoding' 可能會設定為與您的建置程式產生的訊息不同的編碼。此範例示範如何在 Vim 讀取錯誤訊息後修正此問題
function QfMakeConv()
let qflist = getqflist()
for i in qflist
let i.text = iconv(i.text, "cp936", "utf-8")
endfor
call setqflist(qflist)
endfunction
au QuickfixCmdPost make call QfMakeConv()
(Faque Cheng 的範例)另一個選項是使用
'makeencoding'。
Vim 有兩種尋找模式比對的方法:內部和外部。內部 grep 的優點是它可以在所有系統上運作,並使用強大的 Vim 搜尋模式。當 Vim grep 無法執行您想要的操作時,可以使用外部 grep 程式。
內部方法會比較慢,因為檔案會讀取到記憶體中。優點是
行分隔符號和編碼會自動辨識,就像正在編輯檔案一樣。
使用 Vim 搜尋模式。可以使用多行模式。
為了能夠執行此操作,Vim 會載入每個檔案,就像正在編輯它一樣。當檔案中沒有比對時,相關的緩衝區會再次清除。
'hidden' 選項會在此處忽略,以避免在搜尋許多檔案時耗盡記憶體或檔案描述子。但是,當使用
:hide 命令修飾詞時,會保留載入的緩衝區。這使得在相同檔案中進行後續搜尋的速度快很多。
請注意,可以使用
:copen(或
:lopen 表示
:lgrep)來開啟包含連結形式搜尋結果的緩衝區。可以使用
:silent 命令來抑制預設的全螢幕 grep 輸出。
:grep 命令的 ":grep!" 形式不會自動跳到第一個比對。可以結合這些命令來建立 NewGrep 命令
command! -nargs=+ NewGrep execute 'silent grep! <args>' | copen 42
5.1 使用 Vim 的內部 grep
標記:'g' 若沒有 'g' 標記,則每一行只會加入一次。若有 'g' 標記,則每個匹配都會被加入。
'j' 若沒有 'j' 標記,Vim 會跳到第一個匹配項。若有 'j' 標記,則只會更新快速修正列表。若使用 [!],則當前緩衝區中的任何變更都會被捨棄。
'f' 當指定 'f' 標記時,會使用模糊字串匹配來尋找匹配的行。在這種情況下,
{pattern}
會被視為字面字串,而非正規表示式。請參閱
fuzzy-matching 以了解更多關於模糊匹配字串的資訊。
:{count}vim[grep] ... 當在命令前加上數字時,該數字會被用作尋找匹配項的最大數量。使用 ":1vimgrep pattern file" 只會尋找第一個。如果您只想檢查是否有匹配項,並在找到時快速退出,這會很有用。
每隔一秒左右,就會顯示被搜尋的檔案名稱,讓您了解進度。範例
:vimgrep /an error/ *.c
:vimgrep /\<FileName\>/ *.h include/*
:vimgrep /myfunc/ **/*.c
:vim[grep][!]
{pattern}
{file}
... 和上面一樣,但不是用非 ID 字元將模式包起來,而是使用以空白分隔的模式。模式必須以 ID 字元開頭。範例
:vimgrep Error *.c
:lv :lvimgrep :lv[imgrep][!] /{pattern}/[g][j][f]
{file}
... :lv[imgrep][!]
{pattern}
{file}
... 與 ":vimgrep" 相同,只是使用當前視窗的位置列表,而不是快速修正列表。
:vimgrepa :vimgrepadd :vimgrepa[dd][!] /{pattern}/[g][j][f]
{file}
... :vimgrepa[dd][!]
{pattern}
{file}
... 和 ":vimgrep" 相同,但不是建立新的錯誤列表,而是將匹配項附加到目前的列表。
:lvimgrepa :lvimgrepadd :lvimgrepa[dd][!] /{pattern}/[g][j][f]
{file}
... :lvimgrepa[dd][!]
{pattern}
{file}
... 和 ":vimgrepadd" 相同,只是使用當前視窗的位置列表,而不是快速修正列表。
5.2 外部 grep
Vim 可以使用類似於編譯器整合的方式與 "grep" 和類似 grep 的程式(例如 GNU id-utils)進行交互(請參閱上面的
:make)。
[Unix 小知識:Unix "grep" 命令的名稱來自 ":g/re/p",其中 "re" 代表正規表示式。]
:lgr :lgrep :lgr[ep][!] [引數] 與 ":grep" 相同,只是使用當前視窗的位置列表,而不是快速修正列表。
:grepa :grepadd :grepa[dd][!] [引數] 與 ":grep" 相同,但不是建立新的錯誤列表,而是將匹配項附加到目前的列表。範例
:call setqflist([])
:bufdo grepadd! something %
第一個命令會建立一個新的空的錯誤列表。第二個命令會為每個列出的緩衝區執行 "grepadd"。請注意使用 ! 以避免 ":grepadd" 跳到第一個錯誤,這在使用
:bufdo 時是不允許的。以下範例使用引數列表,並避免在沒有匹配項的檔案中發生錯誤
:silent argdo try
\ | grepadd! something %
\ | catch /E480:/
\ | endtry"
5.3 設定外部 grep
如果您安裝了標準的 "grep" 程式,則 :grep 命令可能可以使用預設值正常運作。其語法與標準命令非常相似
:grep foo *.c
將會在所有副檔名為 .c 的檔案中搜尋子字串 "foo"。傳遞給 :grep 的引數會直接傳遞給 "grep" 程式,因此您可以使用 "grep" 支援的任何選項。
預設情況下,:grep 會使用 -n 選項(顯示檔案和行號)來調用 grep。您可以使用
'grepprg' 選項來變更此設定。如果出現以下情況,您將需要設定
'grepprg':
a) 您使用的是不是叫做 "grep" 的程式 b) 您必須使用完整路徑來調用 grep c) 您想要自動傳遞其他選項(例如,不區分大小寫的搜尋)。
解析結果後,Vim 會載入第一個包含匹配項的檔案,並跳到適當的行,這與它在
快速修正 模式中跳到編譯器錯誤的方式相同。然後,您可以使用
:cnext、
:clist 等命令來查看其他匹配項。
5.4 將 :grep 與 id-utils 搭配使用
您可以設定 :grep 來與 GNU id-utils 搭配使用,如下所示
:set grepprg=lid\ -Rgrep\ -s
:set grepformat=%f:%l:%m
接著
:grep (regexp)
會如您預期般運作。(前提是您記得先 mkid :))
5.5 使用 :vimgrep 或 :grep 瀏覽原始碼
使用 Vim 保留的錯誤列表堆疊,您可以瀏覽檔案以尋找函數及其呼叫的函數。例如,假設您必須向 read_file() 函數新增一個引數。您可以輸入以下命令
:vimgrep /\<read_file\>/ *.c
您可以使用 ":cn" 來瀏覽匹配列表並新增引數。在某個地方,您必須從更上層的函數 msg() 取得新的引數,因此也需要變更該函數。因此,您可以使用
:vimgrep /\<msg\>/ *.c
在變更 msg() 函數時,您會發現另一個函數需要從更上層取得引數。您可以再次使用 ":vimgrep" 來尋找這些函數。一旦完成一個函數,您可以使用
:colder
返回上一個函數。
這就像瀏覽樹狀結構:":vimgrep" 會深入一層,建立分支列表。":colder" 會返回上一層。您可以混用 ":vimgrep" 和 "colder" 來以樹狀方式瀏覽所有位置。如果您持續這樣做,您將可以找到所有位置,而無需寫下「待辦事項」清單。
:comp :compiler E666 :comp[iler][!]
{name}
設定選項以與編譯器
{name}
搭配使用。不加 "!" 時,選項會針對目前的緩衝區設定。加上 "!" 時,會設定全域選項。如果您在 "file.foo" 中使用 ":compiler foo",然後在另一個緩衝區中使用 ":compiler! bar",Vim 仍會在 "file.foo" 中繼續使用 "foo"。
"compiler" 目錄中的 Vim 外掛程式會設定選項以使用選定的編譯器。對於
:compiler
,會設定本機選項,而對於
:compiler!
,會設定全域選項。
current_compiler為了支援舊版的 Vim,外掛程式一律使用 "current_compiler",而不是 "b:current_compiler"。此命令實際執行以下操作
刪除 "current_compiler" 和 "b:current_compiler" 變數。
定義 "CompilerSet" 使用者命令。加上 "!" 時,會執行 ":set",不加 "!" 時,會執行 ":setlocal"。
執行 ":runtime! compiler/{name}.{vim,lua}"。外掛程式預期會使用 "CompilerSet" 來設定選項,並將 "current_compiler" 變數設定為編譯器的名稱。
刪除 "CompilerSet" 使用者命令。
將 "b:current_compiler" 設定為 "current_compiler" 的值。
不加 "!" 時,會還原 "current_compiler" 的舊值。
使用 g/b:`c_cppcheck_params` 來設定 cppcheck 參數。全域設定預設包括
--verbose
:啟用詳細輸出。
--force
:強制檢查所有設定。
--inline-suppr
:允許行內抑制。
--enable=...
:啟用特定的檢查,例如警告、樣式、效能、可移植性、資訊和遺失的 include。
-j
:如果可用,則利用多個處理器,由 getconf
命令決定是否可用(需要省略 unusedFunction 檢查)。
對於 C++ 檔案 (filetype == 'cpp'
),會加入 --language=c++
選項,以確保 Cppcheck 將該檔案視為 C++ 處理。
如果目前目錄中存在 compile_commands.json,則會將其作為
--project
參數新增至命令列。否則,預設會將 &path 中的目錄作為 include 目錄傳遞。這些可以透過 g/b:`c_cppcheck_includes` 設定為
-I
旗標列表。Tim Pope 的 vim-apathy 外掛程式 [0] 可以展開 &path。若要同時附加 git repo 中的資料夾,請使用
let &l:path = join(systemlist('git ls-tree -d --name-only -r HEAD'), ',')
[0]
https://github.com/tpope/vim-apathy
.NET CLI 編譯器預設會輸出錯誤和警告。透過將 g:dotnet_errors_only 變數設定為
v:true,可以限制輸出只包含錯誤。
每個錯誤和警告中都包含相關的專案名稱。若要隱藏專案名稱,請將 g:dotnet_show_project_file 變數設定為
v:false。
範例:限制輸出只顯示錯誤,並隱藏專案名稱
let dotnet_errors_only = v:true
let dotnet_show_project_file = v:false
compiler dotnet
您可以為 GCC 編譯器設定一個變數
g:compiler_gcc_ignore_unmatched_lines 忽略與為 GCC 定義的任何模式不符的行。如果從 make 執行的命令輸出產生誤判,則這很有用。
常用的編譯器選項可以透過設定 g:javac_makeprg_params 變數新增至
'makeprg'。例如
let g:javac_makeprg_params = "-Xlint:all -encoding utf-8"
由於預設的 make 程式是 "make",因此 make 的編譯器外掛程式 :compiler make 會將
'makeprg' 和
'errorformat' 選項重設為預設值,並取消設定先前編譯器外掛程式可能已設定的任何變數。
GROFF 編譯器外掛程式使用 mom 巨集集(記錄在 groff_mom 手冊頁中)作為輸入,並期望輸出檔案類型副檔名傳遞給 make,例如 :make html 或 :make pdf。
可以透過在
b:groff_compiler_args
或
g:groff_compiler_args
中設定額外的引數來傳遞給 groff。傳遞給 groff 的
language
引數是使用
'spelllang' 設定的;可以使用設定
b:groff_compiler_lang
來覆寫它。預設編碼為
UTF-8
,可以透過設定
b:groff_compiler_encoding
或
g:groff_compiler_encoding
來變更。
Pandoc 編譯器外掛程式預期輸出檔案類型副檔名傳遞給 make,例如 :make html 或 :make pdf。
可以將額外的引數傳遞給 pandoc
可以透過將它們附加到 make 來傳遞,例如 :make html --self-contained
。
或在 b:pandoc_compiler_args
或 g:pandoc_compiler_args
中設定它們。
--from
引數是使用緩衝區檔案類型進行的合理猜測;可以透過設定
b:pandoc_compiler_from
來覆寫它。
--metadata lang
引數是使用
'spelllang' 設定的;如果假設
--from=markdown
並且未在標題標頭或 YAML 區塊中設定標題,則會將檔案名稱(不含副檔名)用作標題。
Perl 編譯器外掛程式實際上不會編譯,而是會叫用 Perl 的內部語法檢查功能並剖析輸出中可能存在的錯誤,以便您可以在快速修復模式中修正它們。
無論檔案內是否為 "no warnings" 或 "$^W = 0",都會強制顯示警告。若要停用此設定,請將 g:perl_compiler_force_warnings 設定為零值。例如
let g:perl_compiler_force_warnings = 0
當您使用框架執行測試時,Vim 會剖析可能發生的錯誤,並在快速修復模式中呈現給您。
不幸的是,沒有標準的執行測試方式。alltests.py 腳本似乎很常用,僅此而已。因此,對於
'makeprg' 選項有用的值為:setlocal makeprg=./alltests.py 「執行測試套件」setlocal makeprg=python\ %:S 「執行單一測試案例」
發行版本中包含的 TeX 編譯器 ($VIMRUNTIME/compiler/tex.vim) 會盡可能使用 make 命令。如果編譯器在目前目錄中找到名為 "Makefile" 或 "makefile" 的檔案,則會假設您想要使用 make 處理您的
*TeX
檔案,而 makefile 會執行正確的工作。在這種情況下,編譯器會為
*TeX
輸出設定
'errorformat',並保持
'makeprg' 不變。如果找不到 "Makefile" 或 "makefile",編譯器將不會使用 make。您可以透過定義 b:tex_ignore_makefile 或 g:tex_ignore_makefile 變數(僅檢查它們是否存在)來強制編譯器忽略 makefile。
如果編譯器選擇不使用 make,則需要選擇正確的程式來處理您的輸入。如果存在 b:tex_flavor 或 g:tex_flavor 變數(以此優先順序),則它會為 :make 定義 TeX 風格(實際上,這是執行命令的名稱),如果兩個變數都不存在,則預設為 "latex"。例如,在編輯從 AMS-TeX 撰寫的 mypaper.tex 包含的 chapter2.tex 時
:let b:tex_flavor = 'amstex'
:compiler tex
[編輯中...]
:make mypaper
請注意,您必須指定要處理的檔案名稱作為引數(在編輯從 \input 或 \include 包含的檔案時處理正確的檔案;歡迎使用可攜式解決方案,以將 % 替換為無引數)。這不在 make 的語意中,您在其中指定目標,而非來源,但您可以指定不含副檔名 ".tex" 的檔案名稱,並將其視為「根據編譯器,make filename.dvi 或 filename.pdf 或 filename.some_result_extension」。
注意: tex 命令列語法設定為適用於 MikTeX(Srinath Avadhanula 的建議)和 teTeX(Artem Chuprina 檢查過)。來自
errorformat-LaTeX 的建議太複雜,無法在不同的 shell 和作業系統上保持運作,而且也不允許使用其他可用的 TeX 選項(如果有的話)。如果您的 TeX 不支援 "-interaction=nonstopmode",請回報它,並使用不同的方式從命令列表達 \nonstopmode。
Vim 包含 Typst 檔案的編譯器外掛程式。此編譯器會由 Typst 檔案類型外掛程式
ft-typst-plugin 在 Typst 緩衝區中自動啟用。執行
:make 來編譯目前的 Typst 檔案。
g:typst_cmd 預設情況下,Vim 會使用 "typst" 作為執行 Typst 編譯器的命令。可以透過設定
g:typst_cmd 變數來變更它。
let g:typst_cmd = "/path/to/other/command"
'errorformat' 中的每個項目都是類似 scanf 的字串,描述該格式。首先,您需要知道 scanf 的運作方式。請參閱 C 編譯器的文件。以下是 Vim 了解的 % 項目。其他項目無效。
'errorformat' 中的特殊字元為逗號和反斜線。請參閱
efm-entries,了解如何處理它們。請注意,常值 "%" 是由 "%%" 比對,因此不會使用反斜線跳脫。請記住,在
:make
和
:grep
輸出中,所有 NUL 字元都會替換為 SOH (0x01)。
注意:預設情況下,會忽略大小寫之間的差異。如果您想要比對大小寫,請將 "\C" 新增至模式
/\C。
Vim 將讀取任何長度的行,但只會使用前 4095 個位元組,其餘的會被忽略。項目只能是 1023 個位元組長。
基本項目
%f 檔案名稱(尋找字串)%b 緩衝區編號(尋找數字)%o 模組名稱(尋找字串)%l 行號(尋找數字)%e 結束行號(尋找數字)%c 欄號(尋找代表錯誤字元欄的數字、位元組索引,<tab>
是 1 個字元欄)%v 虛擬欄號(尋找代表錯誤螢幕欄的數字 (1 <tab>
== 8 個螢幕欄))%k 結束欄號(尋找代表錯誤字元欄的數字、位元組索引,或如果與 %v 一起使用時,則尋找代表錯誤螢幕結束欄的數字)%t 錯誤類型(尋找單一字元):e - 錯誤訊息 w - 警告訊息 i - 資訊訊息 n - 附註訊息 %n 錯誤編號(尋找數字)%m 錯誤訊息(尋找字串)%r 比對單行檔案訊息的「其餘」部分 %O/P/Q %p 指標行(尋找 '-'、'.'、' ' 或 Tab 的序列,並使用長度作為欄號)%*{conv} 任何 scanf 無法指派的轉換 %% 單一 '%' 字元 %s 搜尋文字(尋找字串)
"%f" 轉換可能取決於目前的
'isfname' 設定。"~/" 會展開為主目錄,而環境變數會展開。
"%f" 和 "%m" 轉換必須偵測字串的結尾。這通常是透過比對後續字元和項目來完成的。如果沒有任何內容跟隨,則會比對行的其餘部分。如果 "%f" 後面跟著 '%' 或反斜線,它會尋找
'isfname' 字元序列。
在 Windows 上,即使使用 "%f:","%f" 中也會包含開頭的 "C:"。這表示無法偵測單一字母的檔案名稱。
"%b" 轉換用於剖析緩衝區編號。這對於參照暫存緩衝區或沒有名稱的緩衝區中的行很有用。如果不存在具有相符編號的緩衝區,則該行會用作非錯誤行。
"%p" 轉換通常後面會跟著 "^"。它用於輸出像這樣的行的編譯器
^
或
---------^
以指出錯誤的欄。這將在多行錯誤訊息中使用。請參閱
errorformat-javac,以取得有用的範例。
"%s" 轉換會指定要搜尋以尋找錯誤行的文字。該文字會用作常值字串。錨點 "^" 和 "$" 會新增至文字,以尋找完全比對搜尋文字的錯誤行,並且該文字會加上 "\V" 原子,使其成為「非常不具魔力」。"%s" 轉換可用於尋找錯誤輸出中沒有行號的行。就像 "grep" shell 命令的輸出一樣。當模式存在時,不會使用行號。
「%o」轉換指定快速修正條目中的模組名稱。如果存在,它將在快速修正錯誤視窗中使用,而不是使用檔名。模組名稱僅用於顯示目的,跳轉到檔案時將使用檔名。
變更目錄
以下的大寫轉換字元指定特殊格式字串的類型。在單一逗號分隔的格式模式開頭,最多可以給定一個作為前綴。某些編譯器產生的訊息包含必須附加到 %f 讀取的每個檔名的目錄名稱(例如:GNU make)。可以使用以下代碼掃描這些目錄名稱;它們將儲存在內部目錄堆疊中。
E379%D「進入目錄」格式字串;預期後接一個 %f,以尋找目錄名稱 %X「離開目錄」格式字串;預期後接一個 %f
可以讀取產生多行訊息的程式輸出,即消耗多行以上的錯誤字串。可能的前綴是:%E 多行錯誤訊息的開始 %W 多行警告訊息的開始 %I 多行資訊訊息的開始 %N 多行註解訊息的開始 %A 多行訊息的開始(未指定類型) %> 下一行再次以目前模式開始
efm-%> %C 多行訊息的延續 %Z 多行訊息的結尾 這些可以與「+」和「-」一起使用,請參閱下面的
efm-ignore。
在模式中使用「\n」無法比對多行訊息。
範例:您的編譯器碰巧以以下格式寫出錯誤(開頭的行號不屬於實際輸出)
1 Error 275
2 line 42
3 column 3
4 ' ' expected after '--'
適當的錯誤格式字串必須如下所示
:set efm=%EError\ %n,%Cline\ %l,%Ccolumn\ %c,%Z%m
為此錯誤產生的
:clist 錯誤訊息是
1:42 col 3 error 275: ' ' expected after '--'
另一個範例:假設有一個 Python 直譯器產生以下錯誤訊息(行號不屬於實際輸出)
1 ============================================================== 2 FAIL: testGetTypeIdCachesResult (dbfacadeTest.DjsDBFacadeTest) 3 -------------------------------------------------------------- 4 Traceback (most recent call last): 5 File "unittests/dbfacadeTest.py", line 89, in testFoo 6 self.assertEquals(34, dtid) 7 File "/usr/lib/python3.8/unittest.py", line 286, in 8 failUnlessEqual 9 raise self.failureException, \ 10 AssertionError: 34 != 33 11 12 -------------------------------------------------------------- 13 Ran 27 tests in 0.063s
假設您希望
:clist 只寫入此訊息的相關資訊,即:5 unittests/dbfacadeTest.py:89: AssertionError: 34 != 33
那麼錯誤格式字串可以定義如下
:set efm=%C\ %.%#,%A\ \ File\ \"%f\"\\,\ line\ %l%.%#,%Z%[%^\ ]%\\@=%m
請注意,這裡的 %C 字串是在 %A 之前給出的:由於運算式 ' %.%#' (代表正規運算式 ' .*') 比對以空格開頭的每一行,後接任意字元到行尾,因此它也會隱藏第 7 行,否則將觸發單獨的錯誤訊息。錯誤格式字串總是逐模式解析,直到出現第一個比對。
efm-%>可以使用 %> 項目來避免嘗試在
'errorformat' 中較早出現的模式。這對於比對幾乎所有內容的模式非常有用。例如,如果錯誤看起來像這樣
Error in line 123 of foo.c
unknown variable "i"
這可以使用以下程式碼找到
:set efm=xxx,%E%>Error in line %l of %f:,%Z%m
其中 "xxx" 具有一個也會比對第二行的模式。
重要提示:沒有記憶體記錄 errorformat 的哪個部分之前比對;錯誤檔案中的每一行都會完整重新執行 error format 行。例如,如果有一個
setlocal efm=aa,bb,cc,dd,ee
其中 aa、bb 等是錯誤格式字串。錯誤檔案的每一行都會比對模式 aa,然後是 bb,然後是 cc 等。僅僅因為 cc 比對了先前的錯誤行,並不表示 dd 會在目前行上首先嘗試,即使 cc 和 dd 是多行 errorformat 字串。
如果檔名只給定一次,並且後面有多個引用此檔名的訊息,則這些前綴很有用。%O 單行檔案訊息:略過比對的部分 %P 單行檔案訊息:將檔案 %f 推入堆疊 %Q 單行檔案訊息:從堆疊中彈出最後一個檔案
範例:假設有一個編譯器產生以下錯誤記錄檔(沒有開頭的行號)
1 [a1.tt] 2 (1,17) error: ';' missing 3 (21,2) warning: variable 'z' not defined 4 (67,3) error: end of file found before string ended 5 6 [a2.tt] 7 8 [a3.tt] 9 NEW compiler v1.1 10 (2,2) warning: variable 'x' not defined 11 (67,3) warning: 's' already defined
此記錄檔列出每個以 [...] 包圍的檔案的多個訊息,這些訊息會被如下的錯誤格式正確解析
:set efm=%+P[%f],(%l\\,%c)%*[\ ]%t%*[^:]:\ %m,%-Q
:clist 的呼叫會根據它們的正確檔名寫入這些訊息
2 a1.tt:1 col 17 error: ';' missing 3 a1.tt:21 col 2 warning: variable 'z' not defined 4 a1.tt:67 col 3 error: end of file found before string ended 8 a3.tt:2 col 2 warning: variable 'x' not defined 9 a3.tt:67 col 3 warning: 's' already defined
與所有比對整行的其他前綴不同,%P、%Q 和 %O 可以用來比對同一行中的多個模式。因此,甚至可以解析如下一行中的巢狀檔案
{"file1" {"file2" error1} error2 {"file3" error3 {"file4" error4 error5}}}
代碼「+」或「-」可以與上面的大寫代碼組合;在這種情況下,它們必須放在字母前面,例如「%+A」或「%-G」:%− 不要在任何輸出中包含比對的多行 %+ 在 %m 錯誤字串中包含整個比對行
有一個前綴僅在與「+」或「-」組合時才有用,即 %G。它會解析略過包含一般資訊的行,例如可以跳過的編譯器版本字串或其他標頭。%-G 忽略此訊息 %+G 一般訊息
模式比對
為了與先前版本的 Vim 向後相容,支援類似 scanf() 的 "%*[]" 標記法。但是,也可以在格式字串中指定(幾乎)任何 Vim 支援的正規運算式。由於正規運算式語言的元字元可以是普通比對字串或檔名的一部分(因此內部必須逸出),元符號必須使用前導「%」來寫入:「%\\」單個「\」字元。請注意,這必須在 ":set errorformat=" 定義中逸出(「%\\」)。「%.」單個「.」字元。「%#」單個「*」(!) 字元。「%^」單個「^」字元。請注意,這沒有用處,該模式已比對行首。「%$」單個「$」字元。請注意,這沒有用處,該模式已比對行尾。「%[」用於「[]」字元範圍的單個「[」字元。「%~」單個「~」字元。當在運算式中使用字元類別時(有關概述,請參閱
/\i),包含「\+」量詞的項目可以使用 scanf() 的 "%*" 標記法撰寫。範例:「%\\d%\\+」(「\d\+」,「任意數字」)等同於「%*\\d」。重要提示:子比對的 \(\.\.\.\) 分組不能在格式規格中使用,因為它保留用於內部轉換。
為了能夠偵測多個編譯器的輸出,可以在
'errorformat' 中放入多個格式模式,並以逗號分隔(請注意:逗號後的空格會被忽略)。使用第一個完全比對的模式。如果找不到比對,則將使用最後一個的比對部分,雖然檔名已移除,且錯誤訊息會設定為整個訊息。如果有一個模式可能會比對來自多個編譯器的輸出(但方式不正確),請將它放在限制性更強的模式之後。
若要在模式中包含逗號,請在逗號前面加上反斜線(您必須在 ":set" 命令中輸入兩個)。若要包含反斜線本身,請給出兩個反斜線(您必須在 ":set" 命令中輸入四個)。您還需要在 ":set" 的空格前面加上反斜線。
如果一行與
'errorformat' 中的其中一個條目不完全比對,則整行會放入錯誤訊息中,且該條目會標記為「無效」。這些行會使用「:cn」和「:cp」命令跳過(除非根本沒有有效的行)。您可以使用「:cl!」來顯示所有錯誤訊息。
如果錯誤格式不包含檔名,則 Vim 無法切換到正確的檔案。您必須手動執行此操作。
例如,Amiga Aztec 編譯器的輸出格式如下
檔名>行號:欄號:錯誤類型:錯誤編號:錯誤訊息
檔名:偵測到錯誤的檔案名稱 行號:偵測到錯誤的行號 欄號:偵測到錯誤的欄號 錯誤類型:錯誤類型,通常是單個「E」或「W」 錯誤編號:錯誤的編號(用於在手冊中查找) 錯誤訊息:錯誤的描述
以下是一些產生單行錯誤輸出的 C 編譯器範例:%f:%l:\ %t%*[^0123456789]%n:\ %m 用於 Manx/Aztec C 錯誤訊息 (scanf() 無法理解 [0-9]) %f\ %l\ %t%*[^0-9]%n:\ %m 用於 SAS C \"%f\"\\,%*[^0-9]%l:\ %m 用於通用 C 編譯器 %f:%l:\ %m 用於 GCC %f:%l:\ %m,%Dgmake[%*\\d]:\ Entering\ directory\%f', %Dgmake[%*\\d]:\ Leaving\ directory\%f' 用於使用 gmake 的 GCC (串連行!) %f(%l)\ :\ %*[^:]:\ %m 舊的 SCO C 編譯器 (pre-OS5) %f(%l)\ :\ %t%*[^0-9]%n:\ %m 同上,帶有錯誤類型和編號 %f:%l:\ %m,In\ file\ included\ from\ %f:%l:,\^I\^Ifrom\ %f:%l%m 用於 GCC,帶有一些額外資訊
請注意空格和雙引號前面的反斜線。這是 `:set` 命令所必需的。逗號前面有兩個反斜線,一個用於 `:set` 命令,另一個用於避免將逗號識別為錯誤格式的分隔符。
篩選訊息
如果您的編譯器產生的錯誤訊息不符合格式字串,您可以編寫一個程式將錯誤訊息轉換為此格式。您可以透過變更
'makeprg' 選項,將此程式與 ":make" 命令一起使用。例如
:set mp=make\ \\\|&\ error_filter
管道符號之前的反斜線是必需的,以避免它被識別為命令分隔符。每個空格前面的反斜線是 `set` 命令所必需的。
Quickfix 維護一個堆疊,用於儲存從 make 輸出中剖析的所有已使用目錄。對於 GNU-make 來說,這相當簡單,因為它總是會列印出它進入和離開的所有目錄的絕對路徑。無論這是否是透過 makefile 中的
'cd' 命令完成,還是使用參數 "-C dir" (在讀取 makefile 之前變更到目錄) 完成。使用開關 "-w" 強制 GNU-make 在處理之前和之後列印出工作目錄可能會很有用。
如果您不使用 GNU-make,則維護正確的目錄會更複雜。例如,AIX-make 不會列印任何關於其工作目錄的資訊。那麼您需要增強 makefile。在 LessTif 的 makefile 中,有一個命令會輸出 "Making {target}
in {dir}
"。這裡的特殊問題是它不會列印離開目錄的資訊,並且不會列印絕對路徑。
為了解決相對路徑和遺失「離開目錄」訊息的問題,Vim 使用以下演算法
1) 檢查給定的目錄是否為目前目錄的子目錄。如果為真,則將其儲存為目前目錄。2) 如果它不是目前目錄的子目錄,則嘗試它是否為上層目錄之一的子目錄。3) 如果仍然找不到該目錄,則假設它是 Vim 目前目錄的子目錄。
此外,對於每個檔案,都會檢查它是否確實存在於已識別的目錄中。如果沒有,則會在目錄堆疊的所有其他目錄中搜尋 (而不是目錄子樹!)。如果仍然找不到,則假設它位於 Vim 的目前目錄中。
此演算法存在限制。這些範例假設 make 只會以 "Making all in dir" 的形式列印有關進入目錄的資訊。
1) 假設您有以下目錄和檔案:./dir1 ./dir1/file1.c ./file1.c
如果 make 在處理目前目錄之前處理目錄 "./dir1",並且檔案 "./file1.c" 中有錯誤,您最終會讓 Vim 載入檔案 "./dir1/file.c"。
這只能透過「離開目錄」訊息來解決。
2) 假設您有以下目錄和檔案:./dir1 ./dir1/dir2 ./dir2
您會得到以下結果
Make 輸出 Vim 解釋的目錄 ------------------------ ---------------------------- Making all in dir1 ./dir1 Making all in dir2 ./dir1/dir2 Making all in dir2 ./dir1/dir2
這可以透過在「進入目錄」訊息中列印絕對目錄,或列印「離開目錄」訊息來解決。
為了避免這個問題,請確保列印絕對目錄名稱和「離開目錄」訊息。
Makefile 範例
Unix: libs: for dn in $(LIBDIRS); do \ (cd $$dn; echo "Entering dir '$$(pwd)'"; make); \ echo "Leaving dir"; \ done
在您的
'errorformat' 中新增 %DEntering\ dir\ '%f',%XLeaving\ dir 來處理上述輸出。
請注意,Vim 不會檢查「離開目錄」訊息中的目錄名稱是否為目前目錄。這就是為什麼您可以只使用訊息 "Leaving dir" 的原因。
下面顯示了一個與產生的訊息相符的
'errorformat' 字串。以下行可以放置在使用者的
init.vim 中,以覆寫 Vim 識別的預設格式,或者參閱
:set+= 以了解如何將此格式額外安裝到預設格式中。
:set efm=%A%f:%l:%c:%*\\d:%*\\d:,
\%C%*\\s%trror:%m,
\%+C%*[^:]%trror:%m,
\%C%*\\s%tarning:%m,
\%C%m
當使用選項 "+E" 叫用 Jikes(TM) 時,它會產生單行錯誤訊息,並且可以使用以下內容比對
:setl efm=%f:%l:%v:%*\\d:%*\\d:%*\\s%m
errorformat-javac 據回報,這個
'errorformat' 適用於 javac,它會輸出一個帶有 "^" 的行來指示錯誤的列。
:setl efm=%A%f:%l:\ %m,%-Z%p^,%-C%.%#
或
:setl efm=%A%f:%l:\ %m,%+Z%p^,%+C%.%#,%-G%.%#
這是來自 Michael F. Lamb 的另一個適用於 Unix 的替代方案,它會先篩選錯誤
:setl errorformat=%Z%f:%l:\ %m,%A%p^,%-G%*[^sl]%.%#
:setl makeprg=javac\ %:S\ 2>&1\ \\\|\ vim-javac-filter
您需要將以下內容放入您路徑中的某個位置 (例如,在 ~/bin 中) 的 "vim-javac-filter" 中,並使其可執行
#!/bin/sed -f
/\^$/s/\t/\ /g;/:[0-9]\+:/{h;d};/^[ \t]*\^/G;
用英語來說,該 sed 指令碼
將單個 Tab 字元變更為單個空格,並且
將帶有檔案名稱、行號、錯誤訊息的行移動到指標行之後。這樣,之間未使用的錯誤文字不會破壞 Vim 的「多行訊息」概念,也不會強迫我們將其包含為「多行訊息的延續」。
errorformat-ant 對於 ant (
https://jakarta.apache.org/),必須修改上述 errorformat,以符合每個 javac 輸出列前面的前導 [javac]
:set efm=%A\ %#[javac]\ %f:%l:\ %m,%-Z\ %#[javac]\ %p^,%-C%.%#
也可以配置
'errorformat' 以處理 ant 以及 javac 或 jikes。如果您使用 jikes,您應該告訴 ant 使用 jikes 的 +E 命令列開關,這會強制 jikes 產生單行錯誤訊息。這就是下面的第二行 (build.xml 檔案) 所執行的操作
<property name = "build.compiler" value = "jikes"/>
<property name = "build.compiler.emacs" value = "true"/>
處理 ant 以及 javac 和 jikes 的
'errorformat' 是
:set efm=\ %#[javac]\ %#%f:%l:%c:%*\\d:%*\\d:\ %t%[%^:]%#:%m,
\%A\ %#[javac]\ %f:%l:\ %m,%-Z\ %#[javac]\ %p^,%-C%.%#
errorformat-LaTeX 以下範例說明如何為 (La)TeX 排版系統指定
'errorformat' 字串,該系統會在多行上顯示錯誤訊息。":clist" 和 ":cc" 等命令的輸出會在單行中顯示多行,並移除前導空白。應該很容易將上述 LaTeX errorformat 調整為任何由多行錯誤組成的編譯器輸出。
這些命令可以放在
vimrc 檔案或一些其他 Vim 指令碼檔案中,例如,一個僅在編輯 LaTeX 來源時載入的包含 LaTeX 相關內容的指令碼。請務必複製範例的所有行 (依給定順序),然後移除註解行。對於某些行開頭的 '\' 標記法,請參閱
line-continuation。
首先準備
'makeprg',以便 LaTeX 會回報多個錯誤;在發生第一個錯誤時不要停止
:set makeprg=latex\ \\\\nonstopmode\ \\\\input\\{$*}
多行錯誤訊息的開始
:set efm=%E!\ LaTeX\ %trror:\ %m,
\%E!\ %m,
多行警告訊息的開始;前兩個還包括行號。一些正規表示式的含義
"%.%#" (".*") 比對 (可能是空的) 字串
"%*\\d" ("\d\+") 比對數字
\%+WLaTeX\ %.%#Warning:\ %.%#line\ %l%.%#,
\%+W%.%#\ at\ lines\ %l--%*\\d,
\%WLaTeX\ %.%#Warning:\ %m,
錯誤/警告訊息的可能延續;第一個還包括行號
\%Cl.%l\ %m,
\%+C\ \ %m.,
\%+C%.%#-%.%#,
\%+C%.%#[]%.%#,
\%+C[]%.%#,
\%+C%.%#%[{}\\]%.%#,
\%+C<%.%#>%.%#,
\%C\ \ %m,
符合以下模式的行不包含任何重要資訊;請勿將其包含在訊息中
\%-GSee\ the\ LaTeX%m,
\%-GType\ \ H\ <return>%m,
\%-G\ ...%.%#,
\%-G%.%#\ (C)\ %.%#,
\%-G(see\ the\ transcript%.%#),
通常排除任何要顯示的空白或僅包含空白的行
\%-G\\s%#,
LaTeX 輸出記錄不會逐行指定錯誤來源檔案的名稱;而是以括號括起來整體給出。以下模式嘗試比對這些名稱並將其儲存在內部堆疊中。這些模式可能會掃描相同的輸入行 (一個接一個),尾隨 "%r" 轉換表示該行其餘部分將在下一次掃描中剖析,直到到達行尾。
忽略以 '('...')' 括起來的檔案名稱;不要將其推送至堆疊,因為該檔案顯然不包含任何錯誤
\%+O(%f)%r,
將檔案名稱推送到堆疊上。該名稱是在 '(' 之後給出的
\%+P(%f%r,
\%+P\ %\\=(%f%r,
\%+P%*[^()](%f%r,
\%+P[%\\d%[^()]%#(%f%r,
掃描到 ')' 時,彈出最後儲存的檔案名稱
\%+Q)%r,
\%+Q%*[^()])%r,
\%+Q[%\\d%*[^()])%r
請注意,在某些情況下,無法正確剖析 LaTeX 輸出記錄中的檔案名稱。剖析器可能因為不平衡的括號而混亂。上述範例僅嘗試捕捉最相關的情況。您可以自訂給定的設定以滿足您自己的目的,例如,可以排除所有惱人的「過滿...」警告而不將其識別為錯誤。或者,除了篩選 LaTeX 編譯器輸出外,也可以直接讀取 [La]TeX 編譯器產生的
*.log
檔案。這包含更多關於可能錯誤原因的有用資訊。但是,要正確剖析如此複雜的檔案,應該使用外部篩選器。請參閱上面更進一步的說明,了解如何讓 Vim 知道此篩選器。
Quickfix 視窗和位置清單視窗中顯示的行的預設格式是
<filename>|<lnum> col <col>|<text>
每一行中顯示的值對應於
getqflist() 函式傳回的「bufnr」、「lnum」、「col」和「text」欄位。
對於某些 Quickfix/位置清單,需要自訂顯示的文字。例如,如果 Quickfix 項目僅存在檔案名稱,則檔案名稱後的兩個 "|" 欄位分隔字元不是必需的。另一個用例是自訂檔案名稱顯示的路徑。根據預設,對於不在目前目錄樹下的檔案,會顯示完整路徑 (可能太長)。檔案路徑可能需要簡化為共同的父目錄。
顯示的文字可以透過將
'quickfixtextfunc' 選項設定為 Vim 函式來自訂。此函式將會以一個字典引數呼叫,並應傳回一個字串列表,以便顯示在 quickfix 或 location list 視窗中。該字典引數將包含以下欄位:
quickfix:當為 quickfix list 呼叫時設為 1,當為 location list 呼叫時設為 0。winid:對於 location list,設為包含 location list 的視窗 ID。對於 quickfix list,設為 0。可用於 getloclist() 以取得 location list 項目。id:quickfix 或 location list 的識別碼。start_idx:應該傳回文字的第一個條目的索引。end_idx:應該傳回文字的最後一個條目的索引。
此函式應為從 start_idx 到 end_idx 的每個條目傳回單行文字,以顯示在 quickfix 視窗中。此函式可以使用
getqflist() 函式並指定 quickfix list 識別碼 "id" 來取得有關條目的資訊。對於 location list,可以使用帶有 "winid" 引數的 getloclist() 函式。如果傳回一個空列表,則將使用預設格式來顯示所有條目。如果傳回列表中的某個項目為空字串,則將使用預設格式來顯示對應的條目。
下面的範例會在 quickfix 視窗中顯示舊檔案列表 (
v:oldfiles)。由於每個條目沒有相關聯的行號、列號和錯誤文字資訊,因此
'quickfixtextfunc' 函式僅傳回檔案名稱。範例:
" create a quickfix list from v:oldfiles
call setqflist([], ' ', {'lines' : v:oldfiles, 'efm' : '%f',
\ 'quickfixtextfunc' : 'QfOldFiles'})
func QfOldFiles(info)
" get information about a range of quickfix entries
let items = getqflist({'id' : a:info.id, 'items' : 1}).items
let l = []
for idx in range(a:info.start_idx - 1, a:info.end_idx - 1)
" use the simplified file name
call add(l, fnamemodify(bufname(items[idx].bufnr), ':p:.'))
endfor
return l
endfunc