pub fn visible_source_lines(
fold_index: &FoldIndex,
scroll: u32,
height: u32,
total_lines: u32,
) -> Vec<u32>Expand description
Number of buffer lines collapsed onto the visible head row of the
closed fold (start_line, end_line) — the count both renderers show
in the ⋯ N lines fold summary. Walks forward from end_line + 1
through any sibling closed folds whose heading is itself hidden by
the region already collapsed (start < probe <= end), so overlapping
folds (e.g. (1,3)+(3,5) from foldmethod=indent) report their
combined span. Folds that merely ABUT — the next fold starts at
end + 1, the first visible line after this one — are NOT chained:
that fold has an on-screen heading and is a separate fold with its
own summary. Shared by the TUI and GPUI renderers so the count stays
identical.
The source lines a pane actually shows, in paint order: walk from
scroll collecting lines until height VISIBLE ones are gathered,
skipping every line hidden inside a closed fold and stepping over a
closed fold’s body in one jump (its head row stands for the whole
range).
The bound is display rows, not source lines, and that is the
entire point. Taking [scroll, scroll + height) and filtering the
folded lines out afterwards looks equivalent and is not: each
collapsed line still spends one of the window’s slots, so the pane
under-fills the moment a fold closes and every line past the window
— further headings, the cursor — is never considered at all. GPUI
shipped that bug (2026-08-09); the TUI had this walk inline from the
start. It lives here now so the two peers cannot drift again.
Soft-wrap is deliberately NOT accounted for: a wrapped line’s extra
segments are display rows the renderers add downstream, so this can
over-collect when wrapping is on. Both renderers cap their row
budget while emitting (shaped_text.len() >= viewport_height /
out.len() >= height), which is where wrap is paid for.
total_lines is CONTENT space —
lattice_core::Buffer::content_line_count, never ropey’s raw
[lattice_core::Buffer::line_count]. This function decides which
source lines get a row, so the raw count’s phantom trailing line
(present for every rope ending in \n, i.e. every normal file)
becomes a phantom painted row: the numbered blank line 220 of a
219-line file that CV.2 was reported for. Both renderers call
through here, so passing the wrong space in either one reintroduces
it in that peer alone.