vim – 在保存时自动格式化golang源代码

huangapple go评论89阅读模式
英文:

vim - automatically formatting golang source code when saving

问题

我正在使用带有vim-golang插件的vim。该插件带有一个名为:Fmt的函数,它使用命令行可执行文件gofmt来“重新格式化”源代码。

我想在每次保存文件时调用:Fmt函数,以便持续重新格式化。我认为这应该通过autocmd指令来完成。但是我有两个疑问:

  1. 我找不到执行该函数的方法。我尝试在autocmd行的末尾写入Fmt和:Fmt,但似乎不起作用。我觉得我漏掉了什么,比如“call”。
  2. 我希望只在保存文件类型为'go'时发生这种情况。我不知道如何结合这两个条件 - 我可以根据文件类型激活变量,并且可以在保存文件时执行一些小操作,比如删除尾随空格,但是分开来做。

所以这是我目前的代码:

" 我可以这样为go设置变量
autocmd FileType go setlocal noexpandtab shiftwidth=4 tabstop=4 softtabstop=4 nolist

" 我可以这样在保存时清除尾随空格(保留光标位置)
autocmd BufWritePre * kz|:%s/\s\+$//e|'z

" 这些都不起作用:
autocmd BufWritePre,FileType go Fmt
autocmd BufWritePre,FileType go :Fmt
英文:

I'm using vim with the vim-golang plugin. This plugin comes with a function called :Fmt that "reformats" the source code using gofmt, a command-line executable.

I want to invoke the :Fmt function each time that I save the file, so it is continuously re-formatted. I think this should be done with a autocmd directive. But I have two doubts:

  1. I could not find a way to execute the function. I tried writting Fmt and :Fmt at the end of the autocmd line, but it didn't seem to work. I think I miss something, like "call".
  2. I want this to happen only when saving a file of filetype 'go'. I don't know how to combine those two conditions - I can activate variables depending on the file type, and I can do small stuff, like removing trailing spaces, whenever a file is saved, but separatedly.

So this is what I have so far:

" I can set variables for go like this
autocmd FileType go setlocal noexpandtab shiftwidth=4 tabstop=4 softtabstop=4 nolist

" I can clean trailing spaces(conserving cursor position) on save like this
autocmd BufWritePre * kz|:%s/\s\+$//e|'z

" None of these worked:
autocmd BufWritePre,FileType go Fmt
autocmd BufWritePre,FileType go :Fmt

答案1

得分: 61

FileType事件在缓冲区写入时不会触发;BufWritePre是正确的事件,但你需要提供一个文件模式,例如*.go

autocmd BufWritePre *.go Fmt

唯一的缺点是这样会重复检测_go_文件类型。你可以通过挂钩到FileType事件来委托处理,并使用特殊的<buffer>模式为每个Go缓冲区定义格式化的自动命令:

autocmd FileType go autocmd BufWritePre <buffer> Fmt

这样做的缺点是,如果文件类型被设置多次,格式化也会运行多次。这可以通过自定义的:augroup来解决,但现在变得非常复杂。或者,如果你确信这是Go缓冲区的唯一BufWritePre自动命令,你可以使用:autocmd! BufWritePre ...(带有!)。

英文:

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 &lt;buffer&gt; pattern:

autocmd FileType go autocmd BufWritePre &lt;buffer&gt; 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 !).

答案2

得分: 2

如果您使用折叠功能,gofmt会弄乱它们(它会打开已关闭的折叠,关闭已打开的折叠)。
为了保持折叠的状态,使用以下自动命令:

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

它使用z寄存器来标记光标位置,因为:mkview和:loadview(保存和恢复折叠)会因某种原因移动光标。

英文:

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 &lt;buffer&gt; execute &quot;normal! mz:mkview\&lt;esc&gt;:Fmt\&lt;esc&gt;:loadview\&lt;esc&gt;`z&quot;

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.

答案3

得分: 2

对于不使用插件的人,这应该可以工作:

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

将以下脚本添加到您的PATH中,否则如果有任何语法错误,gofmt将会删除文件。如果您输入:x,这可能是危险的。

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"

如果您想要在没有此脚本的情况下冒险,您可以将%!gofmt-safe替换为%!gofmtautocmd行中。这样做的好处是在:w时显示语法错误。只要确保不要输入:x:wq

英文:

For those not using the plugin, this should work:

autocmd FileType go autocmd BufWritePre &lt;buffer&gt; execute &quot;normal! mz:mkview\&lt;esc&gt;:%!gofmt-safe\&lt;esc&gt;:loadview\&lt;esc&gt;`z&quot;

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 &gt; &quot;$orig&quot;

&lt;&quot;$orig&quot; gofmt &quot;$@&quot; &gt; &quot;$fmt&quot; 2&gt;/dev/null

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

rm -f &quot;$orig&quot; &quot;$fmt&quot;

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.

huangapple
  • 本文由 发表于 2012年6月10日 22:12:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/10969366.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定