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

calls: update :GoCallers to use gopls #3088

Merged
merged 1 commit into from
Nov 13, 2020
Merged
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
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