Skip to content

[ty] Fix folding ranges for notebooks#23830

Merged
MichaReiser merged 1 commit intomainfrom
micha/fix-notebook-folding-ranges
Mar 13, 2026
Merged

[ty] Fix folding ranges for notebooks#23830
MichaReiser merged 1 commit intomainfrom
micha/fix-notebook-folding-ranges

Conversation

@MichaReiser
Copy link
Member

@MichaReiser MichaReiser commented Mar 9, 2026

Summary

Fixes a bug where folding ranges returned the folding ranges for the entire file
instead of the current cell only.

folding_ranges uses to_local_range here:

let results: Vec<_> = folding_ranges(db, file)
.into_iter()
.filter_map(|folding_range| {
let lsp_range = folding_range
.range
.to_lsp_range(db, file, snapshot.encoding())?;
let kind = folding_range.kind.map(|k| match k {
ty_ide::FoldingRangeKind::Comment => FoldingRangeKind::Comment,
ty_ide::FoldingRangeKind::Imports => FoldingRangeKind::Imports,
ty_ide::FoldingRangeKind::Region => FoldingRangeKind::Region,
});
Some(FoldingRange {
start_line: lsp_range.local_range().start.line,
start_character: Some(lsp_range.local_range().start.character),
end_line: lsp_range.local_range().end.line,
end_character: Some(lsp_range.local_range().end.character),
kind,
collapsed_text: None,
})
})
.collect();

It's only correct to use to_local_range if the ranges are all guaranteed to belong to the same text or cell document. This isn't the case here because folding_ranges returns all folding ranges for the entire notebook and not just the requested cell. This is incorrect.

The fix here is to limit folding_ranges to the cell range if the document is a notebook cell, similar to what we do for semantic tokens:

// If this document is a notebook cell, limit the highlighting range
// to the lines of this cell (instead of highlighting the entire notebook).
// Not only avoids this unnecessary work, this is also required
// because all ranges in the response must be within this **this document**.
let mut cell_range = None;
if snapshot.document().is_cell()
&& let Some(notebook_document) = db.notebook_document(file)
&& let Some(notebook) = source_text(db, file).as_notebook()
{
let cell_index = notebook_document.cell_index_by_uri(snapshot.url());
cell_range = cell_index.and_then(|index| notebook.cell_range(index));
}
let lsp_tokens = generate_semantic_tokens(
db,
file,
cell_range,
snapshot.encoding(),
snapshot
.resolved_client_capabilities()
.supports_multiline_semantic_tokens(),
);

Closes astral-sh/ty#2988

Test Plan

Added E2E test

@MichaReiser MichaReiser requested a review from carljm as a code owner March 9, 2026 08:53
@MichaReiser MichaReiser added the bug Something isn't working label Mar 9, 2026
@MichaReiser MichaReiser requested a review from sharkdp as a code owner March 9, 2026 08:53
@MichaReiser MichaReiser added server Related to the LSP server ty Multi-file analysis & type inference labels Mar 9, 2026
@astral-sh-bot astral-sh-bot bot requested a review from dhruvmanila March 9, 2026 08:53
@MichaReiser MichaReiser assigned BurntSushi and unassigned dhruvmanila Mar 9, 2026
@AlexWaygood AlexWaygood added the notebook Related to (Jupyter) notebooks label Mar 9, 2026
@MichaReiser MichaReiser merged commit f0d4bb4 into main Mar 13, 2026
49 checks passed
@MichaReiser MichaReiser deleted the micha/fix-notebook-folding-ranges branch March 13, 2026 09:21
carljm added a commit that referenced this pull request Mar 13, 2026
* main: (94 commits)
  Fix shell injection via `shell=True` in subprocess calls (#23894)
  [ty] Refactor `relation.rs` to store state on a struct rather than passing around 7 arguments every time we recurse (#23837)
  Don't return code actions for non-Python documents (#23905)
  [ty] Make the default database truly statically infallible (#23929)
  [ty] Add `Download` button to ty playground which creates a zip export (#23478)
  [ty] Respect `kw_only` overwrites in dataclasses (#23930)
  [ty] Clarify in diagnostics that `from __future__ import annotations` only stringifies type annotations (#23928)
  [ty]  Add a `Copy Markdown` button to playground (#23002)
  [ty] Fix folding range classification of lines starting with `#` (#23831)
  [ty] Fix folding ranges for notebooks (#23830)
  [ty] fix too-many-cycle panics when inferring literal type loop variables (#23875)
  Add `RegularCallableTypeOf` and `into_regular_callable` in `ty_extensions` (#23909)
  [ty] treat properties as full structural types (#23925)
  [ty] Avoid duplicated work during multi-inference (#23923)
  [ty]: make `possibly-missing-attribute` ignored by default
  [ty]: split out `possibly-missing-submodule` from `possibly-missing-attribute`
  Update astral-sh/setup-uv action to v7.5.0 (#23922)
  [ty] Show truthiness in ConstraintSet display and simplify falsy error message (#23913)
  Bump 0.15.6 (#23919)
  [ty] Narrow type context during collection literal inference (#23844)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working notebook Related to (Jupyter) notebooks server Related to the LSP server ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Weird code folding in Jupyter notebooks

5 participants