Skip to main content

HighlightCache

Struct HighlightCache 

Source
pub struct HighlightCache { /* private fields */ }
Expand description

The document-owned incremental, virtualized highlight cache.

The correctness model is end-state convergence over DirtyRanges: a line is re-tokenized only while its computed end state differs from the stored one, so an edit repaints just the lines whose state actually changed. It is driven lazily and budgeted by HighlightCache::tokenize_until. Retention is what keeps memory bounded — two facts make it work:

  • Spans are draw output — nothing but visible rows reads them, so they are retained only inside a dense window (the viewport ± HIGHLIGHT_WINDOW_SLACK, set via HighlightCache::set_window), together with per-line end states there (so a keystroke at the caret still converges per-line).
  • States exist to be resumed from — and any row’s state is re-derivable by tokenizing forward, so outside the window only sparse checkpoints survive: one per HIGHLIGHT_CHECKPOINT_STRIDE tokenized rows plus each budget-stop resume point. A cold jump refills the window from the nearest checkpoint (≤ a stride of warm-up, budgeted; the rows render in the fallback style until filled).

Convergence verification is per-line inside the window and checkpoint-grain outside (an out-of-window cascade may run up to one stride past where a fully-dense cache would have stopped — bounded, and such edits are rare: you edit what you see). Memory for a fully swept document: O(window + lines / stride) instead of O(lines).

Implementations§

Source§

impl HighlightCache

Source

pub fn new(syntax: SyntaxDef, theme: TokenTheme, n_lines: u32) -> Self

A cache for an n_lines document over an injected grammar + theme: every line invalid, nothing retained. The retention window defaults to the document top (2 × HIGHLIGHT_WINDOW_SLACK rows) — right for a freshly opened view; the app re-aims it per viewport report via HighlightCache::set_window.

Source

pub fn first_dirty(&self) -> Option<u32>

The first dirty row, if any — None means every line’s state has converged (spans may still be evicted outside the window; see HighlightCache::pending, which the sweep polls instead).

Source

pub fn pending(&self) -> Option<u32>

The next row a budgeted HighlightCache::tokenize_until call would work on: the first dirty row, or — once states have converged — the first window row whose spans await a refill (a window move over already-swept rows). None = nothing to do (the idle-zero-work probe; the app’s sweep keys its subscription off this).

Source

pub fn line_spans(&self, row: u32) -> Option<&[HighlightSpan]>

The cached spans for a line, or None if the row is outside the retention window or not yet tokenized/refilled (the caller renders that line in the default style — never an error, never a stall).

Source

pub fn line_count(&self) -> u32

How many lines the cache is sized for — must track the buffer’s line count (the commit path keeps them equal).

Source

pub fn window_aim(&self) -> Range<u32>

The last rows handed to HighlightCache::set_window (pre-padding) — Document::set_syntax re-aims a replacement cache with this so a grammar swap keeps retention at the viewport instead of silently resetting to the document top.

Source

pub fn set_window(&mut self, rows: Range<u32>)

Aim the retention window at rows (the viewport, in buffer rows) — the cache retains rows ± HIGHLIGHT_WINDOW_SLACK and evicts outside. Repositioning is O(window); rows entering the window refill on the next HighlightCache::tokenize_until (see HighlightCache::pending).

Source

pub fn on_commit(&mut self, start: u32, old: u32, new: u32)

The commit hook: buffer lines [start, start+old) became new lines. Splices the window (keeping the old end state of the last edited line as the convergence probe in the new last slot), drops replaced checkpoints and shifts the rest, and marks [start, start+new) dirty. O(edit + window + #checkpoints); the cascade waits for tokenize_until.

Source

pub fn on_commit_patch(&mut self, spans: &[(u32, u32, u32)])

The commit hook, given the per-edit pre-edit line spans (pre_start, old_lines, new_lines) (ascending, disjoint). Checkpoints, the dense window, and the dirty runs all ride the per-edit spans — NOT the whole transaction’s first-to-last covering range. A scattered multi-caret transaction has a document-scale covering range but O(carets) tiny spans, so this keeps the commit (and the sweep it schedules) O(carets + window + checkpoints), and — critically — leaves the retention window aimed at the viewport: only the actually-edited in-window rows are invalidated, so the visible rows recolor on the next tokenize instead of going stale until a scroll re-aims the window.

Source

pub fn tokenize_until<S: AsRef<str>>( &mut self, target: u32, max_lines: u32, line: impl FnMut(u32) -> S, ) -> u32

Tokenize toward target (inclusive), lazily and budgeted, and return how many lines were tokenized (warm-up included) — the op count the perf canaries assert on. Two phases share the max_lines budget:

  1. The dirty walk — dense convergence semantics: each first-dirty line tokenizes from its start state (stored, or warmed up from the nearest checkpoint); if its new end state differs from the stored one the cascade continues, otherwise it stops (convergence). Where no state is stored to compare against (outside the window, between checkpoints) the cascade keeps going until one is — at most a stride more than a fully-dense cache would have done.
  2. The window refill — rows inside the retention window whose spans were evicted (a window move over already-swept text) are re-derived from the nearest checkpoint. Only rows below the dirty frontier are fillable (states past dirt are unverified).

line(i) hands back line i’s text — an ACCESSOR, never an all-lines Vec, so this never materializes the whole document. A budget stop records a resume checkpoint so the next call continues without re-warming.

Source

pub fn set_theme(&mut self, theme: TokenTheme)

Swap the theme and invalidate the whole cache: a theme change is a full invalidation because syntect resolves colors at tokenize time, so every line’s styles change and must be re-tokenized. States and checkpoints are dropped and every line marked dirty; the old window spans are kept as a stale fallback so the view keeps showing the outgoing theme’s colors (not a flash to default) until the frontier repaints them on the next tokenize_until.

Source

pub fn engine(&self) -> HighlightEngine

A cheap-to-clone, Send + Sync handle to this cache’s grammar + theme, for off-thread bulk tokenization (the parallel/speculative sweep). Shares the Arc-held grammar/theme — no SyntaxSet deep clone.

Trait Implementations§

Source§

impl Debug for HighlightCache

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.