feat: anchor review comments to precise text ranges
This commit is contained in:
@@ -17,6 +17,7 @@ One editor crate; the workspace also includes its patched Crossterm dependency.
|
||||
- `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 versioned local JSON review documents, immutable source anchors, validation, bounded reads, and atomic writes with external-change protection. It has no terminal or network operations. Comparison state owns the active review; `editor_review` keeps native comment/summary buffers and the read-only overview attached to their owning tab, synchronizes drafts on review commands, and guards unsaved teardown. The floating review editor has a tab-owned native pane outside the workspace `PaneTree`; rendering overlays it on the diff owner's rectangle without changing the source layout. Dismissal retains drafts and restores source focus. Working snapshot IDs hash the private captured paths, modes, contents, and notices; anchors also retain exact file text to account for live edits without reanchoring.
|
||||
Version 2 anchors use the existing `plugin::TextPosition` type for zero-based grapheme start/end positions with an exclusive end. The JSON loading boundary migrates strict version 1 line-only records into this model while retaining the original disk bytes for external-write checks. Live code has no legacy coordinate aliases. Selected-comment painting reuses source-side grapheme clipping and wrapping; native selections retain higher priority.
|
||||
- `clipboard`: owns native plain-text provider selection and bounded subprocess I/O; it never computes selections or editing offsets.
|
||||
- `syntax`: owns Tree-sitter grammar detection, per-buffer incremental trees, bundled highlight/local/injection queries, and syntax byte spans; it has no terminal color/geometry or editing dependency.
|
||||
- `markdown`: owns native Markdown link/reference resolution, local destination decoding, and heading fragment lookup through the installed block/inline grammars. It has no editor lifecycle, terminal, LSP, or external-process dependency.
|
||||
|
||||
@@ -39,6 +39,7 @@ Rust tests live alongside their modules; native LSP integration checks are in [`
|
||||
- Editor checks cover Unicode editing, multi-target state, undo/redo, saving failures, and modal paste acceptance and rejection atomicity.
|
||||
- Visual-command checks preserve directed characterwise/linewise ranges and multiple carets through command cancellation and plugin dispatch, exercise remapped command entry, and submit `:diff.comment` on either historical side. Live PTY smoke selects lines, cancels a prompt, then runs `:diff.comment` directly and verifies the saved original range without using the palette.
|
||||
- Presentation regressions render retained characterwise/linewise highlights during command entry in ordinary, split-diff, and unified views. Floating-review checks preserve source rectangles and the workspace layout, place the caret inside the overlay, retain dismissed drafts across tab switches, and restore source focus on Escape or pane close. Live PTY smoke edits, dismisses, reopens, and saves a floating comment and summary before returning to the unchanged diff.
|
||||
- Precise-range checks cover forward/reversed characterwise and partial-multiline selections on both sides, linewise and caret/empty-line fallbacks, source-column navigation, Unicode grapheme bounds, strict v1-to-v2 JSON migration, invalid/mixed schemas, and preserved save-conflict checks. Render checks cover exact text/newline cells, wrapping, horizontal clipping, shared unified context, stale suppression, and native Visual precedence. Live PTY smoke saves a selection containing a wide and combining grapheme, then imports and rewrites a legacy line-only review without changing its body.
|
||||
- Markdown navigation checks cover inline/reference destinations, escaped/percent-encoded paths, heading markup and duplicates, same-document fragments, dirty target reuse, failed navigation atomicity, primary-only following, and `gf` prefix cancellation/configuration overrides.
|
||||
- Jump-history checks cover cross-buffer/same-document navigation, search and picker recording, counts and repeated visits, bounded history, branch truncation, closed buffers, edited-coordinate clamping, dirty text/undo preservation, independent Ctrl+i/Tab bindings, and custom bindings. Diff checks exercise Ctrl+i on either side in split/unified views, both control-letter and modified-Tab terminal events, and plain Tab pane cycling. Real LSP fixtures cover definition round-trips and delayed replies after leaving and returning to the same source location.
|
||||
- Tab checks cover shared edits/history with independent pane layouts, focused views, explorers and viewports; cross-tab close guards, immutable snapshots, hidden comparison refresh/result routing, and separate repository workers. Rendered checks cover sanitized/dirty titles, active-tab visibility in narrow terminals, overlay row reservation, and exclusion of hidden diff geometry from palette polling and viewport reporting.
|
||||
|
||||
+4
-4
@@ -452,13 +452,13 @@ Collapsed folders show a green **`✓`** when every changed file beneath them is
|
||||
|
||||
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.
|
||||
|
||||
**Local review comments** are independent of GitHub and the file-reviewed checkmarks above. Focus either diff text pane and run **`:diff.comment`** to comment at the caret. For a range, make one Visual or Visual Line selection, then type **`:diff.comment`** and press Enter. The palette and configured Visual-mode bindings also work. Multiple independent carets/ranges must be reviewed separately.
|
||||
**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.
|
||||
|
||||
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; drafts remain available for reopening and saving. Insert/Visual/Command Escape first retains its usual modal behavior. Source rows are never replaced with comment text. Magenta **`○`** gutter markers identify current comment ranges; **`●`** identifies the selected comment. Markers preserve addition/deletion signs, appear only on the first wrapped segment, and also work in unified view.
|
||||
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; drafts remain available for reopening and saving. Insert/Visual/Command Escape first retains its usual modal behavior. Source rows are never replaced with comment text. Magenta **`○`** gutter markers identify 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.
|
||||
|
||||
| Command | Effect |
|
||||
| --- | --- |
|
||||
| `:diff.comment` | Add a comment on the current side and caret/selected line range |
|
||||
| `:diff.comment` | Add a comment on the current line or exact selected text range, on the focused side |
|
||||
| `:diff.review.edit [id]` | Edit an existing comment; defaults to the overview entry under the caret or selected comment |
|
||||
| `:diff.review.delete [id]` | Delete that draft comment |
|
||||
| `:diff.review.next` / `:diff.review.previous` | Cycle comments, opening their text and revealing a matching source anchor |
|
||||
@@ -471,7 +471,7 @@ Comments, summaries, and the review overview open in a focused floating editor o
|
||||
|
||||
In a review text pane, **`:w` saves the entire review**, not a source file. Choose a destination with `:diff.review.save path` first, or use `:w path`. Saving includes edits in hidden comment/summary buffers. Normal close, quit, restart, comparison replacement, and source-buffer deletion protect unsaved reviews; forced close/quit retains its explicit discard semantics. An externally changed review file is never silently overwritten, including with `:w!`; use a new path or reopen it after preserving your edits.
|
||||
|
||||
The versioned JSON is the canonical, agent-readable artifact: repository root, summary, optional verdict, and comments with stable IDs, bodies, and anchors. Each anchor retains its immutable comparison revision, side, relative path (old path for renamed Before files), inclusive one-based line range, and exact whole-file text including the final newline. Working comparisons use content-addressed snapshot IDs; captured text additionally freezes any live unsaved edits. The file is limited to 64 MiB. Prefer saving outside the checkout so the review itself does not become another changed file.
|
||||
Version 2 JSON is the canonical, agent-readable artifact: repository root, summary, optional verdict, and comments with stable IDs, bodies, and anchors. 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. Existing version 1 line-only reviews load as equivalent whole-line spans, preserving IDs, text, verdicts, and snapshot identity; the next explicit save writes version 2. Working comparisons use content-addressed snapshot IDs; captured text additionally freezes live unsaved edits. The file limit remains 64 MiB. Prefer saving outside the checkout so the review itself does not become another changed file.
|
||||
|
||||
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