pax_global_header00006660000000000000000000000064141430076500014512gustar00rootroot0000000000000052 comment=dd8ce9a8ddbde6d3e341d57f3653dbb8d6f5a8b8 golang-mvdan-gofumpt-0.2.0/000077500000000000000000000000001414300765000155425ustar00rootroot00000000000000golang-mvdan-gofumpt-0.2.0/.gitattributes000066400000000000000000000001211414300765000204270ustar00rootroot00000000000000# To prevent CRLF breakages on Windows for fragile files, like testdata. * -text golang-mvdan-gofumpt-0.2.0/.github/000077500000000000000000000000001414300765000171025ustar00rootroot00000000000000golang-mvdan-gofumpt-0.2.0/.github/FUNDING.yml000066400000000000000000000000161414300765000207140ustar00rootroot00000000000000github: mvdan golang-mvdan-gofumpt-0.2.0/.github/workflows/000077500000000000000000000000001414300765000211375ustar00rootroot00000000000000golang-mvdan-gofumpt-0.2.0/.github/workflows/test.yml000066400000000000000000000006521414300765000226440ustar00rootroot00000000000000on: [push, pull_request] name: Test jobs: test: strategy: matrix: go-version: [1.16.x, 1.17.x] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - name: Install Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@v2 - name: Test run: go test ./... golang-mvdan-gofumpt-0.2.0/CHANGELOG.md000066400000000000000000000056351414300765000173640ustar00rootroot00000000000000# Changelog ## [0.2.0] - 2021-11-10 This is gofumpt's second major release, based on Go 1.17's gofmt. The jump from Go 1.15's gofmt should bring a mild speed-up, as walking directories with `filepath.WalkDir` uses fewer syscalls. gofumports is now removed, after being deprecated in [0.1.0]. Its main purpose was IDE integration; it is now recommended to use gopls, which in turn implements goimports and supports gofumpt natively. IDEs which don't integrate with gopls (such as GoLand) implement goimports too, so it is safe to use gofumpt as their "format on save" command. See the [installation instructions](https://github.com/mvdan/gofumpt#Installation) for more details. The following [formatting rules](https://github.com/mvdan/gofumpt#Added-rules) are added: * Composite literals should not have leading or trailing empty lines * No empty lines following an assignment operator * Functions using an empty line for readability should use a `) {` line instead * Remove unnecessary empty lines from interfaces Finally, the following changes are made to the gofumpt tool: * Initial support for Go 1.18's type parameters is added * The `-r` flag is removed in favor of `gofmt -r` * The `-s` flag is removed as it is always enabled * Vendor directories are skipped unless given as explicit arguments * The added rules are not applied to generated Go files * The `format` Go API now also applies the `gofmt -s` simplification * Add support for `//gofumpt:diagnose` comments ## [0.1.1] - 2021-03-11 This bugfix release backports fixes for a few issues: * Keep leading empty lines in func bodies if they help readability * Avoid breaking comment alignment on empty field lists * Add support for `//go-sumtype:` directives ## [0.1.0] - 2021-01-05 This is gofumpt's first release, based on Go 1.15.x. It solidifies the features which have worked well for over a year. This release will be the last to include `gofumports`, the fork of `goimports` which applies `gofumpt`'s rules on top of updating the Go import lines. Users who were relying on `goimports` in their editors or IDEs to apply both `gofumpt` and `goimports` in a single step should switch to gopls, the official Go language server. It is supported by many popular editors such as VS Code and Vim, and already bundles gofumpt support. Instructions are available [in the README](https://github.com/mvdan/gofumpt). `gofumports` also added maintenance work and potential confusion to end users. In the future, there will only be one way to use `gofumpt` from the command line. We also have a [Go API](https://pkg.go.dev/mvdan.cc/gofumpt/format) for those building programs with gofumpt. Finally, this release adds the `-version` flag, to print the tool's own version. The flag will work for "master" builds too. [0.2.0]: https://github.com/mvdan/gofumpt/releases/tag/v0.2.0 [0.1.1]: https://github.com/mvdan/gofumpt/releases/tag/v0.1.1 [0.1.0]: https://github.com/mvdan/gofumpt/releases/tag/v0.1.0 golang-mvdan-gofumpt-0.2.0/LICENSE000066400000000000000000000027201414300765000165500ustar00rootroot00000000000000Copyright (c) 2019, Daniel Martí. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. golang-mvdan-gofumpt-0.2.0/LICENSE.google000066400000000000000000000027071414300765000200300ustar00rootroot00000000000000Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. golang-mvdan-gofumpt-0.2.0/README.md000066400000000000000000000252431414300765000170270ustar00rootroot00000000000000# gofumpt go install mvdan.cc/gofumpt@latest Enforce a stricter format than `gofmt`, while being backwards compatible. That is, `gofumpt` is happy with a subset of the formats that `gofmt` is happy with. The tool is a modified fork of `gofmt`, so it can be used as a drop-in replacement. Running `gofmt` after `gofumpt` should be a no-op. For example: gofumpt -l -w . Some of the Go source files in this repository belong to the Go project. The added formatting rules are in the `format` package. Beyond the [added rules below](#Added-rules), the tool differs from gofmt in the following ways: * Vendor directories are skipped unless given as explicit arguments * The added rules are not applied to generated Go files * The `-r` rewrite feature is removed in favor of `gofmt -r` ### Added rules No empty lines following an assignment operator
example ``` func foo() { foo := "bar" } ``` ``` func foo() { foo := "bar" } ```
No empty lines at the beginning or end of a function
example ``` func foo() { println("bar") } ``` ``` func foo() { println("bar") } ```
Functions using an empty line for readability should use a `) {` line instead
example ``` func foo(s string, i int) { println("bar") } ``` ``` func foo(s string, i int, ) { println("bar") } ```
No empty lines around a lone statement (or comment) in a block
example ``` if err != nil { return err } ``` ``` if err != nil { return err } ```
No empty lines before a simple error check
example ``` foo, err := processFoo() if err != nil { return err } ``` ``` foo, err := processFoo() if err != nil { return err } ```
Composite literals should use newlines consistently
example ``` // 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, }, } ```
Empty field lists should use a single line
example ``` var V interface { } = 3 type T struct { } func F( ) ``` ``` var V interface{} = 3 type T struct{} func F() ```
`std` imports must be in a separate group at the top
example ``` import ( "foo.com/bar" "io" "io/ioutil" ) ``` ``` import ( "io" "io/ioutil" "foo.com/bar" ) ```
Short case clauses should take a single line
example ``` switch c { case 'a', 'b', 'c', 'd': } ``` ``` switch c { case 'a', 'b', 'c', 'd': } ```
Multiline top-level declarations must be separated by empty lines
example ``` func foo() { println("multiline foo") } func bar() { println("multiline bar") } ``` ``` func foo() { println("multiline foo") } func bar() { println("multiline bar") } ```
Single var declarations should not be grouped with parentheses
example ``` var ( foo = "bar" ) ``` ``` var foo = "bar" ```
Contiguous top-level declarations should be grouped together
example ``` var nicer = "x" var with = "y" var alignment = "z" ``` ``` var ( nicer = "x" with = "y" alignment = "z" ) ```
Simple var-declaration statements should use short assignments
example ``` var s = "somestring" ``` ``` s := "somestring" ```
The `-s` code simplification flag is enabled by default
example ``` var _ = [][]int{[]int{1}} ``` ``` var _ = [][]int{{1}} ```
Octal integer literals should use the `0o` prefix on modules using Go 1.13 and later
example ``` const perm = 0755 ``` ``` const perm = 0o755 ```
Comments which aren't Go directives should start with a whitespace
example ``` //go:noinline //Foo is awesome. func Foo() {} ``` ``` //go:noinline // Foo is awesome. func Foo() {} ```
Composite literals should not have leading or trailing empty lines
example ``` var _ = []string{ "foo", } var _ = map[string]string{ "foo": "bar", } ``` ``` var _ = []string{ "foo", } var _ = map[string]string{ "foo": "bar", } ```
Remove unnecessary empty lines from interfaces
example ``` type i interface { // comment for a a(x int) int // comment between a and b // comment for b b(x int) int // comment between b and c c(x int) int d(x int) int // comment for e e(x int) int } ``` ``` type i interface { // comment for a a(x int) int // comment between a and b // comment for b b(x int) int // comment between b and c c(x int) int d(x int) int // comment for e e(x int) int } ```
#### Extra rules behind `-extra` Adjacent parameters with the same type should be grouped together
example ``` func Foo(bar string, baz string) {} ``` ``` func Foo(bar, baz string) {} ```
### Installation `gofumpt` is a replacement for `gofmt`, so you can simply `go install` it as described at the top of this README and use it. When using an IDE or editor with Go integration based on `gopls`, it's best to configure the editor to use the `gofumpt` support built into `gopls`. The instructions below show how to set up `gofumpt` for some of the major editors out there. #### Visual Studio Code Enable the language server following [the official docs](https://github.com/golang/vscode-go#readme), and then enable gopls's `gofumpt` option. Note that VS Code will complain about the `gopls` settings, but they will still work. ```json "go.useLanguageServer": true, "gopls": { "formatting.gofumpt": true, }, ``` #### GoLand GoLand doesn't use `gopls` so it should be configured to use `gofumpt` directly. Once `gofumpt` is installed, follow the steps below: - Open **Settings** (File > Settings) - Open the **Tools** section - Find the *File Watchers* sub-section - Click on the `+` on the right side to add a new file watcher - Choose *Custom Template* When a window asks for settings, you can enter the following: * File Types: Select all .go files * Scope: Project Files * Program: Select your `gofumpt` executable * Arguments: `-w $FilePath$` * Output path to refresh: `$FilePath$` * Working directory: `$ProjectFileDir$` * Environment variables: `GOROOT=$GOROOT$;GOPATH=$GOPATH$;PATH=$GoBinDirs$` To avoid unecessary runs, you should disable all checkboxes in the *Advanced* section. #### Vim-go Ensure you are at least running version [v1.24](https://github.com/fatih/vim-go/blob/master/CHANGELOG.md#v124---september-15-2020), and set up `gopls` for formatting code with `gofumpt`: ```vim let g:go_fmt_command="gopls" let g:go_gopls_gofumpt=1 ``` #### Govim With a [new enough version of govim](https://github.com/govim/govim/pull/1005), simply configure `gopls` to use `gofumpt`: ```vim call govim#config#Set("Gofumpt", 1) ``` #### Sublime Text With ST4, install the Sublime Text LSP extension according to [the documentation](https://github.com/sublimelsp/LSP), and enable `gopls`'s `gofumpt` option in the LSP package settings, including setting `lsp_format_on_save` to `true`. ```json "lsp_format_on_save": true, "clients": { "gopls": { "enabled": true, "initializationOptions": { "gofumpt": true, } } } ``` ### Roadmap This tool is a place to experiment. In the long term, the features that work well might be proposed for `gofmt` itself. The tool is also compatible with `gofmt` and is aimed to be stable, so you can rely on it for your code as long as you pin a version of it. ### Frequently Asked Questions > Why attempt to replace `gofmt` instead of building on top of it? Our design is to build on top of `gofmt`, and we'll never add rules which disagree with its formatting. So we extend `gofmt` rather than compete with it. The tool is a modified copy of `gofmt`, for the purpose of allowing its use as a drop-in replacement in editors and scripts. > Why are my module imports being grouped with standard library imports? Any import paths that don't start with a domain name like `foo.com` are effectively reserved by the Go toolchain. Otherwise, adding new standard library packages like `embed` would be a breaking change. See https://github.com/golang/go/issues/32819. Third party modules should use domain names to avoid conflicts. If your module is meant for local use only, you can use `foo.local`. For small example or test modules, `example/...` and `test/...` may be reserved if a proposal is accepted; see https://github.com/golang/go/issues/37641. > How can I use `gofumpt` if I already use `goimports` to replace `gofmt`? Most editors have replaced the `goimports` program with the same functionality provided by a language server like `gopls`. This mechanism is significantly faster and more powerful, since the language server has more information that is kept up to date, necessary to add missing imports. As such, the general recommendation is to let your editor fix your imports - either via `gopls`, such as VSCode or vim-go, or via their own custom implementation, such as GoLand. Then follow the install instructions above to enable the use of `gofumpt` instead of `gofmt`. If you want to avoid integrating with `gopls`, and are OK with the overhead of calling `goimports` from scratch on each save, you should be able to call both tools; for example, `goimports file.go && gofumpt file.go`. ### Contributing Issues and pull requests are welcome! Please open an issue to discuss a feature before sending a pull request. We also use the `#gofumpt` channel over at the [Gophers Slack](https://invite.slack.golangbridge.org/) to chat. When reporting a formatting bug, insert a `//gofumpt:diagnose` comment. The comment will be rewritten to include useful debugging information. For instance: ``` $ cat f.go package p //gofumpt:diagnose $ gofumpt f.go package p //gofumpt:diagnose v0.1.1-0.20211103104632-bdfa3b02e50a -lang=v1.16 ``` ### License Note that much of the code is copied from Go's `gofmt` command. You can tell which files originate from the Go repository from their copyright headers. Their license file is `LICENSE.google`. `gofumpt`'s original source files are also under the 3-clause BSD license, with the separate file `LICENSE`. golang-mvdan-gofumpt-0.2.0/format/000077500000000000000000000000001414300765000170325ustar00rootroot00000000000000golang-mvdan-gofumpt-0.2.0/format/format.go000066400000000000000000000650721414300765000206630ustar00rootroot00000000000000// Copyright (c) 2019, Daniel Martí // See LICENSE for licensing information // Package format exposes gofumpt's formatting in an API similar to go/format. // In general, the APIs are only guaranteed to work well when the input source // is in canonical gofmt format. package format import ( "bytes" "fmt" "go/ast" "go/format" "go/parser" "go/token" "os" "reflect" "regexp" "sort" "strconv" "strings" "unicode" "unicode/utf8" "github.com/google/go-cmp/cmp" "golang.org/x/mod/semver" "golang.org/x/tools/go/ast/astutil" "mvdan.cc/gofumpt/internal/version" ) type Options struct { // LangVersion corresponds to the Go language version a piece of code is // written in. The version is used to decide whether to apply formatting // rules which require new language features. When inside a Go module, // LangVersion should generally be specified as the result of: // // go list -m -f {{.GoVersion}} // // LangVersion is treated as a semantic version, which might start with // a "v" prefix. Like Go versions, it might also be incomplete; "1.14" // is equivalent to "1.14.0". When empty, it is equivalent to "v1", to // not use language features which could break programs. LangVersion string ExtraRules bool } // Source formats src in gofumpt's format, assuming that src holds a valid Go // source file. func Source(src []byte, opts Options) ([]byte, error) { fset := token.NewFileSet() file, err := parser.ParseFile(fset, "", src, parser.ParseComments) if err != nil { return nil, err } File(fset, file, opts) var buf bytes.Buffer if err := format.Node(&buf, fset, file); err != nil { return nil, err } return buf.Bytes(), nil } var rxCodeGenerated = regexp.MustCompile(`^// Code generated .* DO NOT EDIT\.$`) // File modifies a file and fset in place to follow gofumpt's format. The // changes might include manipulating adding or removing newlines in fset, // modifying the position of nodes, or modifying literal values. func File(fset *token.FileSet, file *ast.File, opts Options) { simplify(file) for _, cg := range file.Comments { if cg.Pos() > file.Package { break } for _, line := range cg.List { if rxCodeGenerated.MatchString(line.Text) { return } } } if opts.LangVersion == "" { opts.LangVersion = "v1" } else if opts.LangVersion[0] != 'v' { opts.LangVersion = "v" + opts.LangVersion } if !semver.IsValid(opts.LangVersion) { panic(fmt.Sprintf("invalid semver string: %q", opts.LangVersion)) } f := &fumpter{ File: fset.File(file.Pos()), fset: fset, astFile: file, Options: opts, minSplitFactor: 0.4, } var topFuncType *ast.FuncType pre := func(c *astutil.Cursor) bool { f.applyPre(c) switch node := c.Node().(type) { case *ast.FuncDecl: topFuncType = node.Type case *ast.FieldList: ft, _ := c.Parent().(*ast.FuncType) if ft == nil || ft != topFuncType { break } // For top-level function declaration parameters, // require the line split to be longer. // This avoids func lines which are a bit too short, // and allows func lines which are a bit longer. // // We don't just increase longLineLimit, // as we still want splits at around the same place. if ft.Params == node { f.minSplitFactor = 0.6 } // Don't split result parameters into multiple lines, // as that can be easily confused for input parameters. // TODO: consider the same for single-line func calls in // if statements. // TODO: perhaps just use a higher factor, like 0.8. if ft.Results == node { f.minSplitFactor = 1000 } case *ast.BlockStmt: f.blockLevel++ } return true } post := func(c *astutil.Cursor) bool { f.applyPost(c) // Reset minSplitFactor and blockLevel. switch node := c.Node().(type) { case *ast.FuncType: if node == topFuncType { f.minSplitFactor = 0.4 } case *ast.BlockStmt: f.blockLevel-- } return true } astutil.Apply(file, pre, post) } // Multiline nodes which could easily fit on a single line under this many bytes // may be collapsed onto a single line. const shortLineLimit = 60 // Single-line nodes which take over this many bytes, and could easily be split // into two lines of at least its minSplitFactor factor, may be split. const longLineLimit = 100 var rxOctalInteger = regexp.MustCompile(`\A0[0-7_]+\z`) type fumpter struct { Options *token.File fset *token.FileSet astFile *ast.File // blockLevel is the number of indentation blocks we're currently under. // It is used to approximate the levels of indentation a line will end // up with. blockLevel int minSplitFactor float64 } func (f *fumpter) commentsBetween(p1, p2 token.Pos) []*ast.CommentGroup { comments := f.astFile.Comments i1 := sort.Search(len(comments), func(i int) bool { return comments[i].Pos() >= p1 }) comments = comments[i1:] i2 := sort.Search(len(comments), func(i int) bool { return comments[i].Pos() >= p2 }) comments = comments[:i2] return comments } func (f *fumpter) inlineComment(pos token.Pos) *ast.Comment { comments := f.astFile.Comments i := sort.Search(len(comments), func(i int) bool { return comments[i].Pos() >= pos }) if i >= len(comments) { return nil } line := f.Line(pos) for _, comment := range comments[i].List { if f.Line(comment.Pos()) == line { return comment } } return nil } // addNewline is a hack to let us force a newline at a certain position. func (f *fumpter) addNewline(at token.Pos) { offset := f.Offset(at) field := reflect.ValueOf(f.File).Elem().FieldByName("lines") n := field.Len() lines := make([]int, 0, n+1) for i := 0; i < n; i++ { cur := int(field.Index(i).Int()) if offset == cur { // This newline already exists; do nothing. Duplicate // newlines can't exist. return } if offset >= 0 && offset < cur { lines = append(lines, offset) offset = -1 } lines = append(lines, cur) } if offset >= 0 { lines = append(lines, offset) } if !f.SetLines(lines) { panic(fmt.Sprintf("could not set lines to %v", lines)) } } // removeLines removes all newlines between two positions, so that they end // up on the same line. func (f *fumpter) removeLines(fromLine, toLine int) { for fromLine < toLine { f.MergeLine(fromLine) toLine-- } } // removeLinesBetween is like removeLines, but it leaves one newline between the // two positions. func (f *fumpter) removeLinesBetween(from, to token.Pos) { f.removeLines(f.Line(from)+1, f.Line(to)) } type byteCounter int func (b *byteCounter) Write(p []byte) (n int, err error) { *b += byteCounter(len(p)) return len(p), nil } func (f *fumpter) printLength(node ast.Node) int { var count byteCounter if err := format.Node(&count, f.fset, node); err != nil { panic(fmt.Sprintf("unexpected print error: %v", err)) } // Add the space taken by an inline comment. if c := f.inlineComment(node.End()); c != nil { fmt.Fprintf(&count, " %s", c.Text) } // Add an approximation of the indentation level. We can't know the // number of tabs go/printer will add ahead of time. Trying to print the // entire top-level declaration would tell us that, but then it's near // impossible to reliably find our node again. return int(count) + (f.blockLevel * 8) } func (f *fumpter) tabbedColumn(p token.Pos) int { col := f.Position(p).Column // Like in printLength, add an approximation of the indentation level. // Since any existing tabs were already counted as one column, multiply // the level by 7. return col + (f.blockLevel * 7) } func (f *fumpter) lineEnd(line int) token.Pos { if line < 1 { panic("illegal line number") } total := f.LineCount() if line > total { panic("illegal line number") } if line == total { return f.astFile.End() } return f.LineStart(line+1) - 1 } // rxCommentDirective covers all common Go comment directives: // // //go: | standard Go directives, like go:noinline // //some-words: | similar to the syntax above, like lint:ignore or go-sumtype:decl // //line | inserted line information for cmd/compile // //export | to mark cgo funcs for exporting // //extern | C function declarations for gccgo // //sys(nb)? | syscall function wrapper prototypes // //nolint | nolint directive for golangci // // Note that the "some-words:" matching expects a letter afterward, such as // "go:generate", to prevent matching false positives like "https://site". var rxCommentDirective = regexp.MustCompile(`^([a-z-]+:[a-z]+|line\b|export\b|extern\b|sys(nb)?\b|nolint\b)`) func (f *fumpter) applyPre(c *astutil.Cursor) { f.splitLongLine(c) switch node := c.Node().(type) { case *ast.File: // Join contiguous lone var/const/import lines. // Abort if there are empty lines or comments in between, // includng a leading comment, which could be a directive. newDecls := make([]ast.Decl, 0, len(node.Decls)) for i := 0; i < len(node.Decls); { newDecls = append(newDecls, node.Decls[i]) start, ok := node.Decls[i].(*ast.GenDecl) if !ok || isCgoImport(start) || start.Doc != nil { i++ continue } lastPos := start.Pos() for i++; i < len(node.Decls); { cont, ok := node.Decls[i].(*ast.GenDecl) if !ok || cont.Tok != start.Tok || cont.Lparen != token.NoPos || f.Line(lastPos) < f.Line(cont.Pos())-1 || isCgoImport(cont) { break } start.Specs = append(start.Specs, cont.Specs...) if c := f.inlineComment(cont.End()); c != nil { // don't move an inline comment outside start.Rparen = c.End() } else { // so the code below treats the joined // decl group as multi-line start.Rparen = cont.End() } lastPos = cont.Pos() i++ } } node.Decls = newDecls // Multiline top-level declarations should be separated by an // empty line. // Do this after the joining of lone declarations above, // as joining single-line declarations makes then multi-line. var lastMulti bool var lastEnd token.Pos for _, decl := range node.Decls { pos := decl.Pos() comments := f.commentsBetween(lastEnd, pos) if len(comments) > 0 { pos = comments[0].Pos() } multi := f.Line(pos) < f.Line(decl.End()) if multi && lastMulti && f.Line(lastEnd)+1 == f.Line(pos) { f.addNewline(lastEnd) } lastMulti = multi lastEnd = decl.End() } // Comments aren't nodes, so they're not walked by default. groupLoop: for _, group := range node.Comments { for _, comment := range group.List { if comment.Text == "//gofumpt:diagnose" || strings.HasPrefix(comment.Text, "//gofumpt:diagnose ") { slc := []string{ "//gofumpt:diagnose", version.String(), "-lang=" + f.LangVersion, } if f.ExtraRules { slc = append(slc, "-extra") } comment.Text = strings.Join(slc, " ") } body := strings.TrimPrefix(comment.Text, "//") if body == comment.Text { // /*-style comment continue groupLoop } if rxCommentDirective.MatchString(body) { // this line is a directive continue groupLoop } r, _ := utf8.DecodeRuneInString(body) if !unicode.IsLetter(r) && !unicode.IsNumber(r) && !unicode.IsSpace(r) { // this line could be code like "//{" continue groupLoop } } // If none of the comment group's lines look like a // directive or code, add spaces, if needed. for _, comment := range group.List { body := strings.TrimPrefix(comment.Text, "//") r, _ := utf8.DecodeRuneInString(body) if !unicode.IsSpace(r) { comment.Text = "// " + body } } } case *ast.DeclStmt: decl, ok := node.Decl.(*ast.GenDecl) if !ok || decl.Tok != token.VAR || len(decl.Specs) != 1 { break // e.g. const name = "value" } spec := decl.Specs[0].(*ast.ValueSpec) if spec.Type != nil { break // e.g. var name Type } tok := token.ASSIGN names := make([]ast.Expr, len(spec.Names)) for i, name := range spec.Names { names[i] = name if name.Name != "_" { tok = token.DEFINE } } c.Replace(&ast.AssignStmt{ Lhs: names, Tok: tok, Rhs: spec.Values, }) case *ast.GenDecl: if node.Tok == token.IMPORT && node.Lparen.IsValid() { f.joinStdImports(node) } // Single var declarations shouldn't use parentheses, unless // there's a comment on the grouped declaration. if node.Tok == token.VAR && len(node.Specs) == 1 && node.Lparen.IsValid() && node.Doc == nil { specPos := node.Specs[0].Pos() specEnd := node.Specs[0].End() if len(f.commentsBetween(node.TokPos, specPos)) > 0 { // If the single spec has any comment, it must // go before the entire declaration now. node.TokPos = specPos } else { f.removeLines(f.Line(node.TokPos), f.Line(specPos)) } f.removeLines(f.Line(specEnd), f.Line(node.Rparen)) // Remove the parentheses. go/printer will automatically // get rid of the newlines. node.Lparen = token.NoPos node.Rparen = token.NoPos } case *ast.InterfaceType: var prev *ast.Field for _, method := range node.Methods.List { switch { case prev == nil: removeToPos := method.Pos() if comments := f.commentsBetween(node.Interface, method.Pos()); len(comments) > 0 { // only remove leading line upto the first comment removeToPos = comments[0].Pos() } // remove leading lines if they exist f.removeLines(f.Line(node.Interface)+1, f.Line(removeToPos)) case len(f.commentsBetween(prev.End(), method.Pos())) > 0: // continue default: f.removeLinesBetween(prev.End(), method.Pos()) } prev = method } case *ast.BlockStmt: f.stmts(node.List) comments := f.commentsBetween(node.Lbrace, node.Rbrace) if len(node.List) == 0 && len(comments) == 0 { f.removeLinesBetween(node.Lbrace, node.Rbrace) break } var sign *ast.FuncType var cond ast.Expr switch parent := c.Parent().(type) { case *ast.FuncDecl: sign = parent.Type case *ast.FuncLit: sign = parent.Type case *ast.IfStmt: cond = parent.Cond case *ast.ForStmt: cond = parent.Cond } if len(node.List) > 1 && sign == nil { // only if we have a single statement, or if // it's a func body. break } var bodyPos, bodyEnd token.Pos if len(node.List) > 0 { bodyPos = node.List[0].Pos() bodyEnd = node.List[len(node.List)-1].End() } if len(comments) > 0 { if pos := comments[0].Pos(); !bodyPos.IsValid() || pos < bodyPos { bodyPos = pos } if pos := comments[len(comments)-1].End(); !bodyPos.IsValid() || pos > bodyEnd { bodyEnd = pos } } f.removeLinesBetween(bodyEnd, node.Rbrace) if cond != nil && f.Line(cond.Pos()) != f.Line(cond.End()) { // The body is preceded by a multi-line condition, so an // empty line can help readability. return } if sign != nil { endLine := f.Line(sign.End()) paramClosingIsFirstCharOnEndLine := sign.Params != nil && f.Position(sign.Params.Closing).Column == 1 && f.Line(sign.Params.Closing) == endLine resultClosingIsFirstCharOnEndLine := sign.Results != nil && f.Position(sign.Results.Closing).Column == 1 && f.Line(sign.Results.Closing) == endLine endLineIsIndented := !(paramClosingIsFirstCharOnEndLine || resultClosingIsFirstCharOnEndLine) if f.Line(sign.Pos()) != endLine && endLineIsIndented { // is there an empty line? isThereAnEmptyLine := endLine+1 != f.Line(bodyPos) // The body is preceded by a multi-line function // signature, we move the `) {` to avoid the empty line. switch { case isThereAnEmptyLine && sign.Results != nil && !resultClosingIsFirstCharOnEndLine: sign.Results.Closing += 1 f.addNewline(sign.Results.Closing) case isThereAnEmptyLine && sign.Params != nil && !paramClosingIsFirstCharOnEndLine: sign.Params.Closing += 1 f.addNewline(sign.Params.Closing) } } } f.removeLinesBetween(node.Lbrace, bodyPos) case *ast.CaseClause: f.stmts(node.Body) openLine := f.Line(node.Case) closeLine := f.Line(node.Colon) if openLine == closeLine { // nothing to do break } if len(f.commentsBetween(node.Case, node.Colon)) > 0 { // don't move comments break } if f.printLength(node) > shortLineLimit { // too long to collapse break } f.removeLines(openLine, closeLine) case *ast.CommClause: f.stmts(node.Body) case *ast.FieldList: if node.NumFields() == 0 && len(f.commentsBetween(node.Pos(), node.End())) == 0 { // Empty field lists should not contain a newline. // Do not join the two lines if the first has an inline // comment, as that can result in broken formatting. openLine := f.Line(node.Pos()) closeLine := f.Line(node.End()) f.removeLines(openLine, closeLine) } // Merging adjacent fields (e.g. parameters) is disabled by default. if !f.ExtraRules { break } switch c.Parent().(type) { case *ast.FuncDecl, *ast.FuncType, *ast.InterfaceType: node.List = f.mergeAdjacentFields(node.List) c.Replace(node) case *ast.StructType: // Do not merge adjacent fields in structs. } case *ast.BasicLit: // Octal number literals were introduced in 1.13. if semver.Compare(f.LangVersion, "v1.13") >= 0 { if node.Kind == token.INT && rxOctalInteger.MatchString(node.Value) { node.Value = "0o" + node.Value[1:] c.Replace(node) } } case *ast.AssignStmt: // Only remove lines between the assignment token and the first right-hand side expression f.removeLines(f.Line(node.TokPos), f.Line(node.Rhs[0].Pos())) } } func (f *fumpter) applyPost(c *astutil.Cursor) { switch node := c.Node().(type) { // Adding newlines to composite literals happens as a "post" step, so // that we can take into account whether "pre" steps added any newlines // that would affect us here. case *ast.CompositeLit: if len(node.Elts) == 0 { // doesn't have elements break } openLine := f.Line(node.Lbrace) closeLine := f.Line(node.Rbrace) if openLine == closeLine { // all in a single line break } newlineAroundElems := false newlineBetweenElems := false lastLine := openLine for i, elem := range node.Elts { if elPos := f.Line(elem.Pos()); elPos > lastLine { if i == 0 { newlineAroundElems = true // remove leading lines if they exist f.removeLines(openLine+1, elPos) } else { newlineBetweenElems = true } } lastLine = f.Line(elem.End()) } if closeLine > lastLine { newlineAroundElems = true } if newlineBetweenElems || newlineAroundElems { first := node.Elts[0] if openLine == f.Line(first.Pos()) { // We want the newline right after the brace. f.addNewline(node.Lbrace + 1) closeLine = f.Line(node.Rbrace) } last := node.Elts[len(node.Elts)-1] if closeLine == f.Line(last.End()) { // We want the newline right before the brace. f.addNewline(node.Rbrace) } } // If there's a newline between any consecutive elements, there // must be a newline between all composite literal elements. if !newlineBetweenElems { break } for i1, elem1 := range node.Elts { i2 := i1 + 1 if i2 >= len(node.Elts) { break } elem2 := node.Elts[i2] // TODO: do we care about &{}? _, ok1 := elem1.(*ast.CompositeLit) _, ok2 := elem2.(*ast.CompositeLit) if !ok1 && !ok2 { continue } if f.Line(elem1.End()) == f.Line(elem2.Pos()) { f.addNewline(elem1.End()) } } } } func (f *fumpter) splitLongLine(c *astutil.Cursor) { if os.Getenv("GOFUMPT_SPLIT_LONG_LINES") != "on" { // By default, this feature is turned off. // Turn it on by setting GOFUMPT_SPLIT_LONG_LINES=on. return } node := c.Node() if node == nil { return } newlinePos := node.Pos() start := f.Position(node.Pos()) end := f.Position(node.End()) // If the node is already split in multiple lines, there's nothing to do. if start.Line != end.Line { return } // Only split at the start of the current node if it's part of a list. if _, ok := c.Parent().(*ast.BinaryExpr); ok { // Chains of binary expressions are considered lists, too. } else if c.Index() >= 0 { // For the rest of the nodes, we're in a list if c.Index() >= 0. } else { return } // Like in printLength, add an approximation of the indentation level. // Since any existing tabs were already counted as one column, multiply // the level by 7. startCol := start.Column + f.blockLevel*7 endCol := end.Column + f.blockLevel*7 // If this is a composite literal, // and we were going to insert a newline before the entire literal, // insert the newline before the first element instead. // Since we'll add a newline after the last element too, // this format is generally going to be nicer. if comp := isComposite(node); comp != nil && len(comp.Elts) > 0 { newlinePos = comp.Elts[0].Pos() } // If this is a function call, // and we were to add a newline before the first argument, // prefer adding the newline before the entire call. // End-of-line parentheses aren't very nice, as we don't put their // counterparts at the start of a line too. // We do this by using the average of the two starting positions. if call, _ := node.(*ast.CallExpr); call != nil && len(call.Args) > 0 { first := f.Position(call.Args[0].Pos()) startCol += (first.Column - start.Column) / 2 } // If the start position is too short, we definitely won't split the line. if startCol <= shortLineLimit { return } lineEnd := f.Position(f.lineEnd(start.Line)) // firstLength and secondLength are the split line lengths, excluding // indentation. firstLength := start.Column - f.blockLevel if firstLength < 0 { panic("negative length") } secondLength := lineEnd.Column - start.Column if secondLength < 0 { panic("negative length") } // If the line ends past the long line limit, // and both splits are estimated to take at least minSplitFactor of the limit, // then split the line. minSplitLength := int(f.minSplitFactor * longLineLimit) if endCol > longLineLimit && firstLength >= minSplitLength && secondLength >= minSplitLength { f.addNewline(newlinePos) } } func isComposite(node ast.Node) *ast.CompositeLit { switch node := node.(type) { case *ast.CompositeLit: return node case *ast.UnaryExpr: return isComposite(node.X) // e.g. &T{} default: return nil } } func (f *fumpter) stmts(list []ast.Stmt) { for i, stmt := range list { ifs, ok := stmt.(*ast.IfStmt) if !ok || i < 1 { continue // not an if following another statement } as, ok := list[i-1].(*ast.AssignStmt) if !ok || as.Tok != token.DEFINE || !identEqual(as.Lhs[len(as.Lhs)-1], "err") { continue // not "..., err := ..." } be, ok := ifs.Cond.(*ast.BinaryExpr) if !ok || ifs.Init != nil || ifs.Else != nil { continue // complex if } if be.Op != token.NEQ || !identEqual(be.X, "err") || !identEqual(be.Y, "nil") { continue // not "err != nil" } f.removeLinesBetween(as.End(), ifs.Pos()) } } func identEqual(expr ast.Expr, name string) bool { id, ok := expr.(*ast.Ident) return ok && id.Name == name } // isCgoImport returns true if the declaration is simply: // // import "C" // // Note that parentheses do not affect the result. func isCgoImport(decl *ast.GenDecl) bool { if decl.Tok != token.IMPORT || len(decl.Specs) != 1 { return false } spec := decl.Specs[0].(*ast.ImportSpec) return spec.Path.Value == `"C"` } // joinStdImports ensures that all standard library imports are together and at // the top of the imports list. func (f *fumpter) joinStdImports(d *ast.GenDecl) { var std, other []ast.Spec firstGroup := true lastEnd := d.Pos() needsSort := false for i, spec := range d.Specs { spec := spec.(*ast.ImportSpec) if coms := f.commentsBetween(lastEnd, spec.Pos()); len(coms) > 0 { lastEnd = coms[len(coms)-1].End() } if i > 0 && firstGroup && f.Line(spec.Pos()) > f.Line(lastEnd)+1 { firstGroup = false } else { // We're still in the first group, update lastEnd. lastEnd = spec.End() } path, _ := strconv.Unquote(spec.Path.Value) switch { // Imports with a period are definitely third party. case strings.Contains(path, "."): fallthrough // "test" and "example" are reserved as per golang.org/issue/37641. // "internal" is unreachable. case strings.HasPrefix(path, "test/") || strings.HasPrefix(path, "example/") || strings.HasPrefix(path, "internal/"): fallthrough // To be conservative, if an import has a name or an inline // comment, and isn't part of the top group, treat it as non-std. case !firstGroup && (spec.Name != nil || spec.Comment != nil): other = append(other, spec) continue } // If we're moving this std import further up, reset its // position, to avoid breaking comments. if !firstGroup || len(other) > 0 { setPos(reflect.ValueOf(spec), d.Pos()) needsSort = true } std = append(std, spec) } // Ensure there is an empty line between std imports and other imports. if len(std) > 0 && len(other) > 0 && f.Line(std[len(std)-1].End())+1 >= f.Line(other[0].Pos()) { // We add two newlines, as that's necessary in some edge cases. // For example, if the std and non-std imports were together and // without indentation, adding one newline isn't enough. Two // empty lines will be printed as one by go/printer, anyway. f.addNewline(other[0].Pos() - 1) f.addNewline(other[0].Pos()) } // Finally, join the imports, keeping std at the top. d.Specs = append(std, other...) // If we moved any std imports to the first group, we need to sort them // again. if needsSort { ast.SortImports(f.fset, f.astFile) } } // mergeAdjacentFields returns fields with adjacent fields merged if possible. func (f *fumpter) mergeAdjacentFields(fields []*ast.Field) []*ast.Field { // If there are less than two fields then there is nothing to merge. if len(fields) < 2 { return fields } // Otherwise, iterate over adjacent pairs of fields, merging if possible, // and mutating fields. Elements of fields may be mutated (if merged with // following fields), discarded (if merged with a preceeding field), or left // unchanged. i := 0 for j := 1; j < len(fields); j++ { if f.shouldMergeAdjacentFields(fields[i], fields[j]) { fields[i].Names = append(fields[i].Names, fields[j].Names...) } else { i++ fields[i] = fields[j] } } return fields[:i+1] } func (f *fumpter) shouldMergeAdjacentFields(f1, f2 *ast.Field) bool { if len(f1.Names) == 0 || len(f2.Names) == 0 { // Both must have names for the merge to work. return false } if f.Line(f1.Pos()) != f.Line(f2.Pos()) { // Trust the user if they used separate lines. return false } // Only merge if the types are equal. opt := cmp.Comparer(func(x, y token.Pos) bool { return true }) return cmp.Equal(f1.Type, f2.Type, opt) } var posType = reflect.TypeOf(token.NoPos) // setPos recursively sets all position fields in the node v to pos. func setPos(v reflect.Value, pos token.Pos) { if v.Kind() == reflect.Ptr { v = v.Elem() } if !v.IsValid() { return } if v.Type() == posType { v.Set(reflect.ValueOf(pos)) } if v.Kind() == reflect.Struct { for i := 0; i < v.NumField(); i++ { setPos(v.Field(i), pos) } } } golang-mvdan-gofumpt-0.2.0/format/format_test.go000066400000000000000000000010401414300765000217030ustar00rootroot00000000000000// Copyright (c) 2021, Daniel Martí // See LICENSE for licensing information package format_test import ( "testing" qt "github.com/frankban/quicktest" "mvdan.cc/gofumpt/format" ) func TestSourceIncludesSimplify(t *testing.T) { t.Parallel() in := []byte(` package p var () func f() { for _ = range v { } } `[1:]) want := []byte(` package p func f() { for range v { } } `[1:]) got, err := format.Source(in, format.Options{}) qt.Assert(t, err, qt.IsNil) qt.Assert(t, string(got), qt.Equals, string(want)) } golang-mvdan-gofumpt-0.2.0/format/rewrite.go000066400000000000000000000057761414300765000210610ustar00rootroot00000000000000// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package format import ( "go/ast" "go/token" "reflect" "unicode" "unicode/utf8" ) // Values/types for special cases. var ( identType = reflect.TypeOf((*ast.Ident)(nil)) objectPtrType = reflect.TypeOf((*ast.Object)(nil)) positionType = reflect.TypeOf(token.NoPos) callExprType = reflect.TypeOf((*ast.CallExpr)(nil)) ) func isWildcard(s string) bool { rune, size := utf8.DecodeRuneInString(s) return size == len(s) && unicode.IsLower(rune) } // match reports whether pattern matches val, // recording wildcard submatches in m. // If m == nil, match checks whether pattern == val. func match(m map[string]reflect.Value, pattern, val reflect.Value) bool { // Wildcard matches any expression. If it appears multiple // times in the pattern, it must match the same expression // each time. if m != nil && pattern.IsValid() && pattern.Type() == identType { name := pattern.Interface().(*ast.Ident).Name if isWildcard(name) && val.IsValid() { // wildcards only match valid (non-nil) expressions. if _, ok := val.Interface().(ast.Expr); ok && !val.IsNil() { if old, ok := m[name]; ok { return match(nil, old, val) } m[name] = val return true } } } // Otherwise, pattern and val must match recursively. if !pattern.IsValid() || !val.IsValid() { return !pattern.IsValid() && !val.IsValid() } if pattern.Type() != val.Type() { return false } // Special cases. switch pattern.Type() { case identType: // For identifiers, only the names need to match // (and none of the other *ast.Object information). // This is a common case, handle it all here instead // of recursing down any further via reflection. p := pattern.Interface().(*ast.Ident) v := val.Interface().(*ast.Ident) return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name case objectPtrType, positionType: // object pointers and token positions always match return true case callExprType: // For calls, the Ellipsis fields (token.Position) must // match since that is how f(x) and f(x...) are different. // Check them here but fall through for the remaining fields. p := pattern.Interface().(*ast.CallExpr) v := val.Interface().(*ast.CallExpr) if p.Ellipsis.IsValid() != v.Ellipsis.IsValid() { return false } } p := reflect.Indirect(pattern) v := reflect.Indirect(val) if !p.IsValid() || !v.IsValid() { return !p.IsValid() && !v.IsValid() } switch p.Kind() { case reflect.Slice: if p.Len() != v.Len() { return false } for i := 0; i < p.Len(); i++ { if !match(m, p.Index(i), v.Index(i)) { return false } } return true case reflect.Struct: for i := 0; i < p.NumField(); i++ { if !match(m, p.Field(i), v.Field(i)) { return false } } return true case reflect.Interface: return match(m, p.Elem(), v.Elem()) } // Handle token integers, etc. return p.Interface() == v.Interface() } golang-mvdan-gofumpt-0.2.0/format/simplify.go000066400000000000000000000112501414300765000212140ustar00rootroot00000000000000// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package format import ( "go/ast" "go/token" "reflect" ) type simplifier struct{} func (s simplifier) Visit(node ast.Node) ast.Visitor { switch n := node.(type) { case *ast.CompositeLit: // array, slice, and map composite literals may be simplified outer := n var keyType, eltType ast.Expr switch typ := outer.Type.(type) { case *ast.ArrayType: eltType = typ.Elt case *ast.MapType: keyType = typ.Key eltType = typ.Value } if eltType != nil { var ktyp reflect.Value if keyType != nil { ktyp = reflect.ValueOf(keyType) } typ := reflect.ValueOf(eltType) for i, x := range outer.Elts { px := &outer.Elts[i] // look at value of indexed/named elements if t, ok := x.(*ast.KeyValueExpr); ok { if keyType != nil { s.simplifyLiteral(ktyp, keyType, t.Key, &t.Key) } x = t.Value px = &t.Value } s.simplifyLiteral(typ, eltType, x, px) } // node was simplified - stop walk (there are no subnodes to simplify) return nil } case *ast.SliceExpr: // a slice expression of the form: s[a:len(s)] // can be simplified to: s[a:] // if s is "simple enough" (for now we only accept identifiers) // // Note: This may not be correct because len may have been redeclared in another // file belonging to the same package. However, this is extremely unlikely // and so far (April 2016, after years of supporting this rewrite feature) // has never come up, so let's keep it working as is (see also #15153). if n.Max != nil { // - 3-index slices always require the 2nd and 3rd index break } if s, _ := n.X.(*ast.Ident); s != nil && s.Obj != nil { // the array/slice object is a single, resolved identifier if call, _ := n.High.(*ast.CallExpr); call != nil && len(call.Args) == 1 && !call.Ellipsis.IsValid() { // the high expression is a function call with a single argument if fun, _ := call.Fun.(*ast.Ident); fun != nil && fun.Name == "len" && fun.Obj == nil { // the function called is "len" and it is not locally defined; and // because we don't have dot imports, it must be the predefined len() if arg, _ := call.Args[0].(*ast.Ident); arg != nil && arg.Obj == s.Obj { // the len argument is the array/slice object n.High = nil } } } } // Note: We could also simplify slice expressions of the form s[0:b] to s[:b] // but we leave them as is since sometimes we want to be very explicit // about the lower bound. // An example where the 0 helps: // x, y, z := b[0:2], b[2:4], b[4:6] // An example where it does not: // x, y := b[:n], b[n:] case *ast.RangeStmt: // - a range of the form: for x, _ = range v {...} // can be simplified to: for x = range v {...} // - a range of the form: for _ = range v {...} // can be simplified to: for range v {...} if isBlank(n.Value) { n.Value = nil } if isBlank(n.Key) && n.Value == nil { n.Key = nil } } return s } func (s simplifier) simplifyLiteral(typ reflect.Value, astType, x ast.Expr, px *ast.Expr) { ast.Walk(s, x) // simplify x // if the element is a composite literal and its literal type // matches the outer literal's element type exactly, the inner // literal type may be omitted if inner, ok := x.(*ast.CompositeLit); ok { if match(nil, typ, reflect.ValueOf(inner.Type)) { inner.Type = nil } } // if the outer literal's element type is a pointer type *T // and the element is & of a composite literal of type T, // the inner &T may be omitted. if ptr, ok := astType.(*ast.StarExpr); ok { if addr, ok := x.(*ast.UnaryExpr); ok && addr.Op == token.AND { if inner, ok := addr.X.(*ast.CompositeLit); ok { if match(nil, reflect.ValueOf(ptr.X), reflect.ValueOf(inner.Type)) { inner.Type = nil // drop T *px = inner // drop & } } } } } func isBlank(x ast.Expr) bool { ident, ok := x.(*ast.Ident) return ok && ident.Name == "_" } func simplify(f *ast.File) { // remove empty declarations such as "const ()", etc removeEmptyDeclGroups(f) var s simplifier ast.Walk(s, f) } func removeEmptyDeclGroups(f *ast.File) { i := 0 for _, d := range f.Decls { if g, ok := d.(*ast.GenDecl); !ok || !isEmpty(f, g) { f.Decls[i] = d i++ } } f.Decls = f.Decls[:i] } func isEmpty(f *ast.File, g *ast.GenDecl) bool { if g.Doc != nil || g.Specs != nil { return false } for _, c := range f.Comments { // if there is a comment in the declaration, it is not considered empty if g.Pos() <= c.Pos() && c.End() <= g.End() { return false } } return true } golang-mvdan-gofumpt-0.2.0/go.mod000066400000000000000000000005031414300765000166460ustar00rootroot00000000000000module mvdan.cc/gofumpt go 1.16 require ( github.com/frankban/quicktest v1.14.0 github.com/google/go-cmp v0.5.6 github.com/rogpeppe/go-internal v1.8.1-0.20211023094830-115ce09fd6b4 golang.org/x/mod v0.5.1 golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 golang.org/x/tools v0.1.8-0.20211102182255-bb4add04ddef ) golang-mvdan-gofumpt-0.2.0/go.sum000066400000000000000000000115441414300765000167020ustar00rootroot00000000000000github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.1-0.20211023094830-115ce09fd6b4 h1:Ha8xCaq6ln1a+R91Km45Oq6lPXj2Mla6CRJYcuV2h1w= github.com/rogpeppe/go-internal v1.8.1-0.20211023094830-115ce09fd6b4/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 h1:7zYaz3tjChtpayGDzu6H0hDAUM5zIGA2XW7kRNgQ0jc= golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.8-0.20211102182255-bb4add04ddef h1:/DaKawnTFFxdq/mJT3pM+OkeJlq5gc3ZhkbGVYbqOCw= golang.org/x/tools v0.1.8-0.20211102182255-bb4add04ddef/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= golang-mvdan-gofumpt-0.2.0/gofmt.go000066400000000000000000000172731414300765000172170ustar00rootroot00000000000000// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main import ( "bytes" "flag" "fmt" "go/ast" "go/parser" "go/printer" "go/scanner" "go/token" "io" "io/fs" "os" "path/filepath" "runtime" "runtime/pprof" "strings" exec "golang.org/x/sys/execabs" gformat "mvdan.cc/gofumpt/format" "mvdan.cc/gofumpt/internal/diff" "mvdan.cc/gofumpt/internal/version" ) var ( // main operation modes list = flag.Bool("l", false, "list files whose formatting differs from gofumpt's") write = flag.Bool("w", false, "write result to (source) file instead of stdout") doDiff = flag.Bool("d", false, "display diffs instead of rewriting files") allErrors = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)") // debugging cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file") // gofumpt's own flags langVersion = flag.String("lang", "", "target Go version in the form 1.X (default from go.mod)") extraRules = flag.Bool("extra", false, "enable extra rules which should be vetted by a human") showVersion = flag.Bool("version", false, "show version and exit") ) // Keep these in sync with go/format/format.go. const ( tabWidth = 8 printerMode = printer.UseSpaces | printer.TabIndent | printerNormalizeNumbers // printerNormalizeNumbers means to canonicalize number literal prefixes // and exponents while printing. See https://golang.org/doc/go1.13#gofumpt. // // This value is defined in go/printer specifically for go/format and cmd/gofumpt. printerNormalizeNumbers = 1 << 30 ) var ( fileSet = token.NewFileSet() // per process FileSet exitCode = 0 parserMode parser.Mode // walkingVendorDir is true if we are explicitly walking a vendor directory. walkingVendorDir bool ) func report(err error) { scanner.PrintError(os.Stderr, err) exitCode = 2 } func usage() { fmt.Fprintf(os.Stderr, "usage: gofumpt [flags] [path ...]\n") flag.PrintDefaults() } func initParserMode() { parserMode = parser.ParseComments if *allErrors { parserMode |= parser.AllErrors } } func isGoFile(f fs.DirEntry) bool { // ignore non-Go files name := f.Name() return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") } // If in == nil, the source is the contents of the file with the given filename. func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error { var perm os.FileMode = 0o644 if in == nil { f, err := os.Open(filename) if err != nil { return err } defer f.Close() fi, err := f.Stat() if err != nil { return err } in = f perm = fi.Mode().Perm() } src, err := io.ReadAll(in) if err != nil { return err } file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin) if err != nil { return err } ast.SortImports(fileSet, file) // Apply gofumpt's changes before we print the code in gofumpt's format. if *langVersion == "" { out, err := exec.Command("go", "list", "-m", "-f", "{{.GoVersion}}").Output() out = bytes.TrimSpace(out) if err == nil && len(out) > 0 { *langVersion = string(out) } } gformat.File(fileSet, file, gformat.Options{ LangVersion: *langVersion, ExtraRules: *extraRules, }) res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth}) if err != nil { return err } if !bytes.Equal(src, res) { // formatting has changed if *list { fmt.Fprintln(out, filename) } if *write { // make a temporary backup before overwriting original bakname, err := backupFile(filename+".", src, perm) if err != nil { return err } err = os.WriteFile(filename, res, perm) if err != nil { os.Rename(bakname, filename) return err } err = os.Remove(bakname) if err != nil { return err } } if *doDiff { data, err := diffWithReplaceTempFile(src, res, filename) if err != nil { return fmt.Errorf("computing diff: %s", err) } fmt.Fprintf(out, "diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename)) out.Write(data) } } if !*list && !*write && !*doDiff { _, err = out.Write(res) } return err } func visitFile(path string, f fs.DirEntry, err error) error { if !walkingVendorDir && filepath.Base(path) == "vendor" { return filepath.SkipDir } if err != nil || !isGoFile(f) { return err } if err := processFile(path, nil, os.Stdout, false); err != nil { report(err) } return nil } func main() { // call gofumptMain in a separate function // so that it can use defer and have them // run before the exit. gofumptMain() os.Exit(exitCode) } func gofumptMain() { flag.Usage = usage flag.Parse() // Print the gofumpt version if the user asks for it. if *showVersion { version.Print() return } if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err) exitCode = 2 return } defer f.Close() pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } initParserMode() args := flag.Args() if len(args) == 0 { if *write { fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input") exitCode = 2 return } if err := processFile("", os.Stdin, os.Stdout, true); err != nil { report(err) } return } for _, arg := range args { switch info, err := os.Stat(arg); { case err != nil: report(err) case !info.IsDir(): // Non-directory arguments are always formatted. if err := processFile(arg, nil, os.Stdout, false); err != nil { report(err) } default: // Directories are walked, ignoring non-Go files. walkingVendorDir = filepath.Base(arg) == "vendor" if err := filepath.WalkDir(arg, visitFile); err != nil { report(err) } } } } func diffWithReplaceTempFile(b1, b2 []byte, filename string) ([]byte, error) { data, err := diff.Diff("gofumpt", b1, b2) if len(data) > 0 { return replaceTempFilename(data, filename) } return data, err } // replaceTempFilename replaces temporary filenames in diff with actual one. // // --- /tmp/gofumpt316145376 2017-02-03 19:13:00.280468375 -0500 // +++ /tmp/gofumpt617882815 2017-02-03 19:13:00.280468375 -0500 // ... // -> // --- path/to/file.go.orig 2017-02-03 19:13:00.280468375 -0500 // +++ path/to/file.go 2017-02-03 19:13:00.280468375 -0500 // ... func replaceTempFilename(diff []byte, filename string) ([]byte, error) { bs := bytes.SplitN(diff, []byte{'\n'}, 3) if len(bs) < 3 { return nil, fmt.Errorf("got unexpected diff for %s", filename) } // Preserve timestamps. var t0, t1 []byte if i := bytes.LastIndexByte(bs[0], '\t'); i != -1 { t0 = bs[0][i:] } if i := bytes.LastIndexByte(bs[1], '\t'); i != -1 { t1 = bs[1][i:] } // Always print filepath with slash separator. f := filepath.ToSlash(filename) bs[0] = []byte(fmt.Sprintf("--- %s%s", f+".orig", t0)) bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1)) return bytes.Join(bs, []byte{'\n'}), nil } const chmodSupported = runtime.GOOS != "windows" // backupFile writes data to a new file named filename with permissions perm, // with 0 && isSpace(src[i-1]) { i-- } return append(res, src[i:]...), nil } // isSpace reports whether the byte is a space character. // isSpace defines a space as being among the following bytes: ' ', '\t', '\n' and '\r'. func isSpace(b byte) bool { return b == ' ' || b == '\t' || b == '\n' || b == '\r' } golang-mvdan-gofumpt-0.2.0/internal/000077500000000000000000000000001414300765000173565ustar00rootroot00000000000000golang-mvdan-gofumpt-0.2.0/internal/diff/000077500000000000000000000000001414300765000202665ustar00rootroot00000000000000golang-mvdan-gofumpt-0.2.0/internal/diff/diff.go000066400000000000000000000040041414300765000215230ustar00rootroot00000000000000// Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package diff implements a Diff function that compare two inputs // using the 'diff' tool. package diff import ( "bytes" "io/ioutil" "os" "runtime" exec "golang.org/x/sys/execabs" ) // Returns diff of two arrays of bytes in diff tool format. func Diff(prefix string, b1, b2 []byte) ([]byte, error) { f1, err := writeTempFile(prefix, b1) if err != nil { return nil, err } defer os.Remove(f1) f2, err := writeTempFile(prefix, b2) if err != nil { return nil, err } defer os.Remove(f2) cmd := "diff" if runtime.GOOS == "plan9" { cmd = "/bin/ape/diff" } data, err := exec.Command(cmd, "-u", f1, f2).CombinedOutput() if len(data) > 0 { // diff exits with a non-zero status when the files don't match. // Ignore that failure as long as we get output. err = nil } // If we are on Windows and the diff is Cygwin diff, // machines can get into a state where every Cygwin // command works fine but prints a useless message like: // // Cygwin WARNING: // Couldn't compute FAST_CWD pointer. This typically occurs if you're using // an older Cygwin version on a newer Windows. Please update to the latest // available Cygwin version from https://cygwin.com/. If the problem persists, // please see https://cygwin.com/problems.html // // Skip over that message and just return the actual diff. if len(data) > 0 && !bytes.HasPrefix(data, []byte("--- ")) { i := bytes.Index(data, []byte("\n--- ")) if i >= 0 && i < 80*10 && bytes.Contains(data[:i], []byte("://cygwin.com/")) { data = data[i+1:] } } return data, err } func writeTempFile(prefix string, data []byte) (string, error) { file, err := ioutil.TempFile("", prefix) if err != nil { return "", err } _, err = file.Write(data) if err1 := file.Close(); err == nil { err = err1 } if err != nil { os.Remove(file.Name()) return "", err } return file.Name(), nil } golang-mvdan-gofumpt-0.2.0/internal/version/000077500000000000000000000000001414300765000210435ustar00rootroot00000000000000golang-mvdan-gofumpt-0.2.0/internal/version/version.go000066400000000000000000000011661414300765000230630ustar00rootroot00000000000000// Copyright (c) 2020, Daniel Martí // See LICENSE for licensing information package version import ( "fmt" "os" "runtime/debug" ) var version = "(devel)" // to match the default from runtime/debug func String() string { if testVersion := os.Getenv("GOFUMPT_VERSION_TEST"); testVersion != "" { return testVersion } // don't overwrite the version if it was set by -ldflags=-X if info, ok := debug.ReadBuildInfo(); ok && version == "(devel)" { mod := &info.Main if mod.Replace != nil { mod = mod.Replace } version = mod.Version } return version } func Print() { fmt.Println(String()) } golang-mvdan-gofumpt-0.2.0/main_test.go000066400000000000000000000013711414300765000200560ustar00rootroot00000000000000// Copyright (c) 2019, Daniel Martí // See LICENSE for licensing information package main import ( "flag" "os" "path/filepath" "testing" qt "github.com/frankban/quicktest" "github.com/rogpeppe/go-internal/gotooltest" "github.com/rogpeppe/go-internal/testscript" ) func TestMain(m *testing.M) { os.Exit(testscript.RunMain(m, map[string]func() int{ "gofumpt": func() int { gofumptMain() return exitCode }, })) } var update = flag.Bool("u", false, "update testscript output files") func TestScripts(t *testing.T) { t.Parallel() p := testscript.Params{ Dir: filepath.Join("testdata", "scripts"), UpdateScripts: *update, } err := gotooltest.Setup(&p) qt.Assert(t, err, qt.IsNil) testscript.Run(t, p) } golang-mvdan-gofumpt-0.2.0/testdata/000077500000000000000000000000001414300765000173535ustar00rootroot00000000000000golang-mvdan-gofumpt-0.2.0/testdata/scripts/000077500000000000000000000000001414300765000210425ustar00rootroot00000000000000golang-mvdan-gofumpt-0.2.0/testdata/scripts/assignment-newlines.txt000066400000000000000000000007511414300765000256000ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p func f() { foo := "bar" foo := "bar" _, _ = 0, 1 _, _ = 0, 1 _ = ` foo ` _ = /* inline */ "foo" _ = // inline "foo" } -- foo.go.golden -- package p func f() { foo := "bar" foo := "bar" _, _ = 0, 1 _, _ = 0, 1 _ = ` foo ` _ = /* inline */ "foo" _ = // inline "foo" } golang-mvdan-gofumpt-0.2.0/testdata/scripts/block-empty.txt000066400000000000000000000004431414300765000240320ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p func f() { if true { // lone comment } { } { // lone comment } } -- foo.go.golden -- package p func f() { if true { // lone comment } { } { // lone comment } } golang-mvdan-gofumpt-0.2.0/testdata/scripts/block-single.txt000066400000000000000000000021461414300765000241570ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p func f() { if true { println() } for true { println() } { println(1, 2, 3, 4, `foo bar`) } { // comment directly before println() // comment after } { // comment before println() // comment directly after } // For readability; the empty line helps separate the multi-line // condition from the body. if true && true { println() } for true && true { println() } if true && true { // documented single statement println() } } -- foo.go.golden -- package p func f() { if true { println() } for true { println() } { println(1, 2, 3, 4, `foo bar`) } { // comment directly before println() // comment after } { // comment before println() // comment directly after } // For readability; the empty line helps separate the multi-line // condition from the body. if true && true { println() } for true && true { println() } if true && true { // documented single statement println() } } golang-mvdan-gofumpt-0.2.0/testdata/scripts/cgo.txt000066400000000000000000000004011414300765000223460ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p import "C" import "os" import "C" import ( "io" "utf8" ) -- foo.go.golden -- package p import "C" import "os" import "C" import ( "io" "utf8" ) golang-mvdan-gofumpt-0.2.0/testdata/scripts/comment-spaced.txt000066400000000000000000000026671414300765000245150ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- //go:build tag // +build tag package p //go:generate some command //go:unknowndirective //lint:disablefoo //go-sumtype:decl Foo //nolint //nolint // explanation //nolint:somelinter // explanation //not actually: a directive //https://just.one/url //TODO: do something //export CgoFunc //extern open func c_open(name *byte, mode int, perm int) int //line 123 //sys Unlink(path string) (err error) //sysnb Getpid() (pid int) //foo is foo. type foo int // comment with a tab. // comment with many spaces //comment group //123 numbers too // comment group //123 numbers too //{ //this is probably code //} //////////// // ascii art //---------- // -- foo.go.golden -- //go:build tag // +build tag package p //go:generate some command //go:unknowndirective //lint:disablefoo //go-sumtype:decl Foo //nolint //nolint // explanation //nolint:somelinter // explanation // not actually: a directive // https://just.one/url // TODO: do something //export CgoFunc //extern open func c_open(name *byte, mode int, perm int) int //line 123 //sys Unlink(path string) (err error) //sysnb Getpid() (pid int) // foo is foo. type foo int // comment with a tab. // comment with many spaces // comment group // 123 numbers too // comment group // 123 numbers too //{ //this is probably code //} //////////// // ascii art //---------- // golang-mvdan-gofumpt-0.2.0/testdata/scripts/composite-literals-leading-lines.txt000066400000000000000000000015011414300765000301300ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p var _ = []string{ "foo", } var _ = []string{ "foo", } var _ = []string{ // comment "foo", } var _ = []string{ // comment "foo", } var _ = map[string]string{ "foo": "bar", } var _ = map[string]string{ "foo": "bar", } var _ = map[string]string{ // comment "foo": "bar", } var _ = map[string]string{ // comment "foo": "bar", } -- foo.go.golden -- package p var _ = []string{ "foo", } var _ = []string{ "foo", } var _ = []string{ // comment "foo", } var _ = []string{ // comment "foo", } var _ = map[string]string{ "foo": "bar", } var _ = map[string]string{ "foo": "bar", } var _ = map[string]string{ // comment "foo": "bar", } var _ = map[string]string{ // comment "foo": "bar", } golang-mvdan-gofumpt-0.2.0/testdata/scripts/composite-multiline.txt000066400000000000000000000024671414300765000256160ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p var _ = []int{} var _ = []int{ } var _ = []int{1, 2, 3, 4} var _ = []int{ 1, 2, 3, 4} var _ = [][]string{{ "no need for more newlines", "if wrapping a single expression", }} var _ = []string{` no need for newlines `, ` if no elements are surrounded by newlines `} var _ = []struct{ a int }{ { // consistent a: 1, }, { a: 2, }, { // inconsistent a: 3, }, } var _ = []struct{ a int }{{ a: 1, }, { a: 2, }, { a: 3, }} var _ interface{ } func _(struct{ }) var _ = []interface { }{1, 2, 3} func _( ) type T struct { Foo // comment Bar struct { // comment } } -- foo.go.golden -- package p var _ = []int{} var _ = []int{} var _ = []int{ 1, 2, 3, 4, } var _ = []int{ 1, 2, 3, 4, } var _ = [][]string{{ "no need for more newlines", "if wrapping a single expression", }} var _ = []string{` no need for newlines `, ` if no elements are surrounded by newlines `} var _ = []struct{ a int }{ { // consistent a: 1, }, { a: 2, }, { // inconsistent a: 3, }, } var _ = []struct{ a int }{{ a: 1, }, { a: 2, }, { a: 3, }} var _ interface{} func _(struct{}) var _ = []interface{}{1, 2, 3} func _() type T struct { Foo // comment Bar struct { // comment } } golang-mvdan-gofumpt-0.2.0/testdata/scripts/decl-group-many.txt000066400000000000000000000015321414300765000246070ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p var single = "foo" var another = "bar" const one = 'q' const two = 'w' const three = 'e' const four = 'r' var not = 'a' var v1 = 's' // comment, e.g. directive var v2 = 'd' var v1 = "mixed" const c1 = "mixed" // comment, e.g. directive var v1 = 's' var v2 = 'd' var v3 = 'd' const inline1 = "s1" // c1 const inline2 = "s2" // c2 const inline3 = "s3" // c3 -- foo.go.golden -- package p var ( single = "foo" another = "bar" ) const ( one = 'q' two = 'w' three = 'e' four = 'r' ) var not = 'a' var v1 = 's' // comment, e.g. directive var v2 = 'd' var v1 = "mixed" const c1 = "mixed" // comment, e.g. directive var v1 = 's' var ( v2 = 'd' v3 = 'd' ) const ( inline1 = "s1" // c1 inline2 = "s2" // c2 inline3 = "s3" // c3 ) golang-mvdan-gofumpt-0.2.0/testdata/scripts/decl-group-single.txt000066400000000000000000000015521414300765000251260ustar00rootroot00000000000000gofumpt -w f1.go f2.go cmp f1.go f1.go.golden cmp f2.go f2.go.golden gofumpt -d f1.go.golden f2.go.golden ! stdout . -- f1.go -- package p import "non-grouped" import ( "grouped" ) var single = "foo" var ( // verbose is verbose. verbose = "bar" ) // This entire block has a comment. var ( groupComment = "bar" ) var ( multiple1 string multiple2 string ) const ( first = iota ) var ( multiline = []string{ "foo", "bar", } ) -- f1.go.golden -- package p import "non-grouped" import ( "grouped" ) var single = "foo" // verbose is verbose. var verbose = "bar" // This entire block has a comment. var ( groupComment = "bar" ) var ( multiple1 string multiple2 string ) const ( first = iota ) var multiline = []string{ "foo", "bar", } -- f2.go -- package p func _() { var ( _ int ) } -- f2.go.golden -- package p func _() { var _ int } golang-mvdan-gofumpt-0.2.0/testdata/scripts/decls-separated.txt000066400000000000000000000015061414300765000246450ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p func f1() { println("single line") } func f2() { println("single line") } func f3() { println("multiline") } func f4() { println("multiline") } // l1 is a var. var l1 = []int{ 1, 2, } // l2 is a var. var l2 = []int{ 3, 4, } var ( s3 = ` ok if grouped together ` s4 = ` ok if grouped together ` ) var _ = "ok if either isn't multiline" -- foo.go.golden -- package p func f1() { println("single line") } func f2() { println("single line") } func f3() { println("multiline") } func f4() { println("multiline") } // l1 is a var. var l1 = []int{ 1, 2, } // l2 is a var. var l2 = []int{ 3, 4, } var ( s3 = ` ok if grouped together ` s4 = ` ok if grouped together ` ) var _ = "ok if either isn't multiline" golang-mvdan-gofumpt-0.2.0/testdata/scripts/diagnose.txt000066400000000000000000000017021414300765000233740ustar00rootroot00000000000000cp foo.go foo.go.orig env GOFUMPT_VERSION_TEST=v0.1.1-0.20210524140936-ba6406b58f36 gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -w outdated.go cmp outdated.go foo.go.golden cp foo.go.orig foo.go gofumpt -w -extra foo.go cmp foo.go foo.go.golden-extra cp foo.go.orig foo.go gofumpt -w -lang=v1 foo.go cmp foo.go foo.go.golden-lang gofumpt -d nochange.go ! stdout . gofumpt -d foo.go.golden ! stdout . gofumpt -d -extra foo.go.golden-extra ! stdout . -- go.mod -- module test go 1.16 -- foo.go -- package p //gofumpt:diagnose -- outdated.go -- package p //gofumpt:diagnose v0.1.0 -- nochange.go -- package p //gofumpt:diagnosefoobar -- foo.go.golden -- package p //gofumpt:diagnose v0.1.1-0.20210524140936-ba6406b58f36 -lang=v1.16 -- foo.go.golden-extra -- package p //gofumpt:diagnose v0.1.1-0.20210524140936-ba6406b58f36 -lang=v1.16 -extra -- foo.go.golden-lang -- package p //gofumpt:diagnose v0.1.1-0.20210524140936-ba6406b58f36 -lang=v1 golang-mvdan-gofumpt-0.2.0/testdata/scripts/func-merge-parameters.txt000066400000000000000000000023671414300765000260040ustar00rootroot00000000000000# By default, this rule isn't enabled. gofumpt foo.go cmp stdout foo.go # It's run with -extra. gofumpt -extra foo.go cmp stdout foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p type f func(x int, y int) int type i interface { add(x int, y int) } type s struct { x int y int } func mergeAdjacent(x int, y int) {} func mergeThreeAdjacent(x int, y int, z int) {} func mergeOneWithTwo(x, y int, z int) {} func mergeTwoWithOne(x int, y, z int) {} func mergeWithComment( x int, y int, // comment ) func mergeAllSyntax(x chan []*foo.Bar, y chan []*foo.Bar) {} func dontMergeAnonymousParams(int, int) {} func dontMergeMultipleLines( x int, y int, ) { } func dontMergeMultipleLines2( x, y int, z int, ) { } -- foo.go.golden -- package p type f func(x, y int) int type i interface { add(x, y int) } type s struct { x int y int } func mergeAdjacent(x, y int) {} func mergeThreeAdjacent(x, y, z int) {} func mergeOneWithTwo(x, y, z int) {} func mergeTwoWithOne(x, y, z int) {} func mergeWithComment( x, y int, // comment ) func mergeAllSyntax(x, y chan []*foo.Bar) {} func dontMergeAnonymousParams(int, int) {} func dontMergeMultipleLines( x int, y int, ) { } func dontMergeMultipleLines2( x, y int, z int, ) { } golang-mvdan-gofumpt-0.2.0/testdata/scripts/func-newlines.txt000066400000000000000000000124461414300765000243670ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p func f1() { println("multiple") println("statements") } func f2() { // comment directly before println() // comment after } func _() { f3 := func() { println() } } func multilineParams(p1 string, p2 string) { println("body") } func multilineParamsUnambiguous(p1 string, p2 string, ) { println("body") } func multilineParamsListNoReturn( p1 string, p2 string, ) { println("body") } func multilineParamsListReturningNamedSingleValue( p1 string, p2 string, ) (err error) { println("body") return err } func multilineParamsListReturningSingleValue( p1 string, p2 string, ) error { println("body") return nil } func multilineParamsListReturningNamedMultiValues( p1 string, p2 string, ) (s string, err error) { println("body") return s, err } func multilineParamsListReturningMultiValues( p1 string, p2 string, ) (string, error) { println("body") return "", nil } func multilineParamsListReturningNamedMultiLineValuesList( p1 string, p2 string, ) ( s string, err error, ) { println("body") return s, err } func multilineParamsListReturningMultiLineValues( p1 string, p2 string, ) ( string, error, ) { println("body") return "", nil } func multilineParamsOneParamNoReturn( p1 string, ) { println("body") } func multilineParamsOneParamReturningNamedSingleValue( p1 string, ) (err error) { println("body") return err } func multilineParamsOneParamReturningSingleValue( p1 string, ) error { println("body") return nil } func multilineParamsOneParamReturningNamedMultiValues( p1 string, ) (s string, err error) { println("body") return s, err } func multilineParamsOneParamReturningMultiValues( p1 string, ) (string, error) { println("body") return "", nil } func multilineParamsOneParamReturningNamedMultiLineValuesList( p1 string, ) ( s string, err error, ) { println("body") return s, err } func multilineParamsOneParamReturningMultiLineValues( p1 string, ) ( string, error, ) { println("body") return "", nil } func multilineResults() (p1 string, p2 string) { println("body") } func multilineResultsUnambiguous() (p1 string, p2 string, ) { println("body") } func multilineNoFields( ) { println("body") } func f( foo int, bar string, /* baz */) { body() } func f2( foo int, bar string, ) ( string, error, /* baz */) { return "", nil } func multilineResultsMultipleEmptyLines() (p1 string, p2 string) { println("body") } func multilineParamsWithoutEmptyLine(p1 string, p2 string) { println("body") } func multilineParamsWithoutEmptyLineWithComment(p1 string, p2 string) { // comment println("body") } -- foo.go.golden -- package p func f1() { println("multiple") println("statements") } func f2() { // comment directly before println() // comment after } func _() { f3 := func() { println() } } func multilineParams(p1 string, p2 string, ) { println("body") } func multilineParamsUnambiguous(p1 string, p2 string, ) { println("body") } func multilineParamsListNoReturn( p1 string, p2 string, ) { println("body") } func multilineParamsListReturningNamedSingleValue( p1 string, p2 string, ) (err error) { println("body") return err } func multilineParamsListReturningSingleValue( p1 string, p2 string, ) error { println("body") return nil } func multilineParamsListReturningNamedMultiValues( p1 string, p2 string, ) (s string, err error) { println("body") return s, err } func multilineParamsListReturningMultiValues( p1 string, p2 string, ) (string, error) { println("body") return "", nil } func multilineParamsListReturningNamedMultiLineValuesList( p1 string, p2 string, ) ( s string, err error, ) { println("body") return s, err } func multilineParamsListReturningMultiLineValues( p1 string, p2 string, ) ( string, error, ) { println("body") return "", nil } func multilineParamsOneParamNoReturn( p1 string, ) { println("body") } func multilineParamsOneParamReturningNamedSingleValue( p1 string, ) (err error) { println("body") return err } func multilineParamsOneParamReturningSingleValue( p1 string, ) error { println("body") return nil } func multilineParamsOneParamReturningNamedMultiValues( p1 string, ) (s string, err error) { println("body") return s, err } func multilineParamsOneParamReturningMultiValues( p1 string, ) (string, error) { println("body") return "", nil } func multilineParamsOneParamReturningNamedMultiLineValuesList( p1 string, ) ( s string, err error, ) { println("body") return s, err } func multilineParamsOneParamReturningMultiLineValues( p1 string, ) ( string, error, ) { println("body") return "", nil } func multilineResults() (p1 string, p2 string, ) { println("body") } func multilineResultsUnambiguous() (p1 string, p2 string, ) { println("body") } func multilineNoFields() { println("body") } func f( foo int, bar string, /* baz */ ) { body() } func f2( foo int, bar string, ) ( string, error, /* baz */ ) { return "", nil } func multilineResultsMultipleEmptyLines() (p1 string, p2 string, ) { println("body") } func multilineParamsWithoutEmptyLine(p1 string, p2 string) { println("body") } func multilineParamsWithoutEmptyLineWithComment(p1 string, p2 string) { // comment println("body") } golang-mvdan-gofumpt-0.2.0/testdata/scripts/generated.txt000066400000000000000000000005641414300765000235460ustar00rootroot00000000000000cp foo.go foo.go.orig cp foo.go foo.go.golden exec gofmt -w foo.go.golden gofumpt -w foo.go cmp foo.go foo.go.golden cp foo.go.orig foo.go gofumpt -w . cmp foo.go foo.go.golden -- foo.go -- // foo is a package about bar. // Code generated by foo. DO NOT EDIT. // versions: // foo v1.26.0 package foo type i interface { a(x int) int b(x int) int c(x int) int } golang-mvdan-gofumpt-0.2.0/testdata/scripts/ignore-implicit-vendor.txt000066400000000000000000000011611414300765000261700ustar00rootroot00000000000000gofumpt orig.go.golden cp stdout formatted.go.golden mkdir -p vendor/foo cp orig.go.golden vendor/foo/foo.go # format explicit vendor dir gofumpt -l vendor stdout 'vendor[/\\]foo[/\\]foo.go' # format explicit vendor file gofumpt -l vendor/foo/foo.go stdout 'vendor[/\\]foo[/\\]foo.go' # ignore implicit vendor call gofumpt -l . ! stdout . # format explicit vendor pkg while ignoring rest mkdir vendor/ignore cp orig.go.golden vendor/ignore/ignore.go gofumpt -l vendor/foo . stdout 'vendor[/\\]foo[/\\]foo.go' -- orig.go.golden -- package p func f() { if true { // lone comment } { } { // lone comment } } golang-mvdan-gofumpt-0.2.0/testdata/scripts/interface.txt000066400000000000000000000034461414300765000235520ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p type i1 interface { a(x int) int b(x int) int c(x int) int } type i2 interface { // comment for a a(x int) int // comment between a and b // comment for b b(x int) int // comment between b and c c(x int) int d(x int) int // comment for e e(x int) int } type i3 interface { a(x int) int // standalone comment b(x int) int } type leadingLine1 interface { a(x int) int } type leadingLine2 interface { a(x int) int } type leadingLine3 interface { // comment a(x int) int } type leadingLine4 interface { // comment a(x int) int } type leadingLine5 interface { // comment // comment for a a(x int) int } type leadingLine6 interface { // comment // comment for a a(x int) int } type leadingLine7 interface { // comment // comment for a a(x int) int } type leadingLine8 interface { // comment } -- foo.go.golden -- package p type i1 interface { a(x int) int b(x int) int c(x int) int } type i2 interface { // comment for a a(x int) int // comment between a and b // comment for b b(x int) int // comment between b and c c(x int) int d(x int) int // comment for e e(x int) int } type i3 interface { a(x int) int // standalone comment b(x int) int } type leadingLine1 interface { a(x int) int } type leadingLine2 interface { a(x int) int } type leadingLine3 interface { // comment a(x int) int } type leadingLine4 interface { // comment a(x int) int } type leadingLine5 interface { // comment // comment for a a(x int) int } type leadingLine6 interface { // comment // comment for a a(x int) int } type leadingLine7 interface { // comment // comment for a a(x int) int } type leadingLine8 interface { // comment } golang-mvdan-gofumpt-0.2.0/testdata/scripts/long-lines.txt000066400000000000000000000137641414300765000236650ustar00rootroot00000000000000cp foo.go foo.go.orig gofumpt -w foo.go cmp foo.go foo.go.orig env GOFUMPT_SPLIT_LONG_LINES=on gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p func _() { if err := f(argument1, argument2, argument3, argument4, argument5, argument6, argument7, argument8, argument9, argument10); err != nil { panic(err) } // Tiny arguments to ensure the length calculation is right. if err := f(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); err != nil { panic(err) } // These wouldn't take significantly less horizontal space if split. f(x, "one single very very very very very very very very very very very very very very very very long literal") if err := f(x, "one single very very very very very very very very very very very very very very very very long literal"); err != nil { panic(err) } { { { { println("first", "one single very very very very very very very very very very very very very long literal") } } } } // Allow splitting at the start of sub-lists too. if err := f(argument1, argument2, argument3, argument4, someComplex{argument5, argument6, argument7, argument8, argument9, argument10}); err != nil { panic(err) } if err := f(argument1, argument2, argument3, argument4, &someComplex{argument5, argument6, argument7, argument8, argument9, argument10}); err != nil { panic(err) } if err := f(argument1, argument2, argument3, argument4, []someSlice{argument5, argument6, argument7, argument8, argument9, argument10}); err != nil { panic(err) } // Allow splitting "lists" of binary expressions. if boolean1 && boolean2 && boolean3 && boolean4 && boolean5 && boolean6 && boolean7 && boolean8 && boolean9 && boolean10 && boolean11 { } // Over 100, and we split in a way that doesn't break "len(" off. if boolean1 || boolean2 || boolean3 || boolean4 || len(someVeryLongVarName.SomeVeryLongSelector) > 0 { } } // Note that function declarations have a higher limit of 120. // This line goes beyond the limit of 120, but splitting it would leave the // following line with just 20 non-indentation characters. Not worth it. func LongButNotWorthSplitting(argument1, argument2, argument3, argument4, argument5, argument6, argument7, argument8, argument9 int) bool { } // This line goes well past the limit and it should be split. // Note that it has a nested func type in a parameter. func TooLongWithFuncParam(fn func(int) (int, error), argument1, argument2, argument3, argument4, argument5, argument6, argument7, argument8, argument9, argument10 int) bool { } // This is like LongButNotWorthSplitting, but with a func parameter. func LongButNotWorthSplitting2(fn func(int) (int, error), argument3, argument4, argument5, argument6, argument7, argument8, argument9 int) bool { } // Never split result parameter lists, as that could easily add confusion with // extra input parameters. func NeverSplitResults(argument1, argument2, argument3, argument4, argument5 int) (result1 int, result2, result3, result4, result5, result6, result7, result8 bool) { } -- foo.go.golden -- package p func _() { if err := f(argument1, argument2, argument3, argument4, argument5, argument6, argument7, argument8, argument9, argument10); err != nil { panic(err) } // Tiny arguments to ensure the length calculation is right. if err := f(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); err != nil { panic(err) } // These wouldn't take significantly less horizontal space if split. f(x, "one single very very very very very very very very very very very very very very very very long literal") if err := f(x, "one single very very very very very very very very very very very very very very very very long literal"); err != nil { panic(err) } { { { { println("first", "one single very very very very very very very very very very very very very long literal") } } } } // Allow splitting at the start of sub-lists too. if err := f(argument1, argument2, argument3, argument4, someComplex{ argument5, argument6, argument7, argument8, argument9, argument10, }); err != nil { panic(err) } if err := f(argument1, argument2, argument3, argument4, &someComplex{ argument5, argument6, argument7, argument8, argument9, argument10, }); err != nil { panic(err) } if err := f(argument1, argument2, argument3, argument4, []someSlice{ argument5, argument6, argument7, argument8, argument9, argument10, }); err != nil { panic(err) } // Allow splitting "lists" of binary expressions. if boolean1 && boolean2 && boolean3 && boolean4 && boolean5 && boolean6 && boolean7 && boolean8 && boolean9 && boolean10 && boolean11 { } // Over 100, and we split in a way that doesn't break "len(" off. if boolean1 || boolean2 || boolean3 || boolean4 || len(someVeryLongVarName.SomeVeryLongSelector) > 0 { } } // Note that function declarations have a higher limit of 120. // This line goes beyond the limit of 120, but splitting it would leave the // following line with just 20 non-indentation characters. Not worth it. func LongButNotWorthSplitting(argument1, argument2, argument3, argument4, argument5, argument6, argument7, argument8, argument9 int) bool { } // This line goes well past the limit and it should be split. // Note that it has a nested func type in a parameter. func TooLongWithFuncParam(fn func(int) (int, error), argument1, argument2, argument3, argument4, argument5, argument6, argument7, argument8, argument9, argument10 int) bool { } // This is like LongButNotWorthSplitting, but with a func parameter. func LongButNotWorthSplitting2(fn func(int) (int, error), argument3, argument4, argument5, argument6, argument7, argument8, argument9 int) bool { } // Never split result parameter lists, as that could easily add confusion with // extra input parameters. func NeverSplitResults(argument1, argument2, argument3, argument4, argument5 int) (result1 int, result2, result3, result4, result5, result6, result7, result8 bool) { } golang-mvdan-gofumpt-0.2.0/testdata/scripts/missing-import.txt000066400000000000000000000002121414300765000245570ustar00rootroot00000000000000# A missing import shouldn't matter nor be fixed by gofumpt. gofumpt foo.go cmp stdout foo.go -- foo.go -- package p var _ bytes.Buffer golang-mvdan-gofumpt-0.2.0/testdata/scripts/newline-errcheck.txt000066400000000000000000000021061414300765000250270ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p var Do1 func() error var Do2 func() (int, error) func f() { n1, err := Do2() if err != nil { panic(err) } if n2, err := Do2(); err != nil { panic(err) } n3, err := Do2() if err != nil { panic(err) } select { default: err := Do1() if err != nil { panic(err) } } n4, err := Do2() if err != nil && err.Error() == "complex condition" { panic(err) } err1 := Do1() if err != nil { panic(err) } { if err != nil { panic(err) } } } -- foo.go.golden -- package p var Do1 func() error var Do2 func() (int, error) func f() { n1, err := Do2() if err != nil { panic(err) } if n2, err := Do2(); err != nil { panic(err) } n3, err := Do2() if err != nil { panic(err) } select { default: err := Do1() if err != nil { panic(err) } } n4, err := Do2() if err != nil && err.Error() == "complex condition" { panic(err) } err1 := Do1() if err != nil { panic(err) } { if err != nil { panic(err) } } } golang-mvdan-gofumpt-0.2.0/testdata/scripts/octal-literals.txt000066400000000000000000000012521414300765000245220ustar00rootroot00000000000000cd module cp foo.go foo.go.orig # Initially, the Go language version is too low. gofumpt foo.go cmp stdout foo.go.orig # We can give an explicitly newer version. gofumpt -lang=1.13 foo.go cmp stdout foo.go.golden # If we bump the version in go.mod, it should be picked up. exec go mod edit -go=1.13 gofumpt foo.go cmp stdout foo.go.golden gofumpt -d foo.go.golden ! stdout . # We can give an explicitly older version. gofumpt -lang=v1 foo.go cmp stdout foo.go.orig -- module/go.mod -- module test go 1.12 -- module/foo.go -- package p const ( i = 0 j = 022 k = 0o_7_5_5 l = 1022 ) -- module/foo.go.golden -- package p const ( i = 0 j = 0o22 k = 0o_7_5_5 l = 1022 ) golang-mvdan-gofumpt-0.2.0/testdata/scripts/short-case.txt000066400000000000000000000022561414300765000236600ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p func f(r rune) { switch r { case 'a', 'b', 'c': case 'd', 'e', 'f': case 'a', 'b', 'c': case 'v', 'e', 'r', 'y', 'l', 'o', 'n', 'g', 'l', 'i', 's', 't', '.', '.', '.': // before case 'a', 'b': // inline // after case 'a', // middle 'b': case 'a', 'b', 'c', 'd', 'e', 'f', 'g': // very very long inline comment at the end case 'a', 'b', 'c', 'd': // short comment } { { { { { switch r { case 'i', 'n', 'd', 'e', 'n', 't', 'e', 'd': } } } } } } } -- foo.go.golden -- package p func f(r rune) { switch r { case 'a', 'b', 'c': case 'd', 'e', 'f': case 'a', 'b', 'c': case 'v', 'e', 'r', 'y', 'l', 'o', 'n', 'g', 'l', 'i', 's', 't', '.', '.', '.': // before case 'a', 'b': // inline // after case 'a', // middle 'b': case 'a', 'b', 'c', 'd', 'e', 'f', 'g': // very very long inline comment at the end case 'a', 'b', 'c', 'd': // short comment } { { { { { switch r { case 'i', 'n', 'd', 'e', 'n', 't', 'e', 'd': } } } } } } } golang-mvdan-gofumpt-0.2.0/testdata/scripts/short-decl.txt000066400000000000000000000007501414300765000236510ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p var global = x func f() { var local = x var local2, local3 = x, y var onlyType T var typeAndVar T = x var _ = unused var ( aligned = x vars = y here = y ) } -- foo.go.golden -- package p var global = x func f() { local := x local2, local3 := x, y var onlyType T var typeAndVar T = x _ = unused var ( aligned = x vars = y here = y ) } golang-mvdan-gofumpt-0.2.0/testdata/scripts/simplify.txt000066400000000000000000000005211414300765000234350ustar00rootroot00000000000000# gofumpt changes -s to default to true. gofumpt foo.go cmp stdout foo.go.golden -- foo.go -- package p const () const ( // Comment ) type () type ( // Comment ) var () var ( // Comment ) var _ = [][]int{[]int{1}} -- foo.go.golden -- package p const ( // Comment ) type ( // Comment ) var ( // Comment ) var _ = [][]int{{1}} golang-mvdan-gofumpt-0.2.0/testdata/scripts/std-imports.txt000066400000000000000000000034561414300765000241000ustar00rootroot00000000000000gofumpt -w foo.go cmp foo.go foo.go.golden gofumpt -d foo.go.golden ! stdout . -- foo.go -- package p import ( "io" "io/ioutil" // if the user keeps them in the top group, obey that _ "io/ioutil" _ "image/png" "bufio" // the above is for a side effect; this one has a comment ) import ( "os" "foo.local/one" bytes_ "bytes" "io" ) import ( "foo.local/two" "fmt" ) // If they are in order, but with extra newlines, join them. import ( "more" "std" ) // We need to split std vs non-std in this case too. import ( "foo.local/three" math "math" ) import ( "x" // don't mess up this comment "y" // or many // of them "z" ) // This used to crash gofumpt, as there's no space to insert an extra newline. import ( "std" "non.std/pkg" ) // All of the extra imports below are known to not belong in std. // For example/ and test/, see https://golang.org/issue/37641. import ( "io" "example/foo" "internal/bar" "test/baz" ) -- foo.go.golden -- package p import ( "io" "io/ioutil" // if the user keeps them in the top group, obey that _ "io/ioutil" _ "image/png" "bufio" // the above is for a side effect; this one has a comment ) import ( "io" "os" "foo.local/one" bytes_ "bytes" ) import ( "fmt" "foo.local/two" ) // If they are in order, but with extra newlines, join them. import ( "more" "std" ) // We need to split std vs non-std in this case too. import ( math "math" "foo.local/three" ) import ( "x" // don't mess up this comment "y" // or many // of them "z" ) // This used to crash gofumpt, as there's no space to insert an extra newline. import ( "std" "non.std/pkg" ) // All of the extra imports below are known to not belong in std. // For example/ and test/, see https://golang.org/issue/37641. import ( "io" "example/foo" "internal/bar" "test/baz" ) golang-mvdan-gofumpt-0.2.0/testdata/scripts/typeparams.txt000066400000000000000000000014521414300765000237720ustar00rootroot00000000000000[go1.18] gofumpt foo.go [!go1.18] ! gofumpt foo.go [go1.18] cmp stdout foo.go.golden [!go1.18] stderr 'foo.go:.*expected' -- go.mod -- module test go 1.18 -- foo.go -- package p func Foo[A, B any](x A, y B) {} type Vector[T any] []T var v Vector[int ] type PredeclaredSignedInteger interface { int | int8 | int16 | int32 | int64 } type StringableSignedInteger interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 String() string } func Caller() { Foo[int,int](1,2) } -- foo.go.golden -- package p func Foo[A, B any](x A, y B) {} type Vector[T any] []T var v Vector[int] type PredeclaredSignedInteger interface { int | int8 | int16 | int32 | int64 } type StringableSignedInteger interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 String() string } func Caller() { Foo[int, int](1, 2) }