Skip to main content

DiffSession

Struct DiffSession 

Source
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

Source

pub fn new(buffer_id: BufferId, algorithm: DiffAlgorithm) -> DiffSession

Public constructor used by both DiffSubsystem::register and tests. Starts with an empty HunkIndex tagged with the session’s algorithm.

Source

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).

Source

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).

Source

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.

Source

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.

Source

pub fn pane_group_id(&self) -> Option<PaneGroupId>

Source

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.

Source

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.

Source

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.

Source

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).

Source

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()).

Source

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.

Source

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.

Source

pub fn buffer_id(&self) -> BufferId

Source

pub fn algorithm(&self) -> DiffAlgorithm

Source

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).

Source

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.

Source

pub fn allocate_revision(&self) -> u64

D.2.b: allocate a fresh revision tag. Monotonically increasing; one tag per recompute.

Source

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.

Source

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.

Source

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§

Source§

impl Debug for DiffSession

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync> ⓘ

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<T> IntoMaybeUndefined<T> for T

§

fn into_maybe_undefined(self) -> MaybeUndefined<T>

Converts this value into a three-state builder argument.
§

impl<T> IntoOption<T> for T

§

fn into_option(self) -> Option<T>

Converts this value into an optional builder argument.
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> Pointee for T

§

type Pointer = u32

§

fn debug( pointer: <T as Pointee>::Pointer, f: &mut Formatter<'_>, ) -> Result<(), Error>

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more