mirror of
https://github.com/amix/vimrc
synced 2025-06-16 09:35:01 +08:00
plugins update
This commit is contained in:
@ -1,5 +1,8 @@
|
||||
### What did you do? (required. The issue will be **closed** when not provided.)
|
||||
### What did you do? (required: The issue will be **closed** when not provided)
|
||||
|
||||
<!--
|
||||
If possible, please provide clear steps for reproducing the problem.
|
||||
-->
|
||||
|
||||
### What did you expect to happen?
|
||||
|
||||
@ -9,13 +12,18 @@
|
||||
|
||||
### Configuration (**MUST** fill this out):
|
||||
|
||||
* vim-go version:
|
||||
#### vim-go version:
|
||||
|
||||
* `vimrc` you used to reproduce (use a *minimal* vimrc with other plugins disabled; do not link to a 2,000 line vimrc):
|
||||
#### `vimrc` you used to reproduce (use a *minimal* vimrc with other plugins disabled; do not link to a 2,000 line vimrc):
|
||||
<details><summary>vimrc</summary><br><pre>
|
||||
|
||||
* Vim version (first three lines from `:version`):
|
||||
</pre></details>
|
||||
|
||||
* Go version (`go version`):
|
||||
#### Vim version (first three lines from `:version`):
|
||||
|
||||
* Go environment (`go env`):
|
||||
#### Go version (`go version`):
|
||||
|
||||
#### Go environment
|
||||
<details><summary><code>go env</code> Output:</summary><br><pre>
|
||||
|
||||
</pre></details>
|
||||
|
@ -1,11 +1,50 @@
|
||||
## unplanned
|
||||
|
||||
IMPROVEMENTS:
|
||||
* Add a new option, `g:go_code_completion_enabled`, to control whether omnifunc
|
||||
is set.
|
||||
[[GH-2229]](https://github.com/fatih/vim-go/pull/2229)
|
||||
* Use build tags with golangci-lint.
|
||||
[[GH-2261]](https://github.com/fatih/vim-go/pull/2261)
|
||||
* Allow debugging of packages outside of GOPATH without a go.mod file.
|
||||
[[GH-2269]](https://github.com/fatih/vim-go/pull/2269)
|
||||
* Show which example failed when Example tests fail
|
||||
[[GH-2277]](https://github.com/fatih/vim-go/pull/2277)
|
||||
* Show function signature and return types in preview window when autocompleting functions and methods.
|
||||
[[GH-2289]](https://github.com/fatih/vim-go/pull/2289)
|
||||
|
||||
|
||||
BUG FIXES:
|
||||
* display info about function and function types whose parameters are
|
||||
`interface{}` without truncating the function signature.
|
||||
[[GH-2244]](https://github.com/fatih/vim-go/pull/2244)
|
||||
* install tools that require GOPATH mode when in module mode.
|
||||
[[GH-2253]](https://github.com/fatih/vim-go/pull/2253)
|
||||
* Detect GOPATH when starting `gopls`
|
||||
[[GH-2255]](https://github.com/fatih/vim-go/pull/2255)
|
||||
* Handle `gopls` responses in the same window from which the respective request
|
||||
originated.
|
||||
[[GH-2266]](https://github.com/fatih/vim-go/pull/2266)
|
||||
* Show completion matches from gocode.
|
||||
[[GH-2267]](https://github.com/fatih/vim-go/pull/2267)
|
||||
* Show the completion preview window.
|
||||
[[GH-2268]](https://github.com/fatih/vim-go/pull/2268)
|
||||
* Set the anchor for method documentation correctly.
|
||||
[[GH-2276]](https://github.com/fatih/vim-go/pull/2276)
|
||||
* Respect the LSP information for determining where candidate matches start.
|
||||
[[GH-2291]](https://github.com/fatih/vim-go/pull/2291)
|
||||
* Restore environment variables with backslashes correctly.
|
||||
[[GH-2292]](https://github.com/fatih/vim-go/pull/2292)
|
||||
|
||||
## 1.20 - (April 22, 2019)
|
||||
|
||||
FEATURES:
|
||||
* ***gopls support!***
|
||||
* use gopls for autocompletion by default in Vim8 and Neovim.
|
||||
* use gopls for `:GoDef` by setting `g:go_def_mode='gopls'`.
|
||||
* use gopls for `:GoInfo` by setting `g:go_info_mode='gopls'`.
|
||||
* Add support for golangci-lint.
|
||||
* set `g:go_metalinter_command='golanci-lint'` to use golangci-lint instead
|
||||
* set `g:go_metalinter_command='golangci-lint'` to use golangci-lint instead
|
||||
of gometalinter.
|
||||
* New `:GoDefType` command to jump to a type definition from an instance of the
|
||||
type.
|
||||
@ -60,6 +99,19 @@ IMPROVEMENTS:
|
||||
[[GH-2172]](https://github.com/fatih/vim-go/pull/2172)
|
||||
* Add support for golangci-lint.
|
||||
[[GH-2182]](https://github.com/fatih/vim-go/pull/2182)
|
||||
* Show hover balloon using gopls instead of gocode.
|
||||
[[GH-2202]](https://github.com/fatih/vim-go/pull/2202)
|
||||
* Add a new option, `g:go_debug_log_output`, to control logging with the
|
||||
debugger.
|
||||
[[GH-2203]](https://github.com/fatih/vim-go/pull/2203)
|
||||
* Do not jump to quickfix or location list window when bang is used for async
|
||||
jobs or linting.
|
||||
[[GH-2205]](https://github.com/fatih/vim-go/pull/2205)
|
||||
* Tab complete package names for commands from vendor directories and in
|
||||
modules.
|
||||
[[GH-2213]](https://github.com/fatih/vim-go/pull/2213)
|
||||
* Add support for `gopls` to `g:go_info_mode`.
|
||||
[[GH-2224]](https://github.com/fatih/vim-go/pull/2224)
|
||||
|
||||
BUG FIXES:
|
||||
* Fix opening of non-existent file from `:GoDeclsDir` when the current
|
||||
@ -93,6 +145,10 @@ BUG FIXES:
|
||||
[[GH-2189]](https://github.com/fatih/vim-go/pull/2189)
|
||||
* Highlight pre-release and metadata in versions in go.mod.
|
||||
[[GH-2192]](https://github.com/fatih/vim-go/pull/2192)
|
||||
* Handle runtime panics from `:GoRun` when using Neovim's terminal.
|
||||
[[GH-2209]](https://github.com/fatih/vim-go/pull/2209)
|
||||
* Fix adding tag option when a tag is added.
|
||||
[[GH-2227]](https://github.com/fatih/vim-go/pull/2227)
|
||||
|
||||
## 1.19 - (November 4, 2018)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM golang:1.12.1
|
||||
FROM golang:1.12.4
|
||||
|
||||
RUN apt-get update -y && \
|
||||
apt-get install -y build-essential curl git libncurses5-dev python3-pip && \
|
||||
|
@ -115,7 +115,7 @@ function! go#cmd#RunTerm(bang, mode, files) abort
|
||||
else
|
||||
let cmd .= go#util#Shelljoin(map(copy(a:files), "expand(v:val)"), 1)
|
||||
endif
|
||||
call go#term#newmode(a:bang, cmd, a:mode)
|
||||
call go#term#newmode(a:bang, cmd, s:runerrorformat(), a:mode)
|
||||
endfunction
|
||||
|
||||
" Run runs the current file (and their dependencies if any) and outputs it.
|
||||
@ -167,21 +167,25 @@ function! go#cmd#Run(bang, ...) abort
|
||||
let l:listtype = go#list#Type("GoRun")
|
||||
|
||||
try
|
||||
|
||||
" backup user's errorformat, will be restored once we are finished
|
||||
let l:old_errorformat = &errorformat
|
||||
let &errorformat = s:runerrorformat()
|
||||
if l:listtype == "locationlist"
|
||||
exe 'lmake!'
|
||||
else
|
||||
exe 'make!'
|
||||
endif
|
||||
finally
|
||||
"restore errorformat
|
||||
let &errorformat = l:old_errorformat
|
||||
let &makeprg = default_makeprg
|
||||
endtry
|
||||
|
||||
let items = go#list#Get(l:listtype)
|
||||
let errors = go#util#FilterValids(items)
|
||||
let l:errors = go#list#Get(l:listtype)
|
||||
|
||||
call go#list#Populate(l:listtype, errors, &makeprg)
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !empty(errors) && !a:bang
|
||||
call go#list#Window(l:listtype, len(l:errors))
|
||||
if !empty(l:errors) && !a:bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endif
|
||||
|
||||
@ -278,6 +282,12 @@ function! go#cmd#Generate(bang, ...) abort
|
||||
|
||||
endfunction
|
||||
|
||||
function! s:runerrorformat()
|
||||
let l:panicaddress = "%\\t%#%f:%l +0x%[0-9A-Fa-f]%\\+"
|
||||
let l:errorformat = '%A' . l:panicaddress . "," . &errorformat
|
||||
return l:errorformat
|
||||
endfunction
|
||||
|
||||
" ---------------------
|
||||
" | Vim job callbacks |
|
||||
" ---------------------
|
||||
|
@ -93,22 +93,6 @@ endfunction
|
||||
function! s:async_info(echo, showstatus)
|
||||
let state = {'echo': a:echo}
|
||||
|
||||
function! s:complete(job, exit_status, messages) abort dict
|
||||
if a:exit_status != 0
|
||||
return
|
||||
endif
|
||||
|
||||
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
|
||||
endif
|
||||
|
||||
let result = s:info_filter(self.echo, join(a:messages, "\n"))
|
||||
call s:info_complete(self.echo, result)
|
||||
endfunction
|
||||
" 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)
|
||||
@ -151,6 +135,23 @@ function! s:async_info(echo, showstatus)
|
||||
call go#job#Start(cmd, opts)
|
||||
endfunction
|
||||
|
||||
function! s:complete(job, exit_status, messages) abort dict
|
||||
if a:exit_status != 0
|
||||
return
|
||||
endif
|
||||
|
||||
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
|
||||
endif
|
||||
|
||||
let result = s:info_filter(self.echo, join(a:messages, "\n"))
|
||||
call s:info_complete(self.echo, result)
|
||||
endfunction
|
||||
|
||||
function! s:gocodeFile()
|
||||
let file = tempname()
|
||||
call writefile(go#util#GetLines(), file)
|
||||
@ -241,15 +242,15 @@ function! go#complete#GocodeComplete(findstart, base) abort
|
||||
if s =~ '[(){}\{\}]'
|
||||
return map(copy(s:completions[1]), 's:trim_bracket(v:val)')
|
||||
endif
|
||||
|
||||
return s:completions[1]
|
||||
return s:completions
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! go#complete#Complete(findstart, base) abort
|
||||
let l:state = {'done': 0, 'matches': []}
|
||||
let l:state = {'done': 0, 'matches': [], 'start': -1}
|
||||
|
||||
function! s:handler(state, matches) abort dict
|
||||
function! s:handler(state, start, matches) abort dict
|
||||
let a:state.start = a:start
|
||||
let a:state.matches = a:matches
|
||||
let a:state.done = 1
|
||||
endfunction
|
||||
@ -262,15 +263,16 @@ function! go#complete#Complete(findstart, base) abort
|
||||
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('.')
|
||||
let s:completions = l:state.matches
|
||||
|
||||
return l:state.start
|
||||
|
||||
else "findstart = 0 when we need to return the list of completions
|
||||
return s:completions
|
||||
endif
|
||||
|
@ -48,7 +48,7 @@ function! go#config#TermMode() abort
|
||||
endfunction
|
||||
|
||||
function! go#config#TermEnabled() abort
|
||||
return get(g:, 'go_term_enabled', 0)
|
||||
return has('nvim') && get(g:, 'go_term_enabled', 0)
|
||||
endfunction
|
||||
|
||||
function! go#config#SetTermEnabled(value) abort
|
||||
@ -210,6 +210,10 @@ function! go#config#DebugCommands() abort
|
||||
return g:go_debug_commands
|
||||
endfunction
|
||||
|
||||
function! go#config#DebugLogOutput() abort
|
||||
return get(g:, 'go_debug_log_output', 'debugger, rpc')
|
||||
endfunction
|
||||
|
||||
function! go#config#LspLog() abort
|
||||
" make sure g:go_lsp_log is set so that it can be added to easily.
|
||||
let g:go_lsp_log = get(g:, 'go_lsp_log', [])
|
||||
@ -462,6 +466,10 @@ function! go#config#EchoGoInfo() abort
|
||||
return get(g:, "go_echo_go_info", 1)
|
||||
endfunction
|
||||
|
||||
function! go#config#CodeCompletionEnabled() abort
|
||||
return get(g:, "go_code_completion_enabled", 1)
|
||||
endfunction
|
||||
|
||||
" Set the default value. A value of "1" is a shortcut for this, for
|
||||
" compatibility reasons.
|
||||
if exists("g:go_gorename_prefill") && g:go_gorename_prefill == 1
|
||||
|
@ -12,7 +12,6 @@ if !exists('s:state')
|
||||
\ 'localVars': {},
|
||||
\ 'functionArgs': {},
|
||||
\ 'message': [],
|
||||
\ 'is_test': 0,
|
||||
\}
|
||||
|
||||
if go#util#HasDebug('debugger-state')
|
||||
@ -282,7 +281,7 @@ function! go#debug#Stop() abort
|
||||
silent! exe bufwinnr(bufnr('__GODEBUG_OUTPUT__')) 'wincmd c'
|
||||
|
||||
if has('balloon_eval')
|
||||
let &noballooneval=s:ballooneval
|
||||
let &ballooneval=s:ballooneval
|
||||
let &balloonexpr=s:balloonexpr
|
||||
endif
|
||||
|
||||
@ -507,7 +506,7 @@ function! s:out_cb(ch, msg) abort
|
||||
if has('nvim')
|
||||
let s:state['data'] = []
|
||||
let l:state = {'databuf': ''}
|
||||
|
||||
|
||||
" explicitly bind callback to state so that within it, self will
|
||||
" always refer to state. See :help Partial for more information.
|
||||
let l:state.on_data = function('s:on_data', [], l:state)
|
||||
@ -589,50 +588,41 @@ function! go#debug#Start(is_test, ...) abort
|
||||
endif
|
||||
|
||||
try
|
||||
if len(a:000) > 0
|
||||
let l:pkgname = a:1
|
||||
if l:pkgname[0] == '.'
|
||||
let l:pkgname = go#package#FromPath(l:pkgname)
|
||||
endif
|
||||
else
|
||||
let l:pkgname = go#package#FromPath(getcwd())
|
||||
endif
|
||||
|
||||
if l:pkgname is -1
|
||||
call go#util#EchoError('could not determine package name')
|
||||
return
|
||||
endif
|
||||
|
||||
" cd in to test directory; this is also what running "go test" does.
|
||||
if a:is_test
|
||||
" TODO(bc): Either remove this if it's ok to do so or else record it and
|
||||
" reset cwd after the job completes.
|
||||
lcd %:p:h
|
||||
endif
|
||||
|
||||
let s:state.is_test = a:is_test
|
||||
|
||||
let l:args = []
|
||||
if len(a:000) > 1
|
||||
let l:args = ['--'] + a:000[1:]
|
||||
endif
|
||||
|
||||
let l:cmd = [
|
||||
\ dlv,
|
||||
\ (a:is_test ? 'test' : 'debug'),
|
||||
\ l:pkgname,
|
||||
\]
|
||||
|
||||
" append the package when it's given.
|
||||
if len(a:000) > 0
|
||||
let l:pkgname = go#package#FromPath(a:1)
|
||||
if l:pkgname is -1
|
||||
call go#util#EchoError('could not determine package name')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:cmd += [l:pkgname]
|
||||
endif
|
||||
|
||||
let l:cmd += [
|
||||
\ '--output', tempname(),
|
||||
\ '--headless',
|
||||
\ '--api-version', '2',
|
||||
\ '--log', '--log-output', 'debugger,rpc',
|
||||
\ '--listen', go#config#DebugAddress(),
|
||||
\]
|
||||
let l:debugLogOutput = go#config#DebugLogOutput()
|
||||
if l:debugLogOutput != ''
|
||||
let cmd += ['--log', '--log-output', l:debugLogOutput]
|
||||
endif
|
||||
|
||||
let buildtags = go#config#BuildTags()
|
||||
let l:buildtags = go#config#BuildTags()
|
||||
if buildtags isnot ''
|
||||
let l:cmd += ['--build-flags', '--tags=' . buildtags]
|
||||
endif
|
||||
let l:cmd += l:args
|
||||
|
||||
if len(a:000) > 1
|
||||
let l:cmd += ['--'] + a:000[1:]
|
||||
endif
|
||||
|
||||
let s:state['message'] = []
|
||||
let l:opts = {
|
||||
|
@ -31,8 +31,12 @@ function! go#doc#OpenBrowser(...) abort
|
||||
|
||||
let godoc_url = go#config#DocUrl()
|
||||
let godoc_url .= "/" . import
|
||||
if decl !~ "^package"
|
||||
let godoc_url .= "#" . name
|
||||
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)
|
||||
|
@ -246,7 +246,7 @@ function! go#guru#DescribeInfo(showstatus) abort
|
||||
\ 'selected': -1,
|
||||
\ 'needs_scope': 0,
|
||||
\ 'custom_parse': function('s:info'),
|
||||
\ 'disable_progress': 1,
|
||||
\ 'disable_progress': a:showstatus == 0,
|
||||
\ }
|
||||
|
||||
call s:run_guru(args)
|
||||
|
@ -5,7 +5,7 @@ set cpo&vim
|
||||
let s:templatepath = go#util#Join(expand('<sfile>:p:h:h:h'), '.github', 'ISSUE_TEMPLATE.md')
|
||||
|
||||
function! go#issue#New() abort
|
||||
let body = go#uriEncode(s:issuebody())
|
||||
let body = go#uri#Encode(s:issuebody())
|
||||
let url = "https://github.com/fatih/vim-go/issues/new?body=" . l:body
|
||||
call go#util#OpenBrowser(l:url)
|
||||
endfunction
|
||||
|
@ -214,7 +214,9 @@ function! go#job#Options(args)
|
||||
" the job was started.
|
||||
if self.winid == l:winid
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !self.bang
|
||||
if self.bang
|
||||
call win_gotoid(l:winid)
|
||||
else
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endif
|
||||
endif
|
||||
@ -489,7 +491,9 @@ function! s:neocb(mode, ch, buf, data, callback)
|
||||
|
||||
let l:buf = ''
|
||||
|
||||
" a single empty string means EOF was reached.
|
||||
" A single empty string means EOF was reached. The first item will never be
|
||||
" an empty string except for when it's the only item and is signaling that
|
||||
" EOF was reached.
|
||||
if len(a:data) == 1 && a:data[0] == ''
|
||||
" when there's nothing buffered, return early so that an
|
||||
" erroneous message will not be added.
|
||||
|
@ -86,15 +86,18 @@ function! go#lint#Gometa(bang, autosave, ...) abort
|
||||
call go#list#Clean(l:listtype)
|
||||
echon "vim-go: " | echohl Function | echon "[metalinter] PASS" | echohl None
|
||||
else
|
||||
let l:winid = win_getid(winnr())
|
||||
" Parse and populate our location list
|
||||
call go#list#ParseFormat(l:listtype, errformat, split(out, "\n"), 'GoMetaLinter')
|
||||
|
||||
let errors = go#list#Get(l:listtype)
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
|
||||
if !a:autosave && !a:bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
if a:autosave || a:bang
|
||||
call win_gotoid(l:winid)
|
||||
return
|
||||
endif
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@ -112,13 +115,18 @@ function! go#lint#Golint(bang, ...) abort
|
||||
return
|
||||
endif
|
||||
|
||||
let l:winid = win_getid(winnr())
|
||||
let l:listtype = go#list#Type("GoLint")
|
||||
call go#list#Parse(l:listtype, l:out, "GoLint")
|
||||
let l:errors = go#list#Get(l:listtype)
|
||||
call go#list#Window(l:listtype, len(l:errors))
|
||||
if !a:bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
|
||||
if a:bang
|
||||
call win_gotoid(l:winid)
|
||||
return
|
||||
endif
|
||||
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endfunction
|
||||
|
||||
" Vet calls 'go vet' on the current directory. Any warnings are populated in
|
||||
@ -138,12 +146,15 @@ function! go#lint#Vet(bang, ...) abort
|
||||
|
||||
let l:listtype = go#list#Type("GoVet")
|
||||
if l:err != 0
|
||||
let l:winid = win_getid(winnr())
|
||||
let errorformat = "%-Gexit status %\\d%\\+," . &errorformat
|
||||
call go#list#ParseFormat(l:listtype, l:errorformat, out, "GoVet")
|
||||
let errors = go#list#Get(l:listtype)
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !empty(errors) && !a:bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
else
|
||||
call win_gotoid(l:winid)
|
||||
endif
|
||||
else
|
||||
call go#list#Clean(l:listtype)
|
||||
@ -171,6 +182,7 @@ function! go#lint#Errcheck(bang, ...) abort
|
||||
|
||||
let l:listtype = go#list#Type("GoErrCheck")
|
||||
if l:err != 0
|
||||
let l:winid = win_getid(winnr())
|
||||
let errformat = "%f:%l:%c:\ %m, %f:%l:%c\ %#%m"
|
||||
|
||||
" Parse and populate our location list
|
||||
@ -187,6 +199,8 @@ function! go#lint#Errcheck(bang, ...) abort
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !a:bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
else
|
||||
call win_gotoid(l:winid)
|
||||
endif
|
||||
endif
|
||||
else
|
||||
@ -255,11 +269,13 @@ function! s:golangcilintcmd(bin_path)
|
||||
let cmd = [a:bin_path]
|
||||
let cmd += ["run"]
|
||||
let cmd += ["--print-issued-lines=false"]
|
||||
let cmd += ['--build-tags', go#config#BuildTags()]
|
||||
let cmd += ["--disable-all"]
|
||||
" do not use the default exclude patterns, because doing so causes golint
|
||||
" problems about missing doc strings to be ignored and other things that
|
||||
" golint identifies.
|
||||
let cmd += ["--exclude-use-default=false"]
|
||||
|
||||
return cmd
|
||||
endfunction
|
||||
|
||||
|
@ -7,8 +7,7 @@ scriptencoding utf-8
|
||||
let s:lspfactory = {}
|
||||
|
||||
function! s:lspfactory.get() dict abort
|
||||
if !has_key(self, 'current')
|
||||
" TODO(bc): check that the lsp is still running.
|
||||
if !has_key(self, 'current') || empty(self.current)
|
||||
let self.current = s:newlsp()
|
||||
endif
|
||||
|
||||
@ -21,7 +20,7 @@ function! s:lspfactory.reset() dict abort
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:newlsp()
|
||||
function! s:newlsp() abort
|
||||
if !go#util#has_job()
|
||||
" TODO(bc): start the server in the background using a shell that waits for the right output before returning.
|
||||
call go#util#EchoError('This feature requires either Vim 8.0.0087 or newer with +job or Neovim.')
|
||||
@ -115,16 +114,27 @@ function! s:newlsp()
|
||||
try
|
||||
let l:handler = self.handlers[l:response.id]
|
||||
|
||||
let l:winid = win_getid(winnr())
|
||||
" Always set the active window to the window that was active when
|
||||
" the request was sent. Among other things, this makes sure that
|
||||
" the correct window's location list will be populated when the
|
||||
" list type is 'location' and the user has moved windows since
|
||||
" sending the reques.
|
||||
call win_gotoid(l:handler.winid)
|
||||
|
||||
if has_key(l:response, 'error')
|
||||
call l:handler.requestComplete(0)
|
||||
call go#util#EchoError(l:response.error.message)
|
||||
if has_key(l:handler, 'error')
|
||||
call call(l:handler.error, [l:response.error.message])
|
||||
else
|
||||
call go#util#EchoError(l:response.error.message)
|
||||
endif
|
||||
call win_gotoid(l:winid)
|
||||
return
|
||||
endif
|
||||
call l:handler.requestComplete(1)
|
||||
call call(l:handler.handleResult, [l:response.result])
|
||||
call win_gotoid(l:winid)
|
||||
finally
|
||||
call remove(self.handlers, l:response.id)
|
||||
endtry
|
||||
@ -149,9 +159,19 @@ function! s:newlsp()
|
||||
if !self.last_request_id
|
||||
" TODO(bc): run a server per module and one per GOPATH? (may need to
|
||||
" keep track of servers by rootUri).
|
||||
let l:msg = self.newMessage(go#lsp#message#Initialize(getcwd()))
|
||||
let l:wd = go#util#ModuleRoot()
|
||||
if l:wd == -1
|
||||
call go#util#EchoError('could not determine appropriate working directory for gopls')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:state = s:newHandlerState('gopls')
|
||||
if l:wd == ''
|
||||
let l:wd = getcwd()
|
||||
endif
|
||||
|
||||
let l:msg = self.newMessage(go#lsp#message#Initialize(l:wd))
|
||||
|
||||
let l:state = s:newHandlerState('')
|
||||
let l:state.handleResult = funcref('self.handleInitializeResult', [], l:self)
|
||||
let self.handlers[l:msg.id] = l:state
|
||||
|
||||
@ -194,8 +214,8 @@ function! s:newlsp()
|
||||
endfunction
|
||||
|
||||
function! l:lsp.write(msg) dict abort
|
||||
let l:body = json_encode(a:msg)
|
||||
let l:data = 'Content-Length: ' . strlen(l:body) . "\r\n\r\n" . l:body
|
||||
let l:body = json_encode(a:msg)
|
||||
let l:data = 'Content-Length: ' . strlen(l:body) . "\r\n\r\n" . l:body
|
||||
|
||||
if go#util#HasDebug('lsp')
|
||||
let g:go_lsp_log = add(go#config#LspLog(), "->\n" . l:data)
|
||||
@ -251,10 +271,10 @@ function! s:newlsp()
|
||||
return l:lsp
|
||||
endfunction
|
||||
|
||||
function! s:noop()
|
||||
function! s:noop(...) abort
|
||||
endfunction
|
||||
|
||||
function! s:newHandlerState(statustype)
|
||||
function! s:newHandlerState(statustype) abort
|
||||
let l:state = {
|
||||
\ 'winid': win_getid(winnr()),
|
||||
\ 'statustype': a:statustype,
|
||||
@ -324,7 +344,7 @@ endfunction
|
||||
" 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#Definition(fname, line, col, handler)
|
||||
function! go#lsp#Definition(fname, line, col, handler) abort
|
||||
call go#lsp#DidChange(a:fname)
|
||||
|
||||
let l:lsp = s:lspfactory.get()
|
||||
@ -346,7 +366,7 @@ endfunction
|
||||
" 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#TypeDef(fname, line, col, handler)
|
||||
function! go#lsp#TypeDef(fname, line, col, handler) abort
|
||||
call go#lsp#DidChange(a:fname)
|
||||
|
||||
let l:lsp = s:lspfactory.get()
|
||||
@ -363,11 +383,15 @@ function! s:typeDefinitionHandler(next, msg) abort dict
|
||||
call call(a:next, l:args)
|
||||
endfunction
|
||||
|
||||
function! go#lsp#DidOpen(fname)
|
||||
function! go#lsp#DidOpen(fname) abort
|
||||
if get(b:, 'go_lsp_did_open', 0)
|
||||
return
|
||||
endif
|
||||
|
||||
if !filereadable(a:fname)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:lsp = s:lspfactory.get()
|
||||
let l:msg = go#lsp#message#DidOpen(fnamemodify(a:fname, ':p'), join(go#util#GetLines(), "\n") . "\n")
|
||||
let l:state = s:newHandlerState('')
|
||||
@ -377,9 +401,18 @@ function! go#lsp#DidOpen(fname)
|
||||
let b:go_lsp_did_open = 1
|
||||
endfunction
|
||||
|
||||
function! go#lsp#DidChange(fname)
|
||||
if get(b:, 'go_lsp_did_open', 0)
|
||||
return go#lsp#DidOpen(a:fname)
|
||||
function! go#lsp#DidChange(fname) abort
|
||||
" DidChange is called even when fname isn't open in a buffer (e.g. via
|
||||
" go#lsp#Info); don't report the file as open or as having changed when it's
|
||||
" not actually a buffer.
|
||||
if bufnr(a:fname) == -1
|
||||
return
|
||||
endif
|
||||
|
||||
call go#lsp#DidOpen(a:fname)
|
||||
|
||||
if !filereadable(a:fname)
|
||||
return
|
||||
endif
|
||||
|
||||
let l:lsp = s:lspfactory.get()
|
||||
@ -389,7 +422,11 @@ function! go#lsp#DidChange(fname)
|
||||
call l:lsp.sendMessage(l:msg, l:state)
|
||||
endfunction
|
||||
|
||||
function! go#lsp#DidClose(fname)
|
||||
function! go#lsp#DidClose(fname) abort
|
||||
if !filereadable(a:fname)
|
||||
return
|
||||
endif
|
||||
|
||||
if !get(b:, 'go_lsp_did_open', 0)
|
||||
return
|
||||
endif
|
||||
@ -403,7 +440,7 @@ function! go#lsp#DidClose(fname)
|
||||
let b:go_lsp_did_open = 0
|
||||
endfunction
|
||||
|
||||
function! go#lsp#Completion(fname, line, col, handler)
|
||||
function! go#lsp#Completion(fname, line, col, handler) abort
|
||||
call go#lsp#DidChange(a:fname)
|
||||
|
||||
let l:lsp = s:lspfactory.get()
|
||||
@ -417,10 +454,17 @@ endfunction
|
||||
function! s:completionHandler(next, msg) abort dict
|
||||
" gopls returns a CompletionList.
|
||||
let l:matches = []
|
||||
let l:start = -1
|
||||
|
||||
for l:item in a:msg.items
|
||||
let l:start = l:item.textEdit.range.start.character
|
||||
|
||||
let l:match = {'abbr': l:item.label, 'word': l:item.textEdit.newText, 'info': '', 'kind': go#lsp#completionitemkind#Vim(l:item.kind)}
|
||||
if has_key(l:item, 'detail')
|
||||
let l:item.info = l:item.detail
|
||||
let l:match.info = l:item.detail
|
||||
if go#lsp#completionitemkind#IsFunction(l:item.kind) || go#lsp#completionitemkind#IsMethod(l:item.kind)
|
||||
let l:match.info = printf('func %s %s', l:item.label, l:item.detail)
|
||||
endif
|
||||
endif
|
||||
|
||||
if has_key(l:item, 'documentation')
|
||||
@ -429,7 +473,7 @@ function! s:completionHandler(next, msg) abort dict
|
||||
|
||||
let l:matches = add(l:matches, l:match)
|
||||
endfor
|
||||
let l:args = [l:matches]
|
||||
let l:args = [l:start, l:matches]
|
||||
call call(a:next, l:args)
|
||||
endfunction
|
||||
|
||||
@ -437,6 +481,80 @@ function! s:completionErrorHandler(next, error) abort dict
|
||||
call call(a:next, [[]])
|
||||
endfunction
|
||||
|
||||
function! go#lsp#Hover(fname, line, col, handler) abort
|
||||
call go#lsp#DidChange(a:fname)
|
||||
|
||||
let l:lsp = s:lspfactory.get()
|
||||
let l:msg = go#lsp#message#Hover(a:fname, a:line, a:col)
|
||||
let l:state = s:newHandlerState('')
|
||||
let l:state.handleResult = funcref('s:hoverHandler', [function(a:handler, [], l:state)], l:state)
|
||||
let l:state.error = funcref('s:noop')
|
||||
call l:lsp.sendMessage(l:msg, l:state)
|
||||
endfunction
|
||||
|
||||
function! s:hoverHandler(next, msg) abort dict
|
||||
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
|
||||
|
||||
let l:args = [l:content]
|
||||
call call(a:next, l:args)
|
||||
endfunction
|
||||
|
||||
function! go#lsp#Info(showstatus)
|
||||
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()
|
||||
|
||||
if a:showstatus
|
||||
let l:state = s:newHandlerState('info')
|
||||
else
|
||||
let l:state = s:newHandlerState('')
|
||||
endif
|
||||
|
||||
let l:state.handleResult = funcref('s:infoDefinitionHandler', [function('s:info', []), a:showstatus], 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)
|
||||
endfunction
|
||||
|
||||
function! s:infoDefinitionHandler(next, showstatus, msg) abort dict
|
||||
" gopls returns a []Location; just take the first one.
|
||||
let l:msg = a:msg[0]
|
||||
|
||||
let l:fname = go#path#FromURI(l:msg.uri)
|
||||
let l:line = l:msg.range.start.line+1
|
||||
let l:col = l:msg.range.start.character+1
|
||||
|
||||
let l:lsp = s:lspfactory.get()
|
||||
let l:msg = go#lsp#message#Hover(l:fname, l:line, l:col)
|
||||
|
||||
if a:showstatus
|
||||
let l:state = s:newHandlerState('info')
|
||||
else
|
||||
let l:state = s:newHandlerState('')
|
||||
endif
|
||||
|
||||
let l:state.handleResult = funcref('s:hoverHandler', [function('s:info', [], l:state)], l:state)
|
||||
let l:state.error = funcref('s:noop')
|
||||
call l:lsp.sendMessage(l:msg, l:state)
|
||||
endfunction
|
||||
|
||||
function! s:info(content) abort dict
|
||||
let l:content = a:content[0]
|
||||
" strip off the method set and fields of structs and interfaces.
|
||||
if l:content =~# '^type [^ ]\+ \(struct\|interface\)'
|
||||
let l:content = substitute(l:content, '{.*', '', '')
|
||||
endif
|
||||
call go#util#ShowInfo(l:content)
|
||||
endfunction
|
||||
|
||||
" restore Vi compatibility settings
|
||||
let &cpo = s:cpo_save
|
||||
unlet s:cpo_save
|
||||
|
@ -28,7 +28,7 @@ let s:Event = 23
|
||||
let s:Operator = 24
|
||||
let s:TypeParameter = 25
|
||||
|
||||
function! go#lsp#completionitemkind#Vim(kind)
|
||||
function! go#lsp#completionitemkind#Vim(kind) abort
|
||||
if a:kind == s:Method || a:kind == s:Function || a:kind == s:Constructor
|
||||
return 'f'
|
||||
elseif a:kind == s:Variable || a:kind == s:Constant
|
||||
@ -40,6 +40,22 @@ function! go#lsp#completionitemkind#Vim(kind)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! go#lsp#completionitemkind#IsFunction(kind) abort
|
||||
if a:kind == s:Function
|
||||
return 1
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! go#lsp#completionitemkind#IsMethod(kind) abort
|
||||
if a:kind == s:Method
|
||||
return 1
|
||||
endif
|
||||
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
" restore Vi compatibility settings
|
||||
let &cpo = s:cpo_save
|
||||
unlet s:cpo_save
|
||||
|
@ -2,7 +2,7 @@
|
||||
let s:cpo_save = &cpo
|
||||
set cpo&vim
|
||||
|
||||
function! go#lsp#message#Initialize(wd)
|
||||
function! go#lsp#message#Initialize(wd) abort
|
||||
return {
|
||||
\ 'notification': 0,
|
||||
\ 'method': 'initialize',
|
||||
@ -11,13 +11,17 @@ function! go#lsp#message#Initialize(wd)
|
||||
\ 'rootUri': go#path#ToURI(a:wd),
|
||||
\ 'capabilities': {
|
||||
\ 'workspace': {},
|
||||
\ 'textDocument': {}
|
||||
\ 'textDocument': {
|
||||
\ 'hover': {
|
||||
\ 'contentFormat': ['plaintext'],
|
||||
\ },
|
||||
\ }
|
||||
\ }
|
||||
\ }
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
function! go#lsp#message#Definition(file, line, col)
|
||||
function! go#lsp#message#Definition(file, line, col) abort
|
||||
return {
|
||||
\ 'notification': 0,
|
||||
\ 'method': 'textDocument/definition',
|
||||
@ -30,8 +34,7 @@ function! go#lsp#message#Definition(file, line, col)
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
|
||||
function! go#lsp#message#TypeDefinition(file, line, col)
|
||||
function! go#lsp#message#TypeDefinition(file, line, col) abort
|
||||
return {
|
||||
\ 'notification': 0,
|
||||
\ 'method': 'textDocument/typeDefinition',
|
||||
@ -44,7 +47,7 @@ function! go#lsp#message#TypeDefinition(file, line, col)
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
function! go#lsp#message#DidOpen(file, content)
|
||||
function! go#lsp#message#DidOpen(file, content) abort
|
||||
return {
|
||||
\ 'notification': 1,
|
||||
\ 'method': 'textDocument/didOpen',
|
||||
@ -58,7 +61,7 @@ function! go#lsp#message#DidOpen(file, content)
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
function! go#lsp#message#DidChange(file, content)
|
||||
function! go#lsp#message#DidChange(file, content) abort
|
||||
return {
|
||||
\ 'notification': 1,
|
||||
\ 'method': 'textDocument/didChange',
|
||||
@ -75,7 +78,7 @@ function! go#lsp#message#DidChange(file, content)
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
function! go#lsp#message#DidClose(file)
|
||||
function! go#lsp#message#DidClose(file) abort
|
||||
return {
|
||||
\ 'notification': 1,
|
||||
\ 'method': 'textDocument/didClose',
|
||||
@ -87,7 +90,7 @@ function! go#lsp#message#DidClose(file)
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
function! go#lsp#message#Completion(file, line, col)
|
||||
function! go#lsp#message#Completion(file, line, col) abort
|
||||
return {
|
||||
\ 'notification': 0,
|
||||
\ 'method': 'textDocument/completion',
|
||||
@ -100,7 +103,20 @@ function! go#lsp#message#Completion(file, line, col)
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
function! s:position(line, col)
|
||||
function! go#lsp#message#Hover(file, line, col) abort
|
||||
return {
|
||||
\ 'notification': 0,
|
||||
\ 'method': 'textDocument/hover',
|
||||
\ 'params': {
|
||||
\ 'textDocument': {
|
||||
\ 'uri': go#path#ToURI(a:file)
|
||||
\ },
|
||||
\ 'position': s:position(a:line, a:col),
|
||||
\ }
|
||||
\ }
|
||||
endfunction
|
||||
|
||||
function! s:position(line, col) abort
|
||||
return {'line': a:line - 1, 'character': a:col-1}
|
||||
endfunction
|
||||
|
||||
|
@ -7,7 +7,7 @@ let s:go_major_version = ""
|
||||
function! go#mod#Format() abort
|
||||
" go mod only exists in `v1.11`
|
||||
if empty(s:go_major_version)
|
||||
let tokens = matchlist(go#util#System("go version"), '\d\+.\(\d\+\)\(\.\d\+\)\? ')
|
||||
let tokens = matchlist(go#util#Exec(['go', 'version']), '\d\+.\(\d\+\)\(\.\d\+\)\? ')
|
||||
let s:go_major_version = str2nr(tokens[1])
|
||||
endif
|
||||
|
||||
|
@ -32,7 +32,7 @@ if len(s:goarch) == 0
|
||||
endif
|
||||
endif
|
||||
|
||||
function! go#package#Paths() abort
|
||||
function! s:paths() abort
|
||||
let dirs = []
|
||||
|
||||
if !exists("s:goroot")
|
||||
@ -58,6 +58,58 @@ function! go#package#Paths() abort
|
||||
return dirs
|
||||
endfunction
|
||||
|
||||
function! s:module() abort
|
||||
let [l:out, l:err] = go#util#ExecInDir(['go', 'list', '-m', '-f', '{{.Dir}}'])
|
||||
if l:err != 0
|
||||
return {}
|
||||
endif
|
||||
let l:dir = split(l:out, '\n')[0]
|
||||
|
||||
let [l:out, l:err] = go#util#ExecInDir(['go', 'list', '-m', '-f', '{{.Path}}'])
|
||||
if l:err != 0
|
||||
return {}
|
||||
endif
|
||||
let l:path = split(l:out, '\n')[0]
|
||||
|
||||
return {'dir': l:dir, 'path': l:path}
|
||||
endfunction
|
||||
|
||||
function! s:vendordirs() abort
|
||||
let l:vendorsuffix = go#util#PathSep() . 'vendor'
|
||||
let l:module = s:module()
|
||||
if empty(l:module)
|
||||
let [l:root, l:err] = go#util#ExecInDir(['go', 'list', '-f', '{{.Root}}'])
|
||||
if l:err != 0
|
||||
return []
|
||||
endif
|
||||
let l:root = split(l:root, '\n')[0] . go#util#PathSep() . 'src'
|
||||
|
||||
let [l:dir, l:err] = go#util#ExecInDir(['go', 'list', '-f', '{{.Dir}}'])
|
||||
if l:err != 0
|
||||
return []
|
||||
endif
|
||||
let l:dir = split(l:dir, '\n')[0]
|
||||
|
||||
let l:vendordirs = []
|
||||
while l:dir != l:root
|
||||
let l:vendordir = l:dir . l:vendorsuffix
|
||||
if isdirectory(l:vendordir)
|
||||
let l:vendordirs = add(l:vendordirs, l:vendordir)
|
||||
endif
|
||||
|
||||
let l:dir = fnamemodify(l:dir, ':h')
|
||||
endwhile
|
||||
|
||||
return l:vendordirs
|
||||
endif
|
||||
|
||||
let l:vendordir = l:module.dir . l:vendorsuffix
|
||||
if !isdirectory(l:vendordir)
|
||||
return []
|
||||
endif
|
||||
return [l:vendordir]
|
||||
endfunction
|
||||
|
||||
let s:import_paths = {}
|
||||
" ImportPath returns the import path of the package for current buffer.
|
||||
function! go#package#ImportPath() abort
|
||||
@ -85,7 +137,9 @@ function! go#package#ImportPath() abort
|
||||
endfunction
|
||||
|
||||
|
||||
" FromPath returns the import path of arg.
|
||||
" go#package#FromPath returns the import path of arg. -1 is returned when arg
|
||||
" does not specify a package. -2 is returned when arg is a relative path
|
||||
" outside of GOPATH and not in a module.
|
||||
function! go#package#FromPath(arg) abort
|
||||
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd'
|
||||
let l:dir = getcwd()
|
||||
@ -104,10 +158,10 @@ function! go#package#FromPath(arg) abort
|
||||
|
||||
let l:importpath = split(l:out, '\n')[0]
|
||||
|
||||
" go list returns '_CURRENTDIRECTORY' if the directory is not inside GOPATH.
|
||||
" Check it and retun an error if that is the case
|
||||
" go list returns '_CURRENTDIRECTORY' if the directory is neither in GOPATH
|
||||
" nor in a module. Check it and retun an error if that is the case
|
||||
if l:importpath[0] ==# '_'
|
||||
return -1
|
||||
return -2
|
||||
endif
|
||||
|
||||
return l:importpath
|
||||
@ -144,33 +198,80 @@ function! go#package#Complete(ArgLead, CmdLine, CursorPos) abort
|
||||
return go#package#CompleteMembers(words[1], words[2])
|
||||
endif
|
||||
|
||||
let dirs = go#package#Paths()
|
||||
let dirs = s:paths()
|
||||
let module = s:module()
|
||||
|
||||
if len(dirs) == 0
|
||||
if len(dirs) == 0 && empty(module)
|
||||
" should not happen
|
||||
return []
|
||||
endif
|
||||
|
||||
let vendordirs = s:vendordirs()
|
||||
|
||||
let ret = {}
|
||||
for dir in dirs
|
||||
" this may expand to multiple lines
|
||||
let root = split(expand(dir . '/pkg/' . s:goos . '_' . s:goarch), "\n")
|
||||
call add(root, expand(dir . '/src'))
|
||||
for r in root
|
||||
for i in split(globpath(r, a:ArgLead.'*'), "\n")
|
||||
if isdirectory(i)
|
||||
let i .= '/'
|
||||
elseif i !~ '\.a$'
|
||||
let root = add(root, expand(dir . '/src'), )
|
||||
let root = extend(root, vendordirs)
|
||||
let root = add(root, module)
|
||||
for item in root
|
||||
" item may be a dictionary when operating in a module.
|
||||
if type(item) == type({})
|
||||
if empty(item)
|
||||
continue
|
||||
endif
|
||||
let i = substitute(substitute(i[len(r)+1:], '[\\]', '/', 'g'),
|
||||
let dir = item.dir
|
||||
let path = item.path
|
||||
else
|
||||
let dir = item
|
||||
let path = item
|
||||
endif
|
||||
|
||||
if !empty(module) && dir ==# module.dir
|
||||
if stridx(a:ArgLead, module.path) == 0
|
||||
if len(a:ArgLead) != len(module.path)
|
||||
let glob = globpath(module.dir, substitute(a:ArgLead, module.path . '/\?', '', '').'*')
|
||||
else
|
||||
let glob = module.dir
|
||||
endif
|
||||
elseif stridx(module.path, a:ArgLead) == 0 && stridx(module.path, '/', len(a:ArgLead)) < 0
|
||||
" use the module directory when a:ArgLead is contained in
|
||||
" module.path and module.path does not have any path segments after
|
||||
" a:ArgLead.
|
||||
let glob = module.dir
|
||||
else
|
||||
continue
|
||||
endif
|
||||
else
|
||||
let glob = globpath(dir, a:ArgLead.'*')
|
||||
endif
|
||||
for candidate in split(glob)
|
||||
if isdirectory(candidate)
|
||||
" TODO(bc): use wildignore instead of filtering out vendor
|
||||
" directories manually?
|
||||
if fnamemodify(candidate, ':t') == 'vendor'
|
||||
continue
|
||||
endif
|
||||
let candidate .= '/'
|
||||
elseif candidate !~ '\.a$'
|
||||
continue
|
||||
endif
|
||||
|
||||
if dir !=# path
|
||||
let candidate = substitute(candidate, '^' . dir, path, 'g')
|
||||
else
|
||||
let candidate = candidate[len(dir)+1:]
|
||||
endif
|
||||
" replace a backslash with a forward slash and drop .a suffixes
|
||||
let candidate = substitute(substitute(candidate, '[\\]', '/', 'g'),
|
||||
\ '\.a$', '', 'g')
|
||||
|
||||
" without this the result can have duplicates in form of
|
||||
" 'encoding/json' and '/encoding/json/'
|
||||
let i = go#util#StripPathSep(i)
|
||||
let candidate = go#util#StripPathSep(candidate)
|
||||
|
||||
let ret[i] = i
|
||||
let ret[candidate] = candidate
|
||||
endfor
|
||||
endfor
|
||||
endfor
|
||||
|
58
sources_non_forked/vim-go/autoload/go/package_test.vim
Normal file
58
sources_non_forked/vim-go/autoload/go/package_test.vim
Normal file
@ -0,0 +1,58 @@
|
||||
" don't spam the user when Vim is started in Vi compatibility mode
|
||||
let s:cpo_save = &cpo
|
||||
set cpo&vim
|
||||
|
||||
func! Test_Complete_GOPATH_simple() abort
|
||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/package'
|
||||
silent exe 'edit ' . $GOPATH . '/src/package/package.go'
|
||||
call s:complete('package', ['package'])
|
||||
endfunc
|
||||
|
||||
func! Test_Complete_Module_simple() abort
|
||||
silent exe 'edit ' . fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/package/src/package/package.go'
|
||||
call s:complete('package', ['package'])
|
||||
endfunc
|
||||
|
||||
func! Test_Complete_GOPATH_subdirs() abort
|
||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/package'
|
||||
silent exe 'edit ' . $GOPATH . '/src/package/package.go'
|
||||
call s:complete('package/', ['package/bar', 'package/baz'])
|
||||
endfunc
|
||||
|
||||
func! Test_Complete_Module_subdirs() abort
|
||||
silent exe 'edit ' . fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/package/src/package/package.go'
|
||||
call s:complete('package/', ['package/bar', 'package/baz'])
|
||||
endfunc
|
||||
|
||||
func! Test_Complete_GOPATH_baronly() abort
|
||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/package'
|
||||
silent exe 'edit ' . $GOPATH . '/src/package/package.go'
|
||||
call s:complete('package/bar', ['package/bar'])
|
||||
endfunc
|
||||
|
||||
func! Test_Complete_Module_baronly() abort
|
||||
silent exe 'edit ' . fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/package/src/package/package.go'
|
||||
call s:complete('package/bar', ['package/bar'])
|
||||
endfunc
|
||||
|
||||
func! Test_Complete_GOPATH_vendor() abort
|
||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/package'
|
||||
silent exe 'edit ' . $GOPATH . '/src/package/package.go'
|
||||
call s:complete('foo', ['foo'])
|
||||
endfunc
|
||||
|
||||
func! Test_Complete_Module_vendor() abort
|
||||
silent exe 'edit ' . fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/package/src/package/package.go'
|
||||
call s:complete('foo', ['foo'])
|
||||
endfunc
|
||||
|
||||
func! s:complete(arglead, expected) abort
|
||||
let l:candidates = go#package#Complete(a:arglead, '', 1)
|
||||
call assert_equal(a:expected, l:candidates)
|
||||
endfunc
|
||||
|
||||
" restore Vi compatibility settings
|
||||
let &cpo = s:cpo_save
|
||||
unlet s:cpo_save
|
||||
|
||||
" vim: sw=2 ts=2 et
|
@ -209,13 +209,18 @@ endfunction
|
||||
" Relative paths cannot be properly converted to a URI; when path is a
|
||||
" relative path, the file scheme will not be prepended.
|
||||
function! go#path#ToURI(path)
|
||||
let l:absolute = !go#util#IsWin() && a:path[0] is# '/'
|
||||
let l:prefix = ''
|
||||
let l:path = a:path
|
||||
if l:path[1:2] is# ':\'
|
||||
let l:path = '/' . l:path[0:1] . l:path[3:]
|
||||
|
||||
if go#util#IsWin() && l:path[1:2] is# ':\'
|
||||
let l:absolute = 1
|
||||
let l:prefix = '/' . l:path[0:1]
|
||||
let l:path = l:path[2:]
|
||||
endif
|
||||
|
||||
return substitute(
|
||||
\ (l:path[0] is# '/' ? 'file://' : '') . go#uri#EncodePath(l:path),
|
||||
\ (l:absolute ? 'file://' : '') . l:prefix . go#uri#EncodePath(l:path),
|
||||
\ '\\',
|
||||
\ '/',
|
||||
\ 'g',
|
||||
@ -229,7 +234,7 @@ function! go#path#FromURI(uri) abort
|
||||
let l:path = go#uri#Decode(l:encoded_path)
|
||||
|
||||
" If the path is like /C:/foo/bar, it should be C:\foo\bar instead.
|
||||
if l:path =~# '^/[a-zA-Z]:'
|
||||
if go#util#IsWin() && l:path =~# '^/[a-zA-Z]:'
|
||||
let l:path = substitute(l:path[1:], '/', '\\', 'g')
|
||||
endif
|
||||
|
||||
|
@ -163,17 +163,17 @@ func s:create_cmd(args) abort
|
||||
endfor
|
||||
endif
|
||||
|
||||
" construct options
|
||||
" default value
|
||||
if empty(l:tags)
|
||||
let l:tags = ["json"]
|
||||
endif
|
||||
|
||||
" construct tags
|
||||
call extend(cmd, ["-add-tags", join(l:tags, ",")])
|
||||
|
||||
" construct options
|
||||
if !empty(l:options)
|
||||
call extend(cmd, ["-add-options", join(l:options, ",")])
|
||||
else
|
||||
" default value
|
||||
if empty(l:tags)
|
||||
let l:tags = ["json"]
|
||||
endif
|
||||
|
||||
" construct tags
|
||||
call extend(cmd, ["-add-tags", join(l:tags, ",")])
|
||||
endif
|
||||
elseif l:mode == "remove"
|
||||
if empty(l:cmd_args)
|
||||
|
@ -2,7 +2,7 @@
|
||||
let s:cpo_save = &cpo
|
||||
set cpo&vim
|
||||
|
||||
func! Test_add_tags() abort
|
||||
func! TestAddTags() abort
|
||||
try
|
||||
let l:tmp = gotest#load_fixture('tags/add_all_input.go')
|
||||
silent call go#tags#run(0, 0, 40, "add", bufname(''), 1)
|
||||
@ -13,6 +13,28 @@ func! Test_add_tags() abort
|
||||
endfunc
|
||||
|
||||
|
||||
func! TestAddTags_WithOptions() abort
|
||||
try
|
||||
let l:tmp = gotest#load_fixture('tags/add_all_input.go')
|
||||
silent call go#tags#run(0, 0, 40, "add", bufname(''), 1, 'json,omitempty')
|
||||
call gotest#assert_fixture('tags/add_all_golden_options.go')
|
||||
finally
|
||||
call delete(l:tmp, 'rf')
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
func! TestAddTags_AddOptions() abort
|
||||
try
|
||||
let l:tmp = gotest#load_fixture('tags/add_all_input.go')
|
||||
silent call go#tags#run(0, 0, 40, "add", bufname(''), 1, 'json')
|
||||
call gotest#assert_fixture('tags/add_all_golden.go')
|
||||
silent call go#tags#run(0, 0, 40, "add", bufname(''), 1, 'json,omitempty')
|
||||
call gotest#assert_fixture('tags/add_all_golden_options.go')
|
||||
finally
|
||||
call delete(l:tmp, 'rf')
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
func! Test_remove_tags() abort
|
||||
try
|
||||
let l:tmp = gotest#load_fixture('tags/remove_all_input.go')
|
||||
|
@ -4,31 +4,33 @@ set cpo&vim
|
||||
|
||||
" new creates a new terminal with the given command. Mode is set based on the
|
||||
" global variable g:go_term_mode, which is by default set to :vsplit
|
||||
function! go#term#new(bang, cmd) abort
|
||||
return go#term#newmode(a:bang, a:cmd, go#config#TermMode())
|
||||
function! go#term#new(bang, cmd, errorformat) abort
|
||||
return go#term#newmode(a:bang, a:cmd, a:errorformat, go#config#TermMode())
|
||||
endfunction
|
||||
|
||||
" new creates a new terminal with the given command and window mode.
|
||||
function! go#term#newmode(bang, cmd, mode) abort
|
||||
let mode = a:mode
|
||||
if empty(mode)
|
||||
let mode = go#config#TermMode()
|
||||
" go#term#newmode creates a new terminal with the given command and window mode.
|
||||
function! go#term#newmode(bang, cmd, errorformat, mode) abort
|
||||
let l:mode = a:mode
|
||||
if empty(l:mode)
|
||||
let l:mode = go#config#TermMode()
|
||||
endif
|
||||
|
||||
let state = {
|
||||
let l:state = {
|
||||
\ 'cmd': a:cmd,
|
||||
\ 'bang' : a:bang,
|
||||
\ 'winid': win_getid(winnr()),
|
||||
\ 'stdout': []
|
||||
\ 'stdout': [],
|
||||
\ 'stdout_buf': '',
|
||||
\ 'errorformat': a:errorformat,
|
||||
\ }
|
||||
|
||||
" execute go build in the files directory
|
||||
let cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
||||
let dir = getcwd()
|
||||
let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd ' : 'cd '
|
||||
let l:dir = getcwd()
|
||||
|
||||
execute cd . fnameescape(expand("%:p:h"))
|
||||
execute l:cd . fnameescape(expand("%:p:h"))
|
||||
|
||||
execute mode.' __go_term__'
|
||||
execute l:mode . ' __go_term__'
|
||||
|
||||
setlocal filetype=goterm
|
||||
setlocal bufhidden=delete
|
||||
@ -41,83 +43,103 @@ function! go#term#newmode(bang, cmd, mode) abort
|
||||
"
|
||||
" Don't set an on_stderr, because it will be passed the same data as
|
||||
" on_stdout. See https://github.com/neovim/neovim/issues/2836
|
||||
let job = {
|
||||
let l:job = {
|
||||
\ 'on_stdout': function('s:on_stdout', [], state),
|
||||
\ 'on_exit' : function('s:on_exit', [], state),
|
||||
\ }
|
||||
|
||||
let state.id = termopen(a:cmd, job)
|
||||
let state.termwinid = win_getid(winnr())
|
||||
let l:state.id = termopen(a:cmd, l:job)
|
||||
let l:state.termwinid = win_getid(winnr())
|
||||
|
||||
execute cd . fnameescape(dir)
|
||||
execute l:cd . fnameescape(l:dir)
|
||||
|
||||
" resize new term if needed.
|
||||
let height = go#config#TermHeight()
|
||||
let width = go#config#TermWidth()
|
||||
let l:height = go#config#TermHeight()
|
||||
let l:width = go#config#TermWidth()
|
||||
|
||||
" Adjust the window width or height depending on whether it's a vertical or
|
||||
" horizontal split.
|
||||
if mode =~ "vertical" || mode =~ "vsplit" || mode =~ "vnew"
|
||||
exe 'vertical resize ' . width
|
||||
if l:mode =~ "vertical" || l:mode =~ "vsplit" || l:mode =~ "vnew"
|
||||
exe 'vertical resize ' . l:width
|
||||
elseif mode =~ "split" || mode =~ "new"
|
||||
exe 'resize ' . height
|
||||
exe 'resize ' . l:height
|
||||
endif
|
||||
|
||||
" we also need to resize the pty, so there you go...
|
||||
call jobresize(state.id, width, height)
|
||||
call jobresize(l:state.id, l:width, l:height)
|
||||
|
||||
call win_gotoid(state.winid)
|
||||
call win_gotoid(l:state.winid)
|
||||
|
||||
return state.id
|
||||
return l:state.id
|
||||
endfunction
|
||||
|
||||
function! s:on_stdout(job_id, data, event) dict abort
|
||||
call extend(self.stdout, a:data)
|
||||
" A single empty string means EOF was reached. The first item will never be
|
||||
" the empty string except for when it's the only item and is signaling that
|
||||
" EOF was reached.
|
||||
if len(a:data) == 1 && a:data[0] == ''
|
||||
" when there's nothing buffered, return early so that an
|
||||
" erroneous message will not be added.
|
||||
if self.stdout_buf == ''
|
||||
return
|
||||
endif
|
||||
|
||||
let self.stdout = add(self.stdout, self.stdout_buf)
|
||||
else
|
||||
let l:data = copy(a:data)
|
||||
let l:data[0] = self.stdout_buf . l:data[0]
|
||||
|
||||
" The last element may be a partial line; save it for next time.
|
||||
let self.stdout_buf = l:data[-1]
|
||||
let self.stdout = extend(self.stdout, l:data[:-2])
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:on_exit(job_id, exit_status, event) dict abort
|
||||
let l:winid = win_getid(winnr())
|
||||
call win_gotoid(self.winid)
|
||||
let l:listtype = go#list#Type("_term")
|
||||
|
||||
" usually there is always output so never branch into this clause
|
||||
if empty(self.stdout)
|
||||
call s:cleanlist(self.winid, l:listtype)
|
||||
if a:exit_status == 0
|
||||
call go#list#Clean(l:listtype)
|
||||
call win_gotoid(l:winid)
|
||||
return
|
||||
endif
|
||||
|
||||
let errors = go#util#ParseErrors(self.stdout)
|
||||
let errors = go#util#FilterValids(errors)
|
||||
call win_gotoid(self.winid)
|
||||
|
||||
if !empty(errors)
|
||||
" close terminal; we don't need it anymore
|
||||
call win_gotoid(self.termwinid)
|
||||
close
|
||||
let l:title = self.cmd
|
||||
if type(l:title) == v:t_list
|
||||
let l:title = join(self.cmd)
|
||||
endif
|
||||
|
||||
call win_gotoid(self.winid)
|
||||
let l:i = 0
|
||||
while l:i < len(self.stdout)
|
||||
let self.stdout[l:i] = substitute(self.stdout[l:i], "\r$", '', 'g')
|
||||
let l:i += 1
|
||||
endwhile
|
||||
|
||||
let title = self.cmd
|
||||
if type(title) == v:t_list
|
||||
let title = join(self.cmd)
|
||||
endif
|
||||
call go#list#Populate(l:listtype, errors, title)
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !self.bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endif
|
||||
call go#list#ParseFormat(l:listtype, self.errorformat, self.stdout, l:title)
|
||||
let l:errors = go#list#Get(l:listtype)
|
||||
call go#list#Window(l:listtype, len(l:errors))
|
||||
|
||||
if empty(l:errors)
|
||||
call go#util#EchoError( '[' . l:title . '] ' . "FAIL")
|
||||
call win_gotoid(l:winid)
|
||||
return
|
||||
endif
|
||||
|
||||
call s:cleanlist(self.winid, l:listtype)
|
||||
endfunction
|
||||
" close terminal; we don't need it anymore
|
||||
call win_gotoid(self.termwinid)
|
||||
close!
|
||||
|
||||
function! s:cleanlist(winid, listtype) abort
|
||||
" There are no errors. Clean and close the list. Jump to the window to which
|
||||
" the location list is attached, close the list, and then jump back to the
|
||||
" current window.
|
||||
let winid = win_getid(winnr())
|
||||
call win_gotoid(a:winid)
|
||||
call go#list#Clean(a:listtype)
|
||||
call win_gotoid(l:winid)
|
||||
if self.bang
|
||||
call win_gotoid(l:winid)
|
||||
return
|
||||
endif
|
||||
|
||||
call win_gotoid(self.winid)
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endfunction
|
||||
|
||||
" restore Vi compatibility settings
|
||||
|
@ -17,7 +17,7 @@ func! Test_GoTermNewMode()
|
||||
let cmd = "go run ". go#util#Shelljoin(go#tool#Files())
|
||||
|
||||
set nosplitright
|
||||
call go#term#newmode(0, cmd, '')
|
||||
call go#term#new(0, cmd, &errorformat)
|
||||
let actual = expand('%:p')
|
||||
call assert_equal(actual, l:expected)
|
||||
|
||||
@ -41,7 +41,7 @@ func! Test_GoTermNewMode_SplitRight()
|
||||
let cmd = "go run ". go#util#Shelljoin(go#tool#Files())
|
||||
|
||||
set splitright
|
||||
call go#term#newmode(0, cmd, '')
|
||||
call go#term#new(0, cmd, &errorformat)
|
||||
let actual = expand('%:p')
|
||||
call assert_equal(actual, l:expected)
|
||||
|
||||
|
@ -0,0 +1,3 @@
|
||||
module package
|
||||
|
||||
go 1.12
|
@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("vim-go")
|
||||
}
|
0
sources_non_forked/vim-go/autoload/go/test-fixtures/package/src/package/vendor/foo/.gitkeep
vendored
Normal file
0
sources_non_forked/vim-go/autoload/go/test-fixtures/package/src/package/vendor/foo/.gitkeep
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ExampleHelloWorld() {
|
||||
fmt.Println("Hello, World")
|
||||
// Output: What's shakin
|
||||
}
|
@ -30,8 +30,8 @@ function! go#test#Test(bang, compile, ...) abort
|
||||
call add(args, printf("-timeout=%s", timeout))
|
||||
endif
|
||||
|
||||
if has('nvim') && go#config#TermEnabled()
|
||||
call go#term#new(a:bang, ["go"] + args)
|
||||
if go#config#TermEnabled()
|
||||
call go#term#new(a:bang, ["go"] + args, s:errorformat())
|
||||
endif
|
||||
|
||||
if go#util#has_job()
|
||||
@ -75,14 +75,17 @@ function! go#test#Test(bang, compile, ...) abort
|
||||
execute cd fnameescape(expand("%:p:h"))
|
||||
|
||||
if l:err != 0
|
||||
let l:winid = win_getid(winnr())
|
||||
call go#list#ParseFormat(l:listtype, s:errorformat(), split(out, '\n'), l:cmd)
|
||||
let errors = go#list#Get(l:listtype)
|
||||
call go#list#Window(l:listtype, len(errors))
|
||||
if !empty(errors) && !a:bang
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
elseif empty(errors)
|
||||
if empty(errors)
|
||||
" failed to parse errors, output the original content
|
||||
call go#util#EchoError(out)
|
||||
elseif a:bang
|
||||
call win_gotoid(l:winid)
|
||||
else
|
||||
call go#list#JumpToFirst(l:listtype)
|
||||
endif
|
||||
else
|
||||
call go#list#Clean(l:listtype)
|
||||
@ -163,9 +166,17 @@ function! s:errorformat() abort
|
||||
let format .= ",%-G" . indent . "%#--- PASS: %.%#"
|
||||
|
||||
" Match failure lines.
|
||||
"
|
||||
|
||||
" Example failures start with '--- FAIL: ', followed by the example name
|
||||
" followed by a space , followed by the duration of the example in
|
||||
" parantheses. They aren't nested, though, so don't check for indentation.
|
||||
" The errors from them also aren't indented and don't report file location
|
||||
" or line numbers, so those won't show up. This will at least let the user
|
||||
" know which example failed, though.
|
||||
let format .= ',%G--- FAIL: %\\%(Example%\\)%\\@=%m (%.%#)'
|
||||
|
||||
" Test failures start with '--- FAIL: ', followed by the test name followed
|
||||
" by a space the duration of the test in parentheses
|
||||
" by a space, followed by the duration of the test in parentheses.
|
||||
"
|
||||
" e.g.:
|
||||
" '--- FAIL: TestSomething (0.00s)'
|
||||
|
@ -66,9 +66,9 @@ endfunc
|
||||
func! Test_GoTestShowName() abort
|
||||
let expected = [
|
||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld'},
|
||||
\ {'lnum': 6, 'bufnr': 9, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'so long'},
|
||||
\ {'lnum': 6, 'bufnr': 8, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'so long'},
|
||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'TestHelloWorld/sub'},
|
||||
\ {'lnum': 9, 'bufnr': 9, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'thanks for all the fish'},
|
||||
\ {'lnum': 9, 'bufnr': 8, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'thanks for all the fish'},
|
||||
\ ]
|
||||
|
||||
let g:go_test_show_name=1
|
||||
@ -78,20 +78,27 @@ endfunc
|
||||
|
||||
func! Test_GoTestVet() abort
|
||||
let expected = [
|
||||
\ {'lnum': 6, 'bufnr': 16, 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'Errorf format %v reads arg #1, but call has 0 args'},
|
||||
\ {'lnum': 6, 'bufnr': 11, 'col': 2, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'Errorf format %v reads arg #1, but call has 0 args'},
|
||||
\ ]
|
||||
call s:test('veterror/veterror.go', expected)
|
||||
endfunc
|
||||
|
||||
func! Test_GoTestTestCompilerError() abort
|
||||
let expected = [
|
||||
\ {'lnum': 10, 'bufnr': 11, 'col': 16, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'cannot use r (type struct {}) as type io.Reader in argument to ioutil.ReadAll:'},
|
||||
\ {'lnum': 10, 'bufnr': 9, 'col': 16, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'cannot use r (type struct {}) as type io.Reader in argument to ioutil.ReadAll:'},
|
||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'struct {} does not implement io.Reader (missing Read method)'}
|
||||
\ ]
|
||||
|
||||
call s:test('testcompilerror/testcompilerror_test.go', expected)
|
||||
endfunc
|
||||
|
||||
func! Test_GoTestExample() abort
|
||||
let expected = [
|
||||
\ {'lnum': 0, 'bufnr': 0, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'ExampleHelloWorld'}
|
||||
\ ]
|
||||
call s:test('example/example_test.go', expected)
|
||||
endfunc
|
||||
|
||||
func! s:test(file, expected, ...) abort
|
||||
let $GOPATH = fnameescape(fnamemodify(getcwd(), ':p')) . 'test-fixtures/test'
|
||||
silent exe 'e ' . $GOPATH . '/src/' . a:file
|
||||
|
@ -86,8 +86,10 @@ function! go#tool#Info(showstatus) abort
|
||||
call go#complete#Info(a:showstatus)
|
||||
elseif l:mode == 'guru'
|
||||
call go#guru#DescribeInfo(a:showstatus)
|
||||
elseif l:mode == 'gopls'
|
||||
call go#lsp#Info(a:showstatus)
|
||||
else
|
||||
call go#util#EchoError('go_info_mode value: '. l:mode .' is not valid. Valid values are: [gocode, guru]')
|
||||
call go#util#EchoError('go_info_mode value: '. l:mode .' is not valid. Valid values are: [gocode, guru, gopls]')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@ -112,7 +114,22 @@ function! go#tool#Exists(importpath) abort
|
||||
endfunction
|
||||
|
||||
function! go#tool#DescribeBalloon()
|
||||
return go#guru#DescribeBalloon()
|
||||
let l:fname = fnamemodify(bufname(v:beval_bufnr), ':p')
|
||||
call go#lsp#Hover(l:fname, v:beval_lnum, v:beval_col, funcref('s:balloon', []))
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! s:balloon(msg)
|
||||
let l:msg = a:msg
|
||||
if has('balloon_eval')
|
||||
if has('balloon_multiline')
|
||||
let l:msg = join(a:msg, "\n")
|
||||
else
|
||||
let l:msg = substitute(join(map(deepcopy(a:msg), 'substitute(v:val, "\t", "", "")'), '; '), '{;', '{', '')
|
||||
endif
|
||||
endif
|
||||
|
||||
call balloon_show(l:msg)
|
||||
endfunction
|
||||
|
||||
" restore Vi compatibility settings
|
||||
|
@ -7,7 +7,11 @@ function! go#uri#Encode(value) abort
|
||||
endfunction
|
||||
|
||||
function! go#uri#EncodePath(value) abort
|
||||
return s:encode(a:value, '[^/A-Za-z0-9_.~-]')
|
||||
let l:separator = '/'
|
||||
if go#util#IsWin()
|
||||
let l:separator = '\\'
|
||||
endif
|
||||
return s:encode(a:value, '[^' . l:separator . 'A-Za-z0-9_.~-]')
|
||||
endfunction
|
||||
|
||||
function! s:encode(value, unreserved)
|
||||
|
@ -137,11 +137,33 @@ function! go#util#gomod() abort
|
||||
return substitute(s:exec(['go', 'env', 'GOMOD'])[0], '\n', '', 'g')
|
||||
endfunction
|
||||
|
||||
|
||||
function! go#util#osarch() abort
|
||||
return go#util#env("goos") . '_' . go#util#env("goarch")
|
||||
endfunction
|
||||
|
||||
" go#util#ModuleRoot returns the root directory of the module of the current
|
||||
" buffer.
|
||||
function! go#util#ModuleRoot() abort
|
||||
let [l:out, l:err] = go#util#ExecInDir(['go', 'env', 'GOMOD'])
|
||||
if l:err != 0
|
||||
return -1
|
||||
endif
|
||||
|
||||
let l:module = split(l:out, '\n', 1)[0]
|
||||
|
||||
" When run with `GO111MODULE=on and not in a module directory, the module will be reported as /dev/null.
|
||||
let l:fakeModule = '/dev/null'
|
||||
if go#util#IsWin()
|
||||
let l:fakeModule = 'NUL'
|
||||
endif
|
||||
|
||||
if l:fakeModule == l:module
|
||||
return expand('%:p:h')
|
||||
endif
|
||||
|
||||
return fnamemodify(l:module, ':p:h')
|
||||
endfunction
|
||||
|
||||
" Run a shell command.
|
||||
"
|
||||
" It will temporary set the shell to /bin/sh for Unix-like systems if possible,
|
||||
@ -511,42 +533,6 @@ function! go#util#ParseErrors(lines) abort
|
||||
return errors
|
||||
endfunction
|
||||
|
||||
" FilterValids filters the given items with only items that have a valid
|
||||
" filename. Any non valid filename is filtered out.
|
||||
function! go#util#FilterValids(items) abort
|
||||
" Remove any nonvalid filename from the location list to avoid opening an
|
||||
" empty buffer. See https://github.com/fatih/vim-go/issues/287 for
|
||||
" details.
|
||||
let filtered = []
|
||||
let is_readable = {}
|
||||
|
||||
for item in a:items
|
||||
if has_key(item, 'bufnr')
|
||||
let filename = bufname(item.bufnr)
|
||||
elseif has_key(item, 'filename')
|
||||
let filename = item.filename
|
||||
else
|
||||
" nothing to do, add item back to the list
|
||||
call add(filtered, item)
|
||||
continue
|
||||
endif
|
||||
|
||||
if !has_key(is_readable, filename)
|
||||
let is_readable[filename] = filereadable(filename)
|
||||
endif
|
||||
if is_readable[filename]
|
||||
call add(filtered, item)
|
||||
endif
|
||||
endfor
|
||||
|
||||
for k in keys(filter(is_readable, '!v:val'))
|
||||
echo "vim-go: " | echohl Identifier | echon "[run] Dropped " | echohl Constant | echon '"' . k . '"'
|
||||
echohl Identifier | echon " from location list (nonvalid filename)" | echohl None
|
||||
endfor
|
||||
|
||||
return filtered
|
||||
endfunction
|
||||
|
||||
function! go#util#ShowInfo(info)
|
||||
if empty(a:info)
|
||||
return
|
||||
@ -555,6 +541,39 @@ function! go#util#ShowInfo(info)
|
||||
echo "vim-go: " | echohl Function | echon a:info | echohl None
|
||||
endfunction
|
||||
|
||||
" go#util#SetEnv takes the name of an environment variable and what its value
|
||||
" should be and returns a function that will restore it to its original value.
|
||||
function! go#util#SetEnv(name, value) abort
|
||||
let l:state = {}
|
||||
|
||||
if len(a:name) == 0
|
||||
return function('s:noop', [], l:state)
|
||||
endif
|
||||
|
||||
let l:remove = 0
|
||||
if exists('$' . a:name)
|
||||
let l:oldvalue = eval('$' . a:name)
|
||||
else
|
||||
let l:remove = 1
|
||||
endif
|
||||
|
||||
" wrap the value in single quotes so that it will work on windows when there
|
||||
" are backslashes present in the value (e.g. $PATH).
|
||||
call execute('let $' . a:name . " = '" . a:value . "'")
|
||||
|
||||
if l:remove
|
||||
function! s:remove(name) abort
|
||||
call execute('unlet $' . a:name)
|
||||
endfunction
|
||||
return function('s:remove', [a:name], l:state)
|
||||
endif
|
||||
|
||||
return function('go#util#SetEnv', [a:name, l:oldvalue], l:state)
|
||||
endfunction
|
||||
|
||||
function! s:noop(...) abort dict
|
||||
endfunction
|
||||
|
||||
" restore Vi compatibility settings
|
||||
let &cpo = s:cpo_save
|
||||
unlet s:cpo_save
|
||||
|
@ -32,17 +32,18 @@ CONTENTS *go-contents*
|
||||
INTRO *go-intro*
|
||||
|
||||
Go (golang) support for Vim. vim-go comes with sensible predefined settings
|
||||
(e.g. automatic `gofmt` on save), has autocomplete, snippet support, improved
|
||||
syntax highlighting, go toolchain commands, etc. It is highly customizable,
|
||||
and individual features can be toggled easily. vim-go leverages a number of
|
||||
tools developed by the Go community to provide a seamless Vim experience.
|
||||
(e.g. automatic `gofmt` on save), has code completion, snippet support,
|
||||
improved syntax highlighting, go toolchain commands, etc. It is highly
|
||||
customizable, and individual features can be toggled easily. vim-go leverages
|
||||
a number of tools developed by the Go community to provide a seamless Vim
|
||||
experience.
|
||||
|
||||
* Compile your package with |:GoBuild|, install it with |:GoInstall| or
|
||||
test it with |:GoTest|. Run a single test with |:GoTestFunc|).
|
||||
* Quickly execute your current file(s) with |:GoRun|.
|
||||
* Improved syntax highlighting and folding.
|
||||
* Debug programs with integrated `delve` support with |:GoDebugStart|.
|
||||
* Completion support via `gocode` and `gopls`.
|
||||
* Code completion support via `gocode` and `gopls`.
|
||||
* `gofmt` or `goimports` on save keeps the cursor position and undo history.
|
||||
* Go to symbol/declaration with |:GoDef|.
|
||||
* Look up documentation with |:GoDoc| or |:GoDocBrowser|.
|
||||
@ -127,7 +128,7 @@ or $GOPATH/bin (default: $HOME/go/bin). It requires `git`.
|
||||
Depending on your installation method, you may have to generate the plugin's
|
||||
|:helptags| manually (e.g. `:helptags ALL`).
|
||||
|
||||
Autocompletion is enabled by default via 'omnifunc', which you can trigger
|
||||
Code completion is enabled by default via 'omnifunc', which you can trigger
|
||||
with |i_CTRL-X_CTRL-O| (`<C-x><C-o>`).
|
||||
|
||||
Supported Go plugins~ *vim-go-plugins*
|
||||
@ -138,8 +139,12 @@ The following plugins are supported for use with vim-go:
|
||||
https://github.com/Shougo/neocomplete.vim
|
||||
|
||||
* Real-time completion (Neovim and Vim 8):
|
||||
https://github.com/Shougo/deoplete.nvim and
|
||||
https://github.com/zchee/deoplete-go
|
||||
https://github.com/Shougo/deoplete.nvim
|
||||
|
||||
Add the following line to your vimrc. This instructs deoplete to use omni
|
||||
completion for Go files.
|
||||
|
||||
call deoplete#custom#option('omni_patterns', { 'go': '[^. *\t]\.\w*' })
|
||||
|
||||
* Display source code navigation in a sidebar:
|
||||
https://github.com/majutsushi/tagbar
|
||||
@ -149,9 +154,6 @@ The following plugins are supported for use with vim-go:
|
||||
https://github.com/SirVer/ultisnips or
|
||||
https://github.com/joereynolds/vim-minisnip
|
||||
|
||||
* Integration with `delve` (Neovim only):
|
||||
https://github.com/jodosha/vim-godebug
|
||||
|
||||
* Interactive |:GoDecls| and |:GoDeclsDir|:
|
||||
https://github.com/ctrlpvim/ctrlp.vim or
|
||||
https://github.com/junegunn/fzf.vim or
|
||||
@ -1202,6 +1204,13 @@ balloonexpr`.
|
||||
==============================================================================
|
||||
SETTINGS *go-settings*
|
||||
|
||||
*'g:go_code_completion_enabled'*
|
||||
|
||||
Enable code completion with |'omnifunc'|. By default it is enabled.
|
||||
>
|
||||
let g:go_code_completion_enabled = 1
|
||||
<
|
||||
|
||||
*'g:go_test_show_name'*
|
||||
|
||||
Show the name of each failed test before the errors and logs output by the
|
||||
@ -1251,8 +1260,8 @@ updated. By default it's disabled. The delay can be configured with the
|
||||
|
||||
Use this option to define the command to be used for |:GoInfo|. By default
|
||||
`gocode` is being used as it's the fastest option. But one might also use
|
||||
`guru` as it's covers more cases and is more accurate. Current valid options
|
||||
are: `[gocode, guru]` >
|
||||
`gopls` or `guru` as they cover more cases and are more accurate. Current
|
||||
valid options are: `[gocode, guru, gopls]` >
|
||||
|
||||
let g:go_info_mode = 'gocode'
|
||||
<
|
||||
@ -1635,15 +1644,15 @@ same.
|
||||
*'g:go_gocode_propose_builtins'*
|
||||
|
||||
Specifies whether `gocode` should add built-in types, functions and constants
|
||||
to an autocompletion proposals. By default it is enabled.
|
||||
to code completion proposals. By default it is enabled.
|
||||
>
|
||||
let g:go_gocode_propose_builtins = 1
|
||||
<
|
||||
*'g:go_gocode_propose_source'*
|
||||
|
||||
Specifies whether `gocode` should use source files instead of binary packages
|
||||
for autocompletion proposals. When disabled, only identifiers from the current
|
||||
package and packages that have been installed will proposed.
|
||||
for code completion proposals. When disabled, only identifiers from the
|
||||
current package and packages that have been installed will proposed.
|
||||
>
|
||||
let g:go_gocode_propose_source = 0
|
||||
<
|
||||
@ -1732,8 +1741,8 @@ i.e: |go#statusline#Show()|. By default it's enabled
|
||||
<
|
||||
*'g:go_echo_go_info'*
|
||||
|
||||
Use this option to show the identifier information when completion is done. By
|
||||
default it's enabled >
|
||||
Use this option to show the identifier information when code completion is
|
||||
done. By default it's enabled. >
|
||||
|
||||
let g:go_echo_go_info = 1
|
||||
<
|
||||
@ -2017,8 +2026,9 @@ rest of the commands and mappings become available after starting debug mode.
|
||||
* Setup the debug windows according to |'g:go_debug_windows'|.
|
||||
* Make the `:GoDebug*` commands and `(go-debug-*)` mappings available.
|
||||
|
||||
The current directory is used if [pkg] is empty. Any other arguments will
|
||||
be passed to the program.
|
||||
The directory of the current buffer is used if [pkg] is empty. Any other
|
||||
arguments will be passed to the program. When [pkg] is relative, it will
|
||||
be interpreted relative to the directory of the current buffer.
|
||||
|
||||
Use |:GoDebugStop| to stop `dlv` and exit debugging mode.
|
||||
|
||||
@ -2031,7 +2041,6 @@ rest of the commands and mappings become available after starting debug mode.
|
||||
Use `-test.flag` to pass flags to `go test` when debugging a test; for
|
||||
example `-test.v` or `-test.run TestFoo`
|
||||
|
||||
|
||||
*:GoDebugRestart*
|
||||
:GoDebugRestart
|
||||
|
||||
@ -2153,6 +2162,16 @@ Defaults to `127.0.0.1:8181`:
|
||||
let g:go_debug_address = '127.0.0.1:8181'
|
||||
<
|
||||
|
||||
*'g:go_debug_log_output'*
|
||||
|
||||
Specifies log output options for `dlv`. Value should be a single string
|
||||
of comma-separated options suitable for passing to `dlv`. An empty string
|
||||
(`''`) will suppress logging entirely.
|
||||
Default: `'debugger, rpc'`:
|
||||
>
|
||||
let g:go_debug_log = 'debugger, rpc'
|
||||
<
|
||||
|
||||
*'g:go_highlight_debug'*
|
||||
|
||||
Highlight the current line and breakpoints in the debugger.
|
||||
@ -2164,6 +2183,12 @@ Highlight the current line and breakpoints in the debugger.
|
||||
==============================================================================
|
||||
FAQ TROUBLESHOOTING *go-troubleshooting*
|
||||
|
||||
I get "Unknown function: go#config#..." error when I open a Go file.~
|
||||
|
||||
This often happens to vim-polyglot users when new config options are added to
|
||||
vim-go. Run vim-polyglot's `build` script or make sure that vim-go is loaded
|
||||
before vim-polyglot.
|
||||
|
||||
I get "not an editor command" error when I invoke :GoXXX~
|
||||
|
||||
This happens if vim-go is not installed properly. Be sure you have added this
|
||||
@ -2364,14 +2389,14 @@ You can install and test all Vim versions by running `make`.
|
||||
DONATION *go-donation*
|
||||
|
||||
People have asked for this for a long time, now you can be a fully supporter
|
||||
by being a patreon at: https://www.patreon.com/fatih
|
||||
by being a patreon at: https://www.patreon.com/bhcleek
|
||||
|
||||
By being a patron, you are enabling vim-go to grow and mature, helping me to
|
||||
invest in bug fixes, new documentation, and improving both current and future
|
||||
features. It's completely optional and is just a direct way to support
|
||||
vim-go's ongoing development. Thanks!
|
||||
|
||||
Check it out: https://www.patreon.com/fatih
|
||||
Check it out: https://www.patreon.com/bhcleek
|
||||
|
||||
|
||||
==============================================================================
|
||||
|
@ -25,10 +25,12 @@ setlocal noexpandtab
|
||||
|
||||
compiler go
|
||||
|
||||
" Set autocompletion
|
||||
setlocal omnifunc=go#complete#Complete
|
||||
if !go#util#has_job()
|
||||
setlocal omnifunc=go#complete#GocodeComplete
|
||||
if go#config#CodeCompletionEnabled()
|
||||
" Set autocompletion
|
||||
setlocal omnifunc=go#complete#Complete
|
||||
if !go#util#has_job()
|
||||
setlocal omnifunc=go#complete#GocodeComplete
|
||||
endif
|
||||
endif
|
||||
|
||||
if get(g:, "go_doc_keywordprg_enabled", 1)
|
||||
@ -82,9 +84,16 @@ endif
|
||||
augroup vim-go-buffer
|
||||
autocmd! * <buffer>
|
||||
|
||||
" TODO(bc): notify gopls about changes on CursorHold when the buffer is
|
||||
" modified.
|
||||
" TODO(bc): notify gopls that the file on disk is correct on BufWritePost
|
||||
" The file is registered (textDocument/DidOpen) with gopls in plugin/go.vim
|
||||
" on the FileType event.
|
||||
" TODO(bc): handle all the other events that may be of interest to gopls,
|
||||
" too (e.g. BufFilePost , CursorHold , CursorHoldI, FileReadPost,
|
||||
" StdinReadPre, BufWritePost, TextChange, TextChangedI)
|
||||
if go#util#has_job()
|
||||
autocmd BufWritePost <buffer> call go#lsp#DidChange(expand('<afile>:p'))
|
||||
autocmd FileChangedShell <buffer> call go#lsp#DidChange(expand('<afile>:p'))
|
||||
autocmd BufDelete <buffer> call go#lsp#DidClose(expand('<afile>:p'))
|
||||
endif
|
||||
|
||||
autocmd CursorHold <buffer> call go#auto#auto_type_info()
|
||||
autocmd CursorHold <buffer> call go#auto#auto_sameids()
|
||||
|
@ -101,11 +101,11 @@ function! s:GoInstallBinaries(updateBinaries, ...)
|
||||
" change $GOBIN so go get can automatically install to it
|
||||
let $GOBIN = go_bin_path
|
||||
|
||||
" old_path is used to restore users own path
|
||||
let old_path = $PATH
|
||||
|
||||
" vim's executable path is looking in PATH so add our go_bin path to it
|
||||
let $PATH = go_bin_path . go#util#PathListSep() . $PATH
|
||||
let Restore_path = go#util#SetEnv('PATH', go_bin_path . go#util#PathListSep() . $PATH)
|
||||
|
||||
" GO111MODULE must be off to install golanci-lint and gometalinter
|
||||
let Restore_modules = go#util#SetEnv('GO111MODULE', 'off')
|
||||
|
||||
" when shellslash is set on MS-* systems, shellescape puts single quotes
|
||||
" around the output string. cmd on Windows does not handle single quotes
|
||||
@ -185,7 +185,9 @@ function! s:GoInstallBinaries(updateBinaries, ...)
|
||||
endfor
|
||||
|
||||
" restore back!
|
||||
let $PATH = old_path
|
||||
call call(Restore_path, [])
|
||||
call call(Restore_modules, [])
|
||||
|
||||
if resetshellslash
|
||||
set shellslash
|
||||
endif
|
||||
@ -234,6 +236,22 @@ function! s:gofiletype_post()
|
||||
let &g:fileencodings = s:current_fileencodings
|
||||
endfunction
|
||||
|
||||
function! s:register()
|
||||
if !(&modifiable && expand('<amatch>') ==# 'go')
|
||||
return
|
||||
endif
|
||||
|
||||
let l:RestoreGopath = function('s:noop')
|
||||
if go#config#AutodetectGopath()
|
||||
let l:RestoreGopath = go#util#SetEnv('GOPATH', go#path#Detect())
|
||||
endif
|
||||
call go#lsp#DidOpen(expand('<afile>:p'))
|
||||
call call(l:RestoreGopath, [])
|
||||
endfunction
|
||||
|
||||
function! s:noop(...) abort
|
||||
endfunction
|
||||
|
||||
augroup vim-go
|
||||
autocmd!
|
||||
|
||||
@ -245,6 +263,10 @@ augroup vim-go
|
||||
autocmd BufNewFile *.s if &modifiable | setlocal fileencoding=utf-8 fileformat=unix | endif
|
||||
autocmd BufRead *.s call s:gofiletype_pre()
|
||||
autocmd BufReadPost *.s call s:gofiletype_post()
|
||||
|
||||
if go#util#has_job()
|
||||
autocmd FileType * call s:register()
|
||||
endif
|
||||
augroup end
|
||||
|
||||
" restore Vi compatibility settings
|
||||
|
@ -23,7 +23,7 @@ fi
|
||||
|
||||
dir="/tmp/vim-go-test/$1-install"
|
||||
export GOPATH=$dir
|
||||
export GO111MODULE=off
|
||||
export GO111MODULE=auto
|
||||
export PATH=${GOPATH}/bin:$PATH
|
||||
shift
|
||||
|
||||
|
Reference in New Issue
Block a user