Unite是一個vim的模糊搜尋外掛,透過將模糊搜尋的邏輯和資料來源分離,實現了一個可泛用於各種情境的模糊搜尋框架,例如:檔案搜尋、內文搜尋、git commits等等;加上它作為一個原生vim外掛,幾乎是只要vim能用的地方它就能用,省去不少環境設定的麻煩,過去幾年來它一直在我的開發環境中扮演重要角色。但Unite效能不彰、由於設計上的問題擴充不便,更受不了的是作者Shougo沒事就把一樣的東西一直重寫,而不是好好地維護好一個專案,終於「再次」下定決心換掉 –– 是的,這不是我第一次找,只是過去都沒有成功。
所幸一代新人換舊人,這次很快就找到:fzf。實作品質優秀、效能拔群、設計上擴充容易,加上穩定的維護,用得我老淚縱橫,忍不住就贊助了好幾杯咖啡給來自南韓的作者junegunn。
基本使用
fzf本身其實不是vim外掛而是個模糊搜尋的系統工具,和vim的整合部分靠的是fzf.vim。搜尋語法可參考官方README,方便起見以下截圖參考:

安裝設定
call plug#begin( '~/.config/nvim/plugged' )
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'
就這樣。
我因為個人偏好還有安裝fd做預設檔案搜尋工具用,安裝後在.bashrc中加入一行 export FZF_DEFAULT_COMMAND="fd --type f"
即可,但不用這玩意它也可以正常使用的。
搜尋檔案
執行 :Files
即可進行遞迴式的檔案模糊搜尋,如:
搜尋內文
安裝了rg後,就能用 :Rg
命令來進行內文的模糊搜尋,例如:
在上例中,我先搜尋recordTracksEvents,後來又增加"signup"和"user"來限縮搜尋範圍。咦?但那似乎是過濾了檔名而非內文啊,怎麼回事呢?這是因為:Rg其實僅會在第一個搜尋字詞時喚起ripgrep來進行內文搜尋,在fzf.vim收到其輸出後,在那之後就都只是對這個輸出進行處理,已經沒有內文或檔名的分別了。第一次發現這個行為有些意外,但習慣後倒是意外地方便,上例就是我蠻常使用的方式。
如果想要確保每次更新搜尋字詞ripgrep都會重新執行,可以參考官方README的interactive ripgrep integration一節。
搜尋git控管索引
如果當下的工作目錄是用git控管,那麼直接改用 :GitFiles
查git索引會比用fd快得多了。我個人設定的熱鍵因為歷史因素是CTRL+F:
同理,內文搜尋也必然可以接到git grep,可參考README的GGrep範例自行加入。但根據ripgrep的測速,git grep不見得比較快就是了:

最近使用檔案(MRU,Most Recently Used)
通常在開發一項功能時會摸到的檔案就是固定那幾個,因此能否有個方便的介面可以直接去巡覽這組檔案對我來說至關重要。fzf-vim提供了方便的 :History
讓我可以用美美的介面來作這件事:
利用工作目錄限縮 :Files與 :Rg
在一個目錄結構講究的專案中,需要動到的檔案常常都在同一個目錄之中,這時把nvim的工作目錄直接設在該目錄下就非常有用:將檔案搜尋與內文搜尋都限制在該目錄下來大幅去除整個源碼庫中不需注意的部分:

比起calypso,這在WordPress.com開發上更有用——因為WordPress.com本質上就只是WordPress加上一拖拉庫的外掛和主題,簡單地透過工作目錄,我就可以只專注在核心、一個外掛,或一個主題上。這種開發風格也是我一直很難換到IDE去的諸多原因之一。
預設的:GitFiles並沒有把工作目錄納入參考。比較一下:GitFiles和:Files實際喚起的命令的話:
Files ? dir call fzf#vim#files(, fzf#vim#with_preview(), 0) |
GitFiles ? call fzf#vim#gitfiles(, fzf#vim#with_preview( == “?" ? { “placeholder": “" } : {}), 0) |
會發現GitFiles少了一個dir,如果補上去應該就行了 … 應該啦
小小缺憾
目前用下來,雖然fzf.vim可以用更好的效率取代掉我在Unite 99%的使用情境,唯獨少了一個:回復上一次的搜尋。Unite有:UniteResume命令可以回復上一次的搜尋,因此若在前一次的搜尋中開錯了檔案,我不必重新搜尋,只要執行:UniteResume就可以重新叫出上一次的搜尋結果就行了。但這在fzf.vim中目前的設計似乎是不可行的,詳細的討論可在Resume support – resume a window in same state這個issue中找到。