pub struct DiffSession { /* private fields */ }Expand description
Per-document diff state. Wraps an ArcSwap<HunkIndex> so
consumers read the latest published hunks without holding the
registry lock.
Construction goes through DiffSubsystem::register; direct
instantiation is fine for unit tests but bypasses the registry.
Implementations§
Source§impl DiffSession
impl DiffSession
Sourcepub fn new(buffer_id: BufferId, algorithm: DiffAlgorithm) -> Self
pub fn new(buffer_id: BufferId, algorithm: DiffAlgorithm) -> Self
Public constructor used by both DiffSubsystem::register
and tests. Starts with an empty HunkIndex tagged with the
session’s algorithm.
Sourcepub fn bind_pane_group(&self, id: PaneGroupId)
pub fn bind_pane_group(&self, id: PaneGroupId)
D.4.d.3.a (2026-05-30): bind a PaneGroup to this
session — call once at two-pane session creation,
before any wake or read. Subsequent calls overwrite
(a re-binding scenario isn’t expected in v1 but is
safe).
Sourcepub fn bind_completion(&self, tx: Sender<DiffOutcome>)
pub fn bind_completion(&self, tx: Sender<DiffOutcome>)
D.4.d.3.a: read the linked PaneGroupId, if any.
None for inline :diff sessions; Some(id) for
two-pane sessions registered via :diffthis /
:diffsplit. The teardown path (do_diff_off)
reads this to drop the linked group atomically with
the session.
D.6.e (2026-05-31): bind a DiffOutcome one-shot
sender to this session. Called once after
registration by callers (openDiff plugin flow,
magit-style consumers) that want to be notified
when the user resolves the session via
:diff-accept / :diff-reject. Subsequent binds
overwrite (a re-bind scenario isn’t expected in v1
but is safe — the previous sender is dropped, so
any awaiting receiver observes a Closed error,
matching the typical “session superseded” UX).
Sourcepub fn take_completion(&self) -> Option<Sender<DiffOutcome>>
pub fn take_completion(&self) -> Option<Sender<DiffOutcome>>
D.6.e (2026-05-31): take the bound DiffOutcome
sender, if any. Single-shot: returns Some on the
first call after a bind_completion; subsequent
calls return None. Used by the
do_diff_accept / do_diff_reject teardown path
to fire the signal before dropping the session.
Sourcepub fn awaits_outcome(&self) -> bool
pub fn awaits_outcome(&self) -> bool
True while a completion sender is still bound — i.e. this session is a
programmatic/agent review awaiting a :diff-accept / :diff-reject
verdict (set by Self::bind_completion, cleared by
Self::take_completion at teardown). :diff-accept / :diff-reject
use this (via DiffSubsystem::sessions_awaiting_outcome) to resolve a
pending review even when focus isn’t on the diff pane, so a verdict
typed from the :claude terminal still reaches the agent.
pub fn pane_group_id(&self) -> Option<PaneGroupId>
Sourcepub fn sign_map(&self) -> Arc<DiffSignMap> ⓘ
pub fn sign_map(&self) -> Arc<DiffSignMap> ⓘ
D.3.d.0 (2026-05-29): snapshot the latest published
DiffSignMap. Lock-free ArcSwap::load_full; renderer
hot path. The map is refreshed in lockstep with
hunks by crate::overlay::DiffOverlayRefreshTask.
Sourcepub fn publish_sign_map(&self, map: Arc<DiffSignMap>)
pub fn publish_sign_map(&self, map: Arc<DiffSignMap>)
D.3.d.0: publish a freshly-computed sign map.
Unconditional store (no revision gate) — the
DiffOverlayRefreshTask already serialises map
updates with hunks publishes, so out-of-order
landing isn’t possible from the refresh-task side.
Direct callers (tests, future consumers) bear the
ordering responsibility.
Sourcepub fn baseline_sign_map(&self) -> Arc<DiffSignMap> ⓘ
pub fn baseline_sign_map(&self) -> Arc<DiffSignMap> ⓘ
D-fix.3b: snapshot the latest published BASELINE-side sign map
(the left/baseline pane of a side-by-side diff). Lock-free
ArcSwap::load_full; renderer hot path. Empty for inline :diff.
Sourcepub fn slot_line_count(&self, slot: usize) -> Option<u32>
pub fn slot_line_count(&self, slot: usize) -> Option<u32>
D-fix.5 (2026-06-26): the line count of the rope at slot that
produced the latest published HunkIndex. None if no recompute
has published yet (the slot vector is empty) or slot is out of
range. The UnchangedFoldSource for a buffer at this slot reads
it to bound the complement-of-hunks computation to [0, line_count).
Sourcepub fn publish_slot_line_counts(&self, counts: Vec<u32>)
pub fn publish_slot_line_counts(&self, counts: Vec<u32>)
D-fix.5: publish the per-slot line counts in lockstep with the
hunks. Called by Self::recompute_blocking from the rope
slice it just diffed (slot i ⇒ sources[i].len_lines()).
Sourcepub fn publish_baseline_sign_map(&self, map: Arc<DiffSignMap>)
pub fn publish_baseline_sign_map(&self, map: Arc<DiffSignMap>)
D-fix.3b: publish a freshly-computed baseline-side sign map.
Stored in lockstep with publish_sign_map by recompute_blocking.
Sourcepub fn publish_notify(&self) -> Arc<Notify> ⓘ
pub fn publish_notify(&self) -> Arc<Notify> ⓘ
D.3.a.1: shared Notify fired on every successful
publish. The :diff handler clones this and awaits
notified() in a forwarder task to wake the
virtual_rows_worker immediately on hunk republish.
pub fn buffer_id(&self) -> BufferId
pub fn algorithm(&self) -> DiffAlgorithm
Sourcepub fn current_hunks(&self) -> Arc<HunkIndex> ⓘ
pub fn current_hunks(&self) -> Arc<HunkIndex> ⓘ
Snapshot the latest published hunks. Lock-free; returns a
fresh Arc whose contents are stable for the holder’s
lifetime (RCU semantics).
Sourcepub fn publish(&self, hunks: Arc<HunkIndex>)
pub fn publish(&self, hunks: Arc<HunkIndex>)
Publish a freshly-computed HunkIndex unconditionally.
D.2.a kept this as the simple “replace published” path
for tests; D.2.b’s recompute path prefers
Self::try_publish_if_newer for monotonic ordering
under concurrent spawn_blocking completion.
D.3.a.1: fires publish_notify so the diff-overlay
wake forwarder observes the publish.
Sourcepub fn allocate_revision(&self) -> u64
pub fn allocate_revision(&self) -> u64
D.2.b: allocate a fresh revision tag. Monotonically increasing; one tag per recompute.
Sourcepub fn peek_next_revision(&self) -> u64
pub fn peek_next_revision(&self) -> u64
D.2.b: peek the next revision the session would allocate. Test-friendly; does not consume the slot.
Sourcepub fn try_publish_if_newer(&self, idx: Arc<HunkIndex>) -> bool
pub fn try_publish_if_newer(&self, idx: Arc<HunkIndex>) -> bool
D.2.b: publish idx only if its revision strictly exceeds
the currently-published revision. Returns true on take,
false if the publish was dropped as stale.
Preserves monotonic ordering when multiple recomputes run
concurrently on spawn_blocking and may finish out of
order. The rcu loop retries internally on contention; the
took flag captures whichever decision the winning
closure invocation made.
Sourcepub fn recompute_blocking(&self, sources: &[Rope]) -> Option<Arc<HunkIndex>>
pub fn recompute_blocking(&self, sources: &[Rope]) -> Option<Arc<HunkIndex>>
D.2.b / D.6.a / D.8.c: synchronous recompute.
Allocates a revision, runs the diff engine via
compute_diff over the participant ropes, builds a
HunkIndex stamped with the allocated revision + the
session’s algorithm, and publishes via the
revision-gated path.
sources is an N-slot rope slice in slot order
(slot i feeds Hunk::ranges[i]). The engine picks the
algorithm by sources.len(): N=2 → two-way, N=3 →
three-way with Conflict semantics, N≥4 →
DiffEngineError::Unsupported (recompute drops with a
debug log; mirrors the stale-publish drop semantic).
D.8.c (2026-05-31): signature rewritten from
(baseline: &Rope, current: &Rope, remote: Option<&Rope>) to (sources: &[Rope]). Callers
iterate the descriptor’s sources and snapshot each
rope into a Vec passed here.
Returns Some(idx) on successful publish, None if a
newer revision was already published (stale result
dropped) or the engine rejected the participant set.
This is the body the
DiffSubsystem::schedule_recompute
spawn_blocking closure executes; tests call it
directly to exercise the compute path without tokio.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for DiffSession
impl RefUnwindSafe for DiffSession
impl Send for DiffSession
impl Sync for DiffSession
impl Unpin for DiffSession
impl UnsafeUnpin for DiffSession
impl UnwindSafe for DiffSession
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more