Commit Graph
9 Commits
Author SHA1 Message Date
Bohdan Triapitsyn c47c7190f4 feat(header): session tab tooltips, status dots, cursor context menu
Right-click now opens the session menu under the cursor (the sidebar's
context-menu pattern; the same header-supplied items back both the
"..." dropdown and the context menu via injected menu primitives) and
still never changes the active tab. Hovering a tab shows the sidebar's
session tooltip — title, last-activity time, project, branch and PR
status — after a delay, suppressed while a menu is open or a drag is in
flight. Each tab carries the sidebar's status dot at its end (accent
while the session runs, info-blue for unread), hidden while the hover
controls overlay it. Tab titles fade out instead of ending in "...",
and while the active tab is renaming its hover controls stay hidden so
only the rename controls show.
2026-08-24 20:02:59 +03:00
Bohdan Triapitsyn 77479127a5 fix: reduce code block highlight flicker
Preserve layout with invisible placeholders while worker highlighting loads
Reuse cached highlighted lines on first render when available
Differentiate loading from failed highlighting results for better fallback behavior
2026-08-22 02:10:03 +03:00
Serhii Dziupin 69150366fd fix(ui): correct markdown cache identity, streaming churn, and redundant tiers
Review follow-up on the #2769 highlight caches.

Fingerprint strength. The block/highlight caches are now global and
content-addressed, so a hash collision no longer mis-colors a block — it returns
a *different* block's rendered HTML and shows the user source they never wrote.
Length + one 32-bit FNV-1a is not enough key space for that failure mode at
session scale. `contentFingerprint` now combines two independent 32-bit
multiplicative hashes with a final avalanche (~64 bits); two multiplies per
character are free next to Shiki tokenization.

Streaming churn. Content addressing made every streaming step of the trailing
`live` block insert a new cache entry, so one long message evicted the settled
`full` blocks the fix exists to keep warm. `full` and `live` blocks now use
separate caches; the live cache is small (32 entries / 2MB) because it only has
to absorb repeat renders of the same step.

Redundant worker-side caches. `markdown-worker.ts` is the only sender to the
Shiki worker, and its client cache is larger than the worker-side ones, so the
worker caches could not serve a hit the client had not already served — they
only duplicated up to 48MB of payloads in a second heap. Removed; the reason
memoization belongs on the client is now documented there, along with why only
`highlightTokens` carries a theme in its key.

Dead `cacheKey` plumbing. `renderMarkdownBlocks` kept a `cacheKey` parameter it
only `void`-ed. Removed it and the now-unused `useMorphdomMarkdown` prop; the
remaining call-site local is renamed `fadeKey` for what it actually keys.

Tests: image-mode cache identity, streaming-does-not-evict-settled-blocks,
live-cache reuse, and a 20k same-length-source fingerprint collision check.
Each new guard was verified to fail without its fix.
2026-08-17 16:45:53 +03:00
Serhii DziupinandSerhii Dziupin c3c47e8956 perf(ui): tighten Shiki highlight caches and parallelize fences
Use content fingerprints instead of full source as cache keys, record
entry sizes once (no TextEncoder/JSON.stringify on get/evict), and
highlight multiple markdown fences concurrently.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-11 13:23:43 +00:00
Serhii DziupinandSerhii Dziupin 6ab12fdb61 fix(ui): stop sustained Shiki re-highlight of unchanged markdown
Content-address the markdown HTML cache and memoize Shiki worker/client
results so remounts and long sessions no longer re-tokenize stable code
blocks (openchamber/openchamber#2769).

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-10 13:50:20 +00:00
Leonidandbashrusakh 17af1f3369 fix(vscode): allow Shiki module worker by adding worker-src to CSP (#2047) (#2058)
Co-authored-by: bashrusakh <bashrusakh@users.noreply.github.com>
2026-07-11 14:50:00 +03:00
Bohdan Triapitsyn 782982cdd3 feat(editor): Shiki syntax highlighting in the file editor (CodeMirror)
Bring the CodeMirror file editor up to the same rich highlighting as the Shiki
file view, so toggling edit <-> view is visually consistent. lezer collapses far
more tokens than TextMate (import/from/const are all "keyword"), so a theme
remap can't reach parity — instead, project real Shiki tokens onto decorations.

- Worker: add highlightTokens — tokenize with an arbitrary registered TextMate
  theme and return per-line styled runs with offsets. The theme object ships to
  the worker once per name; later calls send only the name.
- New shikiHighlight CodeMirror extension: a StateField of mark decorations
  built from worker tokens. Re-tokenizes on a short idle (off the keystroke
  path) and maps decorations through edits so colors persist while typing.
- flexokiTheme: add { syntaxColors: false } to keep only the editor UI theme,
  so the lezer highlighter doesn't compete with the Shiki decorations.
- FilesView: enable Shiki highlighting (same language resolver as the file view
  → identical language) and drop lezer token colors when it's active. lezer
  language stays on for indentation/folding/brackets.
2026-06-16 01:08:54 +03:00
Bohdan Triapitsyn e41e5bac91 perf(code): replace react-syntax-highlighter and prismjs with the Shiki worker
Route all non-markdown code highlighting through the off-main-thread Shiki
worker, removing react-syntax-highlighter and prismjs entirely.

- Extend the worker with highlightLines: tokenize a whole block once and return
  per-line inner HTML, so per-line layouts (diffs, gutters, virtualization) make
  one worker call instead of one highlighter per line.
- Add shared WorkerHighlightedCode (whole-block) and useWorkerHighlightedLines
  (per-line) primitives. Colors resolve via the --md-syntax-* CSS variables, so
  theme changes never re-highlight.
- Migrate all 12 react-syntax-highlighter call sites: PermissionCard,
  ToolPart, ContextSidebarTab, ToolOutputDialog (whole block) and
  DiffPreview/WritePreview (per line).
- Migrate VirtualizedCodeBlock off prismjs to the worker, keeping virtua
  virtualization; whole-block tokenization also restores cross-line syntax
  context that per-line highlighting lost.
- Drop react-syntax-highlighter (+types) from ui and web, prismjs (+types) from
  ui, and the orphaned create-element type shim.
2026-06-16 01:07:43 +03:00
Bohdan Triapitsyn 464c4ac0ca perf(markdown): move code highlighting off the main thread into a Shiki worker
Tokenize closed code blocks in a dedicated Shiki Web Worker instead of calling
the shared highlighter synchronously on the UI thread. This removes the
one-shot main-thread highlight stall when a code fence closes on a large block.

Streaming behavior is unchanged: the open (streaming) fence still renders as
plain text and is highlighted once on close. On any worker failure the block
keeps its escaped plain code — highlighting never falls back onto the main
thread.

- Add markdownShikiThemeDefinition (dependency-free CSS-variable theme) so the
  worker can use the theme without pulling in @pierre/diffs / React.
- Add markdown-worker-protocol, markdown-shiki.worker, and the main-thread
  markdown-worker client.
- Route highlightCodeBlocks through the worker; keep the size/VSCode line guard
  and mermaid skip on the main thread.
- Add shiki as a direct dependency (was transitive via @pierre/diffs).
2026-06-16 01:07:43 +03:00