[ty] Adjust start of block folding range to preserve visible header for character-precise LSP clients. (#24917)
<!--
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
<!-- What's the purpose of the change? What does it do, and why? -->
As a step towards https://github.com/astral-sh/ty/issues/3320, this
adjusts the starting character of block[^1] folding ranges emitted by
the language server such that they begin after the colon that delimits
the end of a block header (rather than at the start of the block
header). That lets us preserve a visible block header in
character-precise LSP clients like Zed.
As a small added bonus, this closes
https://github.com/astral-sh/ty/issues/3391.
## Approach
- I expect that it will be helpful to review this diff commit-by-commit.
- I added two helpers, `add_block_body_range` and
`add_block_body_range_after_keyword`, that rescan tokens as necessary to
determine the header-preserving start location of the block body fold. I
then used those helpers to emit folds for all block types.
- Folding for multi-line block headers is required for
https://github.com/astral-sh/ty/issues/3320 but intentionally deferred
to a follow-up.
[^1]: Where a block is, roughly, an indented Python scope. Here are some
examples (where the ellipsis represents the fold region): `def foo():
...`, `class Foo(): ...`, `if foo: ...`, `with foo: ...`, `finally:
...`.
## Test Plan
Please see added and updated snapshot tests.
<!-- How was it tested? -->