簡體   English   中英

fzf.vim:與后備源的模糊匹配

[英]fzf.vim: fuzzy matching with a fall-back source

我想通過以下行為對 select 緩沖區執行 vim 命令:

  1. 調用時,它會向用戶顯示當前目錄中加載的緩沖區和其他最近使用的緩沖區的列表(這與fzf.vim提供的:History命令不同,因為我們僅列出當前目錄中最近使用的緩沖區, fzf.vim 列出所有最近的緩沖區)。 用戶可以搜索他們想要加載的文件名
  2. 如果沒有任何選項與用戶的搜索詞匹配,則通過列出當前目錄中的所有文件並讓用戶模糊搜索來擴展搜索的 scope。

這是我到目前為止所擁有的(假設已經安裝了junegunn/fzf.vim ):

nnoremap <silent> <space><space> :call <SID>recent_files()<CR>

function! s:recent_files_sink(items)
  if len(a:items) == 2
    execute "edit" a:items[1]
    return
  endif
  call fzf#vim#files("", {'options': ['--query', a:items[0]]})
endfunction

" deduped is a list of items without duplicates, this
" function inserts elements from items into deduped
function! s:add_unique(deduped, items)
  let dict = {}
  for item in a:deduped
    let dict[item] = ''
  endfor

  for f in a:items
    if has_key(dict, f) | continue | endif
    let dict[f] = ''
    call add(a:deduped, f)
  endfor
  return a:deduped
endfunction

function! s:recent_files()
  let regex = '^' . fnamemodify(getcwd(), ":p")
  let buffers = filter(map(
        \ getbufinfo({'buflisted':1}), {_, b -> fnamemodify(b.name, ":p")}),
        \ {_, f -> filereadable(f)}
        \ )
  let recent = filter(
        \ map(copy(v:oldfiles), {_, f -> fnamemodify(f, ":p")}),
        \ {_, f -> filereadable(f) && f =~# regex})
  let combined = s:add_unique(buffers, recent)
  call fzf#run(fzf#wrap({
        \ 'source': map(combined, {_, f -> fnamemodify(f, ":~:.")}),
        \ 'sink*': function('s:recent_files_sink'),
        \ 'options': '--print-query --exit-0 --prompt "Recent> "'
        \ }))
endfunction

Space Space調用s:recent_files()列出加載的緩沖區和最近使用的來自 viminfo 的文件。 這里有趣的是調用fzf#run中的sink*選項(從底部算起的第 4 行)。 水槽是另一個 function。 如果選擇了文件名,接收器 function 會加載它以進行編輯,否則,它會調用fzf#vim#files ,列出目錄的內容。

這非常接近我想要的,但有幾個問題:

  1. 當在最近的文件中沒有找到匹配項時,用戶必須按Return來觸發回退。 (人們很容易爭辯說這是正確的行為)
  2. 加載后備 fzf window 時,它以正常模式而不是插入模式啟動
  3. 用戶必須在新的 fzf window 中再次輸入搜索查詢(已解決)

我正在尋找有關如何解決這些問題的建議,尤其是 2 和 3。我也對不完全符合規范但提供良好用戶體驗的解決方案持開放態度。

編輯:我想出了另一種方法來實現這一點,使用它作為 fzf 的源

cat recent_files.txt fifo.txt

其中recent_files.txt是最近文件的列表, fifo.txt是使用mkfifo創建的空 fifo。 可以將映射添加到緩沖區,觸發寫入 fifo 的命令。 這樣,用戶可以使用該映射來包含所有文件的列表,以防他們在最近的文件中找不到匹配項。 如果用戶在最近的文件中找到文件並按 Enter 鍵,這種方法會出現問題。 由於 fzf 直到等待從 fifo 讀取,它不會退出https://github.com/junegunn/fzf/issues/2288

我終於能夠使用 fzf 的reload功能找到一個非常接近的解決方案。 (感謝junegunn

事情是這樣的:

nnoremap <silent> <space><space> :call <SID>recent_files()<CR>

" Initialize fzf with a list of loaded buffers and recent files from
" the current directory. If <space> is pressed, we load a list of all
" the files in the current directory
function! s:recent_files()
  let regex = '^' . fnamemodify(getcwd(), ":p")
  let buffers = filter(map(
        \ getbufinfo({'buflisted':1}), {_, b -> fnamemodify(b.name, ":p")}),
        \ {_, f -> filereadable(f)}
        \ )
  let recent = filter(
        \ map(copy(v:oldfiles), {_, f -> fnamemodify(f, ":p")}),
        \ {_, f -> filereadable(f) && f =~# regex})
  let combined = <SID>add_unique(buffers, recent)

  "-------------------------------------------
  " This is the key piece that makes it work
  "-------------------------------------------
  let options = [
        \ '--bind', 'space:reload:git ls-files',
        \ ]

  call fzf#run(fzf#wrap({
        \ 'source': map(combined, {_, f -> fnamemodify(f, ":~:.")}),
        \ 'options': options
        \ }))
endfunction

" deduped is a list of items without duplicates, this
" function inserts elements from items into deduped
function! s:add_unique(deduped, items)
  let dict = {}
  for item in a:deduped
    let dict[item] = ''
  endfor

  for f in a:items
    if has_key(dict, f) | continue | endif
    let dict[f] = ''
    call add(a:deduped, f)
  endfor
  return a:deduped
endfunction

我使用<space><space>啟動 FZF。 此 FZF window 僅包含當前目錄中的最新文件。 如果我然后按<space> ,則 FZF window 將使用從git ls-files獲得的新文件列表進行更新。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM