Repository navigation
fix: surface rejected-draft and stash losses, and say what Format Document did - #459
Merged
Merged
Conversation
…smatch After the tab closes, a pending edit held behind an in-flight write has no webview replay buffer to fall back on. When the settlement shows the document no longer matches what Quoll just wrote (or the executor reported a divergence), that edit was dropped with only a log line. Now the user gets a toast telling them to reopen the file, unless the document already contains the dropped text. The alive path is unchanged.
…ected draft A draft the host refused stays on screen until another writer changes the file; the reseed then replaced it and the discard notice could only say the text was gone. The notice now carries a Copy draft button that puts the replaced text on the clipboard, so the user can paste it back. The text is held in one slot: a later replaced draft overwrites it, and dismissing the notice or closing the editor drops it. A discard reported by edit-sync carries no text and leaves a still-copyable draft alone.
…d, or failed Format Document used to look identical whether the document was already formatted, read-only, too large to format, or the formatter had thrown: nothing happened. Each of those now shows a short notice in the existing notice slot, and a run that does format clears it. The feedback ranks below every loss notice, so it never replaces one. The failure text makes no "nothing was changed" claim, because a dispatch that throws after updating the document is not rolled back.
…s tab closes When Quoll refuses to save an edit, the refused text exists only in the editor: the file and VS Code's document never held it, so closing the tab asked nothing and the text was gone. Closing the tab now reopens that draft as an untitled Markdown document and says why the edit could not be saved. The guarantee covers an ordinary tab close in a live window; a window close or reload is best effort. E2E routes the reopen through a harness override that is a no-op by default, so suites that are not about the rescue never inherit a dirty untitled document.
The rescue ran last in onDidDispose, after the disposed dispatch, the lint-mirror removal and the revert-rescue. A throw from any of those skipped it, and the refused draft's only copy went with the tab. It reads state.rejection and touches nothing else, so it now runs first; a source-order test pins the position.
The existing test only set up a discard, the top rank, so raising the format kinds' rank left it green: nothing pinned that a format result is declined behind the three weaker loss kinds, or leaves them alone when a format succeeds.
…e behaviour - rejected-draft rescue: the guarantee covers a rejection pending when the tab closes; a stash refused on a post-dispose drain is not covered - host-session-core: a stash dropped post-dispose on an ok settle gets a toast, so the !canDrain header no longer says the output is empty - shell showNotice: list the format-document writer and its declines - styles: the notice surface is shared by every notice kind, and one modifier does carry a rule
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.
Summary
Four outcomes that used to be silent now tell the user what happened, each by reusing an existing toast or the existing notice slot. No recovery store, no new reducer effect, no protocol change.
Changes
onDidDispose. Not covered: an edit stashed behind an in-flight save and refused only when it drains after the tab has closed keeps its existingCannot savetoast and is not reopened (tracked as a follow-up).runFormatDocumentreturnsformatted | unchanged | readonly | too-large | failedinstead of a boolean, and the shell says which. "No changes were needed" is no longer indistinguishable from a failure, and the failure text does not claim nothing changed (adispatchthat throws is not guaranteed to roll back). These notices rank below every loss notice and are cleared by a successful format.Test-only plumbing: the E2E harness gains
openRescuedDraftOverride(same pattern as the existing overrides) and installs a no-op by default, so suites that are not about the rescue never inherit a dirty untitled document. Only the rescue's own suite exercises the real open.Not included
A general recovery store, persistence, keeping a rejected draft on screen behind an unresolved-state gate, and an untitled export for the post-dispose stash drop (notification only).
Related TODO
ARCH-05 (05a-1, 05a-2, 05a-3, 05d).
Test plan
Each slice's tests were observed red against the unchanged source first.
pnpm compilepnpm lintpnpm vitest run— 294 files, 5883 testspnpm test:browser— 82 testspnpm test:e2e— 117 passing, twice in a rowpnpm check:doc-syncpnpm package— vsix audit clean