今更だけど、巷では曖昧な検索(fuzzy find)ができるのがシャレてるらしい。
そんなこと気にもとめたことなかったけど、 unite.vim→ denite.nvimと使ってきたけど、両方、曖昧な検索できるね。
しかし、一覧→normarlモード/insertモードの切替、アクションの多さ、insertモードのおける上下が<c-t>、<c-g>というのがデフォルトマップだったり、とトゥーマッチに感じる部分が多い。Python依存プラグインというのもあって、挙動が安定しないように思える(自分の使い方か悪いかも知れません…)。
次に、 ctrlp.vimを使おうとしたのだけど、 simplenote.vimで作成されるバッファが表示/検索できない。また、基本、ファイル、バッファ、MRU以外の検索の仕方がよく分からなかったので、止め。
それでもって、 fzfなるツールの存在を知る。コマンド結果をfuzzy検索できて、選択できちゃう、みたいな使い方ができる。作成者がvimmerとあって、vim用のプラグインが用意されている。
Ubuntuで使ってみると、パフォーマンスみたいのは良く分からないし、バッファー検索がたまに引っ掛かるような時があるけど、まあ良いじゃないかなと。deniteで表示できていたものとか大体表示される。
さて、Windowsでも使ってみようとするも…
function fzf#vim#files[15]..<SNR>84_fzf[18]..<SNR>84_wrap の処理中にエラーが検出されました:
行 12:
E117: 未知の関数です: fzf#wrap
E15: 無効な式です: fzf#wrap(a:name, opts, a:bang)
行 14:
E121: 未定義の変数です: wrapped
E15: 無効な式です: wrapped
function fzf#vim#files[15]..<SNR>84_fzf の処理中にエラーが検出されました:
行 18:
E117: 未知の関数です: fzf#run
E15: 無効な式です: fzf#run(s:wrap(a:name, merged, bang))
なエラーが出る…どういうことだ。もしや、Mac/Linux/Unix限定?そんなことは無かった。fzfには二つのレポジトリがあってメインである junegunn/fzfをインストールせず、 junegunn/fzf.vimだけをインストールしているためだった。
Ubuntuではfzf
をインストールするために
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install
したときに、‘junegunn/fzf’のvimプラグインも一緒に落としてきていて、それをPlug '~/.fzf'
で指定することでUbuntuでは自然に使用可能な状態になっていた。
なので、Windowsも
git clone --depth 1 https://github.com/junegunn/fzf.git %USERPROFILE%/.fzf
と落してきて、
%USERPROFILE%\.fzf\bin
直下にバイナリーファイル fzf.exe を配置1すれば同様に使用できるようになる。
一応、確認として、一通りの動きを確かめる…よし問題ない…かと思われたが。Rg
コマンドがおかしい。ヒットしない…0件で表示される。どうしてだ。
Rg [PATTERN] rg search result (ALT-A to select all, ALT-D to deselect all)
とあるのでもしやgrep結果をかますのか?と勘違いして
autocmd QuickFixCmdPost *grep* FzfRg!
とやるも意味なし…というか
パターン未入力だと''
が検索されてる?
fzf.vim/plugin/fzf.vim
52行目を見ると
\'command! -bang -nargs=* Rg call fzf#vim#grep("rg --column --line-number --no-heading --color=always --smart-case ".shellescape(<q-args>), 1, <bang>0)',
となっている、そこから fzf#vim#grep
辿ってecho
を仕掛けRg name
を実行すると
rg --column --line-number --no-heading --color=always --smart-case 'name'
と表示される。コマンドプロンプト(cmd.exe)からシングルコーテーションで括って検索させると確かに検索されない、というか'name'
が検索される。
There may be something wrong on windows.を見ると、あまり英語は得意ではないので、勘違いしてるかも知れないが、Widowsのコマンドプロンプトの仕様なんてしったこっちゃねー、という回答。
ならshellescape(<q-args>)
を直せばいいと調べる。
正直、<q-args>を更にshellescape
する意味が分からないが、どうも<q-args>のままでは括ってくれなくて、shellescape
でシングルコーテーションで括られてしまうようだ。
shellescape({string} [, {special}]) shellescape() シェルコマンドの引数として利用できるように{string}をエスケープ する。 MS-WindowsとMS-DOSでは、‘shellslash’ が設定されていない場合、 {string}をダブルクォートで囲み、{string}の中のダブルクォートを 全て二重にする。
Windowsでもset shellslash
は普通するだろ。これを変えるのはありえない。なので普通にダブルコーテーションで括るようにした。幸いにして、fzf.vim
ではコマンドをvimrc(init.vim)
で上書き設定することできる。
if has('win32') || has('win64')
command! -bang -nargs=* FzfRg
\ call fzf#vim#grep(
\ 'rg --column --line-number --no-heading --color=always --smart-case "'.<q-args>.'"', 1,
\ <bang>0)
endif
ちなみにFzfRg
としてるのはlet g:fzf_command_prefix = 'Fzf'
とfzf
系のコマンドの接頭辞に Fzf を付けているため。
'"'.fnameescape(<q-args>).'"'
とかした方がいいのかなぁとか思ったけど、結構そのまま渡すのがいいみたい。エスケープが不十分らしくて
fnameescape()は使うな - 永遠に未完成みたいに書かれたけど、まあ厳密さはそこまで求めてないので。
欲を言えばDenite grep
みたいに実行したらパターンの入力を促されるタイプだったら良かったのだけど、Rg
はそうなってないので、
nnoremap <silent> [fzf]r :<C-u>call <SID>SearchRipgrep()<CR>
function! s:SearchRipgrep()
let l:word = input("Search Word? ")
if l:word =~ "\s*"
execute ":FzfRg " . l:word
endif
endfunction
とテキトーな感じで入力を促すようにしてマッピングする。これならイけそうだ。
おまけだが、 mattn/vim-fzなるものを見付けた…いやぁ vim の進化ってのも激しいね…
-
パス通せばどこでもいいけど ↩︎