v7.16.1
Performance
- make the
Typewriterfallback split incremental (00d2c11) - read
HighlightEditablecaret offsets from line lengths (2a75907) - cache reopen tags across line breaks in
extendLines(d97c520) - binary-search ranges for single-line
HighlightEditablerepaints (de6d955) - resolve preprocessor match line numbers lazily (e939ce1)
- memoize missing closing tags in the JSX guard (f7cab7e)
- use a
SetforLineNumbershighlighted-line lookups (016d350) - defer guard closure allocation to cache misses (eddc39e)
- repaint
css-highlightsin one linear sweep (ce2856e)
Performance
This release is a performance-only patch focused on the new highlight engine, HighlightEditable, Typewriter, LineNumbers, and the static preprocessor. No API changes.
Typewriter
The fallback unit split re-walked the highlighted HTML from index 0 on every tick. Since revealed only grows by one unit per tick, a full animation was O(n²). A stateful splitter now advances forward across calls, and head/tail are built with a single slice. A 30k-unit animation drops from ~4.3s to ~2.6ms.
HighlightEditable
Several hot paths around caret tracking and token painting are cheaper:
- Caret offsets are read from cached line lengths instead of serializing the whole document per keystroke.
- Single-line repaints binary-search the sorted token ranges instead of scanning every token in the document.
- Full
css-highlightsrepaints advance a single cursor over sorted ranges (O(lines + tokens)) instead of rescanning all ranges per line (O(lines × tokens)), which could freeze large files on mount, paste, or undo/redo.
Highlight engine
extendLinescaches close/reopen tag strings across newlines instead of rebuilding them from the scope stack on every line break.- The JSX tag guard memoizes missing closing tags per name, so generic-dense TypeScript no longer pays a full tail scan for every
<T>occurrence. Highlighting ~441 KB of that style drops from ~339ms to ~196ms. - Guard closures are allocated only on cache misses, not on every token boundary.
LineNumbers and static preprocessor
- Highlighted-line membership uses a
Setso each rendered line is O(1) instead of an array scan. - The static preprocessor resolves match line numbers only on warn paths, so the happy path no longer scans the file for newlines on every
<Highlight>match.