feat: fast document open, cloud-sync UX, and a debug HUD - #18
Merged
nprudhomme merged 1 commit intoJul 2, 2026
Merged
Conversation
Opening a document could take ~3s. Instrumentation (new debug HUD) showed the render pipeline was only ~110ms — the time was entirely in the file read. Root cause: OneDrive "files on-demand" hydrating online-only files on first read (a plain `cat` of the same file took 2.3s at 0% CPU; 0.03s once moved to a local folder). Not the app, not the IPC. What this changes: - Read via a dedicated async Rust command `read_document` instead of the fs plugin. `async` keeps the (possibly slow) read off the UI thread — a sync command ran on the main thread and froze the window (FPS → 2). Confined to the home/resource dirs with canonicalization; errors stay generic (addresses the path-traversal review). - In-memory document cache keyed by path + mtime (new cheap `document_mtime` command) → re-opening a document is instant, without serving stale content after an external edit. - Loading spinner shown after a 150ms delay (no flash on fast/cached reads) and a one-time dismissible notice when an uncached read exceeds 600ms, explaining the likely cloud-sync cause (fr + en). Debug tooling (kept for future perf work): - Debug HUD (Cmd/Ctrl+Shift+D): live FPS + per-phase open timings (ipc ping, read, parse, images, mermaid, dom, outline, total), with click-to-copy. The IPC "ping" probe only runs while the HUD is open. - `read_document` logs the raw std::fs read duration to stderr.
nprudhomme
added a commit
that referenced
this pull request
Aug 13, 2026
* chore(release): v0.11.0 Bump version to 0.11.0 and document the user-facing changes since 0.10.0: native File/View menus with Open Recent (#19), fast document open with in-memory cache, cloud-sync UX and a debug HUD (#18), and a search highlight fix on document switch / 1->0 clear (#17). * fix(ui): stop transparent modal backdrops from locking the window A modal backdrop could be left in `display: flex` while fully transparent, covering the whole window at z-index 2000. It swallowed every click and scroll while staying invisible, and because the close path had already detached its listeners, the user had no way to dismiss it — the app was unusable until restart. Reported on 0.10.0: no clicks on Open Folder, no file selection in the sidebar, no scrolling, while the native menu bar still worked. The backdrops were shown and hidden through deferred callbacks. WebKit suspends both animation frames and timers while a window is occluded, so neither the reveal nor the hide is guaranteed to run — leaving the layer displayed but never marked `visible`. Make interactivity follow opacity in CSS: an overlay without `.visible` is now click-through and hidden from the tab order and the accessibility tree. That is the load-bearing guarantee — it holds whatever the reason the layer got stuck, including a keyboard user reaching a destructive button inside an invisible dialog. Defence in depth on top of it: - reveal synchronously (forced reflow, then class) instead of from a frame callback, so a dialog opened on an occluded window is still visible and therefore dismissable; - track an open generation so a pending hide never acts on a backdrop a newer open has claimed, in both confirm-dialog and Preferences; - focus the trap immediately, since callers now reveal before trapping. Tests cover the two suspension modes that produce the field state: frames never delivered, and timers never delivered. Claude-Session: https://claude.ai/code/session_01NcJuB2iR4WEfuQVLpYqWi4 * docs(changelog): record multi-window support in 0.11.0 PR #22 landed without a changelog entry. Covers the new windows, the native Window menu, the arrangement commands, and the switch from broadcast to frontmost-window menu delivery. Claude-Session: https://claude.ai/code/session_01NcJuB2iR4WEfuQVLpYqWi4 * docs(changelog): set the 0.11.0 release date The heading still carried the date the release branch was prepared. Claude-Session: https://claude.ai/code/session_01NcJuB2iR4WEfuQVLpYqWi4
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.
Why
Opening a document could take ~3 seconds. A new debug HUD showed the render pipeline was only ~110 ms — the entire cost was the file read.
Root cause: OneDrive "files on-demand". Online-only (dataless) files are downloaded on first read. A plain
catof the same file:time cat~/Documents(OneDrive-synced)Not the app, not Tauri, not the IPC (a no-op IPC round-trip measured ~1 ms). Nothing in code makes the hydration faster, so this focuses on not freezing, not re-paying the cost, and telling the user.
Changes
Read path
read_document(replaces thefsplugin for document reads).asynckeeps the possibly-slow read off the UI thread — a synchronous command ran on the main thread and froze the window (FPS dropped to ~2 during the read).canonicalize+ prefix check; generic errors (addresses an automated path-traversal review finding).Perceived performance
path + mtime→ re-opening a document is instant. A cheapdocument_mtimecommand (metadata only) validates freshness so an external edit is never served stale.Debug tooling (kept in-repo for future perf work)
Cmd/Ctrl+Shift+D: live FPS + per-phase open timings (ipc ping / read / parse / images / mermaid / dom / outline / total), with click-to-copy. The IPC ping probe only runs while the HUD is open, so normal use pays nothing.read_documentlogs the rawstd::fsread duration to stderr.Tests
npm test(294 passing),npx tsc --noEmit, andcargo checkall pass. HUD formatting logic is unit-tested (debug-overlay.test.ts).Note
Independent of #17 (search highlight fix).
🤖 Generated with Claude Code