diff --git a/README.md b/README.md index 7e88eee..e921fb3 100644 --- a/README.md +++ b/README.md @@ -165,16 +165,16 @@ let g:fzf_commands_expect = 'alt-enter,ctrl-x' Each command in fzf.vim is backed by a Vim function. You can override a command or define a variation of it by calling its corresponding function. -| Command | Vim function | -| --- | --- | -| `Files` | `fzf#vim#files(dir, [spec dict], [fullscreen bool])` | -| `GFiles` | `fzf#vim#gitfiles(git_options, [spec dict], [fullscreen bool])` | -| `GFiles?` | `fzf#vim#gitfiles('?', [spec dict], [fullscreen bool])` | -| `Buffers` | `fzf#vim#buffers([spec dict], [fullscreen bool])` | -| `Colors` | `fzf#vim#colors([spec dict], [fullscreen bool])` | -| `Rg` | `fzf#vim#grep(command, [has_column bool], [spec dict], [fullscreen bool])` | -| `RG` | `fzf#vim#grep2(command_prefix, query, [has_column bool], [spec dict], [fullscreen bool])` | -| ... | ... | +| Command | Vim function | +| --- | --- | +| `Files` | `fzf#vim#files(dir, [spec dict], [fullscreen bool])` | +| `GFiles` | `fzf#vim#gitfiles(git_options, [spec dict], [fullscreen bool])` | +| `GFiles?` | `fzf#vim#gitfiles('?', [spec dict], [fullscreen bool])` | +| `Buffers` | `fzf#vim#buffers([spec dict], [fullscreen bool])` | +| `Colors` | `fzf#vim#colors([spec dict], [fullscreen bool])` | +| `Rg` | `fzf#vim#grep(command, [spec dict], [fullscreen bool])` | +| `RG` | `fzf#vim#grep2(command_prefix, query, [spec dict], [fullscreen bool])` | +| ... | ... | (We can see that the last two optional arguments of each function are identical. They are directly passed to `fzf#wrap` function. If you haven't @@ -243,8 +243,6 @@ command! -bang -nargs=? -complete=dir Files The following example implements `GGrep` command that works similarly to predefined `Ag` or `Rg` using `fzf#vim#grep`. -- The second argument to `fzf#vim#grep` is 0 (false), because `git grep` does - not print column numbers. - We set the base directory to git root by setting `dir` attribute in spec dictionary. - [The preview script](bin/preview.sh) supports `grep` format @@ -254,47 +252,10 @@ predefined `Ag` or `Rg` using `fzf#vim#grep`. ```vim command! -bang -nargs=* GGrep \ call fzf#vim#grep( - \ 'git grep --line-number -- '.shellescape(), 0, + \ 'git grep --line-number -- '.shellescape(), \ fzf#vim#with_preview({'dir': systemlist('git rev-parse --show-toplevel')[0]}), 0) ``` -#### Example: Advanced ripgrep integration - -> The example shown here is now available as the `RG` (all uppercase) command -> that uses `fzf#vim#grep2(command_prefix, query, has_column, ...)` function. -> You no longer need to define it in your Vim configuration file. - -In the default implementation of `Rg`, ripgrep process starts only once with -the initial query (e.g. `:Rg foo`) and fzf filters the output of the process. - -This is okay in most cases because fzf is quite performant even with millions -of lines, but we can make fzf completely delegate its search responsibliity to -ripgrep process by making it restart ripgrep whenever the query string is -updated. In this scenario, fzf becomes a simple selector interface rather than -a "fuzzy finder". - -- We will name the new command all-uppercase `RG` so we can still access the - default version. -- `--bind 'change:reload:rg ... {q}'` will make fzf restart ripgrep process - whenever the query string, denoted by `{q}`, is changed. -- With `--disabled` option, fzf will no longer perform search. The query - string you type on fzf prompt is only used for restarting ripgrep process. -- Also note that we enabled previewer with `fzf#vim#with_preview`. The last - argument to the function, `ctrl-/`, is the key to toggle the preview window. - -```vim -function! RipgrepFzf(query, fullscreen) - let command_fmt = 'rg --column --line-number --no-heading --color=always --smart-case -- %s || true' - let initial_command = printf(command_fmt, shellescape(a:query)) - let reload_command = printf(command_fmt, '{q}') - let spec = {'options': ['--disabled', '--query', a:query, '--bind', 'change:reload:'.reload_command]} - let spec = fzf#vim#with_preview(spec, 'right', 'ctrl-/') - call fzf#vim#grep(initial_command, 1, spec, a:fullscreen) -endfunction - -command! -nargs=* -bang RG call RipgrepFzf(, 0) -``` - Mappings -------- diff --git a/autoload/fzf/vim.vim b/autoload/fzf/vim.vim index f65ff18..2566f56 100755 --- a/autoload/fzf/vim.vim +++ b/autoload/fzf/vim.vim @@ -96,7 +96,7 @@ let s:bin_dir = expand(':p:h:h:h').'/bin/' let s:bin = { \ 'preview': s:bin_dir.'preview.sh', \ 'tags': s:bin_dir.'tags.pl' } -let s:TYPE = {'dict': type({}), 'funcref': type(function('call')), 'string': type(''), 'list': type([])} +let s:TYPE = {'bool': type(0), 'dict': type({}), 'funcref': type(function('call')), 'string': type(''), 'list': type([])} let s:wide = 120 let s:checked = 0 @@ -793,22 +793,22 @@ endfunction " ------------------------------------------------------------------ " Ag / Rg " ------------------------------------------------------------------ -function! s:ag_to_qf(line, has_column) +function! s:ag_to_qf(line) let parts = matchlist(a:line, '\(.\{-}\)\s*:\s*\(\d\+\)\%(\s*:\s*\(\d\+\)\)\?\%(\s*:\(.*\)\)\?') let dict = {'filename': &acd ? fnamemodify(parts[1], ':p') : parts[1], 'lnum': parts[2], 'text': parts[4]} - if a:has_column + if len(parts[3]) let dict.col = parts[3] endif return dict endfunction -function! s:ag_handler(lines, has_column) +function! s:ag_handler(lines) if len(a:lines) < 2 return endif let cmd = s:action_for(a:lines[0], 'e') - let list = map(filter(a:lines[1:], 'len(v:val)'), 's:ag_to_qf(v:val, a:has_column)') + let list = map(filter(a:lines[1:], 'len(v:val)'), 's:ag_to_qf(v:val)') if empty(list) return endif @@ -817,7 +817,7 @@ function! s:ag_handler(lines, has_column) try call s:open(cmd, first.filename) execute first.lnum - if a:has_column + if has_key(first, 'col') call cursor(0, first.col) endif normal! zvzz @@ -847,8 +847,9 @@ function! fzf#vim#ag_raw(command_suffix, ...) return call('fzf#vim#grep', extend(['ag --nogroup --column --color '.a:command_suffix, 1], a:000)) endfunction -" command (string), has_column (bool), [spec (dict)], [fullscreen (bool)] -function! fzf#vim#grep(grep_command, has_column, ...) +" command (string), [spec (dict)], [fullscreen (bool)] +function! fzf#vim#grep(grep_command, ...) + let args = copy(a:000) let words = [] for word in split(a:grep_command) if word !~# '^[a-z]' @@ -860,27 +861,31 @@ function! fzf#vim#grep(grep_command, has_column, ...) let name = join(words, '-') let capname = join(map(words, 'toupper(v:val[0]).v:val[1:]'), '') let opts = { - \ 'column': a:has_column, \ 'options': ['--ansi', '--prompt', capname.'> ', \ '--multi', '--bind', 'alt-a:select-all,alt-d:deselect-all', \ '--delimiter', ':', '--preview-window', '+{2}-/2'] \} + if len(args) && type(args[0]) == s:TYPE.bool + call remove(args, 0) + endif + function! opts.sink(lines) - return s:ag_handler(a:lines, self.column) + return s:ag_handler(a:lines) endfunction let opts['sink*'] = remove(opts, 'sink') try let prev_default_command = $FZF_DEFAULT_COMMAND let $FZF_DEFAULT_COMMAND = a:grep_command - return s:fzf(name, opts, a:000) + return s:fzf(name, opts, args) finally let $FZF_DEFAULT_COMMAND = prev_default_command endtry endfunction -" command_prefix (string), initial_query (string), has_column (bool), [spec (dict)], [fullscreen (bool)] -function! fzf#vim#grep2(command_prefix, query, has_column, ...) +" command_prefix (string), initial_query (string), [spec (dict)], [fullscreen (bool)] +function! fzf#vim#grep2(command_prefix, query, ...) + let args = copy(a:000) let words = [] for word in split(a:command_prefix) if word !~# '^[a-z]' @@ -892,7 +897,6 @@ function! fzf#vim#grep2(command_prefix, query, has_column, ...) let name = join(words, '-') let opts = { \ 'source': ':', - \ 'column': a:has_column, \ 'options': ['--ansi', '--prompt', toupper(name).'> ', '--query', a:query, \ '--disabled', \ '--bind', 'start:reload:'.a:command_prefix.' '.shellescape(a:query), @@ -900,11 +904,14 @@ function! fzf#vim#grep2(command_prefix, query, has_column, ...) \ '--multi', '--bind', 'alt-a:select-all,alt-d:deselect-all', \ '--delimiter', ':', '--preview-window', '+{2}-/2'] \} + if len(args) && type(args[0]) == s:TYPE.bool + call remove(args, 0) + endif function! opts.sink(lines) - return s:ag_handler(a:lines, self.column) + return s:ag_handler(a:lines) endfunction let opts['sink*'] = remove(opts, 'sink') - return s:fzf(name, opts, a:000) + return s:fzf(name, opts, args) endfunction " ------------------------------------------------------------------ diff --git a/doc/fzf-vim.txt b/doc/fzf-vim.txt index 147ce9b..9420fc7 100644 --- a/doc/fzf-vim.txt +++ b/doc/fzf-vim.txt @@ -2,30 +2,29 @@ fzf-vim.txt fzf-vim Last change: June 4 2023 FZF-VIM - TABLE OF CONTENTS *fzf-vim* *fzf-vim-toc* ============================================================================== - fzf :heart: vim |fzf-vim-fzfheart-vim| - Rationale |fzf-vim-rationale| - Why you should use fzf on Vim |fzf-vim-why-you-should-use-fzf-on-vim| - Installation |fzf-vim-installation| - Using vim-plug |fzf-vim-using-vim-plug| - Dependencies |fzf-vim-dependencies| - Commands |fzf-vim-commands| - Customization |fzf-vim-customization| - Global options |fzf-vim-global-options| - Preview window |fzf-vim-preview-window| - Command-local options |fzf-vim-command-local-options| - Advanced customization |fzf-vim-advanced-customization| - Vim functions |fzf-vim-vim-functions| - Example: Customizing Files command |fzf-vim-example-customizing-files-command| - Example: git grep wrapper |fzf-vim-example-git-grep-wrapper| - Example: Advanced ripgrep integration |fzf-vim-example-advanced-ripgrep-integration| - Mappings |fzf-vim-mappings| - Completion functions |fzf-vim-completion-functions| - Custom completion |fzf-vim-custom-completion| - Reducer example |fzf-vim-reducer-example| - Status line of terminal buffer |fzf-vim-status-line-of-terminal-buffer| - Hide statusline |fzf-vim-hide-statusline| - Custom statusline |fzf-vim-custom-statusline| - License |fzf-vim-license| + fzf :heart: vim |fzf-vim-fzfheart-vim| + Rationale |fzf-vim-rationale| + Why you should use fzf on Vim |fzf-vim-why-you-should-use-fzf-on-vim| + Installation |fzf-vim-installation| + Using vim-plug |fzf-vim-using-vim-plug| + Dependencies |fzf-vim-dependencies| + Commands |fzf-vim-commands| + Customization |fzf-vim-customization| + Global options |fzf-vim-global-options| + Preview window |fzf-vim-preview-window| + Command-local options |fzf-vim-command-local-options| + Advanced customization |fzf-vim-advanced-customization| + Vim functions |fzf-vim-vim-functions| + Example: Customizing Files command |fzf-vim-example-customizing-files-command| + Example: git grep wrapper |fzf-vim-example-git-grep-wrapper| + Mappings |fzf-vim-mappings| + Completion functions |fzf-vim-completion-functions| + Custom completion |fzf-vim-custom-completion| + Reducer example |fzf-vim-reducer-example| + Status line of terminal buffer |fzf-vim-status-line-of-terminal-buffer| + Hide statusline |fzf-vim-hide-statusline| + Custom statusline |fzf-vim-custom-statusline| + License |fzf-vim-license| FZF :HEART: VIM *fzf-vim-fzfheart-vim* ============================================================================== @@ -237,18 +236,18 @@ Vim functions~ Each command in fzf.vim is backed by a Vim function. You can override a command or define a variation of it by calling its corresponding function. - ----------+------------------------------------------------------------------------------------------ - Command | Vim function ~ - ----------+------------------------------------------------------------------------------------------ + ----------+----------------------------------------------------------------------- + Command | Vim function ~ + ----------+----------------------------------------------------------------------- `Files` | `fzf#vim#files(dir, [spec dict], [fullscreen bool])` `GFiles` | `fzf#vim#gitfiles(git_options, [spec dict], [fullscreen bool])` `GFiles?` | `fzf#vim#gitfiles('?', [spec dict], [fullscreen bool])` `Buffers` | `fzf#vim#buffers([spec dict], [fullscreen bool])` `Colors` | `fzf#vim#colors([spec dict], [fullscreen bool])` - `Rg` | `fzf#vim#grep(command, [has_column bool], [spec dict], [fullscreen bool])` - `RG` | `fzf#vim#grep2(command_prefix, query, [has_column bool], [spec dict], [fullscreen bool])` + `Rg` | `fzf#vim#grep(command, [spec dict], [fullscreen bool])` + `RG` | `fzf#vim#grep2(command_prefix, query, [spec dict], [fullscreen bool])` ... | ... - ----------+------------------------------------------------------------------------------------------ + ----------+----------------------------------------------------------------------- (We can see that the last two optional arguments of each function are identical. They are directly passed to `fzf#wrap` function. If you haven't @@ -322,49 +321,12 @@ predefined `Ag` or `Rg` using `fzf#vim#grep`. > command! -bang -nargs=* GGrep \ call fzf#vim#grep( - \ 'git grep --line-number -- '.shellescape(), 0, + \ 'git grep --line-number -- '.shellescape(), \ fzf#vim#with_preview({'dir': systemlist('git rev-parse --show-toplevel')[0]}), 0) < {12} bin/preview.sh -Example: Advanced ripgrep integration~ - *fzf-vim-example-advanced-ripgrep-integration* - -The example shown here is now available as the `RG` (all uppercase) command -that uses `fzf#vim#grep2(command_prefix, query, has_column, ...)` function. -You no longer need to define it in your Vim configuration file. - -In the default implementation of `Rg`, ripgrep process starts only once with -the initial query (e.g. `:Rg foo`) and fzf filters the output of the process. - -This is okay in most cases because fzf is quite performant even with millions -of lines, but we can make fzf completely delegate its search responsibliity to -ripgrep process by making it restart ripgrep whenever the query string is -updated. In this scenario, fzf becomes a simple selector interface rather than -a "fuzzy finder". - - - We will name the new command all-uppercase `RG` so we can still access the - default version. - - `--bind 'change:reload:rg ... {q}'` will make fzf restart ripgrep process - whenever the query string, denoted by `{q}`, is changed. - - With `--disabled` option, fzf will no longer perform search. The query string - you type on fzf prompt is only used for restarting ripgrep process. - - Also note that we enabled previewer with `fzf#vim#with_preview`. The last - argument to the function, `ctrl-/`, is the key to toggle the preview window. -> - function! RipgrepFzf(query, fullscreen) - let command_fmt = 'rg --column --line-number --no-heading --color=always --smart-case -- %s || true' - let initial_command = printf(command_fmt, shellescape(a:query)) - let reload_command = printf(command_fmt, '{q}') - let spec = {'options': ['--disabled', '--query', a:query, '--bind', 'change:reload:'.reload_command]} - let spec = fzf#vim#with_preview(spec, 'right', 'ctrl-/') - call fzf#vim#grep(initial_command, 1, spec, a:fullscreen) - endfunction - - command! -nargs=* -bang RG call RipgrepFzf(, 0) -< - MAPPINGS *fzf-vim-mappings* ============================================================================== diff --git a/plugin/fzf.vim b/plugin/fzf.vim index a39cb03..1466fce 100644 --- a/plugin/fzf.vim +++ b/plugin/fzf.vim @@ -54,8 +54,8 @@ call s:defs([ \'command! -bar -bang Colors call fzf#vim#colors(0)', \'command! -bang -nargs=+ -complete=dir Locate call fzf#vim#locate(, fzf#vim#with_preview(), 0)', \'command! -bang -nargs=* Ag call fzf#vim#ag(, fzf#vim#with_preview(), 0)', -\'command! -bang -nargs=* Rg call fzf#vim#grep("rg --column --line-number --no-heading --color=always --smart-case -- ".shellescape(), 1, fzf#vim#with_preview(), 0)', -\'command! -bang -nargs=* RG call fzf#vim#grep2("rg --column --line-number --no-heading --color=always --smart-case -- ", , 1, fzf#vim#with_preview(), 0)', +\'command! -bang -nargs=* Rg call fzf#vim#grep("rg --column --line-number --no-heading --color=always --smart-case -- ".shellescape(), fzf#vim#with_preview(), 0)', +\'command! -bang -nargs=* RG call fzf#vim#grep2("rg --column --line-number --no-heading --color=always --smart-case -- ", , fzf#vim#with_preview(), 0)', \'command! -bang -nargs=* Tags call fzf#vim#tags(, fzf#vim#with_preview({ "placeholder": "--tag {2}:{-1}:{3..}" }), 0)', \'command! -bang -nargs=* BTags call fzf#vim#buffer_tags(, fzf#vim#with_preview({ "placeholder": "{2}:{3..}" }), 0)', \'command! -bar -bang Snippets call fzf#vim#snippets(0)',