🦍

Vimのquickfixとlocation listで好きな方法でファイルを開くプラグインを作った

2021/10/29に公開

始めに

普段Vimでgrepした結果をlocation listに流し込んで使ったりしています。
またLSPでquickfix listも使ったりしています。

特定のファイルの特定行列にジャンプするのはとても便利ですが、
残念なことにデフォルトのファイルを開く方法は以下2とおりで少ないです。

  • Enterで現在のウィンドウに表示
  • CTRL-W + Enter で横分割したウィンドウに表示

これではとても不便です。たとえば画面が小さいときは新しいタブで編集したいといったケースがあります。
そういったケースを実現するためにqfopen.vimというプラグインを作りました。

本記事はプラグインの紹介と実現方法について書いていきます。

qfopen.vimについて

基本、ファイルを開くコマンドをユーザーが入力して決めるという使い方になります。
コマンドはsplitvsplitといったものです。

そしてqfopen.vimはコマンドを提供しておらず、プラグインキーマップを提供して、ユーザーが好きなキーでマッピングするという使い方になります。
自分の場合は次のようにマッピングしています。

augroup qfopen-bufenter
  function! s:qfopen_keymap() abort
    nmap <buffer> a <Plug>(qfopen-action)
    nmap <buffer> <C-v> <Plug>(qfopen-open-vsplit)
    nmap <buffer> <C-x> <Plug>(qfopen-open-split)
    nmap <buffer> <C-t> <Plug>(qfopen-open-tab)
  endfunction
  au!
  au FileType qf call s:qfopen_keymap()
augroup END

しくみ

getloclist()getqflist() を使って、リスト情報(バッファIDや行数、列数など)を取得できます。
ただ、関数を実行するには現在のウィンドウはquickfixなのかlocationなのかを判別する必要があります。
そこでgetwininfo()を使うことで、現在のウィンドウがlocationかどうかの判別が可能になります。
locationの場合loclist1になるので、それを判定すればよいのです。

function! s:is_location(winid) abort
  let info = getwininfo(a:winid)
  if empty(info)
    return 0
  endif
  return info[0].loclist ==# 1
endfunction

これらの関数を使えば、対象ファイルを開いて指定した行と列にジャンプが可能になります。
実際にファイルを開く処理はとてもシンプルで、次のようになっています。
exe opener bufname(info.bufnr)でウィンドウを開いた後にcall cursor(info.lnum, info.col)で行列にカーソルを移動させています。

function! qfopen#open(opener) abort
  let winid = win_getid()
  if s:is_location(winid)
    let list = getloclist(winid)
  else
    let list = getqflist()
  endif
  let info = list[line(".")-1]
  let opener = a:opener
  if opener =~# "vne*" || opener =~# "vs*"
    let opener = "topleft " .. opener
  endif
  exe opener bufname(info.bufnr)
  call cursor(info.lnum, info.col)
  if a:opener !~# "tab*"
    call win_execute(winid, "wincmd J")
  endif
endfunction

最後に

業務で良くgrepを使うので、不便さがだいぶ改善されました。
みなさんも良ければ使ってみてください。

Discussion