Latest Results
[ty] Emit folding ranges from the language server for multi-line block headers. (#24978)
<!--
Thank you for contributing to Ruff/ty! To help us out with reviewing,
please consider the following:
- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title? (Please prefix
with `[ty]` for ty pull
requests.)
- Does this pull request include references to any relevant issues?
- Does this PR follow our AI policy
(https://github.com/astral-sh/.github/blob/main/AI_POLICY.md)?
-->
## Summary
As the final step of https://github.com/astral-sh/ty/issues/3320, this
builds on https://github.com/astral-sh/ruff/pull/24917 to emit folding
ranges for multi-line block headers in addition the the
header-preserving block body ranges that we emitted previously.
The result is that a method like this one:
```py
def foo(
x,
y,
):
z = x + y
return z
```
Will no longer fold like:
```py
def foo(
x,
y,
):
...
```
But will instead fold like:
```py
def foo(...): ...
```
<!-- What's the purpose of the change? What does it do, and why? -->
Closes https://github.com/astral-sh/ty/issues/3320.
## Approach
- I suspect it will be helpful to review this diff commit-by-commit.
- I added a new `add_block_header_ranges` helper which emits folding
ranges that are contained within a block header. That method, and the
previous `add_block_body_range` method, are now both called by a method
called `add_block_ranges` which we use at most callsites[^1].
- I also added an `add_expression_range` helper which ensures that the
normal folding ranges that we emit for expressions (e.g. multi-line
lists) do not duplicate or overlap with the new folds that we emit for
block headers.
- Note that we will now fold expressions within block headers slightly
differently than we do outside them. Within a block header, an the
delimiters of an expression will be retained (e.g., `x = [...]`),
whereas outside a block header they will be elided (e.g., `x = ...`).
This was an intentional choice to bias in the direction that I think we
should be moving for these new folds: folds are more expressive with
delimiters than without. I plan to also adjust the folding behaviour
outside of block headers in a follow-up.
[^1]: The remaining callsites also call `add_block_header_ranges` and
`add_block_body_range`, but do so via
`add_block_body_range_after_keyword`, which does some additional token
scanning to account for block bodies that do not have a corresponding
AST node.
## Test Plan
Please see added/updated tests.
<!-- How was it tested? --> Latest Branches
0%
charlie/loop-constraints-test 0%
charlie/reachability-cache 0%
lerebear/push-pwlqvypsrllr © 2026 CodSpeed Technology