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

Add basic :GoModReplace #35

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
17 changes: 17 additions & 0 deletions autoload/gopher/go.vim
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@ fun! gopher#go#module() abort
return l:out
endfun

" Get the go.mod file location, or -1 if there is none.
fun! gopher#go#gomod() abort
let l:dir = expand('%:p:h')
while 1
" len() check is for Windows; not sure how that's represented.
if l:dir is# '/' || len(l:dir) <= 4
return -1
endif

if filereadable(l:dir + '/go.mod')
return l:dir + '/go.mod'
endif

let l:dir = fnamemodify(l:dir, ':h')
endwhile
endfun

" Get the package path for the file in the current buffer.
fun! gopher#go#package() abort
let [l:out, l:err] = gopher#system#run(['go', 'list', './' . expand('%:h')])
Expand Down
61 changes: 61 additions & 0 deletions autoload/gopher/mod.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
" mod.vim: Utilities for working with go.mod files.

" Add or remove replace directives.
fun! gopher#mod#replace(...)
" TODO: get arguments.
let l:mod = ''
let l:path = ''

if l:mod is# ''
" TODO: be a bit smarter in go.mod file, since now 'require' is considered a
" module as well.
let l:mod = expand('<cWORD>')
endif

if &filetype is# 'go'
let l:gomod = gopher#go#gomod()
if l:gomod is# ''
return gopher#error('No go.mod file found.')
endif

if l:mod is# ''
" On identifier: fmt.Printf("..")
if l:mod =~# '\.'
let l:mod = split(l:mod, '.')[0]
let l:resolve = gopher#pkg#resolve()
if l:resolve is# ''
return gopher#error('Unknown package: %s', l:mod)
endif

let l:mod = l:resolve
" On package: "fmt".
else
let l:mod = trim(l:mod, '"')
endif
endif
endif

if l:mod is# ''
return gopher#error('Not a package: %s', l:mod)
endif

if l:path is# ''
let l:path = '../' . fnamemodify(l:mod, ':t')
endif

let l:line = printf('replace %s => %s', l:mod, l:path)

" TODO: :GoModReplace on something that already exists should remove it.
" TODO: Don't add duplicate replaces.

" Place before first require or replace.
for l:i in range(1, line('$'))
if getline(l:i) =~# '\v^(require|replace)'
call append(l:i-1, [l:line, ''])
return
endif
endfor

" Nothing in the file yet.
call append('$', l:line)
endfun
29 changes: 29 additions & 0 deletions autoload/gopher/pkg.vim
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,32 @@ fun! gopher#pkg#list_interfaces(pkg) abort

return l:out
endfun

" List all imports for the current buffer.
fun! gopher#pkg#list_imports() abort
let [l:out, l:err] = gopher#system#run(['go', 'list', '-f', '{{.Imports}}', expand('%')])
if l:err
call gopher#error(l:out)
return []
endif
return split(trim(l:out, '[]'), ' ')
endfun

" Resolve a package name to the full import path for the current buffer.
"
" fmt → fmt
" http → net/http
" pq → github.com/lib/pq
"
" Returns empty string if the import is not found.
fun! gopher#pkg#resolve(pkg) abort
let l:slash = '/' + a:pkg

for l:import in gopher#pkg#list_imports()
if l:import is# a:pkg || gopher#str#has_suffix(l:import, l:slash)
return l:import
endif
endfor

return ''
endfun
6 changes: 3 additions & 3 deletions doc/gopher.txt
Original file line number Diff line number Diff line change
Expand Up @@ -379,10 +379,10 @@ COMMANDS *gopher-commands*
*g:gopher_gorename_flags* = `[]`
List of flags to add to the `gorename` command.

:GoReplace [module] [path] *:GoReplace*
:GoModReplace [module] [path] *:GoModReplace*

Add a `replace` directive in the project's go.mod. This currently only
works in the `go.mod` buffer.
Add a `replace` directive in the project's go.mod. This works from any
`go` or the `go.mod` buffer.

[module] is a module name; if it's omitted the module on the current
line is used.
Expand Down
2 changes: 2 additions & 0 deletions ftplugin/go.vim
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,5 @@ command! -nargs=* -complete=customlist,gopher#import#complete GoImport
command! -nargs=* -range -complete=customlist,gopher#tags#complete GoTags call gopher#tags#modify(<line1>, <line2>, <count>, <f-args>)
command! -nargs=+ -complete=customlist,gopher#guru#complete GoGuru call gopher#guru#do(<f-args>)
command! -nargs=? -complete=customlist,gopher#rename#complete GoRename call gopher#rename#do(<f-args>)

command! -nargs=* GoModReplace call gopher#mod#replace(<f-args>)
2 changes: 2 additions & 0 deletions ftplugin/gomod.vim
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ call gopher#init#version()
setlocal noexpandtab

compiler go

command! -nargs=* GoModReplace call gopher#mod#replace(<f-args>)