diff --git a/experimental/ast/printer/decl.go b/experimental/ast/printer/decl.go index eda4d10f..cb7b03b7 100644 --- a/experimental/ast/printer/decl.go +++ b/experimental/ast/printer/decl.go @@ -338,16 +338,20 @@ func (p *printer) printBody(body ast.DeclBody) { forceBroken := triviaHasComments(trivia) || len(closeComments) > 0 || p.scopeHasAttachedComments(body.Braces()) - if !forceBroken && !p.bodyShouldBreak(openTok, closeTok) { + if !forceBroken && !p.bodyShouldBreak(openTok, closeTok, body.Decls().Len()) { decls := body.Decls() - p.withGroup(func(p *printer) { - p.withIndent(func(indented *printer) { - for i := range decls.Len() { - indented.printDecl(decls.At(i), gapSoftline) - } + // Only create the indented [dom.Group] in the case where there are decls + // to avoid an indent in the flat case with no decls. + if decls.Len() > 0 { + p.withGroup(func(p *printer) { + p.withIndent(func(indented *printer) { + for i := range decls.Len() { + indented.printDecl(decls.At(i), gapSoftline) + } + }) + p.push(tagSoftlineFlat, tagSoftbreak) }) - p.push(tagSoftlineFlat, tagSoftbreak) - }) + } p.printToken(closeTok, gapNone) return } diff --git a/experimental/ast/printer/format.go b/experimental/ast/printer/format.go index ac6b8fbf..4312da4a 100644 --- a/experimental/ast/printer/format.go +++ b/experimental/ast/printer/format.go @@ -125,7 +125,7 @@ func (p *printer) literalShouldBreak(openTok, closeTok token.Token, count int) b // decl-bearing body scope (`{ ... }` on message, enum, service, // oneof, extend, or RPC method): // -// - [LayoutStrict]: always broken. Callers handle the empty-body +// - [LayoutStrict]: always broken for >0 decls. Callers handle the empty-body // case (rendered as `{}`) before consulting this helper. // // - [LayoutDynamic]: broken if and only if source had a newline between open @@ -133,12 +133,12 @@ func (p *printer) literalShouldBreak(openTok, closeTok token.Token, count int) b // // Callers should OR the result with their own forceBroken signal // (e.g. for scope-attached comments that require expansion). -func (p *printer) bodyShouldBreak(openTok, closeTok token.Token) bool { +func (p *printer) bodyShouldBreak(openTok, closeTok token.Token, declsLen int) bool { switch p.options.Formatting.BodyLayout { case LayoutDynamic: return !sourceWasFlat(openTok, closeTok) default: // LayoutStrict - return true + return declsLen > 0 } } diff --git a/experimental/ast/printer/testdata/format/basic.proto b/experimental/ast/printer/testdata/format/basic.proto index baf22636..ee616820 100644 --- a/experimental/ast/printer/testdata/format/basic.proto +++ b/experimental/ast/printer/testdata/format/basic.proto @@ -22,3 +22,8 @@ import "acme/payment/v1/payment.proto"; /* trailing */ message Foo { /* Foo */ string name = 1; } + +message Bar { + + +} diff --git a/experimental/ast/printer/testdata/format/basic.proto.default.txt b/experimental/ast/printer/testdata/format/basic.proto.default.txt index ebd99566..e141cdec 100644 --- a/experimental/ast/printer/testdata/format/basic.proto.default.txt +++ b/experimental/ast/printer/testdata/format/basic.proto.default.txt @@ -18,3 +18,6 @@ option optimize_for = SPEED; message Foo { /* Foo */ string name = 1; } + +message Bar { +} diff --git a/experimental/ast/printer/testdata/format/basic.proto.legacy.txt b/experimental/ast/printer/testdata/format/basic.proto.legacy.txt index 5f2c3af8..77241087 100644 --- a/experimental/ast/printer/testdata/format/basic.proto.legacy.txt +++ b/experimental/ast/printer/testdata/format/basic.proto.legacy.txt @@ -18,3 +18,5 @@ option optimize_for = SPEED; message Foo { /* Foo */ string name = 1; } + +message Bar {}