From c70f333613ae47fe76f91ea655443571674cf694 Mon Sep 17 00:00:00 2001 From: Billie Cleek Date: Sun, 26 May 2019 13:52:32 -0700 Subject: [PATCH 1/3] complete: separate tests for go#complete#GetInfo --- autoload/go/complete_test.vim | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/autoload/go/complete_test.vim b/autoload/go/complete_test.vim index 43971421c9..59334d3d4c 100644 --- a/autoload/go/complete_test.vim +++ b/autoload/go/complete_test.vim @@ -2,23 +2,27 @@ let s:cpo_save = &cpo set cpo&vim -func! Test_GetInfo() +func! Test_GetInfo_gocode() + let g:go_info_mode = 'gocode' + call s:getinfo() + unlet g:go_info_mode +endfunction + +func! Test_GetInfo_guru() + let g:go_info_mode = 'guru' + call s:getinfo() + unlet g:go_info_mode +endfunction + +func! s:getinfo() let l:filename = 'complete/complete.go' let l:tmp = gotest#load_fixture(l:filename) call cursor(8, 3) - let g:go_info_mode = 'gocode' let expected = 'func Example(s string)' let actual = go#complete#GetInfo() call assert_equal(expected, actual) - - let g:go_info_mode = 'guru' - call go#config#InfoMode() - let actual = go#complete#GetInfo() - call assert_equal(expected, actual) - - unlet g:go_info_mode endfunction " restore Vi compatibility settings From 8ca22ee07bec2a17d8a40b93c2845534c0d0532b Mon Sep 17 00:00:00 2001 From: Billie Cleek Date: Sun, 26 May 2019 21:36:34 -0700 Subject: [PATCH 2/3] add promises Add promises to support awaiting async operations. --- autoload/go/promise.vim | 50 ++++++++++++++++++++++++++++++++++++ autoload/go/promise_test.vim | 41 +++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 autoload/go/promise.vim create mode 100644 autoload/go/promise_test.vim diff --git a/autoload/go/promise.vim b/autoload/go/promise.vim new file mode 100644 index 0000000000..76c2f7c3bd --- /dev/null +++ b/autoload/go/promise.vim @@ -0,0 +1,50 @@ +" don't spam the user when Vim is started in Vi compatibility mode +let s:cpo_save = &cpo +set cpo&vim + +scriptencoding utf-8 + +" New returns a promise. A promise's primary purpose is to make async jobs +" synchronous by awaiting fn. +" +" A promise is a dictionary with two keys: +" 'wrapper': +" A function that wraps fn. It can be used in place of fn. +" 'await': +" A function that waits for wrapper to be called and returns the value +" returned by fn. Returns default if timeout expires. +function! go#promise#New(fn, timeout, default) abort + let l:state = {} + + " explicitly bind to state so that within l:promise's methods, self will + " always refer to state. See :help Partial for more information. + return { + \ 'wrapper': function('s:wrapper', [a:fn], l:state), + \ 'await': function('s:await', [a:timeout, a:default], l:state), + \ } +endfunction + +function! s:wrapper(fn, ...) dict + let self.retval = call(a:fn, a:000) + return self.retval +endfunction + +function! s:await(timeout, default) dict + let l:timer = timer_start(a:timeout, function('s:setretval', [a:default], self)) + while !has_key(self, 'retval') + sleep 50m + endwhile + call timer_stop(l:timer) + + return self.retval +endfunction + +function! s:setretval(val, timer) dict + let self.retval = a:val +endfunction + +" restore Vi compatibility settings +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: sw=2 ts=2 et diff --git a/autoload/go/promise_test.vim b/autoload/go/promise_test.vim new file mode 100644 index 0000000000..f4473fe6d3 --- /dev/null +++ b/autoload/go/promise_test.vim @@ -0,0 +1,41 @@ +" don't spam the user when Vim is started in Vi compatibility mode +let s:cpo_save = &cpo +set cpo&vim + +func! Test_PromiseNew() abort + let l:sut = go#promise#New(function('s:work', []), 100, -1) + call assert_true(has_key(l:sut, 'wrapper')) + call assert_true(has_key(l:sut, 'await')) +endfunc + +func! Test_PromiseAwait() abort + let l:expected = 1 + let l:default = -1 + let l:sut = go#promise#New(function('s:work', [l:expected]), 100, l:default) + + call timer_start(10, l:sut.wrapper) + + let l:actual = call(l:sut.await, []) + call assert_equal(l:expected, l:actual) +endfunc + +func! Test_PromiseAwait_Timeout() abort + let l:desired = 1 + let l:expected = -1 + let l:sut = go#promise#New(function('s:work', [l:desired]), 10, l:expected) + + call timer_start(100, l:sut.wrapper) + + let l:actual = call(l:sut.await, []) + call assert_equal(l:expected, l:actual) +endfunc + +func! s:work(val, timer) + return a:val +endfunc + +" restore Vi compatibility settings +let &cpo = s:cpo_save +unlet s:cpo_save + +" vim: sw=2 ts=2 et From 03febea22359b45446a34b59eba7d809e1ea4a0e Mon Sep 17 00:00:00 2001 From: Billie Cleek Date: Sun, 26 May 2019 21:40:00 -0700 Subject: [PATCH 3/3] support g:go_info_mode='gopls' in go#complete#GetInfo --- autoload/go/complete.vim | 7 +++++- autoload/go/complete_test.vim | 6 ++++++ autoload/go/lsp.vim | 40 ++++++++++++++++++++++++++++++----- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/autoload/go/complete.vim b/autoload/go/complete.vim index 786b1ddf72..296c269ac2 100644 --- a/autoload/go/complete.vim +++ b/autoload/go/complete.vim @@ -79,7 +79,12 @@ endfunction " go#complete#GoInfo returns the description of the identifier under the " cursor. function! go#complete#GetInfo() abort - return s:sync_info(0) + let l:mode = go#config#InfoMode() + if l:mode == 'gopls' && go#util#has_job() + return go#lsp#GetInfo() + else + return s:sync_info(0) + endif endfunction function! go#complete#Info(showstatus) abort diff --git a/autoload/go/complete_test.vim b/autoload/go/complete_test.vim index 59334d3d4c..1c9a091ff3 100644 --- a/autoload/go/complete_test.vim +++ b/autoload/go/complete_test.vim @@ -14,6 +14,12 @@ func! Test_GetInfo_guru() unlet g:go_info_mode endfunction +func! Test_GetInfo_gopls() + let g:go_info_mode = 'gopls' + call s:getinfo() + unlet g:go_info_mode +endfunction + func! s:getinfo() let l:filename = 'complete/complete.go' let l:tmp = gotest#load_fixture(l:filename) diff --git a/autoload/go/lsp.vim b/autoload/go/lsp.vim index 691a176126..554d2b8e58 100644 --- a/autoload/go/lsp.vim +++ b/autoload/go/lsp.vim @@ -542,13 +542,32 @@ function! go#lsp#Info(showstatus) let l:state = s:newHandlerState('') endif - let l:state.handleResult = funcref('s:infoDefinitionHandler', [a:showstatus], l:state) + let l:state.handleResult = funcref('s:infoDefinitionHandler', [function('s:info', [1], l:state), a:showstatus], l:state) let l:state.error = funcref('s:noop') let l:msg = go#lsp#message#Definition(l:fname, l:line, l:col) return l:lsp.sendMessage(l:msg, l:state) endfunction -function! s:infoDefinitionHandler(showstatus, msg) abort dict +function! go#lsp#GetInfo() + let l:fname = expand('%:p') + let [l:line, l:col] = getpos('.')[1:2] + + call go#lsp#DidChange(l:fname) + + let l:lsp = s:lspfactory.get() + + let l:state = s:newHandlerState('') + + let l:info = go#promise#New(function('s:info', [0], l:state), 10000, '') + + let l:state.handleResult = funcref('s:infoDefinitionHandler', [l:info.wrapper, 0], l:state) + let l:state.error = funcref('s:noop') + let l:msg = go#lsp#message#Definition(l:fname, l:line, l:col) + call l:lsp.sendMessage(l:msg, l:state) + return l:info.await() +endfunction + +function! s:infoDefinitionHandler(next, showstatus, msg) abort dict " gopls returns a []Location; just take the first one. let l:msg = a:msg[0] @@ -565,12 +584,22 @@ function! s:infoDefinitionHandler(showstatus, msg) abort dict let l:state = s:newHandlerState('') endif - let l:state.handleResult = funcref('s:hoverHandler', [function('s:info', [], l:state)], l:state) + let l:state.handleResult = funcref('s:hoverHandler', [a:next], l:state) let l:state.error = funcref('s:noop') return l:lsp.sendMessage(l:msg, l:state) endfunction -function! s:info(content) abort dict +function! s:info(show, content) abort dict + let l:content = s:infoFromHoverContent(a:content) + + if a:show + call go#util#ShowInfo(l:content) + endif + + return l:content +endfunction + +function! s:infoFromHoverContent(content) abort let l:content = a:content[0] " strip godoc summary @@ -580,7 +609,8 @@ function! s:info(content) abort dict if l:content =~# '^type [^ ]\+ \(struct\|interface\)' let l:content = substitute(l:content, '{.*', '', '') endif - call go#util#ShowInfo(l:content) + + return l:content endfunction " restore Vi compatibility settings