From ea28320d9d48bdd08714f0e5d2a756417acdfe58 Mon Sep 17 00:00:00 2001 From: Billie Cleek Date: Sun, 2 Jun 2019 22:19:20 -0700 Subject: [PATCH] try to use relative import paths if necessary Teach go#debug#Start, go#lint#Vet, and go#lint#ErrCheck to work in null modules. Refactor go#package#ImportPath to delegate to go#package#FromPath. Teach go#package#FromPath to return a relative package path when in a null module if possible. When the package is not within the current working directory, -2 will still be returned. This allows go#debug#Start, go#lint#Vet, and go#lint#Errcheck to work in null modules. Add a test for go#debug#Start using a relative path in a null module. Correct documentation for :GoDebugStart. Fix `:GoVet` with arguments so that it will run for the package that contains the current buffer instead of just using whatever the current working directory is. --- autoload/go/debug.vim | 21 ++++++++--- autoload/go/debug_test.vim | 12 +++++++ autoload/go/lint.vim | 2 +- autoload/go/lsp.vim | 9 ++--- autoload/go/package.vim | 73 ++++++++++++++++++++++---------------- doc/vim-go.txt | 3 +- 6 files changed, 79 insertions(+), 41 deletions(-) diff --git a/autoload/go/debug.vim b/autoload/go/debug.vim index e2d0b9fa36..272af5d356 100644 --- a/autoload/go/debug.vim +++ b/autoload/go/debug.vim @@ -595,10 +595,23 @@ function! go#debug#Start(is_test, ...) abort " 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 + let l:pkgname = a:1 + if l:pkgname[0] == '.' + let l:pkgabspath = fnamemodify(l:pkgname, ':p') + + let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd' + let l:dir = getcwd() + execute l:cd fnameescape(expand('%:p:h')) + + try + let l:pkgname = go#package#FromPath(l:pkgabspath) + if type(l:pkgname) == type(0) + call go#util#EchoError('could not determine package name') + return + endif + finally + execute l:cd fnameescape(l:dir) + endtry endif let l:cmd += [l:pkgname] diff --git a/autoload/go/debug_test.vim b/autoload/go/debug_test.vim index f5572e51f0..b9aeb2a86f 100644 --- a/autoload/go/debug_test.vim +++ b/autoload/go/debug_test.vim @@ -10,6 +10,10 @@ function! Test_GoDebugStart_RelativePackage() abort call s:debug('./debug/debugmain') endfunction +function! Test_GoDebugStart_RelativePackage_NullModule() abort + call s:debug('./debug/debugmain', 1) +endfunction + function! Test_GoDebugStart_Package() abort call s:debug('debug/debugmain') endfunction @@ -52,14 +56,22 @@ function! Test_GoDebugStart_Errors() abort endtry endfunction +" s:debug takes 2 optional arguments. The first is a package to debug. The +" second is a flag to indicate whether to reset GOPATH after +" gotest#load_fixture is called in order to test behavior outside of GOPATH. function! s:debug(...) abort if !go#util#has_job() return endif try + let $oldgopath = $GOPATH let l:tmp = gotest#load_fixture('debug/debugmain/debugmain.go') + if a:0 > 1 && a:2 == 1 + let $GOPATH = $oldgopath + endif + call go#debug#Breakpoint(6) call assert_false(exists(':GoDebugStop')) diff --git a/autoload/go/lint.vim b/autoload/go/lint.vim index 42d1ae07f7..cdae52f42e 100644 --- a/autoload/go/lint.vim +++ b/autoload/go/lint.vim @@ -141,7 +141,7 @@ function! go#lint#Vet(bang, ...) abort if a:0 == 0 let [l:out, l:err] = go#util#Exec(['go', 'vet', go#package#ImportPath()]) else - let [l:out, l:err] = go#util#Exec(['go', 'tool', 'vet'] + a:000) + let [l:out, l:err] = go#util#ExecInDir(['go', 'tool', 'vet'] + a:000) endif let l:listtype = go#list#Type("GoVet") diff --git a/autoload/go/lsp.vim b/autoload/go/lsp.vim index 15254a4a7b..5fd6930896 100644 --- a/autoload/go/lsp.vim +++ b/autoload/go/lsp.vim @@ -186,15 +186,16 @@ function! s:newlsp() abort let l:wd = getcwd() endif - " do not attempt to send a message to gopls when using neither GOPATH - " mode nor module mode. - if go#package#FromPath(l:wd) == -2 + " do not attempt to send a message to gopls when using a null module in + " module mode. + let l:importpath = go#package#FromPath(l:wd) + if l:importpath == -2 || (type(l:importpath) == type('') && l:importpath[0] == '.') if go#config#NullModuleWarning() && (!has_key(self, 'warned') || !self.warned) let l:oldshortmess=&shortmess if has('nvim') set shortmess-=F endif - call go#util#EchoWarning('Features that rely on gopls will not work correctly outside of GOPATH or a module.') + call go#util#EchoWarning('Features that rely on gopls will not work correctly in a null module.') let self.warned = 1 " Sleep one second to make sure people see the message. Otherwise it is " often immediately overwritten by an async message. diff --git a/autoload/go/package.vim b/autoload/go/package.vim index 6292d1db8c..cdbb09fffb 100644 --- a/autoload/go/package.vim +++ b/autoload/go/package.vim @@ -111,35 +111,29 @@ function! s:vendordirs() abort endfunction let s:import_paths = {} -" ImportPath returns the import path of the package for current buffer. +" ImportPath returns the import path of the package for current buffer. It +" returns -1 if the import path cannot be determined. function! go#package#ImportPath() abort - let dir = expand("%:p:h") + let l:dir = expand("%:p:h") if has_key(s:import_paths, dir) - return s:import_paths[dir] + return s:import_paths[l:dir] endif - let [l:out, l:err] = go#util#ExecInDir(['go', 'list']) - if l:err != 0 - return -1 - endif - - let l:importpath = split(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 - if l:importpath[0] ==# '_' + let l:importpath = go#package#FromPath(l:dir) + if type(l:importpath) == type(0) return -1 endif - let s:import_paths[dir] = l:importpath + let s:import_paths[l:dir] = l:importpath return l:importpath endfunction - " 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. +" outside of GOPATH, not in a module, and not below the current working +" directory. A relative path is returned when in a null module at or below the +" current working directory.. function! go#package#FromPath(arg) abort let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd' let l:dir = getcwd() @@ -150,25 +144,44 @@ function! go#package#FromPath(arg) abort endif execute l:cd fnameescape(l:path) - if glob("*.go") == "" - " There's no Go code in this directory. We might be in a module directory - " which doesn't have any code at this level. - if !empty(s:module()) + try + if glob("*.go") == "" + " There's no Go code in this directory. We might be in a module directory + " which doesn't have any code at this level. To avoid `go list` making a + " bunch of HTTP requests to fetch dependencies, short-circuit `go list` + " and return -1 immediately. + if !empty(s:module()) + return -1 + endif + endif + let [l:out, l:err] = go#util#Exec(['go', 'list']) + if l:err != 0 return -1 endif - endif - let [l:out, l:err] = go#util#Exec(['go', 'list']) - execute l:cd fnameescape(l:dir) - if l:err != 0 - return -1 - endif - let l:importpath = split(l:out, '\n')[0] + let l:importpath = split(l:out, '\n')[0] + finally + execute l:cd fnameescape(l:dir) + endtry - " 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 + " go list returns '_CURRENTDIRECTORY' if the directory is in a null module + " (i.e. neither in GOPATH nor in a module). Return a relative import path + " if possible or an error if that is the case. if l:importpath[0] ==# '_' - return -2 + let l:relativeimportpath = fnamemodify(l:importpath[1:], ':.') + if go#util#IsWin() + let l:relativeimportpath = substitute(l:relativeimportpath, '\\', '/', 'g') + endif + + if l:relativeimportpath == l:importpath[1:] + return '.' + endif + + if l:relativeimportpath[0] == '/' + return -2 + endif + + let l:importpath= printf('./%s', l:relativeimportpath) endif return l:importpath diff --git a/doc/vim-go.txt b/doc/vim-go.txt index a6de22e9d0..1712e24e83 100644 --- a/doc/vim-go.txt +++ b/doc/vim-go.txt @@ -2043,8 +2043,7 @@ rest of the commands and mappings become available after starting debug mode. * Make the `:GoDebug*` commands and `(go-debug-*)` mappings available. 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. + arguments will be passed to the program. Use |:GoDebugStop| to stop `dlv` and exit debugging mode.