英文:
Golang Formatter and Vim - How to destroy history record?
问题
Go(Golang)编程语言配备了一个名为go fmt
的工具。它是一个代码格式化工具,可以自动格式化你的代码(对齐、字母排序、制表、间距、习惯用法等)。它真的很棒。
所以我找到了这个小的自动命令,它在每次将缓冲区保存到文件时都会使用它。
au FileType go au BufWritePre <buffer> Fmt
Fmt是Go vim插件提供的一个函数。
这真的很棒,但是有一个问题。每次格式化程序写入缓冲区时,都会在撤销/重做历史记录中创建一个跳转。当尝试撤销/重做更改时,这变得非常痛苦,因为每两次更改中就有一次是格式化程序(使光标跳转到第一行)。
所以我想知道,在触发Fmt
之后,是否有任何方法可以从撤销/重做历史记录中丢弃最新的更改?
编辑:
好的,到目前为止我有:
au FileType go au BufWritePre <buffer> undojoin | Fmt
但是还不够好。根据:h undojoin
,在撤销之后不允许使用undojoin。当我尝试在撤销之后执行:w
时,它确实会报错。
那么我如何实现类似于这样的伪代码:
if lastAction != undo then
au FileType go au BufWritePre <buffer> undojoin | Fmt
end
如果我解决了这个最后一部分,我认为我就有了一个解决方案。
英文:
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 file.
au FileType go au BufWritePre <buffer> Fmt
Fmt 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 | Fmt
But 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
end
If I get this last bit figured out, I think I have a solution.
答案1
得分: 5
我认为这已经接近你的要求了,完成了你的要求,但我注意到它删除了一个撤销点(我认为这是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命令,所以我在写入文件之前执行它。但同时,它会将光标放在文件的顶部...
英文:
I think this is almost there, accomplishes what you ask, but I see it's deleting one undo point (I think this is expected from undojoin
):
function! GoFmt()
try
exe "undojoin"
exe "Fmt"
catch
endtry
endfunction
au FileType go au BufWritePre <buffer> call GoFmt()
###EDIT
Based on MattyW answer I recalled another alternative:
au FileType go au BufWritePre <buffer> %!gofmt
:%!<some command>
executes a shell command over the buffer, so I do it before writing it to file. But also, it's gonna put the cursor at top of file...
答案2
得分: 3
这是我的尝试。它似乎在读写自动命令和绑定到键上都能很好地工作。它将光标放回原位,并且不包括文件顶部事件在撤销操作中。
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
我检查 modifiable 是因为我将 vim 用作我的分页器。
英文:
Here is my go at this. It seems to be working well both with read/write autocmds and bound to a key. It puts the cursor back
and doesn't include the top-of-file event in the 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
I check modifiable because I use vim as my pager.
答案3
得分: 2
我尝试使用@pepper_chino的答案,但遇到了问题,如果fmt出错,那么vim会在运行GoFmt
之前撤销上一次更改。我以一种冗长而稍微复杂的方式解决了这个问题:
" Fmt调用'go fmt'将文件转换为go的格式标准。由于经常运行,导致撤消缓冲区变得很长且难以使用。此函数包装了Fmt函数,使其与上一次操作合并。由于无法撤消上一个命令本身是一个撤消,因此必须使用try/catch。
function! GoFmt()
" 保存光标/视图信息。
let view = winsaveview()
" 检查Fmt是否会成功。如果失败,则再次运行以填充位置窗口。如果成功,则使用undojoin调用它。
" 将文件复制到临时文件并尝试在其上运行gofmt
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
" 执行Fmt以填充位置窗口
silent Fmt
else
" 现在我们知道Fmt将成功,我们可以将Fmt与当前缓冲区中上一个编辑的撤消合并
try
silent undojoin | silent Fmt
catch
endtry
endif
" 恢复保存的光标/视图信息。
call winrestview(view)
endfunction
command! GoFmt call GoFmt()
以上是要翻译的内容。
英文:
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
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
得分: 1
我只在我的 .vimrc 文件中添加了以下内容:
au BufWritePost *.go !gofmt -w %
当我保存文件时,它会自动运行 gofmt 命令。它不会在缓冲区中重新格式化文件,因此不会打断我正在查看的内容,但是文件在磁盘上是正确格式化的,因此所有的提交都是正确格式化的。如果你想看到正确格式化的代码,只需执行 :e 命令即可。
它也不会影响我的撤销/重做历史记录。
英文:
I just have this in my .vimrc:
au BufWritePost *.go !gofmt -w %
Automatically runs gofmt on the file when I save. It doesn't actually reformat it in the buffer so it doesn't interrupt what I'm looking at, but it's correctly formatted on disk so all check ins are properly formatted. If you want to see the correctly formatted code looks like you can just do :e .
Doesn't do anything to my undo/redo history either
答案5
得分: -2
你可以从默认仓库安装vim插件。另外,这里有一个适用于Pathogen的友好镜像:
https://github.com/jnwhiteh/vim-golang
然后你可以使用:Fmt
命令来安全地执行go fmt!
英文:
You can install the vim plugins from the default repository. Alternatively, a pathogen friendly mirror is here:
https://github.com/jnwhiteh/vim-golang
Then you can use the :Fmt command to safely do a go fmt!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论