ottijp blog

NERDTreeで選択中のノードに対してfzfでファイルを検索する

vimでNERDTreeというファイラプラグインを使っているのですが,NERDTreeで選択中のノードを起点にfzfでファイル検索したいなあと思って,設定を書いてみました.

環境

$ vim --version | head -4
VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Dec 19 2020 21:23:05)
macOS version
Included patches: 1-2164
Compiled by root@Mac-1608412769109.local

$ (cd ~/.vim/bundles/repos/github.com/junegunn/fzf && git rev-parse HEAD)
bf447d77035c0c67f4c9306696bd5541cbcb3e11

$ (cd ~/.vim/bundles/repos/github.com/junegunn/fzf.vim && git rev-parse HEAD)
d43df0ea2f099836c2e3499756101e87bcbd3e25

$ (cd ~/.vim/bundles/repos/github.com/scrooloose/nerdtree && git rev-parse HEAD)
aaa946fb6bd79b9af86fbaf4b6b63fd81d839bd9

.vimrc

NERDTreeのキーマップAPIを使い,NERDTreeでファイルノードかディレクトリノードを選択中にzfをタイプすることでファイル検索を, zgをタイプすることでgrep(ripgrep)検索を行えるようにしました.

キーマップAPIのヘルプは:help NERDTreeKeymapAPIで参照できます.

.vimrc
" function to find file under current node
function! NERDTreeFindFile(node)
  if a:node.path.isDirectory == 1
    let path = a:node.path.str()
  else
    let path = a:node.path.getDir().str()
  endif
  echo path
  NERDTreeClose
  call fzf#vim#files(path)
endfunction
" function to grep files under current node
function! NERDTreeGrepFile(node)
  if a:node.path.isDirectory == 1
    let path = a:node.path.str()
  else
    let path = a:node.path.getDir().str()
  endif
  NERDTreeClose
  call fzf#vim#grep("rg --column --line-number --no-heading --color=always --smart-case \"\" ".shellescape(path), 1, fzf#vim#with_preview())
endfunction
augroup nerdtree
  autocmd!
  " find file under current node
  autocmd VimEnter * call NERDTreeAddKeyMap({
        \ 'key': 'zf',
        \ 'callback': 'NERDTreeFindFile',
        \ 'quickhelpText': 'find file under current node',
        \ 'scope': 'Node' })
  " grep files under current node
  autocmd VimEnter * call NERDTreeAddKeyMap({
        \ 'key': 'zg',
        \ 'callback': 'NERDTreeGrepFile',
        \ 'quickhelpText': 'grep files under current node',
        \ 'scope': 'Node' })
augroup END

NERDTreeAddKeyMapは.vimrcを読み込むタイミングではNot a editor commandというエラーが出てしまうので,VImEnterのタイミングで呼ぶようにしました.

NERDTreeを開いていると,NERDTreeのウィンドウでファイルが開いてしまうので,fzfのファンクションを呼ぶ前にNERDTreeを閉じています. できればNERDTreeは開いたまま,NERDTreeでファイル選択したときにファイルが開くウィンドウで開くようにしたかったのですが, うまい方法が思いつかなったので,このようにしています.

ちなみに,zfしたときのファイル検索で,ファイルを開くのではなく,NERDTree上でファイルを選択(フォーカス)したい場合は, NERDTreeFindFileファンクションを次のようにすることで実現できます.

.vimrc
" function to find file under current node
function! NERDTreeFindFile(node)
  if a:node.path.isDirectory == 1
    let path = a:node.path.str()
  else
    let path = a:node.path.getDir().str()
  endif
  let args = {
  \   'source': 'rg --files -- ' . path,
  \   'sink': { lines -> lines },
  \   'down': '~50%',
  \ }
  let list = fzf#run(fzf#wrap(args))
  if len(list)
    execute 'NERDTreeFind' list[0]
  endif
endfunction

refs


ottijp
都内でアプリケーションエンジニアをしています
© 2024, ottijp