Skip to content

Commit

Permalink
complete vendored packages and modules
Browse files Browse the repository at this point in the history
Teach vim-go how to complete vendored package names and packages in
modules.

Fixes #1909 and fixes #2212
  • Loading branch information
bhcleek committed Apr 7, 2019
1 parent 686167f commit e792d47
Showing 1 changed file with 108 additions and 12 deletions.
120 changes: 108 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,64 @@ 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 = []
let l:i = 0
while l:dir != l:root
let l:i += 1

if l:i == 4
return []
endif
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 +202,71 @@ 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 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 && len(a:ArgLead) != len(module.path)
let glob = globpath(module.dir, substitute(a:ArgLead, module.path, '', '').'*')
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)
let candidate .= '/'
elseif candidate !~ '\.a$'
continue
endif
let i = substitute(substitute(i[len(r)+1:], '[\\]', '/', 'g'),

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

0 comments on commit e792d47

Please sign in to comment.