mvdan/gofumpt

GitHub: mvdan/gofumpt

gofumpt 是基于 gofmt 分支的 Go 代码格式化工具,在保持向后兼容的同时强制执行比 gofmt 更严格的代码格式规则。

Stars: 4041 | Forks: 134

# gofumpt [![Go 参考文档](https://pkg.go.dev/badge/mvdan.cc/gofumpt/format.svg)](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` 标志,因为它总是被启用的。 ### 新增规则 **简单的赋值操作符后不应有换行**
示例 ``` 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() ```
**`std` 导入必须单独放在顶部的组中**
示例 ``` import ( "foo.com/bar" "io" "io/ioutil" ) ``` ``` import ( "io" "io/ioutil" "foo.com/bar" ) ```
**简短的 case 子句应合并为单行**
示例 ``` 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 声明不应使用括号分组**
示例 ``` 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" ```
**默认启用 `-s` 代码简化标志**
示例 ``` var _ = [][]int{[]int{1}} ``` ``` var _ = [][]int{{1}} ```
**在 Go 1.13 及更高版本的模块中,八进制整数字面量应使用 `0o` 前缀**
示例 ``` const perm = 0755 ``` ``` const perm = 0o755 ```
**非 Go 指令的注释应以空格开头**
示例 ``` //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)`)的类型周围的括号,将保持原样。
### `-extra` 背后的额外规则 **具有相同类型的相邻参数应组合在一起**
示例 ``` func Foo(bar string, baz string) {} ``` ``` func Foo(bar, baz string) {} ```
**为清晰起见,避免使用裸返回 (naked returns)**
示例 ``` func Foo() (err error) { return } ``` ``` func Foo() (err error) { return err } ```
### 安装 `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`。
标签:EVTX分析, Go, Ruby工具, SOC Prime, 云安全监控, 代码格式化, 代码规范, 开发工具, 日志审计, 静态分析