ottijp blog

Vimのコマンドラインモードでfzfを動かす

Vimのコマンドラインモードでfzfを起動し,選んだ文字を加工した上でコマンドラインモード上にテキストとして挿入する.vimrcを書きました.

環境

  • macOS: 10.15.3 (Catalina)
  • vim: 8.0 (2016 Sep 12, compiled Mar 25 2018 03:02:16) (kaoriya-vim)

やりたかったこと

よく使うディレクトリのブックマークをテキストで作成しておいて, Vimでファイル保存する際などに,コマンドラインモードで:e と入力した後で, fzfでそのブックマークを選択してパスを挿入する,ということがやりたくて方法を考えてみました.

ブックマークのファイル

こんな感じで,識別用のラベルとパスを書いています.

$HOME/bookmarks
WIP,$HOME/Desktop/WIP
Projects,$HOME/Documents/projects
MEDIA,/Volumes/MEDIA

シェルでの方法

ちなみにZSH上では次のようなコードを書いて,ZLEでfzfするようにしました.

$HOME/.zshrc
fzf-bookmark() {
  local selected
  selected=`(cat ~/bookmarks 2>/dev/null) | fzf`
  if [ -n "$selected" ]; then
    LBUFFER=${LBUFFER}"`awk 'BEGIN{FS=","}{print $2}' <<<"$selected"` "
  fi
  zle reset-prompt
}

zle -N fzf-bookmark
bindkey '^Xb' fzf-bookmark

Vimでの方法

こんなコードを.vimrcに書きました.(2021-01-10 修正)

$HOME/.vimrc
function! s:FzfBookmark()
  let l:BS = "\u08" " <C-h>
  let l:cmdtype = getcmdtype()
  let l:args = {
  \   'source': 'cat $HOME/bookmarks',
  \   'sink': { lines -> lines },
  \   'down': '~50%',
  \ } " sink does nothing
  if l:cmdtype == ':'
    let l:list = fzf#run(fzf#wrap(l:args))
    if len(list)
      return escape(substitute(list[0], '^.\{-,},', '', ''), ' ')
    else
      return 'a' . l:BS " workaround for redraw problem
    endif
  endif
endfunction

cnoremap <expr> <C-x>b <SID>FzfBookmark()

fzfの起動はfzf#run()を使っており, 選択結果を加工して,<C-x>bにマップされる結果として返しています.

これで,コマンドモードで<C-x>bをタイプすることでfzfが起動し, 選択したブックマークのパスが挿入されます.

refs


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