feat: persist diff file review checkmarks
This commit is contained in:
@@ -17,8 +17,8 @@ One editor crate; the workspace also includes its patched Crossterm dependency.
|
||||
Virtual diff leaves retain their original catalog input index for caller-owned annotations. Normal scanned leaves accept optional repository status and old-path metadata without filtering unchanged files; missing tracked deletions add virtual leaves and required directories. Metadata-only updates preserve query, selection, expansion, and view without rebuilding the catalog.
|
||||
- `diff`: owns searchable Before/After selection, category, focus and explorer visibility, request freshness, read-only comparison DTOs, aligned rows with cached grapheme-level change ranges, and shared vertical/independent horizontal offsets. Changed paths form a virtual `files::FilePicker` catalog, reusing the normal tree projection, filtering, and navigation without scanning disk. It has no subprocess or terminal dependencies.
|
||||
- `repository`: discovers jj/Git repositories and local/advertised remote revisions, builds disk snapshots and changed-file hunks, and owns isolated temporary comparison repositories with bounded, cancellable subprocesses. It never saves editor buffers or modifies active refs/checkouts.
|
||||
- `review`: owns the validated local review model, exact immutable anchors, SQLite storage through bundled rusqlite, and atomic JSON import/export with external-change protection. Schema 2 stores review identity, repository, revision, summary, and verdict in `reviews`; `comments` stores ordered comment IDs, bodies, resolution states, and explicit immutable anchor fields. Foreign keys, unique keys, and checks enforce relationships and scalar invariants. Full `u64` comment IDs use checked decimal text because SQLite integers are signed. No JSON documents are stored in SQLite.
|
||||
`Store` retains compare-and-swap review revisions and atomic whole-review saves: metadata and replacement comment rows commit together. Read transactions reconstruct validated reviews from one consistent snapshot, including when listing in descending ID order. Stored text is bounded to 64 MiB per review, including a fixed per-comment overhead. JSON version 3 is an independent import/export format. Incompatible databases, including schema 1 document storage, are rejected and preserved without migration or reset. CLI metadata, sole-review restoration, and selector labels reuse loaded reviews; selector choices live only in the displayed buffer.
|
||||
- `review`: owns the validated local review model, exact immutable anchors, persisted file checkmarks, SQLite storage through bundled rusqlite, and atomic JSON import/export with external-change protection. Schema 3 stores review identity, repository, revision, summary, and verdict in `reviews`; `comments` stores ordered comment IDs, bodies, resolution states, and explicit immutable anchor fields. `reviewed_files` stores revision pairs, paths, optional old paths, and optional exact live After text. Foreign keys, unique keys, and checks enforce relationships and scalar invariants. Full `u64` comment IDs use checked decimal text because SQLite integers are signed. No JSON documents are stored in SQLite.
|
||||
`Store` retains compare-and-swap review revisions and atomic whole-review saves: metadata and replacement comment/checkmark rows commit together. Read transactions reconstruct validated reviews from one consistent snapshot, including when listing in descending ID order. Stored text is bounded to 64 MiB per review, including a fixed per-comment/checkmark overhead. JSON version 4 is an independent import/export format. Incompatible databases, including schemas 1 and 2, are rejected and preserved without migration or reset. CLI metadata, sole-review restoration, and selector labels reuse loaded reviews; selector choices live only in the displayed buffer.
|
||||
The review CLI keeps `list`/`show` read-only. Comment deletion validates the explicit review/comment IDs through an existing read-only store before opening it for a compare-and-swap save; absent storage and invalid targets do not create reviews or a database.
|
||||
`editor_review` commits native comment/summary buffers on dismissal or switching, and verdicts/deletions immediately. It restores a sole stored review or opens the floating selector for multiple reviews. Exports retain their own file baseline and do not become automatic persistence targets; imports get fresh database identities. Review editors remain tab-owned native panes outside the workspace `PaneTree`. Storage opens lazily when a comparison is ready; the session supplies the configured or XDG default directory. Direct `Editor` callers inject a directory with `set_review_directory` to enable persistence.
|
||||
Successful SQLite autosaves and JSON-only saves share one acknowledgement operation: clear review dirtiness and advance the owning tab's native draft saved baselines only after persistence succeeds. Failed writes retain unsaved state; JSON exports do not acknowledge a pending SQLite save.
|
||||
|
||||
@@ -76,6 +76,7 @@ Manual-resolution checks cover immediate persistence, reopen/export/import, inde
|
||||
Live PTY/CLI smoke composes and explicitly saves a comment, resolves it in the editor, observes an empty default CLI comment list with explicit counts, retrieves the resolved comment and exact excerpt with `--all`, and unresolves it. Each transition advances the same stored review revision; listing absent storage creates no data directory.
|
||||
CLI deletion checks exercise explicit review/comment IDs, resolved-comment deletion, repository isolation, preserved summaries/verdicts/other comments, last-comment deletion, missing targets/storage, and stale-save conflicts through the executable. CLI smoke verifies persisted deletion and rejects a repeated deletion without advancing the review revision.
|
||||
Relational-storage smoke inspects typed review/comment columns, round-trips exact Unicode anchors through the store and JSON export/import, deletes through the real CLI, and confirms the stored review and existing export remain intact.
|
||||
Reviewed-file checks cover SQLite/JSON round-trips, unmarking, exact revision pairs and rename paths across catalog reordering, lazy loading, live text/final-newline mismatch, edit-triggered invalidation, selected-review isolation, hidden-draft isolation, conflicts, and transactional rollback. Live PTY smoke marks a file in a real Git comparison, verifies the SQLite row, restarts the editor, observes the restored checkmark, unmarks it, and verifies row removal with unchanged source bytes.
|
||||
|
||||
|
||||
Conflicted-revision regressions preserve unchanged symlinks, defer oversized unselected blobs until file selection, compare selected conflict text with jj's projection, and exclude unchanged conflicts when comparing later revisions. Live terminal smoke covers local bookmark selection and opening an actual conflicted file without changing the checkout.
|
||||
|
||||
+5
-5
@@ -462,9 +462,9 @@ Mark or unmark a diff file with **`c` while browsing the changed-file tree**, **
|
||||
|
||||
Collapsed folders show a green **`✓`** when every changed file beneath them is reviewed, including nested files and descendants hidden by filtering. Expanded folders stay unmarked. Folder marks update automatically when a descendant's review mark or the changed-file catalog changes.
|
||||
|
||||
Review marks belong only to the open comparison and survive filtering, file navigation, lazy loading, tabs, split/unified/orientation changes, and pinned checkout-only transitions. A new or recomputed comparison clears them. Editing a writable After file clears only that file's mark; unchanged refreshes and saves preserve it. Marks do not change document text, undo history, or repository state, and are not persisted after closing the comparison.
|
||||
Review marks are saved with the selected local review and restored when the same immutable Before/After revision pair and file paths are reopened. They survive filtering, file navigation, lazy loading, tabs, split/unified/orientation changes, and pinned checkout-only transitions. Other comparisons do not inherit their marks; returning to a previously reviewed comparison restores them. Editing a writable After file clears only that file's mark and saves the removal; unchanged refreshes and saves preserve it. Marks on live text also retain its exact contents, including the final newline, so different unsaved text cannot inherit a checkmark. Marks do not change document text, undo history, or repository state. Without configured SQLite storage, use `:diff.review.save path` to save them as JSON.
|
||||
|
||||
**Local review comments** are independent of GitHub and the file-reviewed checkmarks above. Focus either diff text pane and run **`:diff.comment`** to comment on the current line. A characterwise Visual selection (`v`) anchors its exact text, including partial lines and multiline spans; Visual Line (`V`) anchors whole selected lines. Type **`:diff.comment`** and press Enter, or use the palette/a configured binding. Multiple independent carets/ranges must be reviewed separately.
|
||||
**Local review comments** share local storage with the file-reviewed checkmarks above; neither feature publishes to GitHub. Focus either diff text pane and run **`:diff.comment`** to comment on the current line. A characterwise Visual selection (`v`) anchors its exact text, including partial lines and multiline spans; Visual Line (`V`) anchors whole selected lines. Type **`:diff.comment`** and press Enter, or use the palette/a configured binding. Multiple independent carets/ranges must be reviewed separately.
|
||||
|
||||
Comments, summaries, and the review overview open in a focused floating editor over the whole diff text workspace, not a source-side split. The source layout, file explorer, and viewports stay unchanged. Normal editing, selections, and undo/redo work in editable review buffers. Escape in Normal mode or `:pane.close` dismisses the window and returns to the diff, discarding that editor's unsaved text. An unsaved new comment is not attached to the review; an existing comment or summary reopens with its last saved text and no discarded undo history. Insert/Visual/Command Escape first retains its usual modal behavior. Source rows are never replaced with comment text. Magenta **`○`** gutter markers identify saved comment ranges; **`●`** identifies the selected comment. Its exact current text range has a magenta background, including wrapped continuations and selected newline cells; native Visual selections take precedence. Stale comments have neither markers nor text highlighting. Markers preserve addition/deletion signs, appear only on the first wrapped segment, and also work in unified view.
|
||||
|
||||
@@ -485,7 +485,7 @@ Local review buffers (comments, summaries, overview, and stored-review selector)
|
||||
| `:diff.review.open [id or path]` | Show stored reviews, open a stored review ID, or import a JSON review as a new review |
|
||||
| `:diff.review.new` | Create a separate stored review for the current repository |
|
||||
|
||||
Comment and summary text is committed only by **`:w`** or **`:diff.review.save`**, which saves the entire review, including hidden drafts. Dismissing an editor discards its unsaved text; switching between review editors can retain hidden drafts but does not save them. Verdicts, deletions, and manual resolution changes commit immediately to local SQLite without committing draft text. `:diff.review.save path` or `:w path` additionally exports JSON; later metadata autosaves still go to SQLite and leave that export unchanged. Imports create a new stored review identity rather than overwriting another review.
|
||||
Comment and summary text is committed only by **`:w`** or **`:diff.review.save`**, which saves the entire review, including hidden drafts. Dismissing an editor discards its unsaved text; switching between review editors can retain hidden drafts but does not save them. File checkmarks, verdicts, deletions, and manual resolution changes commit immediately to local SQLite without committing draft text. `:diff.review.save path` or `:w path` additionally exports JSON; later metadata autosaves still go to SQLite and leave that export unchanged. Imports create a new stored review identity rather than overwriting another review.
|
||||
|
||||
From the shell, use `vamp --review delete REVIEW_ID COMMENT_ID [--repo PATH] [--json]` to delete a stored comment immediately without opening the editor. Find IDs with `vamp --review list` and `vamp --review show REVIEW_ID --all`. The repository defaults to the current checkout. Both resolved and unresolved comments can be deleted; the review and any JSON exports remain intact. An editor holding the old review revision must reload before saving.
|
||||
|
||||
@@ -493,9 +493,9 @@ Storage defaults to `$XDG_DATA_HOME/vamp/reviews/reviews.sqlite3`, or `~/.local/
|
||||
|
||||
Write errors, locked databases, incompatible schemas, and conflicting edits from another editor instance retain dirty drafts and report the failure. Failed text saves leave the committed review unchanged; unrelated metadata autosaves cannot commit those drafts. Normal destructive closes remain guarded until drafts are explicitly saved or discarded. `:w!` does not bypass database revision conflicts; export your draft before reopening the current stored review. JSON exports retain external-file-change protection. Only the current database schema is accepted; existing incompatible databases are preserved rather than reset or migrated.
|
||||
|
||||
The current SQLite format is schema 2: typed `reviews` and `comments` tables, not serialized JSON documents. Schema 1 databases are incompatible and are left untouched; there is no migration or automatic reset. JSON version 3 remains the sharing format, independent of the database schema.
|
||||
The current SQLite format is schema 3: typed `reviews`, `comments`, and `reviewed_files` tables, not serialized JSON documents. Older databases are incompatible and are left untouched; there is no migration or automatic reset. JSON version 4 is the sharing format, independent of the database schema.
|
||||
|
||||
Version 3 JSON is the agent-readable sharing format: repository root, summary, optional verdict, and comments with stable IDs, bodies, required boolean `resolved` states, and anchors. New comments are unresolved. Database review IDs and optimistic storage revisions stay internal. Each anchor retains its immutable comparison revision, side, relative path (old path for renamed Before files), and exact whole-file text including the final newline. `start` and `end` contain zero-based source `row` and extended-grapheme `column` coordinates; `end` is exclusive. Columns count complete Unicode graphemes, not bytes, code points, UTF-16 units, or screen cells. Overview/window labels display one-based rows and columns. Older JSON formats, including version 2, are rejected and preserved without migration. Working comparisons use content-addressed snapshot IDs; captured text additionally freezes live unsaved edits. Stored reviews have a 64 MiB aggregate text budget including 64 bytes of overhead per comment; imported/exported JSON files have a separate 64 MiB serialized-size limit.
|
||||
Version 4 JSON is the agent-readable sharing format: repository root, summary, optional verdict, comments, and a required `reviewed_files` array. Each reviewed file stores its immutable `revisions` pair, relative `path`, optional rename `old_path`, and optional exact live `after` text. Comments have stable IDs, bodies, required boolean `resolved` states, and anchors. New comments are unresolved. Database review IDs and optimistic storage revisions stay internal. Each anchor retains its immutable comparison revision, side, relative path (old path for renamed Before files), and exact whole-file text including the final newline. `start` and `end` contain zero-based source `row` and extended-grapheme `column` coordinates; `end` is exclusive. Columns count complete Unicode graphemes, not bytes, code points, UTF-16 units, or screen cells. Overview/window labels display one-based rows and columns. Older JSON formats are rejected and preserved without migration. Working comparisons use content-addressed snapshot IDs; captured text additionally freezes live unsaved edits. Stored reviews have a 64 MiB aggregate text budget including 64 bytes of overhead per comment and reviewed file; imported/exported JSON files have a separate 64 MiB serialized-size limit.
|
||||
|
||||
Reopening requires the same repository root. Comments whose revision, path, or exact file text no longer matches are **stale**: their original anchors remain unchanged and their gutter markers disappear. Unloaded files are shown as **not checked** until visited; refresh the overview to update its statuses. There is no automatic reanchoring, server, authentication, or review-publishing operation.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user