Skip to content

Commit dd1dd81

Browse files
committed
go.mod file support
This adds initial support for the `go.mod` file. It adds the followings: * Syntax highligthing. We highlight keywords, strings, operator and semver version. It works pretty well for now. * Auto fmt on save. Command `:GoModFmt` or `Plug(go-mod-fmt)` for custom mappings Before we fully support the semantics of go.mod, I think this initially will be helpful because I discovered that `go.mod` is read and edited a lot. So going forward, this will make it easier experimenting with Go modules. related: #1906
1 parent b6381dd commit dd1dd81

File tree

11 files changed

+216
-1
lines changed

11 files changed

+216
-1
lines changed

autoload/go/config.vim

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,14 @@ function! go#config#SetAsmfmtAutosave(value) abort
278278
let g:go_asmfmt_autosave = a:value
279279
endfunction
280280

281+
function! go#config#ModfmtAutosave() abort
282+
return get(g:, "go_modfmt_autosave", 1)
283+
endfunction
284+
285+
function! go#config#SetModfmtAutosave(value) abort
286+
let g:go_modfmt_autosave = a:value
287+
endfunction
288+
281289
function! go#config#DocMaxHeight() abort
282290
return get(g:, "go_doc_max_height", 20)
283291
endfunction

autoload/go/fix.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/Users/fatih/go/src/github.com/fatih/goautofix/vim/fix.vim

autoload/go/mod.vim

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
function! go#mod#Format() abort
2+
let fname = fnamemodify(expand("%"), ':p:gs?\\?/?')
3+
4+
" Save cursor position and many other things.
5+
let l:curw = winsaveview()
6+
7+
" Write current unsaved buffer to a temp file
8+
let l:tmpname = tempname() . '.go'
9+
call writefile(go#util#GetLines(), l:tmpname)
10+
if go#util#IsWin()
11+
let l:tmpname = tr(l:tmpname, '\', '/')
12+
endif
13+
14+
let current_col = col('.')
15+
let l:args = ['go', 'mod', 'edit', '--fmt', l:tmpname]
16+
let [l:out, l:err] = go#util#Exec(l:args)
17+
let diff_offset = len(readfile(l:tmpname)) - line('$')
18+
19+
if l:err == 0
20+
call go#mod#update_file(l:tmpname, fname)
21+
else
22+
let errors = s:parse_errors(fname, l:out)
23+
call s:show_errors(errors)
24+
endif
25+
26+
" We didn't use the temp file, so clean up
27+
call delete(l:tmpname)
28+
29+
" Restore our cursor/windows positions.
30+
call winrestview(l:curw)
31+
32+
" be smart and jump to the line the new statement was added/removed
33+
call cursor(line('.') + diff_offset, current_col)
34+
35+
" Syntax highlighting breaks less often.
36+
syntax sync fromstart
37+
endfunction
38+
39+
" update_file updates the target file with the given formatted source
40+
function! go#mod#update_file(source, target)
41+
" remove undo point caused via BufWritePre
42+
try | silent undojoin | catch | endtry
43+
44+
let old_fileformat = &fileformat
45+
if exists("*getfperm")
46+
" save file permissions
47+
let original_fperm = getfperm(a:target)
48+
endif
49+
50+
call rename(a:source, a:target)
51+
52+
" restore file permissions
53+
if exists("*setfperm") && original_fperm != ''
54+
call setfperm(a:target , original_fperm)
55+
endif
56+
57+
" reload buffer to reflect latest changes
58+
silent edit!
59+
60+
let &fileformat = old_fileformat
61+
let &syntax = &syntax
62+
63+
let l:listtype = go#list#Type("GoModFmt")
64+
65+
" the title information was introduced with 7.4-2200
66+
" https://github.com/vim/vim/commit/d823fa910cca43fec3c31c030ee908a14c272640
67+
if has('patch-7.4.2200')
68+
" clean up previous list
69+
if l:listtype == "quickfix"
70+
let l:list_title = getqflist({'title': 1})
71+
else
72+
let l:list_title = getloclist(0, {'title': 1})
73+
endif
74+
else
75+
" can't check the title, so assume that the list was for go fmt.
76+
let l:list_title = {'title': 'Format'}
77+
endif
78+
79+
if has_key(l:list_title, "title") && l:list_title['title'] == "Format"
80+
call go#list#Clean(l:listtype)
81+
endif
82+
endfunction
83+
84+
" parse_errors parses the given errors and returns a list of parsed errors
85+
function! s:parse_errors(filename, content) abort
86+
let splitted = split(a:content, '\n')
87+
88+
" list of errors to be put into location list
89+
let errors = []
90+
for line in splitted
91+
let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\)\s*\(.*\)')
92+
if !empty(tokens)
93+
call add(errors,{
94+
\"filename": a:filename,
95+
\"lnum": tokens[2],
96+
\"col": tokens[3],
97+
\"text": tokens[4],
98+
\ })
99+
endif
100+
endfor
101+
102+
return errors
103+
endfunction
104+
105+
" show_errors opens a location list and shows the given errors. If the given
106+
" errors is empty, it closes the the location list
107+
function! s:show_errors(errors) abort
108+
let l:listtype = go#list#Type("GoModFmt")
109+
if !empty(a:errors)
110+
call go#list#Populate(l:listtype, a:errors, 'Format')
111+
echohl Error | echomsg "GoModFmt returned error" | echohl None
112+
endif
113+
114+
" this closes the window if there are no errors or it opens
115+
" it if there is any
116+
call go#list#Window(l:listtype, len(a:errors))
117+
endfunction
118+
119+
function! go#mod#ToggleModfmtAutoSave() abort
120+
if go#config#ModfmtAutosave()
121+
call go#config#SetModfmtAutosave(0)
122+
call go#util#EchoProgress("auto mod fmt disabled")
123+
return
124+
end
125+
126+
call go#config#SetModfmtAutosave(1)
127+
call go#util#EchoProgress("auto fmt enabled")
128+
endfunction

ftdetect/gofiletype.vim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,8 @@ au BufReadPost *.s call s:gofiletype_post()
3131

3232
au BufRead,BufNewFile *.tmpl set filetype=gohtmltmpl
3333

34+
au BufNewFile *.mod setfiletype gomod | setlocal fileencoding=utf-8 fileformat=unix
35+
au BufRead *.mod call s:gofiletype_pre("gomod")
36+
au BufReadPost *.mod call s:gofiletype_post()
37+
3438
" vim: sw=2 ts=2 et

ftplugin/go/commands-fix.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/Users/fatih/go/src/github.com/fatih/goautofix/vim/commands-fix.vim

ftplugin/go/commands.vim

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ command! -range=0 GoSameIdsToggle call go#guru#ToggleSameIds()
2020
command! -range=0 GoSameIdsAutoToggle call go#guru#AutoToogleSameIds()
2121

2222
" -- tags
23-
command! -nargs=* -range GoAddTags call go#tags#Add(<line1>, <line2>, <count>, <f-args>)
23+
command! -nargs=? -range GoAddTags call go#tags#Add(<line1>, <line2>, <count>, <f-args>)
2424
command! -nargs=* -range GoRemoveTags call go#tags#Remove(<line1>, <line2>, <count>, <f-args>)
2525

26+
" -- mod
27+
command! -nargs=0 -range GoModFmt call go#mod#Format()
28+
2629
" -- tool
2730
command! -nargs=* -complete=customlist,go#tool#ValidFiles GoFiles echo go#tool#Files(<f-args>)
2831
command! -nargs=0 GoDeps echo go#tool#Deps()

ftplugin/gomod.vim

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
" gomod.vim: Vim filetype plugin for Go assembler.
2+
3+
if exists("b:did_ftplugin")
4+
finish
5+
endif
6+
let b:did_ftplugin = 1
7+
8+
let b:undo_ftplugin = "setl fo< com< cms<"
9+
10+
setlocal formatoptions-=t
11+
12+
setlocal comments=s1:/*,mb:*,ex:*/,://
13+
setlocal commentstring=//\ %s
14+
15+
" vim: sw=2 ts=2 et

ftplugin/gomod/commands.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
command! -nargs=0 -range GoModFmt call go#mod#Format()

ftplugin/gomod/mappings.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nnoremap <silent> <Plug>(go-mod-fmt) :<C-u>call go#mod#Format()<CR>

plugin/go.vim

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,13 @@ function! s:asmfmt_autosave()
226226
endif
227227
endfunction
228228

229+
function! s:modfmt_autosave()
230+
" go.mod code formatting on save
231+
if get(g:, "go_modfmt_autosave", 1)
232+
call go#mod#Format()
233+
endif
234+
endfunction
235+
229236
function! s:metalinter_autosave()
230237
" run gometalinter on save
231238
if get(g:, "go_metalinter_autosave", 0)
@@ -253,6 +260,7 @@ augroup vim-go
253260
endif
254261

255262
autocmd BufWritePre *.go call s:fmt_autosave()
263+
autocmd BufWritePre *.mod call s:modfmt_autosave()
256264
autocmd BufWritePre *.s call s:asmfmt_autosave()
257265
autocmd BufWritePost *.go call s:metalinter_autosave()
258266
autocmd BufNewFile *.go call s:template_autocreate()

0 commit comments

Comments
 (0)