Skip to content

Commit

Permalink
Merge pull request #2822 from bhcleek/lsp/doc
Browse files Browse the repository at this point in the history
doc: use gopls to get documentation under the cursor
  • Loading branch information
bhcleek authored Apr 17, 2020
2 parents f935649 + b639fb4 commit 82a5ed6
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 61 deletions.
59 changes: 11 additions & 48 deletions autoload/go/doc.vim
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,20 @@ set cpo&vim
let s:buf_nr = -1

function! go#doc#OpenBrowser(...) abort
" check if we have gogetdoc as it gives us more and accurate information.
" Only supported if we have json_decode as it's not worth to parse the plain
" non-json output of gogetdoc
let bin_path = go#path#CheckBinPath('gogetdoc')
if !empty(bin_path) && exists('*json_decode')
let [l:json_out, l:err] = s:gogetdoc(1)
if len(a:000) == 0
let [l:out, l:err] = go#lsp#DocLink()
if l:err
call go#util#EchoError(json_out)
call go#util#EchoError(l:out)
return
endif

let out = json_decode(json_out)
if type(out) != type({})
call go#util#EchoError("gogetdoc output is malformed")
if len(l:out) == 0
call go#util#EchoWarning("could not path for doc URL")
endif

let import = out["import"]
let name = out["name"]
let decl = out["decl"]
let l:godoc_url = printf('%s/%s', go#config#DocUrl(), l:out)

let godoc_url = go#config#DocUrl()
let godoc_url .= "/" . import
if decl !~ '^package'
let anchor = name
if decl =~ '^func ('
let anchor = substitute(decl, '^func ([^ ]\+ \*\?\([^)]\+\)) ' . name . '(.*', '\1', '') . "." . name
endif
let godoc_url .= "#" . anchor
endif

call go#util#OpenBrowser(godoc_url)
call go#util#OpenBrowser(l:godoc_url)
return
endif

Expand All @@ -52,27 +35,24 @@ function! go#doc#OpenBrowser(...) abort
let exported_name = pkgs[1]

" example url: https://godoc.org/github.com/fatih/set#Set
let godoc_url = go#config#DocUrl() . "/" . pkg . "#" . exported_name
let godoc_url = printf('%s/%s#%s', go#config#DocUrl(), pkg, exported_name)
call go#util#OpenBrowser(godoc_url)
endfunction

function! go#doc#Open(newmode, mode, ...) abort
" With argument: run "godoc [arg]".
if len(a:000)
let [l:out, l:err] = go#util#Exec(['go', 'doc'] + a:000)
else " Without argument: run gogetdoc on cursor position.
let [l:out, l:err] = s:gogetdoc(0)
if out == -1
return
endif
else " Without argument: use gopls to get documentation
let [l:out, l:err] = go#lsp#Doc()
endif

if l:err
call go#util#EchoError(out)
return
endif

call s:GodocView(a:newmode, a:mode, out)
call s:GodocView(a:newmode, a:mode, l:out)
endfunction

function! s:GodocView(newposition, position, content) abort
Expand Down Expand Up @@ -181,23 +161,6 @@ function! s:GodocView(newposition, position, content) abort
nnoremap <buffer> <silent> <Esc>[ <Esc>[
endfunction

function! s:gogetdoc(json) abort
let l:cmd = [
\ 'gogetdoc',
\ '-tags', go#config#BuildTags(),
\ '-pos', expand("%:p:gs!\\!/!") . ':#' . go#util#OffsetCursor()]
if a:json
let l:cmd += ['-json']
endif

if &modified
let l:cmd += ['-modified']
return go#util#ExecInDir(l:cmd, go#util#archive())
endif

return go#util#ExecInDir(l:cmd)
endfunction

" returns the package and exported name. exported name might be empty.
" ie: fmt and Println
" ie: github.com/fatih/set and New
Expand Down
89 changes: 78 additions & 11 deletions autoload/go/lsp.vim
Original file line number Diff line number Diff line change
Expand Up @@ -898,21 +898,82 @@ function! go#lsp#Hover(fname, line, col, handler) abort
endfunction

function! s:hoverHandler(next, msg) abort dict
try
let l:content = split(a:msg.contents.value, '; ')
if len(l:content) > 1
let l:curly = stridx(l:content[0], '{')
let l:content = extend([l:content[0][0:l:curly]], map(extend([l:content[0][l:curly+1:]], l:content[1:]), '"\t" . v:val'))
let l:content[len(l:content)-1] = '}'
endif
if a:msg is v:null || !has_key(a:msg, 'contents')
return
endif

let l:args = [l:content]
try
let l:value = json_decode(a:msg.contents.value)
let l:args = [l:value.signature]
call call(a:next, l:args)
catch
" TODO(bc): log the message and/or show an error message.
endtry
endfunction

function! go#lsp#Doc() abort
let l:fname = expand('%:p')
let [l:line, l:col] = go#lsp#lsp#Position()

call go#lsp#DidChange(l:fname)

let l:lsp = s:lspfactory.get()
let l:msg = go#lsp#message#Hover(l:fname, l:line, l:col)
let l:state = s:newHandlerState('doc')
let l:resultHandler = go#promise#New(function('s:docFromHoverResult', [], l:state), 10000, '')
let l:state.handleResult = l:resultHandler.wrapper
let l:state.error = l:resultHandler.wrapper
call l:lsp.sendMessage(l:msg, l:state)
return l:resultHandler.await()
endfunction

function! s:docFromHoverResult(msg) abort dict
if type(a:msg) is type('')
return [a:msg, 1]
endif

if a:msg is v:null || !has_key(a:msg, 'contents')
return
endif

let l:value = json_decode(a:msg.contents.value)
let l:doc = l:value.fullDocumentation
if len(l:doc) is 0
let l:doc = 'Undocumented'
endif
let l:content = printf("%s\n\n%s", l:value.signature, l:doc)
return [l:content, 0]
endfunction

function! go#lsp#DocLink() abort
let l:fname = expand('%:p')
let [l:line, l:col] = go#lsp#lsp#Position()

call go#lsp#DidChange(l:fname)

let l:lsp = s:lspfactory.get()
let l:msg = go#lsp#message#Hover(l:fname, l:line, l:col)
let l:state = s:newHandlerState('doc url')
let l:resultHandler = go#promise#New(function('s:docLinkFromHoverResult', [], l:state), 10000, '')
let l:state.handleResult = l:resultHandler.wrapper
let l:state.error = l:resultHandler.wrapper
call l:lsp.sendMessage(l:msg, l:state)
return l:resultHandler.await()
endfunction

function! s:docLinkFromHoverResult(msg) abort dict
if type(a:msg) is type('')
return [a:msg, 1]
endif

if a:msg is v:null || !has_key(a:msg, 'contents')
return
endif

let l:doc = json_decode(a:msg.contents.value)
return [l:doc.link, '']
endfunction

function! go#lsp#Info(showstatus)
let l:fname = expand('%:p')
let [l:line, l:col] = go#lsp#lsp#Position()
Expand Down Expand Up @@ -973,13 +1034,19 @@ function! s:infoDefinitionHandler(next, showstatus, msg) abort dict
let l:state = s:newHandlerState('')
endif

let l:state.handleResult = funcref('s:hoverHandler', [a:next], l:state)
let l:state.handleResult = a:next
let l:state.error = funcref('s:noop')
return l:lsp.sendMessage(l:msg, l:state)
endfunction

function! s:info(show, content) abort dict
let l:content = s:infoFromHoverContent(a:content)
function! s:info(show, msg) abort dict
if a:msg is v:null || !has_key(a:msg, 'contents')
return
endif

let l:value = json_decode(a:msg.contents.value)
let l:content = [l:value.singleLine]
let l:content = s:infoFromHoverContent(l:content)

if a:show
call go#util#ShowInfo(l:content)
Expand Down
2 changes: 1 addition & 1 deletion autoload/go/lsp/message.vim
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ function! go#lsp#message#ConfigurationResult(items) abort
for l:item in a:items
let l:config = {
\ 'buildFlags': [],
\ 'hoverKind': 'NoDocumentation',
\ 'hoverKind': 'Structured',
\ }
let l:buildtags = go#config#BuildTags()
if buildtags isnot ''
Expand Down
1 change: 0 additions & 1 deletion plugin/go.vim
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ let s:packages = {
\ 'errcheck': ['github.com/kisielk/errcheck@master'],
\ 'fillstruct': ['github.com/davidrjenni/reftools/cmd/fillstruct@master'],
\ 'godef': ['github.com/rogpeppe/godef@master'],
\ 'gogetdoc': ['github.com/zmb3/gogetdoc@master'],
\ 'goimports': ['golang.org/x/tools/cmd/goimports@master'],
\ 'golint': ['golang.org/x/lint/golint@master'],
\ 'gopls': ['golang.org/x/tools/gopls@latest', {}, {'after': function('go#lsp#Restart', [])}],
Expand Down

0 comments on commit 82a5ed6

Please sign in to comment.