mirror of
https://github.com/dense-analysis/ale.git
synced 2025-12-22 12:01:25 +08:00
ALEFindReferences: add -fzf flag to show output in fzf (#5018)
* references: add ALEFindReferences -fzf option Allows using -fzf to show previews using fzf.vim. Includes: - add support for opening in bufers, splits, tabs and for adding matches quickfix - add support for -relative - add fzf preview `--highlight-line` option - add fzf.vim autoload module * tests: fix references tests for fzf support update
This commit is contained in:
85
autoload/ale/fzf.vim
Normal file
85
autoload/ale/fzf.vim
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
" Author: bretello https://github.com/bretello
|
||||||
|
" Description: Functions for integrating with fzf
|
||||||
|
|
||||||
|
" Handle references found with ALEFindReferences using fzf
|
||||||
|
function! ale#fzf#ShowReferences(item_list, options) abort
|
||||||
|
let l:name = 'LSP References'
|
||||||
|
let l:capname = 'References'
|
||||||
|
let l:items = copy(a:item_list)
|
||||||
|
let l:cwd = getcwd() " no-custom-checks
|
||||||
|
let l:sep = has('win32') ? '\' : '/'
|
||||||
|
|
||||||
|
function! s:relative_paths(line) closure abort
|
||||||
|
return substitute(a:line, '^' . l:cwd . l:sep, '', '')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
if get(a:options, 'use_relative_paths')
|
||||||
|
let l:items = map(filter(l:items, 'len(v:val)'), 's:relative_paths(v:val)')
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:start_query = ''
|
||||||
|
let l:fzf_options = {
|
||||||
|
\ 'source': items,
|
||||||
|
\ 'options': ['--prompt', l:name.'> ', '--query', l:start_query,
|
||||||
|
\ '--multi', '--bind', 'alt-a:select-all,alt-d:deselect-all',
|
||||||
|
\ '--delimiter', ':', '--preview-window', '+{2}/2']
|
||||||
|
\}
|
||||||
|
|
||||||
|
call add(l:fzf_options['options'], '--highlight-line') " this only works for more recent fzf versions (TODO: handle version check?)
|
||||||
|
|
||||||
|
" wrap with #with_preview and #fzfwrap before adding the sinklist,
|
||||||
|
" otherwise --expect options are not added
|
||||||
|
let l:opts_with_preview = fzf#vim#with_preview(l:fzf_options)
|
||||||
|
let l:bang = 0 " TODO: handle bang
|
||||||
|
let l:wrapped = fzf#wrap(l:name, l:opts_with_preview, l:bang)
|
||||||
|
|
||||||
|
call remove(l:wrapped, 'sink*') " remove the default sinklist to add in our custom sinklist
|
||||||
|
|
||||||
|
function! l:wrapped.sinklist(lines) closure abort
|
||||||
|
if len(a:lines) <2
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let l:cmd = a:lines[0]
|
||||||
|
|
||||||
|
function! s:references_to_qf(line) closure abort
|
||||||
|
" mimics ag_to_qf in junegunn/fzf.vim
|
||||||
|
let l:parts = matchlist(a:line, '\(.\{-}\)\s*:\s*\(\d\+\)\%(\s*:\s*\(\d\+\)\)\?\%(\s*:\(.*\)\)\?')
|
||||||
|
let l:filename = &autochdir ? fnamemodify(l:parts[1], ':p') : l:parts[1]
|
||||||
|
|
||||||
|
return {'filename': l:filename, 'lnum': l:parts[2], 'col': l:parts[3], 'text': l:parts[4]}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let l:references = map(filter(a:lines[1:], 'len(v:val)'), 's:references_to_qf(v:val)')
|
||||||
|
|
||||||
|
if empty(l:references)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get(a:options, 'open_in') is# 'quickfix'
|
||||||
|
call setqflist([], 'r')
|
||||||
|
call setqflist(l:references, 'a')
|
||||||
|
|
||||||
|
call ale#util#Execute('cc 1')
|
||||||
|
endif
|
||||||
|
|
||||||
|
function! s:action(key, file) abort
|
||||||
|
" copied from fzf.vim
|
||||||
|
let l:default_action = {
|
||||||
|
\ 'ctrl-t': 'tab split',
|
||||||
|
\ 'ctrl-x': 'split',
|
||||||
|
\ 'ctrl-v': 'vsplit' }
|
||||||
|
|
||||||
|
let fzf_actions = get(g:, 'fzf_action', l:default_action)
|
||||||
|
let l:Cmd = get(fzf_actions, a:key, 'edit')
|
||||||
|
|
||||||
|
let l:cursor_cmd = escape('call cursor(' . a:file['lnum'] . ',' . a:file['col'] . ')', ' ')
|
||||||
|
let l:fullcmd = l:Cmd . ' +' . l:cursor_cmd . ' ' . fnameescape(a:file['filename'])
|
||||||
|
silent keepjumps keepalt execute fullcmd
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
return map(l:references, 's:action(cmd, v:val)')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
call fzf#run(l:wrapped)
|
||||||
|
endfunction
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
let g:ale_default_navigation = get(g:, 'ale_default_navigation', 'buffer')
|
let g:ale_default_navigation = get(g:, 'ale_default_navigation', 'buffer')
|
||||||
let g:ale_references_show_contents = get(g:, 'ale_references_show_contents', 1)
|
let g:ale_references_show_contents = get(g:, 'ale_references_show_contents', 1)
|
||||||
|
let g:ale_references_use_fzf = get(g:, 'ale_references_use_fzf', 0)
|
||||||
|
|
||||||
let s:references_map = {}
|
let s:references_map = {}
|
||||||
|
|
||||||
@@ -82,6 +83,16 @@ function! ale#references#FormatLSPResponseItem(response_item, options) abort
|
|||||||
endtry
|
endtry
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if get(a:options, 'use_fzf') == 1
|
||||||
|
let l:filename = ale#util#ToResource(a:response_item.uri)
|
||||||
|
let l:nline = a:response_item.range.start.line + 1
|
||||||
|
let l:ncol = a:response_item.range.start.character + 1
|
||||||
|
|
||||||
|
" grep-style output (filename:line:col:text) so that fzf can properly
|
||||||
|
" show matches and previews using ':' as delimiter
|
||||||
|
return l:filename . ':' . l:nline . ':' . l:ncol . ':' . l:line_text
|
||||||
|
endif
|
||||||
|
|
||||||
if get(a:options, 'open_in') is# 'quickfix'
|
if get(a:options, 'open_in') is# 'quickfix'
|
||||||
return {
|
return {
|
||||||
\ 'filename': l:filename,
|
\ 'filename': l:filename,
|
||||||
@@ -100,8 +111,10 @@ function! ale#references#FormatLSPResponseItem(response_item, options) abort
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! ale#references#HandleLSPResponse(conn_id, response) abort
|
function! ale#references#HandleLSPResponse(conn_id, response) abort
|
||||||
if has_key(a:response, 'id')
|
if ! (has_key(a:response, 'id') && has_key(s:references_map, a:response.id))
|
||||||
\&& has_key(s:references_map, a:response.id)
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
let l:options = remove(s:references_map, a:response.id)
|
let l:options = remove(s:references_map, a:response.id)
|
||||||
|
|
||||||
" The result can be a Dictionary item, a List of the same, or null.
|
" The result can be a Dictionary item, a List of the same, or null.
|
||||||
@@ -119,7 +132,13 @@ function! ale#references#HandleLSPResponse(conn_id, response) abort
|
|||||||
if empty(l:item_list)
|
if empty(l:item_list)
|
||||||
call ale#util#Execute('echom ''No references found.''')
|
call ale#util#Execute('echom ''No references found.''')
|
||||||
else
|
else
|
||||||
if get(l:options, 'open_in') is# 'quickfix'
|
if get(l:options, 'use_fzf') == 1
|
||||||
|
if !exists('*fzf#run')
|
||||||
|
throw 'fzf#run function not found. You also need Vim plugin from the main fzf repository (i.e. junegunn/fzf *and* junegunn/fzf.vim)'
|
||||||
|
endif
|
||||||
|
|
||||||
|
call ale#fzf#ShowReferences(l:item_list, l:options)
|
||||||
|
elseif get(l:options, 'open_in') is# 'quickfix'
|
||||||
call setqflist([], 'r')
|
call setqflist([], 'r')
|
||||||
call setqflist(l:item_list, 'a')
|
call setqflist(l:item_list, 'a')
|
||||||
call ale#util#Execute('cc 1')
|
call ale#util#Execute('cc 1')
|
||||||
@@ -127,7 +146,6 @@ function! ale#references#HandleLSPResponse(conn_id, response) abort
|
|||||||
call ale#preview#ShowSelection(l:item_list, l:options)
|
call ale#preview#ShowSelection(l:item_list, l:options)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:OnReady(line, column, options, linter, lsp_details) abort
|
function! s:OnReady(line, column, options, linter, lsp_details) abort
|
||||||
@@ -165,6 +183,7 @@ function! s:OnReady(line, column, options, linter, lsp_details) abort
|
|||||||
\ 'use_relative_paths': has_key(a:options, 'use_relative_paths') ? a:options.use_relative_paths : 0,
|
\ 'use_relative_paths': has_key(a:options, 'use_relative_paths') ? a:options.use_relative_paths : 0,
|
||||||
\ 'open_in': get(a:options, 'open_in', 'current-buffer'),
|
\ 'open_in': get(a:options, 'open_in', 'current-buffer'),
|
||||||
\ 'show_contents': a:options.show_contents,
|
\ 'show_contents': a:options.show_contents,
|
||||||
|
\ 'use_fzf': get(a:options, 'use_fzf', g:ale_references_use_fzf),
|
||||||
\}
|
\}
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
@@ -185,6 +204,8 @@ function! ale#references#Find(...) abort
|
|||||||
let l:options.open_in = 'quickfix'
|
let l:options.open_in = 'quickfix'
|
||||||
elseif l:option is? '-contents'
|
elseif l:option is? '-contents'
|
||||||
let l:options.show_contents = 1
|
let l:options.show_contents = 1
|
||||||
|
elseif l:option is? '-fzf'
|
||||||
|
let l:options.use_fzf = 1
|
||||||
endif
|
endif
|
||||||
endfor
|
endfor
|
||||||
endif
|
endif
|
||||||
|
|||||||
16
doc/ale.txt
16
doc/ale.txt
@@ -2280,6 +2280,16 @@ g:ale_references_show_contents
|
|||||||
If set to `true` or `1`, matches found by `:ALEFindReferences` will be
|
If set to `true` or `1`, matches found by `:ALEFindReferences` will be
|
||||||
shown with a preview of the matching line.
|
shown with a preview of the matching line.
|
||||||
|
|
||||||
|
*ale-options.references_use_fzf*
|
||||||
|
*g:ale_references_use_fzf*
|
||||||
|
references_use_fzf
|
||||||
|
g:ale_references_use_fzf
|
||||||
|
Type: |Boolean| or |Number|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
If set to `true` or `1`, matches found by `:ALEFindReferences` will be
|
||||||
|
always shown using |fzf-vim| (https://github.com/junegunn/fzf.vim).
|
||||||
|
|
||||||
*ale-options.rename_tsserver_find_in_comments*
|
*ale-options.rename_tsserver_find_in_comments*
|
||||||
*g:ale_rename_tsserver_find_in_comments*
|
*g:ale_rename_tsserver_find_in_comments*
|
||||||
rename_tsserver_find_in_comments
|
rename_tsserver_find_in_comments
|
||||||
@@ -4085,6 +4095,7 @@ documented in additional help files.
|
|||||||
`:ALEFindReferences -vsplit` - Open the location in a vertical split.
|
`:ALEFindReferences -vsplit` - Open the location in a vertical split.
|
||||||
`:ALEFindReferences -quickfix` - Put the locations into quickfix list.
|
`:ALEFindReferences -quickfix` - Put the locations into quickfix list.
|
||||||
`:ALEFindReferences -contents` - Show line contents for matches.
|
`:ALEFindReferences -contents` - Show line contents for matches.
|
||||||
|
`:ALEFindReferences -fzf` - Show matches/previews using |fzf-vim|.
|
||||||
|
|
||||||
The default method used for navigating to a new location can be changed
|
The default method used for navigating to a new location can be changed
|
||||||
by modifying |g:ale_default_navigation|.
|
by modifying |g:ale_default_navigation|.
|
||||||
@@ -4092,6 +4103,11 @@ documented in additional help files.
|
|||||||
The default behaviour on whether to show line content for matches can
|
The default behaviour on whether to show line content for matches can
|
||||||
be changed by modifying |g:ale_references_show_contents|.
|
be changed by modifying |g:ale_references_show_contents|.
|
||||||
|
|
||||||
|
The default behaviour on whether to use `fzf` to show matches/file previews
|
||||||
|
can be changed by modifying |g:ale_references_use_fzf|. `-fzf` can be combined
|
||||||
|
with `-tab`, `-split`, `-vsplit`, `-quickfix` and `-relative`, while line
|
||||||
|
contents/file previews are always shown.
|
||||||
|
|
||||||
You can add `-relative` to the command to view results with relatives paths,
|
You can add `-relative` to the command to view results with relatives paths,
|
||||||
instead of absolute paths. This option has no effect if `-quickfix` is used.
|
instead of absolute paths. This option has no effect if `-quickfix` is used.
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ Execute(Results should be shown for tsserver responses):
|
|||||||
\ 'ignorethis': 'x',
|
\ 'ignorethis': 'x',
|
||||||
\ 'open_in': 'tab',
|
\ 'open_in': 'tab',
|
||||||
\ 'use_relative_paths': 1,
|
\ 'use_relative_paths': 1,
|
||||||
|
\ 'use_fzf': 0,
|
||||||
\ }
|
\ }
|
||||||
\ }
|
\ }
|
||||||
\)
|
\)
|
||||||
@@ -283,7 +284,7 @@ Execute(tsserver reference requests should be sent):
|
|||||||
\ [0, 'ts@references', {'file': expand('%:p'), 'line': 2, 'offset': 5}]
|
\ [0, 'ts@references', {'file': expand('%:p'), 'line': 2, 'offset': 5}]
|
||||||
\ ],
|
\ ],
|
||||||
\ g:message_list
|
\ g:message_list
|
||||||
AssertEqual {'42': {'show_contents': 1, 'open_in': 'current-buffer', 'use_relative_paths': 0}}, ale#references#GetMap()
|
AssertEqual {'42': {'show_contents': 1, 'open_in': 'current-buffer', 'use_relative_paths': 0, 'use_fzf': 0, }}, ale#references#GetMap()
|
||||||
|
|
||||||
Execute('-relative' argument should enable 'use_relative_paths' in HandleTSServerResponse):
|
Execute('-relative' argument should enable 'use_relative_paths' in HandleTSServerResponse):
|
||||||
runtime ale_linters/typescript/tsserver.vim
|
runtime ale_linters/typescript/tsserver.vim
|
||||||
@@ -293,7 +294,7 @@ Execute('-relative' argument should enable 'use_relative_paths' in HandleTSServe
|
|||||||
|
|
||||||
call g:InitCallback()
|
call g:InitCallback()
|
||||||
|
|
||||||
AssertEqual {'42': {'show_contents': 1, 'open_in': 'current-buffer', 'use_relative_paths': 1}}, ale#references#GetMap()
|
AssertEqual {'42': {'show_contents': 1, 'open_in': 'current-buffer', 'use_relative_paths': 1, 'use_fzf': 0}}, ale#references#GetMap()
|
||||||
|
|
||||||
Execute(`-tab` should display results in tabs):
|
Execute(`-tab` should display results in tabs):
|
||||||
runtime ale_linters/typescript/tsserver.vim
|
runtime ale_linters/typescript/tsserver.vim
|
||||||
@@ -303,7 +304,7 @@ Execute(`-tab` should display results in tabs):
|
|||||||
|
|
||||||
call g:InitCallback()
|
call g:InitCallback()
|
||||||
|
|
||||||
AssertEqual {'42': {'show_contents': 1, 'open_in': 'tab', 'use_relative_paths': 0}}, ale#references#GetMap()
|
AssertEqual {'42': {'show_contents': 1, 'open_in': 'tab', 'use_relative_paths': 0, 'use_fzf': 0}}, ale#references#GetMap()
|
||||||
|
|
||||||
Execute(The default navigation type should be used):
|
Execute(The default navigation type should be used):
|
||||||
runtime ale_linters/typescript/tsserver.vim
|
runtime ale_linters/typescript/tsserver.vim
|
||||||
@@ -314,7 +315,7 @@ Execute(The default navigation type should be used):
|
|||||||
|
|
||||||
call g:InitCallback()
|
call g:InitCallback()
|
||||||
|
|
||||||
AssertEqual {'42': {'show_contents': 1, 'open_in': 'tab', 'use_relative_paths': 0}}, ale#references#GetMap()
|
AssertEqual {'42': {'show_contents': 1, 'open_in': 'tab', 'use_relative_paths': 0, 'use_fzf': 0}}, ale#references#GetMap()
|
||||||
|
|
||||||
Execute(`-split` should display results in splits):
|
Execute(`-split` should display results in splits):
|
||||||
runtime ale_linters/typescript/tsserver.vim
|
runtime ale_linters/typescript/tsserver.vim
|
||||||
@@ -324,7 +325,7 @@ Execute(`-split` should display results in splits):
|
|||||||
|
|
||||||
call g:InitCallback()
|
call g:InitCallback()
|
||||||
|
|
||||||
AssertEqual {'42': {'show_contents': 1, 'open_in': 'split', 'use_relative_paths': 0}}, ale#references#GetMap()
|
AssertEqual {'42': {'show_contents': 1, 'open_in': 'split', 'use_relative_paths': 0, 'use_fzf': 0}}, ale#references#GetMap()
|
||||||
|
|
||||||
Execute(`-vsplit` should display results in vsplits):
|
Execute(`-vsplit` should display results in vsplits):
|
||||||
runtime ale_linters/typescript/tsserver.vim
|
runtime ale_linters/typescript/tsserver.vim
|
||||||
@@ -334,7 +335,7 @@ Execute(`-vsplit` should display results in vsplits):
|
|||||||
|
|
||||||
call g:InitCallback()
|
call g:InitCallback()
|
||||||
|
|
||||||
AssertEqual {'42': {'show_contents': 1, 'open_in': 'vsplit', 'use_relative_paths': 0}}, ale#references#GetMap()
|
AssertEqual {'42': {'show_contents': 1, 'open_in': 'vsplit', 'use_relative_paths': 0, 'use_fzf': 0}}, ale#references#GetMap()
|
||||||
|
|
||||||
Execute(`-quickfix` should display results in quickfix):
|
Execute(`-quickfix` should display results in quickfix):
|
||||||
runtime ale_linters/typescript/tsserver.vim
|
runtime ale_linters/typescript/tsserver.vim
|
||||||
@@ -344,7 +345,7 @@ Execute(`-quickfix` should display results in quickfix):
|
|||||||
|
|
||||||
call g:InitCallback()
|
call g:InitCallback()
|
||||||
|
|
||||||
AssertEqual {'42': {'show_contents': 1, 'open_in': 'quickfix', 'use_relative_paths': 0}}, ale#references#GetMap()
|
AssertEqual {'42': {'show_contents': 1, 'open_in': 'quickfix', 'use_relative_paths': 0, 'use_fzf': 0}}, ale#references#GetMap()
|
||||||
|
|
||||||
Given python(Some Python file):
|
Given python(Some Python file):
|
||||||
foo
|
foo
|
||||||
@@ -627,7 +628,7 @@ Execute(LSP reference requests should be sent):
|
|||||||
\ ],
|
\ ],
|
||||||
\ g:message_list
|
\ g:message_list
|
||||||
|
|
||||||
AssertEqual {'42': {'show_contents': 1, 'open_in': 'current-buffer', 'use_relative_paths': 0}}, ale#references#GetMap()
|
AssertEqual {'42': {'show_contents': 1, 'open_in': 'current-buffer', 'use_relative_paths': 0, 'use_fzf': 0}}, ale#references#GetMap()
|
||||||
|
|
||||||
Execute('-relative' argument should enable 'use_relative_paths' in HandleLSPResponse):
|
Execute('-relative' argument should enable 'use_relative_paths' in HandleLSPResponse):
|
||||||
runtime ale_linters/python/pylsp.vim
|
runtime ale_linters/python/pylsp.vim
|
||||||
@@ -638,4 +639,4 @@ Execute('-relative' argument should enable 'use_relative_paths' in HandleLSPResp
|
|||||||
|
|
||||||
call g:InitCallback()
|
call g:InitCallback()
|
||||||
|
|
||||||
AssertEqual {'42': {'show_contents': 1, 'open_in': 'current-buffer', 'use_relative_paths': 1}}, ale#references#GetMap()
|
AssertEqual {'42': {'show_contents': 1, 'open_in': 'current-buffer', 'use_relative_paths': 1, 'use_fzf': 0}}, ale#references#GetMap()
|
||||||
|
|||||||
Reference in New Issue
Block a user