148 lines
3.9 KiB
VimL
148 lines
3.9 KiB
VimL
|
" don't spam the user when Vim is started in Vi compatibility mode
|
||
|
let s:cpo_save = &cpo
|
||
|
set cpo&vim
|
||
|
|
||
|
let s:go_major_version = ""
|
||
|
|
||
|
function! go#mod#Format() abort
|
||
|
" go mod only exists in `v1.11`
|
||
|
if empty(s:go_major_version)
|
||
|
let tokens = matchlist(go#util#Exec(['go', 'version']), '\d\+.\(\d\+\)\(\.\d\+\)\? ')
|
||
|
if len(tokens) > 0
|
||
|
let s:go_major_version = str2nr(tokens[1])
|
||
|
else
|
||
|
let s:go_major_version = ""
|
||
|
endif
|
||
|
endif
|
||
|
|
||
|
if !empty(s:go_major_version) && s:go_major_version < "11"
|
||
|
call go#util#EchoError("Go v1.11 is required to format go.mod file")
|
||
|
return
|
||
|
endif
|
||
|
|
||
|
let fname = fnamemodify(expand("%"), ':p:gs?\\?/?')
|
||
|
|
||
|
" Save cursor position and many other things.
|
||
|
let l:curw = winsaveview()
|
||
|
|
||
|
" Write current unsaved buffer to a temp file
|
||
|
let l:tmpname = tempname() . '.mod'
|
||
|
call writefile(go#util#GetLines(), l:tmpname)
|
||
|
if go#util#IsWin()
|
||
|
let l:tmpname = tr(l:tmpname, '\', '/')
|
||
|
endif
|
||
|
|
||
|
let current_col = col('.')
|
||
|
let l:args = ['go', 'mod', 'edit', '--fmt', l:tmpname]
|
||
|
let [l:out, l:err] = go#util#Exec(l:args)
|
||
|
let diff_offset = len(readfile(l:tmpname)) - line('$')
|
||
|
|
||
|
if l:err == 0
|
||
|
call go#mod#update_file(l:tmpname, fname)
|
||
|
else
|
||
|
let errors = s:parse_errors(fname, l:out)
|
||
|
call s:show_errors(errors)
|
||
|
endif
|
||
|
|
||
|
" We didn't use the temp file, so clean up
|
||
|
call delete(l:tmpname)
|
||
|
|
||
|
" Restore our cursor/windows positions.
|
||
|
call winrestview(l:curw)
|
||
|
|
||
|
" be smart and jump to the line the new statement was added/removed
|
||
|
call cursor(line('.') + diff_offset, current_col)
|
||
|
|
||
|
" Syntax highlighting breaks less often.
|
||
|
syntax sync fromstart
|
||
|
endfunction
|
||
|
|
||
|
" update_file updates the target file with the given formatted source
|
||
|
function! go#mod#update_file(source, target)
|
||
|
" remove undo point caused via BufWritePre
|
||
|
try | silent undojoin | catch | endtry
|
||
|
|
||
|
let old_fileformat = &fileformat
|
||
|
if exists("*getfperm")
|
||
|
" save file permissions
|
||
|
let original_fperm = getfperm(a:target)
|
||
|
endif
|
||
|
|
||
|
call rename(a:source, a:target)
|
||
|
|
||
|
" restore file permissions
|
||
|
if exists("*setfperm") && original_fperm != ''
|
||
|
call setfperm(a:target , original_fperm)
|
||
|
endif
|
||
|
|
||
|
" reload buffer to reflect latest changes
|
||
|
silent edit!
|
||
|
|
||
|
let &fileformat = old_fileformat
|
||
|
let &syntax = &syntax
|
||
|
|
||
|
let l:listtype = go#list#Type("GoModFmt")
|
||
|
|
||
|
" clean up previous list
|
||
|
if l:listtype == "quickfix"
|
||
|
let l:list_title = getqflist({'title': 1})
|
||
|
else
|
||
|
let l:list_title = getloclist(0, {'title': 1})
|
||
|
endif
|
||
|
|
||
|
if has_key(l:list_title, "title") && l:list_title['title'] == "Format"
|
||
|
call go#list#Clean(l:listtype)
|
||
|
endif
|
||
|
endfunction
|
||
|
|
||
|
" parse_errors parses the given errors and returns a list of parsed errors
|
||
|
function! s:parse_errors(filename, content) abort
|
||
|
let splitted = split(a:content, '\n')
|
||
|
|
||
|
" list of errors to be put into location list
|
||
|
let errors = []
|
||
|
for line in splitted
|
||
|
let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\s*\(.*\)')
|
||
|
if !empty(tokens)
|
||
|
call add(errors,{
|
||
|
\"filename": a:filename,
|
||
|
\"lnum": tokens[2],
|
||
|
\"text": tokens[3],
|
||
|
\ })
|
||
|
endif
|
||
|
endfor
|
||
|
|
||
|
return errors
|
||
|
endfunction
|
||
|
|
||
|
" show_errors opens a location list and shows the given errors. If the given
|
||
|
" errors is empty, it closes the the location list
|
||
|
function! s:show_errors(errors) abort
|
||
|
let l:listtype = go#list#Type("GoModFmt")
|
||
|
if !empty(a:errors)
|
||
|
call go#list#Populate(l:listtype, a:errors, 'Format')
|
||
|
call go#util#EchoError("GoModFmt returned error")
|
||
|
endif
|
||
|
|
||
|
" this closes the window if there are no errors or it opens
|
||
|
" it if there is any
|
||
|
call go#list#Window(l:listtype, len(a:errors))
|
||
|
endfunction
|
||
|
|
||
|
function! go#mod#ToggleModFmtAutoSave() abort
|
||
|
if go#config#ModFmtAutosave()
|
||
|
call go#config#SetModFmtAutosave(0)
|
||
|
call go#util#EchoProgress("auto mod fmt disabled")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
call go#config#SetModFmtAutosave(1)
|
||
|
call go#util#EchoProgress("auto mod fmt enabled")
|
||
|
endfunction
|
||
|
|
||
|
" restore Vi compatibility settings
|
||
|
let &cpo = s:cpo_save
|
||
|
unlet s:cpo_save
|
||
|
|
||
|
" vim: sw=2 ts=2 et
|