From 99fd637b50cebd4dcdb030a8ea03de9fd861d074 Mon Sep 17 00:00:00 2001 From: Doria Keung Date: Mon, 6 Jul 2026 15:21:49 -0400 Subject: [PATCH 1/2] Fix legacy formatter behaviour for bodies with no comments or decls --- experimental/ast/printer/decl.go | 18 ++++++++++-------- experimental/ast/printer/format.go | 6 +++--- .../ast/printer/testdata/format/basic.proto | 5 +++++ .../testdata/format/basic.proto.default.txt | 3 +++ .../testdata/format/basic.proto.legacy.txt | 2 ++ 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/experimental/ast/printer/decl.go b/experimental/ast/printer/decl.go index eda4d10f..9970e8ab 100644 --- a/experimental/ast/printer/decl.go +++ b/experimental/ast/printer/decl.go @@ -338,16 +338,18 @@ 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) - } + 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 {} From a695d77b47d67ff4b3ec96622ec376f542a0bb98 Mon Sep 17 00:00:00 2001 From: Doria Keung Date: Mon, 6 Jul 2026 15:42:35 -0400 Subject: [PATCH 2/2] Address comment --- experimental/ast/printer/decl.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/experimental/ast/printer/decl.go b/experimental/ast/printer/decl.go index 9970e8ab..cb7b03b7 100644 --- a/experimental/ast/printer/decl.go +++ b/experimental/ast/printer/decl.go @@ -340,6 +340,8 @@ func (p *printer) printBody(body ast.DeclBody) { p.scopeHasAttachedComments(body.Braces()) if !forceBroken && !p.bodyShouldBreak(openTok, closeTok, body.Decls().Len()) { decls := body.Decls() + // 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) {