Skip to main content

Module subsystem

Module subsystem 

Source
Expand description

D.2.a / D.2.b / D.2.c — DiffSubsystem.

Registry + compute + routing layer for the diff subsystem. Sessions are Arc-shared so consumers (the future inline overlay D.3, side-by-side D.4, hunk-transfer ops D.5, :describe-diff D.2.d) can hold a stable handle while the registry continues to mutate around them.

§Slice landing order

§Concurrency model

  • Registry / descriptor / watchers / debouncer mutation goes through std::sync::Mutex. Mutation is buffer-open / buffer-close / lazy-debouncer-spawn frequency — never per-frame.
  • Per-session published hunks: ArcSwap<HunkIndex> is read lock-free from any thread (the renderer, :describe-diff, etc.).
  • The session’s Arc itself is cloned out of the registry under the registry lock, then released. Holders may keep the Arc past a drop_session call — the registry forgets the entry, but in-flight readers see a coherent snapshot until they release their clone (RCU). Matches the standard BufferRegistry / cells_matrix_cell pattern in this crate.
  • Bus subscription is centralized (one subscription on the subsystem; one drainer task). On each DocumentChanged the drainer resolves DocumentId → BufferId, looks up dependents in the watchers inverse index, and pokes each session’s Debouncer. The per-session debouncer is lazy — no task at rest; a tokio task spawns on first poke, sleeps the debounce window, and self-terminates after the burst quiesces. Rationale + scaling discussion in §3.4.

Structs§

BufferSource
D.8.b (2026-05-31): live-rope participant backed by a buffer. Replaces the prior BufferSource + BufferSource two-struct split (both had identical shape — provider + buffer_id — and only differed in which trait they implemented). The trait collapse to DiffParticipantSource makes the split structurally redundant.
Debouncer
Per-session debounce controller.
DiffDescriptor
The “what to diff against what” pair for a session.
DiffGetPlan
D.5.b (2026-05-30): describes the edit the diff-mode do (diff-get) operator would apply when invoked at a given cursor row on the active side of a session. Produced by DiffSubsystem::compute_get_edit; consumed by dispatch which translates it into an apply_edit_blocking call and re-positions the cursor.
DiffSession
Per-document diff state. Wraps an ArcSwap<HunkIndex> so consumers read the latest published hunks without holding the registry lock.
DiffSessionDescription
One row of :describe-diff output. Produced by DiffSubsystem::describe_sessions and rendered into the help-buffer body by DiffSubsystem::build_describe_diff_content.
DiffSubscriptionGuard
RAII guard returned by DiffSubsystem::bind. Holds the bus SubscriptionId + the drainer task JoinHandle. On Drop, unsubscribes the bus subscription and aborts the drainer task.
DiffSubsystem
Process-wide registry + routing layer for diff sessions.
OnDiskSource
D.3.a (2026-05-29): on-disk file participant source.
StaticSource
In-memory participant source — an owned Rope cloned on every Self::snapshot.

Enums§

DiffGetOutcome
D.6.d (2026-05-31): outcome of resolving the diff-mode do chord or :diffget [<bufnr>] ex-command. Mirrors DiffPutOutcome’s tri-state but for the get direction:
DiffOutcome
D.6.e (2026-05-31): resolution signal fired through a DiffSession’s completion channel when the user invokes :diff-accept / :diff-reject. Consumed by the future openDiff plugin flow (Claude Code, AI multi-file edits) and by any in-tree consumer (magit plugin, AI proposals) that wants to know how the user resolved a session.
DiffPutOutcome
D.5.c (2026-05-30) / D.6.d (2026-05-31): outcome of resolving the diff-mode dp chord or :diffput [<bufnr>] ex-command. Distinguishes four cases the dispatch handler must surface differently:
MembershipError
D.8.d (2026-05-31): errors the subsystem’s membership API returns when mutating a session’s participant set. Distinct from [DiffEngineError] (which is the engine crate’s surface) so callers don’t have to import lattice_diff just to pattern-match on add_participant failures. The engine’s cap on arity (N ≥ 4 rejected in v1) surfaces here as EngineRejected(DiffEngineError::Unsupported{...}).

Constants§

DEFAULT_DEBOUNCE_WINDOW
Default debounce window. Matches Helix’s diff debounce (50ms); short enough that the visual lag is imperceptible during sustained typing, long enough that a burst of 5–10 keystrokes collapses to a single recompute. Overridable via DiffSubsystem::with_debounce_window for tests and host configuration.

Traits§

BufferTextProvider
One-trait seam between the diff subsystem and the host’s buffer storage. Required for BufferSource to resolve a [BufferId] to its live rope at snapshot time.
DiffParticipantSource
One participant in a diff session — produces the rope to diff for one slot in Hunk::ranges.
DocumentBufferResolver
Translates the protocol-layer [DocumentId] carried in Event::DocumentChanged / Event::DocumentClosed back to a host-layer [BufferId]. The host supplies an impl backed by BufferRegistry. Kept as a trait so the subsystem stays independent of buffer-registry layout (and so tests can inject a stub mapping).

Type Aliases§

DiffSubsystemHandle
Cheap-clone service handle for the diff subsystem. DX.3/C7 (BC.6): registered in the ServiceRegistry at boot so diff-mode’s on_activate can reach the session for a buffer (ctx.service::<DiffSubsystemHandle>()) and register a HunkFoldSource via the FoldOverlayService — mirroring how MultibufferMode reaches its MultibufferRegistryHandle. Follows the Arc/TypeId convention: register Arc<DiffSubsystem>, look up Arc<DiffSubsystem>.