Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple Definitions Returned #449

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,15 @@ other reference to the currently highlighted element.
### Jump to definition

While the cursor is on any identifier call `LSClientGoToDefinition` (`<C-]>` if
using the default mappings) to jump to the location of the definition. If the
cursor moves before the server responds the response will be ignored.
using the default mappings) to jump to the location of the definition. When
multiple definitions are available, the quickfix list will be opened.
If the cursor moves before the server responds the response will be ignored.

### Jump to declaration

While the cursor is on any identifier call `LSClientGoToDeclaration` (`gd` if
using the default mappings) to jump to the location of the declaration.
If the cursor moves before the server responds the response will be ignored.

### Find references

Expand Down
4 changes: 4 additions & 0 deletions autoload/lsc/config.vim
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ if !exists('s:initialized')
let s:default_maps = {
\ 'GoToDefinition': '<C-]>',
\ 'GoToDefinitionSplit': ['<C-W>]', '<C-W><C-]>'],
\ 'GoToDeclaration': 'gd',
\ 'GoToDeclarationSplit': ['<C-W>]', '<C-W>gd'],
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we can map '<C-W>]' again since it's mapped for GoToDefinitionSplit

Suggested change
\ 'GoToDeclarationSplit': ['<C-W>]', '<C-W>gd'],
\ 'GoToDeclarationSplit': ['<C-W>]', '<C-W>gd'],

\ 'FindReferences': 'gr',
\ 'NextReference': '<C-n>',
\ 'PreviousReference': '<C-p>',
Expand Down Expand Up @@ -54,6 +56,8 @@ function! lsc#config#mapKeys() abort
for l:command in [
\ 'GoToDefinition',
\ 'GoToDefinitionSplit',
\ 'GoToDeclaration',
\ 'GoToDeclarationSplit',
\ 'FindReferences',
\ 'NextReference',
\ 'PreviousReference',
Expand Down
63 changes: 38 additions & 25 deletions autoload/lsc/reference.vim
Original file line number Diff line number Diff line change
@@ -1,45 +1,58 @@
let s:popup_id = 0

function! lsc#reference#goToDeclaration(mods, issplit) abort
call lsc#file#flushChanges()
call lsc#server#userCall('textDocument/declaration',
\ lsc#params#documentPosition(),
\ lsc#util#gateResult('GoTo',
\ function('<SID>GoTo', ['declaration', a:mods, a:issplit])))
endfunction

function! lsc#reference#goToDefinition(mods, issplit) abort
call lsc#file#flushChanges()
call lsc#server#userCall('textDocument/definition',
\ lsc#params#documentPosition(),
\ lsc#util#gateResult('GoToDefinition',
\ function('<SID>GoToDefinition', [a:mods, a:issplit])))
\ lsc#util#gateResult('GoTo',
\ function('<SID>GoTo', ['definition', a:mods, a:issplit])))
endfunction

function! s:GoToDefinition(mods, issplit, result) abort
function! s:GoTo(label, mods, issplit, result) abort
if type(a:result) == type(v:null) ||
\ (type(a:result) == type([]) && len(a:result) == 0)
call lsc#message#error('No definition found')
call lsc#message#error('No'. a:label .'found')
return
endif
if type(a:result) == type([])
if type(a:result) == type([]) && (a:label ==# 'declaration' || len(a:result) == 1)
let l:location = a:result[0]
elseif type(a:result) == type([]) && len(a:result) > 1
call s:setQuickFixLocations('Definitions', a:result)
call copen()
else
let l:location = a:result
endif
let l:file = lsc#uri#documentPath(l:location.uri)
let l:line = l:location.range.start.line + 1
let l:character = l:location.range.start.character + 1
let l:dotag = &tagstack && exists('*gettagstack') && exists('*settagstack')
if l:dotag
let l:from = [bufnr('%'), line('.'), col('.'), 0]
let l:tagname = expand('<cword>')
let l:stack = gettagstack()
if l:stack.curidx > 1
let l:stack.items = l:stack.items[0:l:stack.curidx-2]
else
let l:stack.items = []
if exists('l:location')
let l:file = lsc#uri#documentPath(l:location.uri)
let l:line = l:location.range.start.line + 1
let l:character = l:location.range.start.character + 1
let l:dotag = &tagstack && exists('*gettagstack') && exists('*settagstack')
if l:dotag
let l:from = [bufnr('%'), line('.'), col('.'), 0]
let l:tagname = expand('<cword>')
let l:stack = gettagstack()
if l:stack.curidx > 1
let l:stack.items = l:stack.items[0:l:stack.curidx-2]
else
let l:stack.items = []
endif
let l:stack.items += [{'from': l:from, 'tagname': l:tagname}]
let l:stack.curidx = len(l:stack.items)
call settagstack(win_getid(), l:stack)
endif
call s:goTo(l:file, l:line, l:character, a:mods, a:issplit)
if l:dotag
let l:curidx = gettagstack().curidx + 1
call settagstack(win_getid(), {'curidx': l:curidx})
endif
let l:stack.items += [{'from': l:from, 'tagname': l:tagname}]
let l:stack.curidx = len(l:stack.items)
call settagstack(win_getid(), l:stack)
endif
call s:goTo(l:file, l:line, l:character, a:mods, a:issplit)
if l:dotag
let l:curidx = gettagstack().curidx + 1
call settagstack(win_getid(), {'curidx': l:curidx})
endif
endfunction

Expand Down
16 changes: 13 additions & 3 deletions doc/lsc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ COMMANDS *lsc-commands*
*:LSClientGoToDefinition*
Jump to the location defining the element under the cursor. Sends a
"textDocument/definition" request with the location set to the cursor's
position. If the cursor is not in the same position when the server responds
the jump will be canceled. With |lsc-default-map| this command is bound to
`<c-]>`.
position. When multiple definitions are returned, the quickfix list will
be opened to prompt the user for choice. If the cursor is not in the same
position when the server responds the jump will be canceled.
With |lsc-default-map| this command is bound to `<c-]>`.

If this version of vim supports |settagstack| the tag stack will also be
updated to include this jump. Jump back with `<c-t>` or |:pop|, it is not
Expand All @@ -75,6 +76,15 @@ will default to opening a vertical split, while >
<
will prefer a new tab.

*:LSClientGoToDeclaration*
Similiar to |LSClientGoToDefinition| but expects only a single result when
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should treat declarations specially since they allow multiple too.

What do you think about always jumping to the first element in the list for either case, but also populating the quickfix list with the extras when there are more?

issuing the default binding `gd`.
This is not compliant to the current protocol since it accepts multiple
declaration results as well.

*:LSClientGoToDeclarationSplit*
In accordance to |LSClientGoToDeclaration| and |LSClientGoToDefinitionSplit|.

*:LSClientFindReferences*
Populate the |quickfix| with a list of location which reference the element
under the cursor, including it's definition. Sends a "textDocument/references"
Expand Down
4 changes: 4 additions & 0 deletions plugin/lsc.vim
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ command! LSClientGoToDefinitionSplit
\ call lsc#reference#goToDefinition(<q-mods>, 1)
command! LSClientGoToDefinition
\ call lsc#reference#goToDefinition(<q-mods>, 0)
command! LSClientGoToDeclarationSplit
\ call lsc#reference#goToDeclaration(<q-mods>, 1)
command! LSClientGoToDeclaration
\ call lsc#reference#goToDeclaration(<q-mods>, 0)
command! LSClientFindReferences call lsc#reference#findReferences()
command! LSClientNextReference call lsc#reference#findNext(1)
command! LSClientPreviousReference call lsc#reference#findNext(-1)
Expand Down
5 changes: 5 additions & 0 deletions test/integration/test/vim_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ void main() {
expect(result, '2');
});

test('loads plugin', () async {
final result = await vim.expr('exists(\':LSClientGoToDeclaration\')');
expect(result, '1');
});

test('opens files, has filetype detection', () async {
await vim.edit('foo.txt');
expect(await vim.expr('&ft'), 'text');
Expand Down