fix(indent): don't pull deeper indent onto blank line above unindented sibling - #1922
Merged
Conversation
sinelaw
force-pushed
the
claude/wonderful-archimedes-0e5SR
branch
from
June 3, 2026 19:05
654d9df to
d787128
Compare
sinelaw
force-pushed
the
claude/wonderful-archimedes-0e5SR
branch
3 times, most recently
from
June 23, 2026 04:52
4739853 to
46ec8c3
Compare
…d sibling
Pressing Enter on an empty line that sits between a deeply-indented block
above and an unindented line below was inserting indentation matching the
previous block, displacing the new cursor to a column the user had already
clearly exited. The empty-line heuristic in `calculate_indent_pattern`
looked only backwards for a reference line; if that reference happened to
be inside a nested block while the *next* non-empty line was at column 0,
the new line still inherited the deeper indent.
Add a forward look-ahead: if the next non-empty line is at a strictly
smaller indent and does not start with a closing delimiter (`}`, `]`,
`)`), use that smaller indent instead. Closing delimiters are excluded so
that the existing "cursor on blank line inside a still-open block" case
(e.g. `fn main() { … <empty> … }`) still indents into the body.
Reported as a corner case on issue #1425 after the original fix shipped.
…or's own indent
Address review feedback on the previous fix. The empty-line branch in
`calculate_indent_pattern` previously combined two heuristics — look back
for a "reference" indent from the previous non-empty line, then
look ahead for a less-indented sibling (excluding hardcoded `}`/`]`/`)`
closers) — that fought each other. Both guess what the user "really
meant" from context they have not actually typed on the cursor's line,
and the C-family-only closer list is poorly motivated for plain text
and for languages with non-bracket closers (Lua `end`, Bash `fi`,
HTML `</tag>`, etc.).
Replace both with the simpler rule: when the cursor is on an empty or
whitespace-only line, the new line copies that line's own indent. For
a truly empty line that is 0; for a line with N columns of leading
whitespace it is N.
This removes the C-family token list entirely and is fully
language-agnostic. The well-formed "still inside an open block" case
remains handled upstream by tree-sitter; for incomplete syntax the user
can press Tab when they want indentation, instead of the editor
guessing wrong half the time.
Two existing assertions that pinned the old guess (`fn main() { let x =
1;\n\n}` and the same with no closing brace) are updated to reflect the
new semantic and renamed to describe what they actually pin down.
sinelaw
force-pushed
the
claude/wonderful-archimedes-0e5SR
branch
from
July 17, 2026 11:53
46ec8c3 to
6bb700d
Compare
…use cursor's own indent" This reverts commit 6bb700d. The refactor went beyond the targeted #1425 corner-case fix and changed the empty-line indent contract: it expected Enter on an empty line inside a function body to produce indent 0, while the tree-sitter indent path (by design, per the refactor's own comment) still returns the body indent. That contradiction broke the refactor's own unit tests (test_indent_on_empty_line_does_not_pull_block_indent, test_indent_after_empty_line_incomplete_syntax_does_not_guess_body) and the pre-existing e2e test test_indent_after_empty_line_in_function_body on all CI platforms. Keeping the first commit's forward look-ahead fix, which addresses the reported corner case without changing the inside-a-block behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSg2p6UXLuJwXSs79Ko2Ma
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the corner case reported on issue #1425 after the original fix shipped.
Pressing Enter on an empty line that sits between a deeply-indented block above and an unindented line below was auto-indenting the new line to the previous block's indent — even though the very next non-empty line is already at column 0:
Before this PR the new line was indented to column 8 (matching
line4); after this PR it stays at column 0.Why the previous fix didn't catch this
The original #1425 fix (
indent_for_cursor_in_leading_ws) only fires when the cursor is on a non-empty line whose leading whitespace would otherwise be displaced. On a fully empty line the heuristic incalculate_indent_patternlooked only backwards for a reference line and copied its indent (or +tab_size if the previous line ended with{/[/(/:). It never consulted what comes after the cursor, so the deeper context above always won.Fix
Add a forward look-ahead in the empty-line branch of
calculate_indent_pattern: find the first non-empty line at or after the cursor and, if its first non-whitespace byte is not a closing delimiter (},],)) and its indent is strictly smaller than the previous-line reference, use the smaller indent instead.Closing delimiters are excluded so that the existing
test_indent_on_empty_line_uses_referencecase still indents into the function body:Test plan
test_enter_on_blank_line_above_unindented_uses_following_indentfails (returns 8) before the fix, passes afterprimitives::indenttests still pass — includingtest_indent_on_empty_line_uses_reference(the inside-a-block case),test_indent_after_empty_line_incomplete_syntax, and the original Auto Indent is too diligent #1425 regressiontest_enter_at_start_of_unindented_line_after_blank_does_not_indentcargo test -p fresh-editor --libpasses (2428 tests)cargo fmt --all -- --checkcleancargo clippy -p fresh-editor --lib --no-depsintroduces no new warnings onindent.rsfreshbinary:fn main() { let x = 1; <empty> }: pressing Enter on the empty line still indents to Col 5 (4-space body indent) ✓https://claude.ai/code/session_01Rf7NU26qRrBim3DPt12eqw
Generated by Claude Code