pub struct FindState { /* private fields */ }Expand description
The search view-state: the active query, the active match’s decoration id, and the coverage/cap bookkeeping.
The one design rule: the store IS the match set — the sorted FindMatch
decorations, in (start, id) = document order. This state deliberately
holds no handle list; count, order, and N-of-M all derive from store queries
(one fact, one owner). The set is repaired eagerly per commit via
FindState::on_commit, so it is always current — undo/redo inherit the
repair through the shared view-rebase mover.
Implementations§
Source§impl FindState
impl FindState
Sourcepub fn match_count(&self, store: &DecorationStore) -> usize
pub fn match_count(&self, store: &DecorationStore) -> usize
How many live matches the current query has — the store IS the match set,
so this is the O(1) root-summary find_count read.
Sourcepub fn active_id(&self) -> Option<DecorationId>
pub fn active_id(&self) -> Option<DecorationId>
The decoration handle of the active match, if any — the render layer
compares each FindMatch decoration to this to pick the distinct style.
Sourcepub fn capped(&self) -> bool
pub fn capped(&self) -> bool
Whether the match set is a capped prefix of the document
(FIND_MATCH_CAP).
Sourcepub fn scope(&self) -> Option<Range<u32>>
pub fn scope(&self) -> Option<Range<u32>>
The find-in-selection scope — matches exist only inside it. None means
the whole document.
Sourcepub fn set_scope(
&mut self,
scope: Option<Range<u32>>,
buffer: &Buffer,
store: &mut DecorationStore,
now_ms: u64,
)
pub fn set_scope( &mut self, scope: Option<Range<u32>>, buffer: &Buffer, store: &mut DecorationStore, now_ms: u64, )
Set (or clear with None) the find-in-selection scope, re-scanning
synchronously — the scope is part of what matches, so changing it is a
query change, not a display filter.
An empty range clears the scope rather than pinning zero matches forever: searching everything is a recoverable surprise, silently searching nothing is not. A scope equal to the current one is a no-op.
Sourcepub fn set_query(
&mut self,
query: Option<FindQuery>,
buffer: &Buffer,
store: &mut DecorationStore,
now_ms: u64,
)
pub fn set_query( &mut self, query: Option<FindQuery>, buffer: &Buffer, store: &mut DecorationStore, now_ms: u64, )
Set (or clear with None) the query and scan synchronously; never
scrolls, and clears the active match. A query equal to the current one is
a no-op (no needless re-scan).
The full scan runs scan_buffer — whole-document in coverage but
windowed in memory, and a capped dense query stops at
O(bytes-until-cap) instead of copying the rope’s tail.
Sourcepub fn pattern_error(&self) -> Option<&str>
pub fn pattern_error(&self) -> Option<&str>
Why the current pattern does not parse, if it does not — for the find bar
to show. None whenever the query is matching normally (including when
it simply has no hits).
Sourcepub fn maybe_rescan(
&mut self,
buffer: &Buffer,
store: &mut DecorationStore,
now_ms: u64,
) -> bool
pub fn maybe_rescan( &mut self, buffer: &Buffer, store: &mut DecorationStore, now_ms: u64, ) -> bool
Refill a capped match set: re-scan iff a query is active, the set is
capped with room below the cap, and the debounce window has elapsed.
now_ms is an injected monotonic clock — the widget passes real time,
the headless suite a fake. Returns whether it scanned.
Because the eager per-commit repair keeps the set current, the only job here is growing a capped set’s coverage after matches inside it died.
Sourcepub fn on_commit(
&mut self,
patch: &Patch,
buffer: &Buffer,
store: &mut DecorationStore,
)
pub fn on_commit( &mut self, patch: &Patch, buffer: &Buffer, store: &mut DecorationStore, )
Repair the match set around a committed patch — the mover hook called
from the view-rebase path AFTER DecorationStore::apply_patch (it needs
post-patch positions). No-op when find is idle.
The influence window depends on the matcher. A literal query (post-edit
coordinates, k = needle byte length): every affected placement must
overlap new.start−(k−1) .. new.end+(k−1) (a created/destroyed match
contains a changed byte or the join point). A line-scoped query
(whole-word / regex) instead repairs the whole lines the edit touched —
a match cannot cross a newline, so nothing off those lines can have
changed — with no k−1 widening and no anchor/guard (the greedy phase the
widening repairs does not exist there). The rest of this describes the
literal path. Matches touching the window are removed
wholesale (DecorationStore::take_matching_in); the re-scan zone is
then the window widened (a) to the removed extents — a merely-touching
match must be re-findable, not lost — and (b) a further k−1 bytes each
way, because a placement overlapping the removal zone (one whose old
greedy blocker just died — the self-overlap phase repair) can start up
to k−1 bytes left of it and end as far right. Two clamps keep the
zone from double-owning text: the scan starts at the last surviving
match ending in the left margin (the anchor), and candidates
overlapping the first surviving match right of the zone are dropped
(the guard). The zone is greedily re-scanned with the same pure
scan and batch-reinserted. Matches outside every zone keep their
decoration ids (id stability is what lets the active match survive
unrelated edits).
Active survival: untouched active stays (same id); an active removed by a window transfers to a re-created match at its exact post-patch start; otherwise it clears.
Cap: coverage_end rides the patch first; windows clamp to it, so
repairs beyond a capped set’s coverage are skipped (the refill’s job).
If a repair pushes the live count past FIND_MATCH_CAP, the tail is
trimmed so the set stays a prefix of the document.