Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: x/tools/cmd/goimports: add flag to remove blank lines in import for regrouping during formatting #64271

Open
win5do opened this issue Nov 20, 2023 · 3 comments
Labels
Milestone

Comments

@win5do
Copy link

win5do commented Nov 20, 2023

current

The goimports will retain blank lines and multiple groups will exist after formatting.

testdata in.go:

import (
	"fmt"


	"github.com/foo/a"
	"github.com/foo/b"

	"go.pkg.com/bar/x"
	"go.pkg.com/bar/y"
	"context"


	"github.com/foo/c"
	"go.pkg.com/bar/z"
)

goimports -local go.pkg.com in.go output:

package foo

import (
        "fmt"

        "github.com/foo/a"
        "github.com/foo/b"

        "context"

        "go.pkg.com/bar/x"
        "go.pkg.com/bar/y"

        "github.com/foo/c"

        "go.pkg.com/bar/z"
)

expect

Would like a tool to automate the removal of blank lines and regrouping.

Add a -r flag, goimports -r -local go.pkg.com in.go output:

package foo

import (
        "context"
        "fmt"

        "github.com/foo/a"
        "github.com/foo/b"
        "github.com/foo/c"

        "go.pkg.com/bar/x"
        "go.pkg.com/bar/y"
        "go.pkg.com/bar/z"
)

implement

It's easy to implement, here's the pseudo-code:

// add flag
regroup = flag.Bool("r", false, "remove blank line and regroup imports")


func processFile() {
    if *regroup {
        src = removeBlankLineInImport(src)
    }

    // origin imports.Process
    res, err := imports.Process(target, src, opt)
}

func removeBlankLineInImport(src []byte) []byte {
    // 1. parset AST
    // 2. find first import block start and end line
    // 3. rewrite src, remove blank line in import block
}

No breaking changes, and even regrouping keeps compatibility with the original goimports rules.

We forked goimports in our internal project and added this feature so that if the proposal is accepted, I can submit a PR.

@gopherbot gopherbot added this to the Proposal milestone Nov 20, 2023
@ianlancetaylor ianlancetaylor moved this to Incoming in Proposals Dec 2, 2023
@qfornaguera
Copy link

Yes pls, EZ 🍬

var (
	// main operation modes
	list   = flag.Bool("l", false, "list files whose formatting differs from goimport'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")
	srcdir = flag.String("srcdir", "", "choose imports as if source code is from `dir`. When operating on a single file, dir may instead be the complete file name.")
	clean  = flag.Bool("c", false, "previously cleans imports block to a initial state before formatting (removes all blank line-breaks)")

	verbose bool // verbose logging

	cpuProfile     = flag.String("cpuprofile", "", "CPU profile output")
	memProfile     = flag.String("memprofile", "", "memory profile output")
	memProfileRate = flag.Int("memrate", 0, "if > 0, sets runtime.MemProfileRate")

	options = &imports.Options{
		TabWidth:  8,
		TabIndent: true,
		Comments:  true,
		Fragment:  true,
		Env: &imports.ProcessEnv{
			GocmdRunner: &gocommand.Runner{},
		},
	}
	exitCode = 0
)
func processFile(filename string, in io.Reader, out io.Writer, argType argumentType) error {
	opt := options
	if argType == fromStdin {
		nopt := *options
		nopt.Fragment = true
		opt = &nopt
	}

	if in == nil {
		f, err := os.Open(filename)
		if err != nil {
			return err
		}
		defer f.Close()
		in = f
	}

	src, err := io.ReadAll(in)
	if err != nil {
		return err
	}

	if *clean {
		src = cleanBlanks(src)
	}
func cleanBlanks(src []byte) []byte {
	begin := bytes.Index(src, []byte("import ("))
	noImportBlock := begin == -1
	if noImportBlock {
		return src
	}

	// finding imports block closure
	end := begin + bytes.Index(src[begin:], []byte(")"))
	cleaned := bytes.ReplaceAll(src[begin:end], []byte("\n\n"), []byte("\n"))
	src = bytes.Replace(src, src[begin:end], cleaned, 1)
	return src
}

@alexec
Copy link

alexec commented Jan 9, 2025

This is just what I want.

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/641995 mentions this issue: cmd/goimports: add regroup flag support regroup imports

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Incoming
Development

No branches or pull requests

4 participants