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!

Comment From: connorszczepaniak-wk

If goimports supported this, it would allow us to use it instead of https://github.com/rinchsan/gosimports (which is a fork intended to solve exactly this problem). gosimports does the job, but it'd be preferable to use goimports since more people are likely to have it installed vs. gosimports.

Comment From: connorszczepaniak-wk

@win5do what's the status of your CL? Wondering what else needs to be done to get this landed -- I would also be happy to help out if necessary!

Comment From: win5do

@connorszczepaniak-wk

CL is on hold; its implementation seems too inelegant. You could try it out.

Comment From: gopherbot

Change https://go.dev/cl/719140 mentions this issue: goimports: add regroup option to produce at most 3 import groups