mirror of
				https://github.com/amix/vimrc
				synced 2025-10-31 06:33:35 +08:00 
			
		
		
		
	Updated plugins
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,41 @@ | ||||
| ## 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) | ||||
|  | ||||
| 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) | ||||
|  | ||||
| ## 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 +90,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 +136,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,8 +242,7 @@ 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 | ||||
|  | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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() | ||||
| @ -420,7 +457,7 @@ function! s:completionHandler(next, msg) abort dict | ||||
|   for l:item in a:msg.items | ||||
|     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 | ||||
|     endif | ||||
|  | ||||
|     if has_key(l:item, 'documentation') | ||||
| @ -437,6 +474,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 | ||||
|  | ||||
| @ -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
									
								
							| @ -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) | ||||
|  | ||||
| @ -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': 7, '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': 7, 'col': 0, 'valid': 1, 'vcol': 0, 'nr': -1, 'type': '', 'pattern': '', 'text': 'thanks for all the fish'}, | ||||
|       \ ] | ||||
|  | ||||
|   let g:go_test_show_name=1 | ||||
| @ -78,14 +78,14 @@ 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': 10, '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': 8, '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)'} | ||||
|       \ ] | ||||
|  | ||||
|  | ||||
| @ -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,37 @@ 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 | ||||
|  | ||||
|   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
	 Amir Salihefendic
					Amir Salihefendic