FZF and VIM
前言
fzf本身并不是一个vim 插件,本来作者只提供了基本的wrapper函数(比如fzf#run). 但后来作者发现很多人并不熟悉VIMScript, 所以就创建一个默认的vim plugin.
为什么在VIM里用fzf?
fzf可以异步地运行,不影响vim操作,比同类的其他插件都快得多。
如何安装
有两种安装方式vundle或vim-plug
vundle
set rtp+=/home/harriszh/.fzf/
...
Plugin 'junegunn/fzf.vim'
vim-plug
Plug '/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文件
Command | List |
---|---|
Files [PATH] |
普通文件查找 (similar to :FZF ) |
GFiles [OPTS] |
git文件查找 (git ls-files ) |
GFiles? |
git文件查找 (git status ) |
Buffers |
buffer文件切换 |
Colors |
Color schemes |
Ag [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 buffer |
Marks |
Marks |
Windows |
Windows |
Locate PATTERN |
locate command output |
History |
v:oldfiles and open buffers |
History: |
命令历史查找 |
History/ |
Search history |
Snippets |
Snippets (UltiSnips) |
Commits |
Git commits (requires fugitive.vim) |
BCommits |
Git commits for the current buffer |
Commands |
Commands |
Maps |
Normal mode mappings |
Helptags |
Help tags 1 |
Filetypes |
File types |
例子
Files
与FZF
一样的作用,它会列出所有文件,选中后vim会打开选中的文件
Buffers
用于在存在于buffer中的文件间切换
Lines
用于在存在于buffer里的文件中寻找含有某个关键词的行
BLines
和Lines
类似,只不过它只在当前buffer里查找
因为ripgrep是目前性能最好的文本内容搜索工具,所以我们可以自己定义一个命令
command! -bang -nargs=* Rg
\ call fzf#vim#grep(
\ 'rg --column --line-number --no-heading --color=always --smart-case '.shellescape(), 1,
\ 0 ? fzf#vim#with_preview('up:60%')
\ : fzf#vim#with_preview('right:50%:hidden', '?'),
\ 0)
这样输入:Rg
定制化
按键绑定
上面的命令都可以通过ctrl-t
, ctrl-x
, ctrl-v
来在new tab, new split, new vsplit窗口打开
" This is the default extra key bindings
let g:fzf_action = {
\ 'ctrl-t': 'tab split',
\ 'ctrl-x': 'split',
\ 'ctrl-v': 'vsplit' }
" Default fzf layout
" - down / up / left / right
let g:fzf_layout = { 'down': '~40%' }
" In Neovim, you can set up fzf window using a Vim command
let 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 scheme
let 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 command
let 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(), 0,
\ { 'dir': systemlist('git rev-parse --show-toplevel')[0] }, 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'}, 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 above
command! -bang -nargs=* Ag
\ call fzf#vim#ag(,
\ 0 ? fzf#vim#with_preview('up:60%')
\ : fzf#vim#with_preview('right:50%:hidden', '?'),
\ 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(), 1,
\ 0 ? fzf#vim#with_preview('up:60%')
\ : fzf#vim#with_preview('right:50%:hidden', '?'),
\ 0)
" Likewise, Files command with preview window
command! -bang -nargs=? -complete=dir Files
\ call fzf#vim#files(, fzf#vim#with_preview(), 0)
映射
Mapping | Description |
---|---|
|
Normal mode mappings |
|
Insert mode mappings |
|
Visual mode mappings |
|
Operator-pending mappings |
|
cat /usr/share/dict/words |
|
Path completion using find (file + dir) |
|
File completion using find |
|
File completion using ag |
|
Line completion (all open buffers) |
|
Line completion (current buffer only) |
映射用法
" Mapping selecting mappings
nmap (fzf-maps-n)
xmap (fzf-maps-x)
omap (fzf-maps-o)
" Insert mode completion
imap (fzf-complete-word)
imap (fzf-complete-path)
imap (fzf-complete-file-ag)
imap (fzf-complete-line)
" Advanced customization using autoload functions
inoremap 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 name | Type | Description |
---|---|---|
source |
string | External command to generate input to fzf (e.g. find . ) |
source |
list | Vim list as input to fzf |
sink |
string | Vim command to handle the selected item (e.g. e , tabe ) |
sink |
funcref | Reference to function to process each selected item |
sink* |
funcref | Similar to sink , but takes the list of output lines at once |
options |
string | Options to fzf |
dir |
string | Working directory |
up /down /left /right |
number/string | Use tmux pane with the given size (e.g. 20 , 50% ) |
window (Neovim only) |
string | Command to open fzf window (e.g. vertical aboveleft 30new ) |
launcher |
string | External terminal emulator to start fzf with (GVim only) |
launcher |
funcref | Function for generating launcher string (GVim only) |
completion helper
fzf#vim#complete
是一个helper函数,用来创建自己的自动补全功能。 如果第一个参数是一个命令字符或一个vim list, 那么它会被用作source.
" Replace the default dictionary completion with fzf-based fuzzy completion
inoremap 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 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))', '').'.'
endfunction
inoremap fzf#vim#complete({
\ 'source': 'cat /usr/share/dict/words',
\ 'reducer': function('make_sentence'),
\ 'options': '--multi --reverse --margin 15%,0',
\ 'left': 20})
总结
结合FZF,vim可实现快速文件跳转,特别是在结合Rg或ctags或git以后,可以快速地跳转到满足某种条件的文件中。
希望大家可以结合FZF创造出更多的使用方法。有任何好点子,欢迎联系本人