mvdan/gofumpt
GitHub: mvdan/gofumpt
gofumpt 是基于 gofmt 分支的 Go 代码格式化工具,在保持向后兼容的同时强制执行比 gofmt 更严格的代码格式规则。
Stars: 4041 | Forks: 134
# gofumpt
[](https://pkg.go.dev/mvdan.cc/gofumpt/format)
```
go install mvdan.cc/gofumpt@latest
```
在保持向后兼容的同时,强制执行比 `gofmt` 更严格的格式。
也就是说,`gofumpt` 满意的格式是 `gofmt` 满意格式的子集。
该工具是 Go 1.26.0 版本 `gofmt` 的一个分支,需要 Go 1.25 或更高版本。
它可以用作格式化 Go 代码的直接替代方案,
并且在运行 `gofumpt` 之后再运行 `gofmt` 应该不会产生任何更改。
例如:
```
gofumpt -l -w .
```
本仓库中的部分 Go 源文件属于 Go 项目。
该项目包含了 Go 1.26.0 版本的 `go/printer` 和 `go/doc/comment` 副本,
以确保无论使用什么版本的 Go 都能获得一致的格式化效果。
[新增的格式化规则](#Added-rules) 是在 `format` 包中实现的。
除非作为显式参数提供,否则将跳过 `vendor` 和 `testdata` 目录。
类似地,除非作为显式参数提供,新增的规则也不适用于生成的 Go 文件。
`go.mod` 文件中的 [`ignore` 指令](https://go.dev/ref/mod#go-mod-file-ignore) 也会被遵守,
除非其中的目录或文件作为显式参数提供。
最后,请注意,移除了 `-r` 重写标志以推荐使用 `gofmt -r`,
并且隐藏了 `-s` 标志,因为它总是被启用的。
### 新增规则
**简单的赋值操作符后不应有换行**
**函数体周围不应有空行**
**函数应将 `) {` 分开,以通过缩进提高可读性**
**代码块中单独的语句(或注释)周围不应有空行**
**简单的错误检查之前不应有空行**
**复合字面量应一致地使用换行**
**左括号在行尾的多行函数调用,应将右括号放在行首**
**空字段列表应使用单行**
**`std` 导入必须单独放在顶部的组中**
**简短的 case 子句应合并为单行**
**多行顶层声明必须用空行分隔**
**单个 var 声明不应使用括号分组**
**连续的顶层声明应组合在一起**
**简单的变量声明语句应使用短赋值**
**默认启用 `-s` 代码简化标志**
**在 Go 1.13 及更高版本的模块中,八进制整数字面量应使用 `0o` 前缀**
**非 Go 指令的注释应以空格开头**
**复合字面量不应有前导或尾随空行**
**字段列表不应有前导或尾随空行**
**绝对无用的括号应被移除**
### `-extra` 背后的额外规则
**具有相同类型的相邻参数应组合在一起**
**为清晰起见,避免使用裸返回 (naked returns)**
### 安装
`gofumpt` 是 `gofmt` 的替代品,因此您只需按照此 README 顶部的说明执行 `go install` 并使用它即可。
当使用基于 `gopls` 的 Go 集成 IDE 或编辑器时,
最好将编辑器配置为使用 `gopls` 内置的 `gofumpt` 支持。
以下说明展示了如何为主流编辑器设置 `gofumpt`。
#### Visual Studio Code
按照[官方文档](https://github.com/golang/vscode-go#readme) 启用语言服务器,
然后启用 gopls 的 `gofumpt` 选项。请注意,VS Code 会警告 `gopls` 的设置问题,但它们仍然有效。
```
"go.useLanguageServer": true,
"gopls": {
"formatting.gofumpt": true,
},
```
#### GoLand
GoLand 不使用 `gopls`,因此应将其配置为直接使用 `gofumpt`。
安装 `gofumpt` 后,请按照以下步骤操作:
- 打开 **Settings** (File > Settings)
- 打开 **Tools** 部分
- 找到 *File Watchers* 子部分
- 点击右侧的 `+` 添加新的文件监视器
- 选择 *Custom Template*
当窗口要求输入设置时,您可以输入以下内容:
* File Types:选择所有 .go 文件
* Scope:Project Files
* Program:选择您的 `gofumpt` 可执行文件
* Arguments:`-w $FilePath$`
* Output path to refresh:`$FilePath$`
* Working directory:`$ProjectFileDir$`
* Environment variables:`GOROOT=$GOROOT$;GOPATH=$GOPATH$;PATH=$GoBinDirs$`
为避免不必要的运行,您应该禁用 *Advanced* 部分中的所有复选框。
#### Vim
配置取决于您使用的插件:[vim-go](https://github.com/fatih/vim-go)
或 [govim](https://github.com/govim/govim)。
##### vim-go
配置 `gopls` 使用 `gofumpt`:
```
let g:go_fmt_command="gopls"
let g:go_gopls_gofumpt=1
```
##### govim
配置 `gopls` 使用 `gofumpt`:
```
call govim#config#Set("Gofumpt", 1)
```
#### Neovim
当使用 [`lspconfig`](https://github.com/neovim/nvim-lspconfig) 时,将 `gofumpt` 设置传递给 `gopls`:
```
require('lspconfig').gopls.setup({
settings = {
gopls = {
gofumpt = true
}
}
})
```
#### Emacs
对于 8.0.0 或更高版本的 [lsp-mode](https://emacs-lsp.github.io/lsp-mode/) 用户:
```
(setq lsp-go-use-gofumpt t)
```
对于 `8.0.0` 之前版本的 `lsp-mode` 用户:
```
(lsp-register-custom-settings
'(("gopls.gofumpt" t)))
```
对于 [eglot](https://github.com/joaotavora/eglot) 用户:
```
(setq-default eglot-workspace-configuration
'((:gopls . ((gofumpt . t)))))
```
#### Helix
使用 `gopls` 语言服务器时,在 `~/.config/helix/languages.toml` 中修改 Go 设置:
```
[language-server.gopls.config]
"formatting.gofumpt" = true
```
#### Sublime Text
对于 ST4,根据[文档](https://github.com/sublimelsp/LSP) 安装 Sublime Text LSP 扩展,
并在 LSP 包设置中启用 `gopls` 的 `gofumpt` 选项,
包括将 `lsp_format_on_save` 设置为 `true`。
```
"lsp_format_on_save": true,
"clients":
{
"gopls":
{
"enabled": true,
"initializationOptions": {
"gofumpt": true,
}
}
}
```
### Zed
要在 Zed 中使用 `gofumpt`,您需要在 LSP 设置中设定 `gofumpt` 选项。这可以通过在 `initialization_options` 中提供 `"gofumpt": true` 来实现。
```
"lsp": {
"gopls": {
"initialization_options": {
"gofumpt": true
}
}
}
```
### 路线图
这个工具是一个实验场所。从长远来看,运行良好的功能可能会被提议加入 `gofmt` 本身。
该工具也与 `gofmt` 兼容并力求稳定,因此只要您固定它的版本,就可以在您的代码中依赖它。
### 使用 `go/format` 和 `cmd/gofmt` 进行更新
`internal/govendor` 包含特定 Go 版本下冻结的 `go/format` 及其依赖项的副本,因此安装特定版本的 `gofumpt` 将产生完全相同的格式化行为,而与 Go 版本无关。
由于该工具是 `cmd/gofmt` 的分支,`gofmt.go`、`internal.go`、`format/rewrite.go` 和 `format/simplify.go` 均继承自上游。
它们包含了必要的一些修改,并会手动进行更新。
请注意,其中有两个文件位于 `format` 包中,因为我们希望通过 Go API 暴露语法简化功能。
### 常见问题解答
我们的设计是基于 `gofmt` 构建的,我们永远不会添加与其格式化冲突的规则。因此,我们是在扩展 `gofmt`,而不是与其竞争。
该工具是 `gofmt` 的修改副本,旨在允许其在编辑器和脚本中作为直接替代品使用。
任何不以像 `foo.com` 这样的域名开头的导入路径,实际上都[由 Go 工具链保留](https://github.com/golang/go/issues/32819)。
第三方模块应该以域名开头,即使是像 `foo.local` 这样的本地域名,或者使用[保留的路径前缀](https://github.com/golang/go/issues/37641)。
为了与这些规则明确之前建立的模块保持向后兼容,`gofumpt` 会将任何与当前模块路径共享前缀的导入路径视为第三方。例如,如果当前模块是 `mycorp/mod1`,那么 `mycorp/...` 中的所有导入路径都将被视为第三方。
大多数编辑器已将 `goimports` 程序替换为语言服务器(如 `gopls`)提供的相同功能。这种机制明显更快、更强大,因为语言服务器拥有更多保持最新所需的信息,这对于添加缺失的导入是必要的。
因此,一般建议是让您的编辑器修复导入——要么通过 `gopls`(如 VSCode 或 vim-go),要么通过它们自己的自定义实现(如 GoLand)。然后按照上面的安装说明启用 `gofumpt` 而不是 `gofmt`。
如果您想避免与 `gopls` 集成,并且可以接受每次保存时从头调用 `goimports` 的开销,您应该可以同时调用这两个工具;例如,`goimports file.go && gofumpt file.go`。
### 贡献
欢迎提交 Issues 和 pull requests!在发送 pull request 之前,请先打开一个 issue 讨论该功能。
我们还在 [Gophers Slack](https://invite.slack.golangbridge.org/) 的 `#gofumpt` 频道进行交流。
报告格式化 bug 时,请插入 `//gofumpt:diagnose` 注释。
该注释将被重写,以包含有用的调试信息。
例如:
```
$ cat f.go
package p
//gofumpt:diagnose
$ gofumpt f.go
package p
//gofumpt:diagnose v0.1.1-0.20211103104632-bdfa3b02e50a -lang=go1.16
```
### 许可证
请注意,许多代码是从 Go 的 `gofmt` 命令复制而来的。您可以从它们的版权头中看出哪些文件源自 Go 仓库。它们的许可证文件是 `LICENSE.google`。
`gofumpt` 的原始源文件也采用 3 条款 BSD 许可证,并使用单独的文件 `LICENSE`。
示例
``` func foo() { foo := "bar" } ``` ``` func foo() { foo := "bar" } ```示例
``` func foo() { println("bar") } ``` ``` func foo() { println("bar") } ```示例
``` func foo(s string, i int) { println("bar") } // With an empty line it's slightly better, but still not great. func bar(s string, i int) { println("bar") } ``` ``` func foo(s string, i int, ) { println("bar") } // With an empty line it's slightly better, but still not great. func bar(s string, i int, ) { println("bar") } ```示例
``` if err != nil { return err } ``` ``` if err != nil { return err } ```示例
``` foo, err := processFoo() if err != nil { return err } ``` ``` foo, err := processFoo() if err != nil { return err } ```示例
``` // A newline before or after an element requires newlines for the opening and // closing braces. var ints = []int{1, 2, 3, 4} // A newline between consecutive elements requires a newline between all // elements. var matrix = [][]int{ {1}, {2}, { 3, }, } ``` ``` var ints = []int{ 1, 2, 3, 4, } var matrix = [][]int{ {1}, {2}, { 3, }, } ```示例
``` result := compute( a, b, c) ``` ``` result := compute( a, b, c, ) ```示例
``` var V interface { } = 3 type T struct { } func F( ) ``` ``` var V interface{} = 3 type T struct{} func F() ```示例
``` import ( "foo.com/bar" "io" "io/ioutil" ) ``` ``` import ( "io" "io/ioutil" "foo.com/bar" ) ```示例
``` switch c { case 'a', 'b', 'c', 'd': } ``` ``` switch c { case 'a', 'b', 'c', 'd': } ```示例
``` func foo() { println("multiline foo") } func bar() { println("multiline bar") } ``` ``` func foo() { println("multiline foo") } func bar() { println("multiline bar") } ```示例
``` var ( foo = "bar" ) ``` ``` var foo = "bar" ```示例
``` var nicer = "x" var with = "y" var alignment = "z" ``` ``` var ( nicer = "x" with = "y" alignment = "z" ) ```示例
``` var s = "somestring" ``` ``` s := "somestring" ```示例
``` var _ = [][]int{[]int{1}} ``` ``` var _ = [][]int{{1}} ```示例
``` const perm = 0755 ``` ``` const perm = 0o755 ```示例
``` //go:noinline //Foo is awesome. func Foo() {} ``` ``` //go:noinline // Foo is awesome. func Foo() {} ```示例
``` var _ = []string{ "foo", } var _ = map[string]string{ "foo": "bar", } ``` ``` var _ = []string{ "foo", } var _ = map[string]string{ "foo": "bar", } ```示例
``` type Person interface { Name() string Age() int } type ZeroFields struct { // No fields are needed here. } ``` ``` type Person interface { Name() string Age() int } type ZeroFields struct { // No fields are needed here. } ```示例
``` type C chan (int) var _ = f((3)) ``` ``` type C chan int var _ = f(3) ``` 二元或一元表达式周围的括号,以及需要它们(如 `chan (<-chan T)`)的类型周围的括号,将保持原样。示例
``` func Foo(bar string, baz string) {} ``` ``` func Foo(bar, baz string) {} ```示例
``` func Foo() (err error) { return } ``` ``` func Foo() (err error) { return err } ```标签:EVTX分析, Go, Ruby工具, SOC Prime, 云安全监控, 代码格式化, 代码规范, 开发工具, 日志审计, 静态分析