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.

Comment From: qfornaguera

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
}

Comment From: alexec

This is just what I want.

Comment From: gopherbot

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

Comment From: lsytj0413

any update on this?

Comment From: abc-valera

This would be very helpful!