0 0 0 0


Go (Golang) programming language comes with a tool called go fmt. Its a code formatter, which formats your code automagically (alignments, alphabetic sorting, tabbing, spacing, idioms...). Its really awesome.

So I've found this little autocommand which utilizes it in Vim, each time buffer is saved to FileType go au BufWritePre <buffer> FmtFmt is a function that comes with Go vim plugin.

This is really great, but it has 1 problem. Each time formatter writes to buffer, it creates a jump in undo/redo history. Which becomes very painful when trying to undo/redo changes, since every 2nd change is formatter (making cursor jump to line 1).

So I am wondering, is there any way to discard latest change from undo/redo history after triggering Fmt?

EDIT:Ok, so far I have:au FileType go au BufWritePre <buffer> undojoin | FmtBut its not all good yet. According to :h undojoin, undojoin is not allowed after undo. And sure enough, it fires an error when I try to :w after an undo.

So how do I achieve something like this pseudo-code:

if lastAction != undo then
    au FileType go au BufWritePre <buffer> undojoin | Fmt

If I get this last bit figured out, I think I have a solution.

Best Answer:

I attempted to use @pepper_chino's answer but ran into issues where if fmt errors then vim would undo the last change prior to running GoFmt. I worked around this in a long and slightly convoluted way:

" Fmt calls 'go fmt' to convert the file to go's format standards. This being
" run often makes the undo buffer long and difficult to use. This function
" wraps the Fmt function causing it to join the format with the last action.
" This has to have a try/catch since you can't undojoin if the previous
" command was itself an undo.
function! GoFmt()
  " Save cursor/view info.
  let view = winsaveview()
  " Check if Fmt will succeed or not. If it will fail run again to populate location window. If it succeeds then we call it with an undojoin.
  " Copy the file to a temp file and attempt to run gofmt on it
  let TempFile = tempname()
  let SaveModified = &modified
  exe 'w ' . TempFile
  let &modified = SaveModified
  silent exe '! ' . g:gofmt_command . ' ' . TempFile
  call delete(TempFile)
  if v:shell_error
    " Execute Fmt to populate the location window
    silent Fmt
    " Now that we know Fmt will succeed we can now run Fmt with its undo
    " joined to the previous edit in the current buffer
      silent undojoin | silent Fmt
  " Restore the saved cursor/view info.
  call winrestview(view)
command! GoFmt call GoFmt()

Copyright © 2011 Dowemo All rights reserved.    Creative Commons   AboutUs