vim - automatically formatting golang source code when saving

The FileType event doesn't fire on buffer writes; BufWritePre is the correct one, but you need to provide a file pattern, e.g. *.go:

autocmd BufWritePre *.go Fmt

The only downside is that this duplicates the detection of the go filetype. You could delegate this by hooking into the FileType event, and then define the formatting autocmd for each Go buffer by using the special <buffer> pattern:

autocmd FileType go autocmd BufWritePre <buffer> Fmt

This has the downside that if the filetype ever gets set multiple times, you'll run the formatting multiple times, too. That could be solved via a custom :augroup, but now it becomes really complex. Or, if you're really sure that this is the only BufWritePre autocmd for Go buffers, you could use :autocmd! BufWritePre ... (with a !).


If you use folds, gofmt messes these up (it opens closed folds, closes open ones). To keep folds as they where use the following autocommand

autocmd FileType go autocmd BufWritePre <buffer> execute "normal! mz:mkview\<esc>:Fmt\<esc>:loadview\<esc>`z"

It uses the z register to mark the cursor position because :mkview and :loadview (wich save and restores the folds) move the cursor for some reason.


For those not using the plugin, this should work:

autocmd FileType go autocmd BufWritePre <buffer> execute "normal! mz:mkview\<esc>:%!gofmt-safe\<esc>:loadview\<esc>`z"

Add the following script to your PATH, this is needed otherwise gofmt will nuke the file if there are any syntax errors. This can be dangerous if you type :x for instance.

gofmt-safe

#!/usr/bin/env bash

orig=$(mktemp)
fmt=$(mktemp)

cat > "$orig"

<"$orig" gofmt "$@" > "$fmt" 2>/dev/null

if [ $? -eq 0 ]; then
    cat "$fmt"
else
    cat "$orig"
fi

rm -f "$orig" "$fmt"

If you want live dangerously without this script, you can replace %!gofmt-safe with %!gofmt in the autocmd line. This has the benefit of showing you syntax errors on :w. Just make sure not to type :x or :wq.

Tags:

Vim

Go