feat: show diff hunk scope labels

Show per-side Tree-sitter scope paths inline and as sticky continuation labels.
Keep presentation rows out of source coordinates, selections, and edits.

Verified: cargo test (949 passed), cargo build, and real PTY smoke covering
split/unified, wrapping, both split axes, sticky scrolling, live rename and undo.

Size exception: 549 implementation lines added plus deleted, excluding tests
and docs. Keep syntax extraction and coordinate-safe rendering together as one
working behavior.
This commit is contained in:
Valdemar Lorenzen
2026-10-15 14:15:05 +02:00
parent 75dc31b66f
commit a43094dda3
5 changed files with 958 additions and 68 deletions
+2
View File
@@ -104,6 +104,8 @@ Each buffer has a frontend-owned parser/tree cache. Unchanged revision/path skip
Diff highlighting lazily owns two instances of the same syntax cache, keyed by the accepted comparison request ID and selected file. Before detects language from the old path when renamed; After uses the new path. Scrolling, focus changes, and explorer toggling reuse parsed spans without copying/reparsing snapshots. A fresh comparison identity prevents stale Working-checkout colors even when labels and paths are unchanged. Closing the view releases snapshot caches. Syntax styles patch foreground/modifiers over diff backgrounds; historical panes never receive live-buffer semantic tokens.
Scope context is a lazily built row index over the existing primary/injected syntax trees, invalidated by source or grammar changes and warmed by diff updates. Ordinary buffer highlighting does not build it. The frontend's visual-row projection inserts inline/sticky scope labels in wrapped and unwrapped diffs; source alignment and excerpt ranges contain no label rows. Coloring, native selection/caret overlays, and source navigation skip these presentation rows. Before/After labels use their independent trees rather than live-workspace symbol analysis.
## Clipboard providers
macOS publishes `public.utf8-plain-text` through the native Pasteboard Manager, checking allocation and OS-status failures before reporting success. Publication is synchronous and avoids per-copy interpreter/process startup; native calls do not have a subprocess deadline. Reads retain fixed JXA/AppKit `NSPasteboardTypeString` access through `osascript`. Both paths preserve literal RTF/EPS text rather than treating it as rich clipboard data. Linux supports Wayland with `wl-paste`/`wl-copy`, or X11 with `xclip`, on PATH with the corresponding display environment. Other platforms report unsupported access. Subprocess-backed access has a two-second deadline and bounded output; failures terminate/reap the process group.
+2
View File
@@ -438,6 +438,8 @@ Review marks belong only to the open comparison and survive filtering, file navi
Text panes show change excerpts with **10 unchanged lines above and below** each change, preserving original file line numbers. Overlapping or touching excerpts merge; omitted stretches show an unchanged-line count in both panes. Files with only metadata changes show their notice or “No text changes” rather than unrelated source.
**Scope labels** identify named enclosing functions/classes and containers, such as `impl Review › run`. Muted, unnumbered rows appear at excerpt starts and scope changes; the current scope stays at the top when its declaration scrolls out of view. Each split side uses its own source, so renamed functions keep distinct old/new names. Unified labels use `−` for Before, `+` for After, and `±` for shared names. Narrow panes prefer the innermost name. Labels are presentation only: motions, selections, copying, editing, and line jumps retain original source coordinates. Context comes from the existing Tree-sitter trees, including supported injected code, without requiring an LSP; unsupported syntax gets no guessed label.
In **Normal mode** with a text pane focused, **`[` expands above** and **`]` expands below** the excerpt containing the caret, revealing up to **15 lines** per keypress in either pane. In editable After's Insert mode these keys insert literal text. Expansion clamps at file boundaries and merges excerpts when they meet. Existing visible source stays anchored. Opening a file resets its excerpts to the configured initial context. Live edits recompute changes while retaining expanded context; the caret stays visible even when the last text change is reverted.
Live typing highlights only the displayed source rows while retaining each snapshot's original syntax tree for multiline and injected-language context. Line-width caches and unchanged hunk layouts avoid repeated full-file work; edits that change line alignment or revert changes recompute the diff. Already-queued printable Insert keys share a redraw, but every key still passes through normal bindings, snippet handling, and undo history. Mode changes and other terminal events retain their order.