Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

complete vendored packages and modules #2213

Merged
merged 1 commit into from
Apr 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 111 additions & 12 deletions autoload/go/package.vim
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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
Expand Down Expand Up @@ -144,33 +196,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
Expand Down
58 changes: 58 additions & 0 deletions autoload/go/package_test.vim
Original file line number Diff line number Diff line change
@@ -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
Empty file.
Empty file.
3 changes: 3 additions & 0 deletions autoload/go/test-fixtures/package/src/package/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module package

go 1.12
7 changes: 7 additions & 0 deletions autoload/go/test-fixtures/package/src/package/package.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import "fmt"

func main() {
fmt.Println("vim-go")
}
Empty file.
2 changes: 1 addition & 1 deletion scripts/run-vim
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down