From 0c276aac90f5a49fcf2609d348a11ee0608dd558 Mon Sep 17 00:00:00 2001 From: Dalius Dobravolskas Date: Sat, 5 Feb 2022 14:54:26 +0200 Subject: Allows to use quickfix for references. (#4033) * Allows to use quickfix for references. E.g. following mapping could be used to find references for item under cursor and put result into quickfix list: ``` nnoremap af :ALEFindReferences -quickfix ``` Fixes #1759 * Documentation update. --- autoload/ale/references.vim | 69 ++++++++++++++++++++++++++------ doc/ale.txt | 9 +++-- test/test_find_references.vader | 88 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 17 deletions(-) diff --git a/autoload/ale/references.vim b/autoload/ale/references.vim index 38ff0d3d..be2254e2 100644 --- a/autoload/ale/references.vim +++ b/autoload/ale/references.vim @@ -16,6 +16,23 @@ function! ale#references#ClearLSPData() abort let s:references_map = {} endfunction +function! ale#references#FormatTSResponseItem(response_item, options) abort + if get(a:options, 'open_in') is# 'quickfix' + return { + \ 'filename': a:response_item.file, + \ 'lnum': a:response_item.start.line, + \ 'col': a:response_item.start.offset, + \} + else + return { + \ 'filename': a:response_item.file, + \ 'line': a:response_item.start.line, + \ 'column': a:response_item.start.offset, + \ 'match': substitute(a:response_item.lineText, '^\s*\(.\{-}\)\s*$', '\1', ''), + \} + endif +endfunction + function! ale#references#HandleTSServerResponse(conn_id, response) abort if get(a:response, 'command', '') is# 'references' \&& has_key(s:references_map, a:response.request_seq) @@ -25,23 +42,43 @@ function! ale#references#HandleTSServerResponse(conn_id, response) abort let l:item_list = [] for l:response_item in a:response.body.refs - call add(l:item_list, { - \ 'filename': l:response_item.file, - \ 'line': l:response_item.start.line, - \ 'column': l:response_item.start.offset, - \ 'match': substitute(l:response_item.lineText, '^\s*\(.\{-}\)\s*$', '\1', ''), - \}) + call add( + \ l:item_list, + \ ale#references#FormatTSResponseItem(l:response_item, l:options) + \) endfor if empty(l:item_list) call ale#util#Execute('echom ''No references found.''') else - call ale#preview#ShowSelection(l:item_list, l:options) + if get(l:options, 'open_in') is# 'quickfix' + call setqflist([], 'r') + call setqflist(l:item_list, 'a') + call ale#util#Execute('cc 1') + else + call ale#preview#ShowSelection(l:item_list, l:options) + endif endif endif endif endfunction +function! ale#references#FormatLSPResponseItem(response_item, options) abort + if get(a:options, 'open_in') is# 'quickfix' + return { + \ 'filename': ale#path#FromURI(a:response_item.uri), + \ 'lnum': a:response_item.range.start.line + 1, + \ 'col': a:response_item.range.start.character + 1, + \} + else + return { + \ 'filename': ale#path#FromURI(a:response_item.uri), + \ 'line': a:response_item.range.start.line + 1, + \ 'column': a:response_item.range.start.character + 1, + \} + endif +endfunction + function! ale#references#HandleLSPResponse(conn_id, response) abort if has_key(a:response, 'id') \&& has_key(s:references_map, a:response.id) @@ -53,18 +90,22 @@ function! ale#references#HandleLSPResponse(conn_id, response) abort if type(l:result) is v:t_list for l:response_item in l:result - call add(l:item_list, { - \ 'filename': ale#path#FromURI(l:response_item.uri), - \ 'line': l:response_item.range.start.line + 1, - \ 'column': l:response_item.range.start.character + 1, - \}) + call add(l:item_list, + \ ale#references#FormatLSPResponseItem(l:response_item, l:options) + \) endfor endif if empty(l:item_list) call ale#util#Execute('echom ''No references found.''') else - call ale#preview#ShowSelection(l:item_list, l:options) + if get(l:options, 'open_in') is# 'quickfix' + call setqflist([], 'r') + call setqflist(l:item_list, 'a') + call ale#util#Execute('cc 1') + else + call ale#preview#ShowSelection(l:item_list, l:options) + endif endif endif endfunction @@ -119,6 +160,8 @@ function! ale#references#Find(...) abort let l:options.open_in = 'split' elseif l:option is? '-vsplit' let l:options.open_in = 'vsplit' + elseif l:option is? '-quickfix' + let l:options.open_in = 'quickfix' endif endfor endif diff --git a/doc/ale.txt b/doc/ale.txt index a4974ec2..371f17c5 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -3289,15 +3289,16 @@ ALEFindReferences *ALEFindReferences* The locations opened in different ways using the following variations. - `:ALEFindReferences -tab` - Open the location in a new tab. - `:ALEFindReferences -split` - Open the location in a horizontal split. - `:ALEFindReferences -vsplit` - Open the location in a vertical split. + `:ALEFindReferences -tab` - Open the location in a new tab. + `:ALEFindReferences -split` - Open the location in a horizontal split. + `:ALEFindReferences -vsplit` - Open the location in a vertical split. + `:ALEFindReferences -quickfix` - Put the locations into quickfix list. The default method used for navigating to a new location can be changed by modifying |g:ale_default_navigation|. You can add `-relative` to the command to view results with relatives paths, - instead of absolute paths. + instead of absolute paths. This option has no effect if `-quickfix` is used. The selection can be opened again with the |ALERepeatSelection| command. diff --git a/test/test_find_references.vader b/test/test_find_references.vader index 9931e740..f8f7a7d7 100644 --- a/test/test_find_references.vader +++ b/test/test_find_references.vader @@ -187,6 +187,57 @@ Execute(Results should be shown for tsserver responses): \ }, \ g:options +Execute(Results should be put to quickfix for tsserver responses): + call ale#references#SetMap( + \ { + \ 3: { + \ 'ignorethis': 'x', + \ 'open_in': 'quickfix', + \ } + \ } + \) + call ale#references#HandleTSServerResponse(1, { + \ 'command': 'references', + \ 'request_seq': 3, + \ 'success': v:true, + \ 'body': { + \ 'symbolStartOffset': 9, + \ 'refs': [ + \ { + \ 'file': '/foo/bar/app.ts', + \ 'isWriteAccess': v:true, + \ 'lineText': 'import {doSomething} from ''./whatever''', + \ 'end': {'offset': 24, 'line': 9}, + \ 'start': {'offset': 9, 'line': 9}, + \ 'isDefinition': v:true, + \ }, + \ { + \ 'file': '/foo/bar/app.ts', + \ 'isWriteAccess': v:false, + \ 'lineText': ' doSomething()', + \ 'end': {'offset': 18, 'line': 804}, + \ 'start': {'offset': 3, 'line': 804}, + \ 'isDefinition': v:false, + \ }, + \ { + \ 'file': '/foo/bar/other/app.ts', + \ 'isWriteAccess': v:false, + \ 'lineText': ' doSomething()', + \ 'end': {'offset': 18, 'line': 51}, + \ 'start': {'offset': 3, 'line': 51}, + \ 'isDefinition': v:false, + \ }, + \ ], + \ 'symbolDisplayString': 'import doSomething', + \ 'symbolName': 'doSomething()', + \ }, + \}) + + AssertEqual + \ 3, + \ len(getqflist()) + AssertEqual {}, ale#references#GetMap() + Execute(The preview window should not be opened for empty tsserver responses): call ale#references#SetMap({3: {}}) call ale#references#HandleTSServerResponse(1, { @@ -283,6 +334,16 @@ Execute(`-vsplit` should display results in vsplits): AssertEqual {'42': {'open_in': 'vsplit', 'use_relative_paths': 0}}, ale#references#GetMap() +Execute(`-quickfix` should display results in quickfix): + runtime ale_linters/typescript/tsserver.vim + call setpos('.', [bufnr(''), 2, 5, 0]) + + ALEFindReferences -quickfix + + call g:InitCallback() + + AssertEqual {'42': {'open_in': 'quickfix', 'use_relative_paths': 0}}, ale#references#GetMap() + Given python(Some Python file): foo somelongerline @@ -327,6 +388,33 @@ Execute(LSP reference responses should be handled): \ g:item_list AssertEqual {}, ale#references#GetMap() +Execute(LSP reference responses should be put to quickfix): + call ale#references#SetMap({3: { 'open_in': 'quickfix' }}) + call ale#references#HandleLSPResponse( + \ 1, + \ { + \ 'id': 3, + \ 'result': [ + \ { + \ 'uri': ale#path#ToURI(ale#path#Simplify(g:dir . '/completion_dummy_file')), + \ 'range': { + \ 'start': {'line': 2, 'character': 7}, + \ }, + \ }, + \ { + \ 'uri': ale#path#ToURI(ale#path#Simplify(g:dir . '/other_file')), + \ 'range': { + \ 'start': {'line': 7, 'character': 15}, + \ }, + \ }, + \ ], + \ } + \) + + AssertEqual + \ 2, + \ len(getqflist()) + Execute(Preview windows should not be opened for empty LSP reference responses): call ale#references#SetMap({3: {}}) call ale#references#HandleLSPResponse(1, {'id': 3, 'result': []}) -- cgit v1.2.3