" 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