diff --git a/syntax/printer.go b/syntax/printer.go index 7dc183a02..17a664d30 100644 --- a/syntax/printer.go +++ b/syntax/printer.go @@ -1079,11 +1079,22 @@ func (p *Printer) command(cmd Command, redirs []*Redirect) (startRedirs int) { p.ifClause(x, false) case *Subshell: p.WriteByte('(') - if len(x.Stmts) > 0 && startsWithLparen(x.Stmts[0]) { + stmts := x.Stmts + if len(stmts) > 0 && startsWithLparen(stmts[0]) { p.wantSpace = spaceRequired + // Add a space between nested parentheses if we're printing them in a single line, + // to avoid the ambiguity between `((` and `( (`. + if (x.Lparen.Line() != stmts[0].Pos().Line() || len(stmts) > 1) && !p.singleLine { + p.wantSpace = spaceNotRequired + + if p.minify { + p.mustNewline = true + } + } } else { p.wantSpace = spaceNotRequired } + p.spacePad(stmtsPos(x.Stmts, x.Last)) p.nestedStmts(x.Stmts, x.Last, x.Rparen) p.wantSpace = spaceNotRequired @@ -1338,7 +1349,7 @@ func (p *Printer) stmtList(stmts []*Stmt, last []Comment) { // statement. p.comments(c) } - if !p.minify || p.wantSpace == spaceRequired { + if p.mustNewline || !p.minify || p.wantSpace == spaceRequired { p.newlines(pos) } p.line = pos.Line() diff --git a/syntax/printer_test.go b/syntax/printer_test.go index 59483f689..30607cd8b 100644 --- a/syntax/printer_test.go +++ b/syntax/printer_test.go @@ -616,6 +616,28 @@ var printTests = []printCase{ "`declare`", "$(declare)", }, + { + "(\n(foo >redir))", + "(\n\t(foo >redir)\n)", + }, + { + "( (foo) )", + "( (foo))", + }, + { + "( (foo); bar )", + "(\n\t(foo)\n\tbar\n)", + }, + { + "( ((foo++)) )", + "( ((foo++)))", + }, + { + "( ((foo++)); bar )", + "(\n\t((foo++))\n\tbar\n)", + }, + samePrint("(\n\t((foo++))\n)"), + samePrint("(foo && bar)"), } func TestPrintWeirdFormat(t *testing.T) {