Skip to content

Commit 1fa67dc

Browse files
committed
Fix conditional expression keyword detection to avoid breaking after
`if`/`else` Fix #291
1 parent c3c27e2 commit 1fa67dc

4 files changed

Lines changed: 64 additions & 40 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This file documents the changes made to the formatter with each release.
99
- Make sure to keep tool at the top of the script, above class_name and extends (#285)
1010
- Fixed generic type parameters breaking across lines (#283)
1111
- Fixed is not being lost in a parenthesized expression (#284)
12+
- Fixed conditional expression keyword detection to avoid breaking after `if`/`else` keywords (#291)
1213
- Godot addon: Fixed performance issues when typing on Steam version of Godot (#262)
1314

1415
## Release 0.22.0 (2026-07-21)

src/formatter.rs

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,48 +2056,59 @@ fn process_conditional_expression(
20562056
let group_index = begin_group(render_elements);
20572057
render_elements.push(RenderElement::ForceBreakingParent);
20582058

2059-
if let Some(value) = node.child(0) {
2060-
process_node(input, value, render_elements);
2061-
}
2062-
2063-
render_elements.push(RenderElement::SoftLine);
2064-
let if_space_index = render_elements.len() + 1;
2065-
render_elements.push(RenderElement::Branch {
2066-
if_single_line: Some(RangeRenderElement {
2067-
start: if_space_index,
2068-
end: if_space_index + 1,
2069-
}),
2070-
if_multiline: None,
2071-
});
2072-
render_elements.push(RenderElement::Space);
2073-
2074-
if let Some(if_kw) = node.child(1) {
2075-
process_node(input, if_kw, render_elements);
2076-
}
2077-
2078-
if let Some(cond) = node.child(2) {
2079-
render_elements.push(RenderElement::Space);
2080-
process_node(input, cond, render_elements);
2081-
}
2082-
2083-
render_elements.push(RenderElement::SoftLine);
2084-
let else_space_index = render_elements.len() + 1;
2085-
render_elements.push(RenderElement::Branch {
2086-
if_single_line: Some(RangeRenderElement {
2087-
start: else_space_index,
2088-
end: else_space_index + 1,
2089-
}),
2090-
if_multiline: None,
2091-
});
2092-
render_elements.push(RenderElement::Space);
2059+
// The conditional keywords or things like not are anonymous children in the
2060+
// syntax tree, so we have to walk every child in source order to find
2061+
// where's what.
2062+
let mut previous_child: Option<tree_sitter::Node> = None;
2063+
let mut child_index = 0;
2064+
while child_index < child_count {
2065+
let Some(child) = node.child(child_index as u32) else {
2066+
child_index += 1;
2067+
continue;
2068+
};
2069+
let child_kind = GDScriptNodeKind::get_kind_from_ast_node(child);
2070+
let is_current_conditional_keyword = child.kind() == "if" || child.kind() == "else";
2071+
2072+
if let Some(previous) = previous_child {
2073+
let previous_kind = GDScriptNodeKind::get_kind_from_ast_node(previous);
2074+
if is_current_conditional_keyword
2075+
&& previous_kind != GDScriptNodeKind::LineContinuation
2076+
&& previous_kind != GDScriptNodeKind::Comment
2077+
{
2078+
render_elements.push(RenderElement::SoftLine);
2079+
} else {
2080+
process_separator_between_sibling_nodes(
2081+
GDScriptNodeKind::Condition,
2082+
&previous,
2083+
&child,
2084+
render_elements,
2085+
);
2086+
}
20932087

2094-
if let Some(else_kw) = node.child(3) {
2095-
process_node(input, else_kw, render_elements);
2096-
}
2088+
if previous_kind == GDScriptNodeKind::LineContinuation {
2089+
let indent_index = begin_indent(render_elements, input.continuation_indent_level);
2090+
process_node(input, child, render_elements);
2091+
finish_indent(render_elements, indent_index);
2092+
previous_child = Some(child);
2093+
child_index += 1;
2094+
continue;
2095+
}
2096+
}
20972097

2098-
if let Some(value) = node.child(4) {
2099-
render_elements.push(RenderElement::Space);
2100-
process_node(input, value, render_elements);
2098+
if child_kind == GDScriptNodeKind::LineContinuation {
2099+
let start_byte = child.start_byte();
2100+
render_elements.push(RenderElement::Text {
2101+
range: RangeSourceBytes {
2102+
start_byte,
2103+
end_byte: start_byte + 1,
2104+
},
2105+
});
2106+
render_elements.push(RenderElement::HardLine);
2107+
} else {
2108+
process_node(input, child, render_elements);
2109+
}
2110+
previous_child = Some(child);
2111+
child_index += 1;
21012112
}
21022113

21032114
finish_group(render_elements, group_index);

tests/expected/line_continuation_indent.gd

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,9 @@ func _get_message() -> String:
3737
var greeting: String = "\
3838
Hello world"
3939
return greeting
40+
41+
42+
# Issue #291: would lose tokens, ensure they're preserved.
43+
var test = true \
44+
if not false \
45+
else false

tests/input/line_continuation_indent.gd

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,9 @@ func _get_message() -> String:
3737
var greeting: String = "\
3838
Hello world"
3939
return greeting
40+
41+
42+
# Issue #291: would lose tokens, ensure they're preserved.
43+
var test = true \
44+
if not false \
45+
else false

0 commit comments

Comments
 (0)