Skip to content

Commit

Permalink
Merge pull request #3088 from bhcleek/lsp/callers
Browse files Browse the repository at this point in the history
calls: update :GoCallers to use gopls
  • Loading branch information
bhcleek authored Nov 13, 2020
2 parents 7e22229 + ab0f3d1 commit aebffac
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 39 deletions.
31 changes: 31 additions & 0 deletions autoload/go/calls.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
" don't spam the user when Vim is started in Vi compatibility mode
let s:cpo_save = &cpo
set cpo&vim

function! go#calls#Callers() abort
if !go#config#GoplsEnabled()
call go#util#EchoError("go_referrers_mode is 'gopls', but gopls is disabled")
endif
let [l:line, l:col] = getpos('.')[1:2]
let [l:line, l:col] = go#lsp#lsp#Position(l:line, l:col)
let l:fname = expand('%:p')
call go#lsp#Callers(l:fname, l:line, l:col, funcref('s:parse_output', ['callers']))
return
endfunction

" This uses Vim's errorformat to parse the output and put it into a quickfix
" or locationlist.
function! s:parse_output(mode, output) abort
let errformat = ",%f:%l:%c:\ %m"
let l:listtype = go#list#Type("GoCallers")
call go#list#ParseFormat(l:listtype, errformat, a:output, a:mode, 0)

let errors = go#list#Get(l:listtype)
call go#list#Window(l:listtype, len(errors))
endfunction

" restore Vi compatibility settings
let &cpo = s:cpo_save
unlet s:cpo_save

" vim: sw=2 ts=2 et
48 changes: 48 additions & 0 deletions autoload/go/calls_test.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
" don't spam the user when Vim is started in Vi compatibility mode
let s:cpo_save = &cpo
set cpo&vim

scriptencoding utf-8

func! Test_Callers() abort
try
let l:tmp = gotest#write_file('calls/caller.go', [
\ 'package main',
\ '',
\ 'import "fmt"',
\ '',
\ 'func Quux() {}',
\ '',
\ 'func main() {',
\ "\tQuux()",
\ "\tQuux()",
\ '',
\ "\tfmt.Println(\"vim-go\")",
\ '}',
\ ])

let l:expected = [
\ {'lnum': 8, 'bufnr': bufnr(''), 'col': 2, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'module': '', 'text': 'main'},
\ {'lnum': 9, 'bufnr': bufnr(''), 'col': 2, 'pattern': '', 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'module': '', 'text': 'main'},
\ ]

call go#calls#Callers()

let l:actual = getloclist(0)
let l:start = reltime()
while len(l:actual) != len(l:expected) && reltimefloat(reltime(l:start)) < 10
sleep 100m
let l:actual = getloclist(0)
endwhile

call gotest#assert_quickfix(l:actual, l:expected)
finally
call delete(l:tmp, 'rf')
endtry
endfunc

" restore Vi compatibility settings
let &cpo = s:cpo_save
unlet s:cpo_save

" vim: sw=2 ts=2 et
12 changes: 0 additions & 12 deletions autoload/go/guru.vim
Original file line number Diff line number Diff line change
Expand Up @@ -352,18 +352,6 @@ function! go#guru#Callees(selected) abort
call s:run_guru(args)
endfunction

" Show possible callers of selected function
function! go#guru#Callers(selected) abort
let args = {
\ 'mode': 'callers',
\ 'format': 'plain',
\ 'selected': a:selected,
\ 'needs_scope': 1,
\ }

call s:run_guru(args)
endfunction

" Show path from callgraph root to selected function
function! go#guru#Callstack(selected) abort
let args = {
Expand Down
1 change: 1 addition & 0 deletions autoload/go/list.vim
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ let s:default_list_type_commands = {
\ "GoVet": "quickfix",
\ "GoReferrers": "locationlist",
\ "GoImplements": "locationlist",
\ "GoCallers": "locationlist",
\ "_guru": "locationlist",
\ "_term": "locationlist",
\ "_job": "locationlist",
Expand Down
101 changes: 81 additions & 20 deletions autoload/go/lsp.vim
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ function! go#lsp#TypeDef(fname, line, col, handler) abort
let l:state = s:newHandlerState('type definition')
let l:msg = go#lsp#message#TypeDefinition(fnamemodify(a:fname, ':p'), a:line, a:col)
let l:state.handleResult = funcref('s:typeDefinitionHandler', [function(a:handler, [], l:state)], l:state)
return l:lsp.sendMessage(l:msg, l:state)
return l:lsp.sendMessage(l:msg, l:state)
endfunction

function! s:typeDefinitionHandler(next, msg) abort dict
Expand All @@ -624,6 +624,59 @@ function! s:typeDefinitionHandler(next, msg) abort dict
call call(a:next, l:args)
endfunction

" go#lsp#Callers calls gopls to get callers of the identifier at
" line and col in fname. handler should be a dictionary function that takes a
" list of strings in the form 'file:line:col: message'. handler will be
" attached to a dictionary that manages state (statuslines, sets the winid,
" etc.)
function! go#lsp#Callers(fname, line, col, handler) abort
call go#lsp#DidChange(a:fname)

let l:lsp = s:lspfactory.get()
let l:state = s:newHandlerState('callers')
let l:msg = go#lsp#message#PrepareCallHierarchy(fnamemodify(a:fname, ':p'), a:line, a:col)
let l:state.handleResult = funcref('s:prepareCallHierarchyHandler', [function(a:handler, [], l:state)], l:state)
return l:lsp.sendMessage(l:msg, l:state)
endfunction

function! s:prepareCallHierarchyHandler(next, msg) abort dict
if a:msg is v:null || len(a:msg) == 0
return
endif

let l:lsp = s:lspfactory.get()
let l:state = s:newHandlerState('callers')
let l:msg = go#lsp#message#IncomingCalls(a:msg[0])
let l:state.handleResult = funcref('s:incomingCallsHandler', [function(a:next, [], l:state)], l:state)
return l:lsp.sendMessage(l:msg, l:state)
endfunction

function! s:incomingCallsHandler(next, msg) abort dict
if a:msg is v:null || len(a:msg) == 0
return
endif

let l:locations = []
for l:item in a:msg
try
let l:fname = go#path#FromURI(l:item.from.uri)

for l:fromRange in l:item.fromRanges
let l:line = l:fromRange.start.line+1
let l:content = s:lineinfile(l:fname, l:line)
if l:content is -1
continue
endif
let l:locations = add(l:locations, printf('%s:%s:%s: %s', l:fname, l:line, go#lsp#lsp#PositionOf(content, l:fromRange.start.character), l:item.from.name))
endfor
catch
endtry
endfor

call call(a:next, [l:locations])
return
endfunction

function! go#lsp#DidOpen(fname) abort
if get(b:, 'go_lsp_did_open', 0)
return
Expand Down Expand Up @@ -852,26 +905,12 @@ function! s:handleLocations(next, msg) abort
for l:loc in l:msg
let l:fname = go#path#FromURI(l:loc.uri)
let l:line = l:loc.range.start.line+1
let l:bufnr = bufnr(l:fname)
let l:bufinfo = getbufinfo(l:fname)

try
if l:bufnr == -1 || len(l:bufinfo) == 0 || l:bufinfo[0].loaded == 0
let l:filecontents = readfile(l:fname, '', l:line)
else
let l:filecontents = getbufline(l:fname, l:line)
endif

if len(l:filecontents) == 0
continue
endif

let l:content = l:filecontents[-1]
catch
call go#util#EchoError(printf('%s (line %s): %s at %s', l:fname, l:line, v:exception, v:throwpoint))
endtry
let l:content = s:lineinfile(l:fname, l:line)
if l:content is -1
continue
endif

let l:item = printf('%s:%s:%s: %s', go#path#FromURI(l:loc.uri), l:line, go#lsp#lsp#PositionOf(l:content, l:loc.range.start.character), l:content)
let l:item = printf('%s:%s:%s: %s', l:fname, l:line, go#lsp#lsp#PositionOf(l:content, l:loc.range.start.character), l:content)

let l:result = add(l:result, l:item)
endfor
Expand Down Expand Up @@ -1687,6 +1726,28 @@ function! s:dedup(list)
return sort(keys(l:dict))
endfunction

function! s:lineinfile(fname, line) abort
let l:bufnr = bufnr(a:fname)
let l:bufinfo = getbufinfo(a:fname)

try
if l:bufnr == -1 || len(l:bufinfo) == 0 || l:bufinfo[0].loaded == 0
let l:filecontents = readfile(a:fname, '', a:line)
else
let l:filecontents = getbufline(a:fname, a:line)
endif

if len(l:filecontents) == 0
return -1
endif

return l:filecontents[-1]
catch
call go#util#EchoError(printf('%s (line %s): %s at %s', a:fname, a:line, v:exception, v:throwpoint))
return -1
endtry
endfunction

" restore Vi compatibility settings
let &cpo = s:cpo_save
unlet s:cpo_save
Expand Down
29 changes: 26 additions & 3 deletions autoload/go/lsp/message.vim
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,29 @@ function! go#lsp#message#References(file, line, col) abort
\ }
endfunction

function! go#lsp#message#PrepareCallHierarchy(file, line, col) abort
return {
\ 'notification': 0,
\ 'method': 'textDocument/prepareCallHierarchy',
\ 'params': {
\ 'textDocument': {
\ 'uri': go#path#ToURI(a:file)
\ },
\ 'position': s:position(a:line, a:col),
\ }
\ }
endfunction

function! go#lsp#message#IncomingCalls(item) abort
return {
\ 'notification': 0,
\ 'method': 'callHierarchy/incomingCalls',
\ 'params': {
\ 'item': a:item,
\ }
\ }
endfunction

function! go#lsp#message#Hover(file, line, col) abort
return {
\ 'notification': 0,
Expand Down Expand Up @@ -367,7 +390,7 @@ function! go#lsp#message#ConfigurationResult(items) abort
return l:result
endfunction

function go#lsp#message#ExecuteCommand(cmd, args) abort
function! go#lsp#message#ExecuteCommand(cmd, args) abort
return {
\ 'notification': 0,
\ 'method': 'workspace/executeCommand',
Expand All @@ -378,13 +401,13 @@ function go#lsp#message#ExecuteCommand(cmd, args) abort
\ }
endfunction

function go#lsp#message#ApplyWorkspaceEditResponse(ok) abort
function! go#lsp#message#ApplyWorkspaceEditResponse(ok) abort
return {
\ 'applied': a:ok,
\ }
endfunction

function s:workspaceFolder(key, val) abort
function! s:workspaceFolder(key, val) abort
return {'uri': go#path#ToURI(a:val), 'name': a:val}
endfunction

Expand Down
6 changes: 3 additions & 3 deletions doc/vim-go.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1560,9 +1560,9 @@ default this is enabled.
*'g:go_guru_scope'*

Use this option to define the scope of the analysis to be passed for guru
related commands, such as |:GoImplements|, |:GoCallers|, etc. You can change
it on-the-fly with |:GoGuruScope|. The input should be a a list of package
pattern. An example input might be:
related commands, such as |:GoImplements|, |:GoChannelPeers|, etc. You can
change it on-the-fly with |:GoGuruScope|. The input should be a a list of
package pattern. An example input might be:
`["github.com/fatih/color","github.com/fatih/structs"]`

Also see |go-guru-scope|.
Expand Down
4 changes: 3 additions & 1 deletion ftplugin/go/commands.vim
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ if go#package#InGOPATH()
command! -range=% GoWhicherrs call go#guru#Whicherrs(<count>)
command! -range=% GoCallees call go#guru#Callees(<count>)
command! -range=% GoDescribe call go#guru#Describe(<count>)
command! -range=% GoCallers call go#guru#Callers(<count>)
command! -range=% GoCallstack call go#guru#Callstack(<count>)
command! -range=% GoFreevars call go#guru#Freevars(<count>)
command! -range=% GoChannelPeers call go#guru#ChannelPeers(<count>)
Expand All @@ -22,6 +21,9 @@ command! -range=0 GoSameIdsClear call go#guru#ClearSameIds()
command! -range=0 GoSameIdsToggle call go#guru#ToggleSameIds()
command! -range=0 GoSameIdsAutoToggle call go#guru#AutoToggleSameIds()

" -- calls
command! -range=0 GoCallers call go#calls#Callers(<count>)

" -- tags
command! -nargs=* -range GoAddTags call go#tags#Add(<line1>, <line2>, <count>, <f-args>)
command! -nargs=* -range GoRemoveTags call go#tags#Remove(<line1>, <line2>, <count>, <f-args>)
Expand Down

0 comments on commit aebffac

Please sign in to comment.