perf: highlight files off the main thread (no freeze on file click) - #23
Merged
Conversation
Opening any highlightable file froze the UI: syntect ran line-by-line and tags were applied per region synchronously on the GTK main thread, scaling with file size (pathological on minified single-line files). Now load_file shows the content as plain text immediately (set_text), then a worker thread computes the highlight spans and the main thread applies the tags in idle-chunked batches (1500/tick) — so the click never blocks. A per-view epoch (stored on the widget, like tree.rs) cancels a stale highlight when a new file is opened mid-run. Lines over 10k bytes (minified blobs) are left unhighlighted; the rest of the file still highlights. - highlight: shared syntax/theme sets via OnceLock (Send+Sync, loaded once off the main thread) replace per-thread thread_locals; new compute_spans (pure, thread-safe), highlight_async, apply_spans_chunked. Char-offset spans also fix the latent byte-vs-char offset bug on non-ASCII files. - textview: load_file calls highlight_async instead of the synchronous path. - tests: compute_spans offset bounds, unhighlightable, long-line guard.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Clicking any highlightable file froze the UI. `highlight_buffer_with_theme` ran syntect line-by-line and applied tags per region synchronously on the GTK main thread, scaling with file size — and going pathological on minified single-line files (one giant `highlight_line` call).
Fix
`load_file` now shows the content as plain text immediately (`set_text`), then:
A per-view epoch (stored on the widget via `set_data`, the same pattern as `tree.rs`) cancels a stale highlight when a newer file is opened mid-run. Lines over 10k bytes (minified blobs) are skipped by the highlighter; the rest of the file still highlights.
The click never blocks the UI regardless of file size or content.
Notes
Scope
`src/highlight.rs` (shared sets, `compute_spans`/`highlight_async`/`apply_spans_chunked`/epoch; diff fns reuse the shared sets), `src/textview.rs` (call site).
Checks
fmt ✅ · clippy `-D warnings` ✅ · tests ✅ (108, incl. 3 new `compute_spans` tests: offset bounds, unhighlightable, long-line guard)