Respect newlines in if/else and let expressions (#1259)

Change the formatter to prevent multiline if/else and let expressions
from collapsing into a single line.
This commit is contained in:
Daniel Chao
2025-10-28 11:26:31 -07:00
committed by GitHub
parent fbcf83aa76
commit 825fcf5d1d
5 changed files with 86 additions and 5 deletions

View File

@@ -872,11 +872,14 @@ internal class Builder(sourceText: String, private val grammarVersion: GrammarVe
}
private fun formatIf(node: Node): FormatNode {
val separator = if (node.isMultiline()) forceLine() else spaceOrLine()
val nodes =
formatGeneric(node.children) { _, next ->
if (next.type == NodeType.IF_ELSE_EXPR && next.children[0].type == NodeType.IF_EXPR) {
Space
} else spaceOrLine()
// produce `else if` in the case of nested if.
// note: don't need to handle if `next.children[0]` is an affix because that can't be
// emitted as `else if` anyway.
if (next.type == NodeType.IF_ELSE_EXPR && next.children[0].type == NodeType.IF_EXPR) Space
else separator
}
return Group(newId(), nodes)
}
@@ -968,10 +971,11 @@ internal class Builder(sourceText: String, private val grammarVersion: GrammarVe
}
private fun formatLetExpr(node: Node): FormatNode {
val separator = if (node.isMultiline()) forceLine() else spaceOrLine()
val nodes =
formatGenericWithGen(
node.children,
{ _, next -> if (next.type == NodeType.LET_PARAMETER_DEFINITION) Space else spaceOrLine() },
{ _, next -> if (next.type == NodeType.LET_PARAMETER_DEFINITION) Space else separator },
) { node, next ->
if (next == null) {
if (node.type == NodeType.LET_EXPR) {
@@ -1323,7 +1327,7 @@ internal class Builder(sourceText: String, private val grammarVersion: GrammarVe
}
private fun hasTrailingAffix(node: Node, next: Node): Boolean {
if (node.span.lineEnd < next.span.lineBegin) return false
if (node.isMultiline()) return false
var n: Node? = next
while (n != null) {
if (n.type.isAffix && node.span.lineEnd == n.span.lineBegin) return true
@@ -1450,6 +1454,8 @@ internal class Builder(sourceText: String, private val grammarVersion: GrammarVe
// returns true if this node is not an affix or terminal
private fun Node.isProper(): Boolean = !type.isAffix && type != NodeType.TERMINAL
private fun Node.isMultiline(): Boolean = span.lineBegin < span.lineEnd
private inline fun <T> List<T>.splitOn(pred: (T) -> Boolean): Pair<List<T>, List<T>> {
val index = indexOfFirst { pred(it) }
return if (index == -1) {

View File

@@ -5,3 +5,29 @@ foo =
else
if (someAnotherCondition) 30000
else 4
foo2 = if (bar) 1 else 2
// respect newlines in if/else if they exist.
// if anything of these wrap, everything wraps.
foo3 =
if (bar)
1 else 2
foo4 =
if (bar) 1 else
2
foo5 =
if (bar) 1
else 2
foo6 =
if (bar)
1
else
2
foo7 =
if /* some comment */ (bar) 1
else 2

View File

@@ -15,3 +15,11 @@ qux = let ( // some comment
bar = 5
)
bar
quzzy =
let (baz = 1) baz + 1
// respect newlines in lets
quzzzy =
let (baz = 1)
baz + 1

View File

@@ -7,3 +7,37 @@ foo =
30000
else
4
foo2 = if (bar) 1 else 2
// respect newlines in if/else if they exist.
// if anything of these wrap, everything wraps.
foo3 =
if (bar)
1
else
2
foo4 =
if (bar)
1
else
2
foo5 =
if (bar)
1
else
2
foo6 =
if (bar)
1
else
2
foo7 =
if /* some comment */ (bar)
1
else
2

View File

@@ -25,3 +25,10 @@ qux =
bar = 5
)
bar
quzzy = let (baz = 1) baz + 1
// respect newlines in lets
quzzzy =
let (baz = 1)
baz + 1