mirror of
1
0
Fork 0
ultimate-vim/sources_non_forked/vim-go/autoload/go/complete.vim

295 lines
7.5 KiB
VimL
Raw Normal View History

2018-12-17 06:28:27 -05:00
" don't spam the user when Vim is started in Vi compatibility mode
let s:cpo_save = &cpo
set cpo&vim
2018-03-31 10:56:26 -04:00
function! s:gocodeCommand(cmd, args) abort
2018-11-01 06:03:42 -04:00
let l:gocode_bin = "gocode"
let l:gomod = go#util#gomod()
if filereadable(l:gomod)
let l:gocode_bin = "gocode-gomod"
endif
let bin_path = go#path#CheckBinPath(l:gocode_bin)
2016-06-26 07:12:36 -04:00
if empty(bin_path)
2018-03-31 10:56:26 -04:00
return []
2016-06-26 07:12:36 -04:00
endif
2018-06-14 06:31:12 -04:00
let socket_type = go#config#GocodeSocketType()
2018-03-31 10:56:26 -04:00
let cmd = [bin_path]
let cmd = extend(cmd, ['-sock', socket_type])
let cmd = extend(cmd, ['-f', 'vim'])
2018-09-24 20:40:17 -04:00
if go#config#GocodeProposeBuiltins()
let cmd = extend(cmd, ['-builtin'])
endif
if go#config#GocodeProposeSource()
let cmd = extend(cmd, ['-source'])
2018-12-17 06:28:27 -05:00
else
let cmd = extend(cmd, ['-fallback-to-source', '-cache'])
2018-09-24 20:40:17 -04:00
endif
2018-11-01 06:03:42 -04:00
if go#config#GocodeUnimportedPackages()
let cmd = extend(cmd, ['-unimported-packages'])
endif
2018-03-31 10:56:26 -04:00
let cmd = extend(cmd, [a:cmd])
let cmd = extend(cmd, a:args)
return cmd
endfunction
function! s:sync_gocode(cmd, args, input) abort
" We might hit cache problems, as gocode doesn't handle different GOPATHs
" well. See: https://github.com/nsf/gocode/issues/239
2016-11-09 12:22:55 -05:00
let old_goroot = $GOROOT
let $GOROOT = go#util#env("goroot")
2016-06-26 07:12:36 -04:00
try
2018-03-31 10:56:26 -04:00
let cmd = s:gocodeCommand(a:cmd, a:args)
" gocode can sometimes be slow, so redraw now to avoid waiting for gocode
" to return before redrawing automatically.
redraw
let [l:result, l:err] = go#util#Exec(cmd, a:input)
finally
let $GOROOT = old_goroot
endtry
2016-11-09 12:22:55 -05:00
2018-03-31 10:56:26 -04:00
if l:err != 0
return "[0, []]"
endif
if &encoding != 'utf-8'
let l:result = iconv(l:result, 'utf-8', &encoding)
2016-06-26 07:12:36 -04:00
endif
2014-10-31 17:30:24 -04:00
2018-03-31 10:56:26 -04:00
return l:result
2016-06-11 09:56:50 -04:00
endfunction
2016-12-27 09:46:49 -05:00
function! s:gocodeAutocomplete() abort
2018-03-31 10:56:26 -04:00
" use the offset as is, because the cursor position is the position for
" which autocomplete candidates are needed.
return s:sync_gocode('autocomplete',
\ [expand('%:p'), go#util#OffsetCursor()],
\ go#util#GetLines())
2016-06-11 09:56:50 -04:00
endfunction
2014-10-31 17:30:24 -04:00
2018-03-31 10:56:26 -04:00
" go#complete#GoInfo returns the description of the identifier under the
" cursor.
2016-12-27 09:46:49 -05:00
function! go#complete#GetInfo() abort
2018-03-31 10:56:26 -04:00
return s:sync_info(0)
endfunction
2018-09-24 20:40:17 -04:00
function! go#complete#Info(showstatus) abort
2018-06-14 06:31:12 -04:00
if go#util#has_job(1)
2018-09-24 20:40:17 -04:00
return s:async_info(1, a:showstatus)
2018-03-31 10:56:26 -04:00
else
2018-08-25 12:13:42 -04:00
return s:sync_info(1)
2018-03-31 10:56:26 -04:00
endif
endfunction
2018-09-24 20:40:17 -04:00
function! s:async_info(echo, showstatus)
let state = {'echo': a:echo}
2018-03-31 10:56:26 -04:00
2018-09-24 20:40:17 -04:00
function! s:complete(job, exit_status, messages) abort dict
if a:exit_status != 0
return
2018-03-31 10:56:26 -04:00
endif
2018-09-24 20:40:17 -04:00
if &encoding != 'utf-8'
let i = 0
while i < len(a:messages)
let a:messages[i] = iconv(a:messages[i], 'utf-8', &encoding)
let i += 1
endwhile
2018-03-31 10:56:26 -04:00
endif
2018-09-24 20:40:17 -04:00
let result = s:info_filter(self.echo, join(a:messages, "\n"))
2018-08-25 12:13:42 -04:00
call s:info_complete(self.echo, result)
2018-03-31 10:56:26 -04:00
endfunction
2018-09-24 20:40:17 -04:00
" explicitly bind complete to state so that within it, self will
" always refer to state. See :help Partial for more information.
let state.complete = function('s:complete', [], state)
2018-03-31 10:56:26 -04:00
" add 1 to the offset, so that the position at the cursor will be included
" in gocode's search
2016-06-26 07:12:36 -04:00
let offset = go#util#OffsetCursor()+1
2018-03-31 10:56:26 -04:00
" We might hit cache problems, as gocode doesn't handle different GOPATHs
" well. See: https://github.com/nsf/gocode/issues/239
let env = {
\ "GOROOT": go#util#env("goroot")
\ }
2018-09-24 20:40:17 -04:00
let opts = {
\ 'bang': 1,
\ 'complete': state.complete,
\ 'for': '_',
\ }
if a:showstatus
let opts.statustype = 'gocode'
endif
let opts = go#job#Options(l:opts)
2018-03-31 10:56:26 -04:00
let cmd = s:gocodeCommand('autocomplete',
2016-06-26 07:12:36 -04:00
\ [expand('%:p'), offset])
2018-09-24 20:40:17 -04:00
" TODO(bc): Don't write the buffer to a file; pass the buffer directly to
2018-03-31 10:56:26 -04:00
" gocode's stdin. It shouldn't be necessary to use {in_io: 'file', in_name:
" s:gocodeFile()}, but unfortunately {in_io: 'buffer', in_buf: bufnr('%')}
2018-09-24 20:40:17 -04:00
" doesn't work.
call extend(opts, {
2018-03-31 10:56:26 -04:00
\ 'env': env,
\ 'in_io': 'file',
\ 'in_name': s:gocodeFile(),
2018-09-24 20:40:17 -04:00
\ })
2016-06-26 07:12:36 -04:00
2018-09-24 20:40:17 -04:00
call go#job#Start(cmd, opts)
2018-03-31 10:56:26 -04:00
endfunction
function! s:gocodeFile()
let file = tempname()
call writefile(go#util#GetLines(), file)
return file
endfunction
2018-08-25 12:13:42 -04:00
function! s:sync_info(echo)
2018-03-31 10:56:26 -04:00
" add 1 to the offset, so that the position at the cursor will be included
" in gocode's search
let offset = go#util#OffsetCursor()+1
let result = s:sync_gocode('autocomplete',
\ [expand('%:p'), offset],
\ go#util#GetLines())
2018-08-25 12:13:42 -04:00
let result = s:info_filter(a:echo, result)
return s:info_complete(a:echo, result)
2018-03-31 10:56:26 -04:00
endfunction
2018-08-25 12:13:42 -04:00
function! s:info_filter(echo, result) abort
2018-03-31 10:56:26 -04:00
if empty(a:result)
2015-01-18 07:58:28 -05:00
return ""
2016-06-26 07:12:36 -04:00
endif
2018-03-31 10:56:26 -04:00
let l:result = eval(a:result)
if len(l:result) != 2
return ""
2016-06-26 07:12:36 -04:00
endif
2018-03-31 10:56:26 -04:00
let l:candidates = l:result[1]
if len(l:candidates) == 1
" When gocode panics in vim mode, it returns
" [0, [{'word': 'PANIC', 'abbr': 'PANIC PANIC PANIC', 'info': 'PANIC PANIC PANIC'}]]
2018-08-25 12:13:42 -04:00
if a:echo && l:candidates[0].info ==# "PANIC PANIC PANIC"
2018-03-31 10:56:26 -04:00
return ""
endif
return l:candidates[0].info
endif
2016-06-26 07:12:36 -04:00
2018-03-31 10:56:26 -04:00
let filtered = []
2016-06-26 07:12:36 -04:00
let wordMatch = '\<' . expand("<cword>") . '\>'
" escape single quotes in wordMatch before passing it to filter
let wordMatch = substitute(wordMatch, "'", "''", "g")
2018-03-31 10:56:26 -04:00
let filtered = filter(l:candidates, "v:val.info =~ '".wordMatch."'")
2016-06-26 07:12:36 -04:00
2019-03-08 06:04:56 -05:00
if len(l:filtered) == 0
return "no matches"
elseif len(l:filtered) > 1
return "ambiguous match"
2016-06-26 07:12:36 -04:00
endif
2018-03-31 10:56:26 -04:00
return l:filtered[0].info
2014-10-31 17:30:24 -04:00
endfunction
2018-08-25 12:13:42 -04:00
function! s:info_complete(echo, result) abort
2019-03-08 06:04:56 -05:00
if a:echo
call go#util#ShowInfo(a:result)
2016-06-26 07:12:36 -04:00
endif
2018-08-25 12:13:42 -04:00
return a:result
2015-01-18 07:58:28 -05:00
endfunction
2014-10-31 17:30:24 -04:00
2016-12-27 09:46:49 -05:00
function! s:trim_bracket(val) abort
2016-06-26 07:12:36 -04:00
let a:val.word = substitute(a:val.word, '[(){}\[\]]\+$', '', '')
return a:val
2015-03-14 16:02:10 -04:00
endfunction
2019-03-27 11:08:56 -04:00
let s:completions = []
function! go#complete#GocodeComplete(findstart, base) abort
2016-06-26 07:12:36 -04:00
"findstart = 1 when we need to get the text length
if a:findstart == 1
2019-03-27 11:08:56 -04:00
let l:completions = []
execute "silent let l:completions = " . s:gocodeAutocomplete()
if len(l:completions) == 0 || len(l:completions) >= 2 && len(l:completions[1]) == 0
" no matches. cancel and leave completion mode.
call go#util#EchoInfo("no matches")
return -3
endif
let s:completions = l:completions[1]
return col('.') - l:completions[0] - 1
2016-06-26 07:12:36 -04:00
"findstart = 0 when we need to return the list of completions
else
let s = getline(".")[col('.') - 1]
if s =~ '[(){}\{\}]'
2018-03-31 10:56:26 -04:00
return map(copy(s:completions[1]), 's:trim_bracket(v:val)')
2014-10-31 17:30:24 -04:00
endif
2018-03-31 10:56:26 -04:00
return s:completions[1]
2016-06-26 07:12:36 -04:00
endif
2018-03-31 10:56:26 -04:00
endfunction
2014-10-31 17:30:24 -04:00
2019-03-27 11:08:56 -04:00
function! go#complete#Complete(findstart, base) abort
let l:state = {'done': 0, 'matches': []}
function! s:handler(state, matches) abort dict
let a:state.matches = a:matches
let a:state.done = 1
endfunction
"findstart = 1 when we need to get the start of the match
if a:findstart == 1
call go#lsp#Completion(expand('%:p'), line('.'), col('.'), funcref('s:handler', [l:state]))
while !l:state.done
sleep 10m
endwhile
let s:completions = l:state.matches
if len(l:state.matches) == 0
" no matches. cancel and leave completion mode.
call go#util#EchoInfo("no matches")
return -3
endif
return col('.')
else "findstart = 0 when we need to return the list of completions
return s:completions
endif
endfunction
2016-12-27 09:46:49 -05:00
function! go#complete#ToggleAutoTypeInfo() abort
2018-06-14 06:31:12 -04:00
if go#config#AutoTypeInfo()
call go#config#SetAutoTypeInfo(0)
2016-08-02 08:48:32 -04:00
call go#util#EchoProgress("auto type info disabled")
return
end
2018-06-14 06:31:12 -04:00
call go#config#SetAutoTypeInfo(1)
2016-08-02 08:48:32 -04:00
call go#util#EchoProgress("auto type info enabled")
endfunction
2018-12-17 06:28:27 -05:00
" restore Vi compatibility settings
let &cpo = s:cpo_save
unlet s:cpo_save
2016-06-26 07:12:36 -04:00
" vim: sw=2 ts=2 et