pub struct FoldIndex { /* private fields */ }Expand description
O(log folds) lookup index built once per frame (or per publish) over a snapshot of the active document’s folds.
Perf plan C. Renderers used to call
folds.iter().any(|f| ...) per visible line in the gutter compose
loop — O(rows × folds) per pane per frame. With this index the
per-line check drops to a partition-point binary search plus a
constant-time fast path for the common non-overlapping case.
Build cost is O(folds); for the typical buffer with <50 folds
it’s <1 µs. The build is intentionally per-frame on the renderer
side (no host-side caching / invalidation discipline) — the saving
is the per-line walk, not the construction.
Fold semantics (paramount goal #3, vim parity):
closed_fold_start_at(line)is true iffline == f.start_linefor some closed foldf.line_inside_closed_fold(line)is true ifff.start_line < line && line <= f.end_linefor some closed fold. Start lines are NOT inside (vim renders the heading row).fold_start_at_any(line)covers open + closed folds. Used by the gutter glyph provider (open-fold caret vs closed-fold chevron).
Implementations§
Source§impl FoldIndex
impl FoldIndex
Sourcepub fn from_folds(folds: &[Fold], foldenable: bool) -> FoldIndex
pub fn from_folds(folds: &[Fold], foldenable: bool) -> FoldIndex
Build an index from a fold snapshot. O(folds) — one filter +
two sorts.
Sourcepub fn closed_fold_start_at(&self, line: u32) -> bool
pub fn closed_fold_start_at(&self, line: u32) -> bool
True iff line is the start row of a closed fold. Matches
Editor::fold_start_at(line).is_some() semantics.
Sourcepub fn closed_fold_at(&self, line: u32) -> Option<(u32, u32)>
pub fn closed_fold_at(&self, line: u32) -> Option<(u32, u32)>
(start, end) of the closed fold starting at line, or
None if no closed fold starts there. Mirrors
Editor::fold_start_at(line) but yields just the row range
the renderer + fold-aware viewport math actually need —
&Fold would force us to hold a Vec<Fold> snapshot in the
index, while two u32s are 8 bytes per entry and cache-
friendly. Used by Editor::fold_aware_highlight_end_line
to advance buf_line past a closed fold in the viewport
stretch loop.
Sourcepub fn enclosing_closed_fold(&self, line: u32) -> Option<(u32, u32)>
pub fn enclosing_closed_fold(&self, line: u32) -> Option<(u32, u32)>
The innermost closed fold whose interior contains line
(start_line < line <= end_line), or None. The interior
excludes the start row — the fold head stays visible — so a
head line reports None here even though it bounds a fold.
Used by the fold-aware scroll walk
(Editor::bottom_anchored_scroll) to hop from a hidden body
line straight up to its visible head in one step, instead of
iterating every collapsed line. line_inside_closed_fold
answers the same question as a bool; this returns the range
so the caller can jump.
Sourcepub fn visible_anchor(&self, line: u32) -> u32
pub fn visible_anchor(&self, line: u32) -> u32
The row line is actually DISPLAYED on: itself when visible, else
the head of the outermost closed fold that swallows it.
Two lines share an anchor exactly when they occupy the same row on
screen. That is what makes it the right comparison for a motion that
has to look like it moved — zj / zk step between fold edges, and
an edge collapsed inside a closed fold is not a place the cursor can
visibly go (see Editor::do_goto_fold).
Outermost, not innermost, which is why this walks rather than
calling Self::enclosing_closed_fold once: closed folds nest, and a
sub-fold’s head is itself hidden when its parent is also closed. The
walk climbs head-to-head until it reaches one nothing encloses, so the
answer is a row that is genuinely on screen. Bounded by fold nesting
depth (single digits in practice) and each step is the same binary
search the predicates beside it use.
Collapses to the identity under :set nofoldenable, like every other
predicate here — nothing is folded, so nothing is hidden.
Sourcepub fn line_inside_closed_fold(&self, line: u32) -> bool
pub fn line_inside_closed_fold(&self, line: u32) -> bool
True iff line falls strictly inside the interior of some closed
fold (start_line < line <= end_line). Matches the existing
Editor::line_inside_closed_fold semantics.
Sourcepub fn fold_start_at_any(&self, line: u32) -> bool
pub fn fold_start_at_any(&self, line: u32) -> bool
True iff line is the start row of any fold (open or closed).
Mirrors Editor::fold_start_at_any(line).is_some().
Sourcepub fn fold_start_kind_at(&self, line: u32) -> Option<FoldMarker>
pub fn fold_start_kind_at(&self, line: u32) -> Option<FoldMarker>
Whether a fold starts at line, and if so whether it is
collapsed. Some(true) = closed fold head, Some(false) = open
(expanded) fold head, None = no fold starts here. Gates on
foldenable. This is what a gutter renderer consults to pick the
collapsed vs expanded marker glyph — the shared peer of the TUI’s
fold_glyph_for, so both renderers show a marker on every
foldable head (not just collapsed ones) and agree on which glyph.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for FoldIndex
impl RefUnwindSafe for FoldIndex
impl Send for FoldIndex
impl Sync for FoldIndex
impl Unpin for FoldIndex
impl UnsafeUnpin for FoldIndex
impl UnwindSafe for FoldIndex
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more