Skip to content

Commit 529740e

Browse files
committed
format: align opening and closing parens in multi-line calls
In a multi-line call, if the opening paren is at the end of a line but the closing paren is not at the start of a line, or vice versa, insert a newline so they are placed consistently. Fixes #74.
1 parent a7ca065 commit 529740e

3 files changed

Lines changed: 142 additions & 0 deletions

File tree

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,36 @@ var matrix = [][]int{
182182

183183
</details>
184184

185+
**Multi-line function calls should match opening and closing parentheses**
186+
187+
<details><summary><i>Example</i></summary>
188+
189+
```go
190+
result := compute(a, b,
191+
c,
192+
)
193+
194+
result := compute(
195+
a,
196+
b,
197+
c)
198+
```
199+
200+
```go
201+
result := compute(
202+
a, b,
203+
c,
204+
)
205+
206+
result := compute(
207+
a,
208+
b,
209+
c,
210+
)
211+
```
212+
213+
</details>
214+
185215
**Empty field lists should use a single line**
186216

187217
<details><summary><i>Example</i></summary>

format/format.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -961,6 +961,32 @@ func (f *fumpter) applyPost(c *astutil.Cursor) {
961961
f.addNewline(elem1.End())
962962
}
963963
}
964+
965+
// In a multi-line call, the opening parenthesis at the end of a line
966+
// should be matched by a closing parenthesis at the start of a line,
967+
// and vice versa. See https://github.com/mvdan/gofumpt/issues/74.
968+
case *ast.CallExpr:
969+
if len(node.Args) == 0 {
970+
break
971+
}
972+
openLine := f.Line(node.Lparen)
973+
closeLine := f.Line(node.Rparen)
974+
if openLine == closeLine {
975+
break
976+
}
977+
firstLine := f.Line(node.Args[0].Pos())
978+
lastEnd := node.Args[len(node.Args)-1].End()
979+
if comment := f.inlineComment(lastEnd); comment != nil {
980+
lastEnd = comment.End()
981+
}
982+
lastLine := f.Line(lastEnd)
983+
openAtEOL := openLine != firstLine
984+
closeAtBOL := closeLine != lastLine
985+
if openAtEOL && !closeAtBOL {
986+
f.addNewline(node.Rparen)
987+
} else if closeAtBOL && !openAtEOL {
988+
f.addNewline(node.Lparen + 1)
989+
}
964990
}
965991
}
966992

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
exec gofumpt -w foo.go
2+
cmp foo.go foo.go.golden
3+
4+
exec gofumpt -d foo.go.golden
5+
! stdout .
6+
7+
-- foo.go --
8+
package p
9+
10+
func _() {
11+
// already consistent
12+
_ = call(a, b, c)
13+
14+
_ = call(
15+
a,
16+
b,
17+
c,
18+
)
19+
20+
// closing paren at start of line, opening paren not at end of line:
21+
// move opening paren so both are consistent.
22+
_ = call(a, b,
23+
c,
24+
)
25+
26+
// opening paren at end of line, closing paren not at start of line:
27+
// move closing paren so both are consistent.
28+
_ = call(
29+
a,
30+
b,
31+
c)
32+
33+
// inline comment after the last argument should still cause the
34+
// closing paren to be moved to its own line.
35+
_ = call(
36+
a,
37+
b,
38+
c) // trailing
39+
40+
// nested calls
41+
_ = outer(inner(
42+
a,
43+
b))
44+
}
45+
-- foo.go.golden --
46+
package p
47+
48+
func _() {
49+
// already consistent
50+
_ = call(a, b, c)
51+
52+
_ = call(
53+
a,
54+
b,
55+
c,
56+
)
57+
58+
// closing paren at start of line, opening paren not at end of line:
59+
// move opening paren so both are consistent.
60+
_ = call(
61+
a, b,
62+
c,
63+
)
64+
65+
// opening paren at end of line, closing paren not at start of line:
66+
// move closing paren so both are consistent.
67+
_ = call(
68+
a,
69+
b,
70+
c,
71+
)
72+
73+
// inline comment after the last argument should still cause the
74+
// closing paren to be moved to its own line.
75+
_ = call(
76+
a,
77+
b,
78+
c,
79+
) // trailing
80+
81+
// nested calls
82+
_ = outer(inner(
83+
a,
84+
b,
85+
))
86+
}

0 commit comments

Comments
 (0)