当前位置: 首页 > Linux

VIM与模糊搜索神器FZF的集成用法 - 从简单到高级

时间:2023-04-06 05:52:00 Linux

FZF and VIM前言fzf本身并不是一个vim 插件,本来作者只提供了基本的wrapper函数(比如fzf#run). 但后来作者发现很多人并不熟悉VIMScript, 所以就创建一个默认的vim plugin.为什么在VIM里用fzf?fzf可以异步地运行,不影响vim操作,比同类的其他插件都快得多。如何安装有两种安装方式vundle或vim-plugvundleset rtp+=/home/harriszh/.fzf/...Plugin 'junegunn/fzf.vim'vim-plugPlug '/usr/local/opt/fzf'Plug 'junegunn/fzf.vim'如果你希望通过vim-plug来安装fzf, 那么使用下面设置Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }Plug 'junegunn/fzf.vim'vim下支持的命令这些命令都是FZF调用某个工具产生文件,文件内容, tag, comment, command,然后FZF用一个小窗口把它们显示出来,用户就可以用模糊搜索的方式来选择一个或多个选项,按下enter键后就可以用VIM打开它们或跳转到相应的行。如Files针对的就是文件, GFiles针对的就是git文件CommandListFiles [PATH]普通文件查找 (similar to :FZF)GFiles [OPTS]git文件查找 (git ls-files)GFiles?git文件查找 (git status)Buffersbuffer文件切换ColorsColor schemesAg [PATTERN]ag search result (ALT-A to select all, ALT-D to deselect all)Lines [QUERY]加载的所有buffer里查找BLines [QUERY]在当前buffer里查找包含某关键词的行Tags [QUERY]以Tag查找 (ctags -R)BTags [QUERY]Tags in the current bufferMarksMarksWindowsWindowsLocate PATTERNlocate command outputHistoryv:oldfiles and open buffersHistory:命令历史查找History/Search historySnippetsSnippets (UltiSnips)CommitsGit commits (requires fugitive.vim)BCommitsGit commits for the current bufferCommandsCommandsMapsNormal mode mappingsHelptagsHelp tags 1FiletypesFile types例子Files与FZF一样的作用,它会列出所有文件,选中后vim会打开选中的文件Buffers用于在存在于buffer中的文件间切换Lines <keyword>用于在存在于buffer里的文件中寻找含有某个关键词的行BLines <keyword>和Lines类似,只不过它只在当前buffer里查找因为ripgrep是目前性能最好的文本内容搜索工具,所以我们可以自己定义一个命令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#with_preview('up:60%') \ : fzf#vim#with_preview('right:50%:hidden', '?'), \ <bang>0)这样输入:Rg <keyword>会调用ripgrep来递归搜索当前目录定制化按键绑定上面的命令都可以通过ctrl-t, ctrl-x, ctrl-v来在new tab, new split, new vsplit窗口打开" This is the default extra key bindingslet g:fzf_action = { \ 'ctrl-t': 'tab split', \ 'ctrl-x': 'split', \ 'ctrl-v': 'vsplit' }" Default fzf layout" - down / up / left / rightlet g:fzf_layout = { 'down': '~40%' }" In Neovim, you can set up fzf window using a Vim commandlet g:fzf_layout = { 'window': 'enew' }let g:fzf_layout = { 'window': '-tabnew' }let g:fzf_layout = { 'window': '10split enew' }" Customize fzf colors to match your color schemelet g:fzf_colors =\ { 'fg': ['fg', 'Normal'], \ 'bg': ['bg', 'Normal'], \ 'hl': ['fg', 'Comment'], \ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'], \ 'bg+': ['bg', 'CursorLine', 'CursorColumn'], \ 'hl+': ['fg', 'Statement'], \ 'info': ['fg', 'PreProc'], \ 'border': ['fg', 'Ignore'], \ 'prompt': ['fg', 'Conditional'], \ 'pointer': ['fg', 'Exception'], \ 'marker': ['fg', 'Keyword'], \ 'spinner': ['fg', 'Label'], \ 'header': ['fg', 'Comment'] }" Enable per-command history." CTRL-N and CTRL-P will be automatically bound to next-history and" previous-history instead of down and up. If you don't like the change," explicitly bind the keys to down and up in your $FZF_DEFAULT_OPTS.let g:fzf_history_dir = '~/.local/share/fzf-history'本地设定" [Buffers] 如果可能跳到已存在窗口let g:fzf_buffers_jump = 1" [[B]Commits] 自定义被'git log'使用的选项let g:fzf_commits_log_options = '--graph --color=always --format="%C(auto)%h%d %s %C(black)%C(bold)%cr"'" [Tags] 定义用来产生tag的命令let g:fzf_tags_command = 'ctags -R'" [Commands] --expect expression for directly executing the commandlet g:fzf_commands_expect = 'alt-enter,ctrl-x'高级定制也可以使用autoload函数来定义自己的命令" Command for git grep" - fzf#vim#grep(command, with_column, [options], [fullscreen])command! -bang -nargs=* GGrep \ call fzf#vim#grep( \ 'git grep --line-number '.shellescape(<q-args>), 0, \ { 'dir': systemlist('git rev-parse --show-toplevel')[0] }, <bang>0)" Override Colors command. You can safely do this in your .vimrc as fzf.vim" will not override existing commands.command! -bang Colors \ call fzf#vim#colors({'left': '15%', 'options': '--reverse --margin 30%,0'}, <bang>0)" Augmenting Ag command using fzf#vim#with_preview function" * fzf#vim#with_preview([[options], preview window, [toggle keys...]])" * For syntax-highlighting, Ruby and any of the following tools are required:" - Highlight: http://www.andre-simon.de/doku/highlight/en/highlight.php" - CodeRay: http://coderay.rubychan.de/" - Rouge: https://github.com/jneen/rouge"" :Ag - Start fzf with hidden preview window that can be enabled with "?" key" :Ag! - Start fzf in fullscreen and display the preview window abovecommand! -bang -nargs=* Ag \ call fzf#vim#ag(<q-args>, \ <bang>0 ? fzf#vim#with_preview('up:60%') \ : fzf#vim#with_preview('right:50%:hidden', '?'), \ <bang>0)" Similarly, we can apply it to fzf#vim#grep. To use ripgrep instead of ag: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#with_preview('up:60%') \ : fzf#vim#with_preview('right:50%:hidden', '?'), \ <bang>0)" Likewise, Files command with preview windowcommand! -bang -nargs=? -complete=dir Files \ call fzf#vim#files(<q-args>, fzf#vim#with_preview(), <bang>0)映射MappingDescription<plug>(fzf-maps-n)Normal mode mappings<plug>(fzf-maps-i)Insert mode mappings<plug>(fzf-maps-x)Visual mode mappings<plug>(fzf-maps-o)Operator-pending mappings<plug>(fzf-complete-word)cat /usr/share/dict/words<plug>(fzf-complete-path)Path completion using find (file + dir)<plug>(fzf-complete-file)File completion using find<plug>(fzf-complete-file-ag)File completion using ag<plug>(fzf-complete-line)Line completion (all open buffers)<plug>(fzf-complete-buffer-line)Line completion (current buffer only)映射用法" Mapping selecting mappingsnmap <leader><tab> <plug>(fzf-maps-n)xmap <leader><tab> <plug>(fzf-maps-x)omap <leader><tab> <plug>(fzf-maps-o)" Insert mode completionimap <c-x><c-k> <plug>(fzf-complete-word)imap <c-x><c-f> <plug>(fzf-complete-path)imap <c-x><c-j> <plug>(fzf-complete-file-ag)imap <c-x><c-l> <plug>(fzf-complete-line)" Advanced customization using autoload functionsinoremap <expr> <c-x><c-k> fzf#vim#complete#word({'left': '15%'})创建自己的插件fzf#run()是vim集成的核心函数,它接受一个字典变量作为输入, 你至少要通过sink选项来告诉fzf如何处理选中的条目。比如:call fzf#run({'sink': 'tabedit', 'options': '--multi --reverse'})call fzf#run({'source': 'git ls-files', 'sink': 'e', 'right': '40%'})call fzf#run({'source': map(split(globpath(&rtp, 'colors/*.vim')), \ 'fnamemodify(v:val, ":t:r")'), \ 'sink': 'colo', 'left': '25%'})下表是它可用的所有选项Option nameTypeDescriptionsourcestringExternal command to generate input to fzf (e.g. find .)sourcelistVim list as input to fzfsinkstringVim command to handle the selected item (e.g. e, tabe)sinkfuncrefReference to function to process each selected itemsink*funcrefSimilar to sink, but takes the list of output lines at onceoptionsstringOptions to fzfdirstringWorking directoryup/down/left/rightnumber/stringUse tmux pane with the given size (e.g. 20, 50%)window (Neovim only)stringCommand to open fzf window (e.g. vertical aboveleft 30new)launcherstringExternal terminal emulator to start fzf with (GVim only)launcherfuncrefFunction for generating launcher string (GVim only)completion helperfzf#vim#complete是一个helper函数,用来创建自己的自动补全功能。 如果第一个参数是一个命令字符或一个vim list, 那么它会被用作source." Replace the default dictionary completion with fzf-based fuzzy completioninoremap <expr> <c-x><c-k> fzf#vim#complete('cat /usr/share/dict/words')对于高级用户,可以传入一个字典选项。它的选项和fzf#run是一致的,除了下面几个选项。reducer (funcref)把fzf的输出转成单一字符串prefix (funcref or string; default: k*$)用于匹配想自动补全字符串的正则表达式或者是一个函数source或options可以是一个函数引用, 它用prefix作为输入参数,返回最终的值sink或sink*被忽略" 全局补全 (不仅仅是buffers. 需要安装ripgrep)inoremap <expr> <c-x><c-l> fzf#vim#complete(fzf#wrap({ \ 'prefix': '^.*$', \ 'source': 'rg -n ^ --color always', \ 'options': '--ansi --delimiter : --nth 3..', \ 'reducer': { lines -> join(split(lines[0], ':\zs')[2:], '') }}))Reducer例子:function! s:make_sentence(lines)return substitute(join(a:lines), '^.', '\=toupper(submatch(0))', '').'.'endfunctioninoremap <expr> <c-x><c-s> fzf#vim#complete({\ 'source': 'cat /usr/share/dict/words',\ 'reducer': function('<sid>make_sentence'),\ 'options': '--multi --reverse --margin 15%,0',\ 'left': 20})总结结合FZF,vim可实现快速文件跳转,特别是在结合Rg或ctags或git以后,可以快速地跳转到满足某种条件的文件中。希望大家可以结合FZF创造出更多的使用方法。有任何好点子,欢迎联系本人