I want to run gofmt on save on vim without installing any plugin. This is what I have tried (inspired by https://gist.github.com/tbrisbout/a91ac3419440cde40c5f54dc32c94427):
function! GoFmt()
let file = expand('%')
silent execute "!gofmt -w " . file
edit!
endfunction
command! GoFmt call GoFmt()
augroup go_autocmd
autocmd BufWritePost *.go GoFmt
augroup END
This just works when there is no format error. However, if the code contains error, it shows error message at the bottom of the screen and (it seems like) it appears on the buffer as text, so the whole code gets broken. Is there an simple way to handle this kind of work on vim?
Gofmt is both a code formatter and a linter, a design decision that makes it harder than necessary to integrate it with Vim. In practice, it means that things can go three ways:
For example, we could naively try to use
gofmtforgqand friends by way of:help 'formatprg'but the chances of eventually overwritting our code with crap like:are too high. Like in your case, we can do
uto undo but that's not fun. I guess we will have to work aroundgofmt's bad design.First step: switch to
:help BufWritePre. We have seen thatgofmtcan handlestdin, which allows us to format the buffer as well as the file. That is handy because formatting the file after it was written writes the file a second time for no good reason and forces us to reload it in Vim… and all that seems wasteful.:help BufWritePostis best kept for things that don't affect Vim's state.Second step: filter the whole buffer through
gofmt.Third step: "handle" the worst case scenario with a basic undo. If the external command returns an error, we can get it via
:help v:shell_errorand do what needs to be done.Fourth step: try to keep the cursor in place.
See
:help winsaveview()and:help winrestview().Fifth step: if applicable, create a quickfix list with the errors reported by
gofmt.:help getline()gives us all the lines of the buffer—therefore all the errors—in a list of which we modify each item so that the file name is the current file name instead of the useless<standard input>. We give that list to:help :cexprto create a quickfix list before undoing the filter.This step has a bit of a "draw the rest of the * howl" vibe but it really is just a simple
:help substitute()in a simple:help map(). For the{ foo, bar -> baz }syntax, see:help lambda.Sixth and last step: open the quickfix window if there are any valid errors, with
:help :cwindow.