Golang Formatter和Vim - 如何破坏历史记录?

时间:2013-08-30 12:16:11

标签: vim go

Go(Golang)编程语言附带了一个名为go fmt的工具。它是一个代码格式化程序,可以自动格式化代码(对齐,字母排序,制表,间距,习语......)。它非常棒。

所以我发现这个小自动命令在Vim中使用它,每次缓冲区都保存到文件中。 au FileType go au BufWritePre <buffer> Fmt Fmt是Go vim插件附带的一个功能。

这真的很棒,但它有一个问题。每次格式化程序写入缓冲区时,它都会在撤消/重做历史记录中创建跳转。在尝试撤消/重做更改时会变得非常痛苦,因为每次第二次更改都是格式化程序(使光标跳转到第1行)。

所以我想知道,有没有办法在触发Fmt后撤消撤消/重做历史记录的最新更改?

修改 好的,到目前为止我有: au FileType go au BufWritePre <buffer> undojoin | Fmt 但它还不是很好。根据{{​​1}},撤消后不允许使用undojoin。当然,当我在撤消后尝试:h undojoin时会触发错误。

那么我如何实现像这样的伪代码:

:w

如果我弄清楚最后一点,我想我有一个解决方案。

5 个答案:

答案 0 :(得分:4)

我认为这几乎就在那里,完成了你的要求,但我看到它正在删除一个撤销点(我认为这是从undojoin开始的):

function! GoFmt()
    try                
        exe "undojoin"
        exe "Fmt"
    catch              
    endtry
endfunction
au FileType go au BufWritePre <buffer> call GoFmt()

修改

根据MattyW的回答,我回忆起另一种选择:

au FileType go au BufWritePre <buffer> %!gofmt

:%!<some command>在缓冲区上执行shell命令,所以我在将它写入文件之前执行。但是,它会把光标放在文件顶部......

答案 1 :(得分:2)

这是我的目标。它似乎与读/写autocmds和绑定到一个键都很好。它将光标放回原位 并且不包括undos中的文件顶部事件。

function! GoFormatBuffer()
    if &modifiable == 1
        let l:curw=winsaveview()
        let l:tmpname=tempname()
        call writefile(getline(1,'$'), l:tmpname)
        call system("gofmt " . l:tmpname ." > /dev/null 2>&1")
        if v:shell_error == 0
            try | silent undojoin | catch | endtry
            silent %!gofmt -tabwidth=4
        endif
        call delete(l:tmpname)
        call winrestview(l:curw)
    endif
endfunction

我检查是可修改的,因为我使用vim作为我的寻呼机。

答案 2 :(得分:1)

我在.vimrc中有这个:

au BufWritePost *.go !gofmt -w %

保存时自动在文件上运行gofmt。它实际上并没有在缓冲区中重新格式化,因此它不会中断我正在查看的内容,但它在磁盘上的格式正确,因此所有签入都已正确格式化。如果您希望看到格式正确的代码,您可以执行:e

对我的撤消/重做历史记录不做任何事情

答案 3 :(得分:1)

我尝试使用@ pepper_chino的答案,但遇到了问题,如果fmt错误然后vim将在运行GoFmt之前撤消上一次更改。我以一种漫长且有点复杂的方式解决了这个问题:

" 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
  else
    " Now that we know Fmt will succeed we can now run Fmt with its undo
    " joined to the previous edit in the current buffer
    try                
      silent undojoin | silent Fmt
    catch              
    endtry
  endif
  " Restore the saved cursor/view info.
  call winrestview(view)
endfunction
command! GoFmt call GoFmt()

答案 4 :(得分:-3)

您可以从默认存储库安装vim插件。或者,这里有一个病原体友好的镜子:

https://github.com/jnwhiteh/vim-golang

然后你可以使用:Fmt命令安全地进行fmt!