Skip to main content

Session

Struct Session 

Source
pub struct Session { /* private fields */ }
Expand description

A session is a named editing context.

Sessions hold the kernel state (buffers, options, etc.) and can have multiple clients attached. Think of it like a tmux session.

§Client Management (Phase 11.2)

The session tracks connected clients via two maps:

  • clients: Role and editing state ownership (Owner/Follow/Share)
  • presence: Display preferences and cursor positions (for rendering)

Implementations§

Source§

impl Session

Source

pub fn new(id: SessionId) -> Self

Create a new session with the given ID.

Source

pub fn from_state(id: SessionId, state: SessionState) -> Self

Create a new session with a custom state.

This allows the runner to inject module-initialized registries into sessions. The state should be created with populated registries from module initialization.

§Example
use reovim_server::{Session, SessionId, SessionState};

// Create state with populated registries from modules
let state = SessionState::with_registries(
    kernel, initial_mode, vfs,
    mode_registry, command_registry, keymap_registry, resolver_registry,
    compositor,
);

let session = Session::from_state(SessionId::new("main"), state);
Source

pub fn subscribe_notifications(&self) -> Receiver<Notification>

Subscribe to notifications (gRPC only).

Returns a receiver for the notification broadcast channel. Used by NotificationService to stream updates to clients.

Source

pub fn emit_notification(&self, notification: Notification)

Emit a notification to all subscribers (gRPC only).

Sends a notification to all connected clients via the broadcast channel. If no clients are subscribed, the notification is silently dropped.

Source

pub const fn capture_tracker(&self) -> &CaptureTracker

Get the capture tracker for CLI→Server→TUI→Server→CLI relay (gRPC only).

Source

pub const fn presence(&self) -> &PresenceMap

Get the presence map for multi-client tracking (Phase 14, gRPC only).

Source

pub fn add_client(&self, client_id: ClientId)

Add a client to the session as independent.

New clients default to independent (no relation) with their own editing state. The client’s mode stack is initialized with the session’s home mode. The client’s windows are initialized with the session’s active buffer. Call set_client_relation() to change to Following/Sharing.

§Per-Client Windows (#471)

Each client gets their own WindowLayout with independent cursors. If the session has an active buffer, a window is created for it.

Source

pub fn add_client_with_metadata( &self, client_id: ClientId, metadata: ClientMetadata, )

Add a client with metadata.

Creates an independent client with the given metadata. This is the preferred method for gRPC handlers that have client info.

Source

pub fn add_client_with_state(&self, client: Client)

Add a client with a specific initial state.

Used for restoring clients or creating clients with pre-configured state.

Source

pub fn remove_client(&self, client_id: ClientId) -> Option<Client>

Remove a client from the session.

Returns the removed client if found.

§Debug Infrastructure (#481)

Before removing a client, this method dumps the client’s ring buffer to a file at ~/.local/share/reovim/crash/client-{id}-{timestamp}.log for post-mortem analysis. A CLIENT_DISCONNECT entry is logged to the server ring buffer with the dump file path.

Source

pub fn get_client(&self, client_id: ClientId) -> Option<Client>

Get a client’s role (immutable).

Source

pub fn set_client_relation( &self, client_id: ClientId, relation: Option<ClientRelation>, ) -> Result<(), TransitionResult>

Set a client’s relation with validation.

Use this to change between Independent/Following/Sharing modes. Pass None for independent, Some(ClientRelation::Following { target }) for following, or Some(ClientRelation::Sharing { with }) for sharing.

§Validation

Validates the transition:

  • Cannot target self
  • Target must exist
  • Cannot create cycles (A → B → A)
  • Following → Sharing upgrade may require cursor sync (returns RequiresCursorSync)
§Errors

Returns Err(TransitionResult) if:

  • Client not found (TargetNotFound)
  • Attempting to target self (CannotTargetSelf)
  • Change would create a cycle (WouldCreateCycle)
  • Following → Sharing requires cursor sync first (RequiresCursorSync)
Source

pub fn set_client_relation_unchecked( &self, client_id: ClientId, relation: Option<ClientRelation>, ) -> bool

Set a client’s relation without validation.

Use sparingly - prefer set_client_relation() for safety. This is useful for initialization where validation isn’t needed.

§Returns

true if the client was found and relation set, false otherwise.

Source

pub fn sync_and_set_relation( &self, client_id: ClientId, target_id: ClientId, relation: Option<ClientRelation>, ) -> Result<(), TransitionResult>

Sync cursor and set relation.

Use this when set_client_relation() returns RequiresCursorSync. This syncs the cursor first, then sets the relation.

§Errors

Returns Err(TransitionResult) if:

  • Client or target not found (TargetNotFound)
  • Attempting to target self (CannotTargetSelf)
  • Change would create a cycle (WouldCreateCycle)
Source

pub fn client_state(&self, client_id: ClientId) -> Option<EditingState>

Get the effective editing state for a client.

  • Owner: Returns own state
  • Follow: Returns target’s state (read-only access)
  • Share: Returns owner’s state (for display)

Returns None if client not found or target chain is broken.

Source

pub fn update_client_state<F>(&self, client_id: ClientId, f: F) -> bool
where F: FnOnce(&mut EditingState),

Update a client’s editing state via closure.

  • Independent: Updates own state
  • Following: No-op (input ignored)
  • Sharing: Updates target’s state

Returns true if state was updated.

Source

pub fn with_clients<F, R>(&self, f: F) -> R
where F: FnOnce(&HashMap<ClientId, Client>) -> R,

Execute a closure with read access to the clients map.

Source

pub fn with_clients_mut<F, R>(&self, f: F) -> R
where F: FnOnce(&mut HashMap<ClientId, Client>) -> R,

Execute a closure with write access to the clients map.

Source

pub fn with_client_extensions<F, R>( &self, client_id: ClientId, f: F, ) -> Option<R>
where F: FnOnce(&ExtensionMap) -> R,

Run a closure on a client’s ExtensionMap without cloning.

EditingState::clone() creates an empty ExtensionMap because Box<dyn SessionExtensionDyn> is not Clone. This method provides direct read access to extensions through the clients lock.

Respects Follow/Share relations via effective_state().

Source

pub fn with_client_extensions_mut<F, R>( &self, client_id: ClientId, f: F, ) -> Option<R>
where F: FnOnce(&mut ExtensionMap) -> R,

Run a closure with mutable access to a client’s ExtensionMap.

Used by bridge lifecycle hooks that need to mutate per-client state (e.g., auto-dismiss on mode change). Respects Follow/Share relations via find_input_target.

Returns None if the client doesn’t exist or input is ignored (Following).

Source

pub fn with_tick_mut<F, R>(&self, client_id: ClientId, f: F) -> Option<R>
where F: FnOnce(&mut ExtensionMap, &mut ExtensionMap, &ServiceRegistry) -> R,

Execute a tick closure with mutable access to client + shared extensions (#546).

Lock order: clients (write) → state (write). Same order as resolve_key_for_client. Returns None if client not connected or input is ignored (Following).

Used by TokioTickScheduler for periodic state advancement.

Source

pub fn client_count(&self) -> usize

Get count of connected clients.

Source

pub fn has_client(&self, client_id: ClientId) -> bool

Check if a client is connected.

Source

pub const fn id(&self) -> &SessionId

Get the session ID.

Source

pub async fn with_state<F, R>(&self, f: F) -> R
where F: FnOnce(&SessionState) -> R,

Execute a closure with read access to the session state.

This is the primary way to query session data.

Note: Currently synchronous but kept async for future I/O operations.

Source

pub async fn with_state_mut<F, R>(&self, f: F) -> R
where F: FnOnce(&mut SessionState) -> R,

Execute a closure with write access to the session state.

Use this for mutations like inserting text, moving cursor, etc.

Note: Currently synchronous but kept async for future I/O operations.

Source

pub fn with_state_sync<F, R>(&self, f: F) -> R
where F: FnOnce(&SessionState) -> R,

Synchronous read access (for contexts where async isn’t needed).

Source

pub fn with_state_mut_sync<F, R>(&self, f: F) -> R
where F: FnOnce(&mut SessionState) -> R,

Synchronous write access.

Source

pub fn with_bridge_context<F, R>(&self, client_id: ClientId, f: F) -> Option<R>

Execute a closure with combined read access to a client’s extensions, shared extensions, and pre-collected opponent extension maps (#543).

Acquires locks in established order: clients (read) first, then state (read). Resolves effective_state() for all clients to collect opponent data as driver-layer ClientId + &ExtensionMap pairs.

Returns None if client_id is not connected or has no effective state.

Source

pub async fn resolve_key_for_client( &self, client_id: ClientId, key: &KeyEvent, ) -> Option<(ResolveResult, StateChanges)>

Resolve a key with per-client mode stack (#471).

This method provides access to both session state AND per-client mode stack, enabling multi-client mode isolation. The key is resolved using the client’s mode stack instead of the shared session mode stack.

§Arguments
  • client_id - Client ID to resolve for
  • key - Key event to resolve
§Returns
  • Some((ResolveResult, StateChanges)) - if key was resolved
  • None - if client not found, client is Following, or no resolver
§Relation Behavior
  • Independent: Uses own mode stack and windows
  • Following: Returns None (input ignored)
  • Sharing: Uses target’s mode stack and windows
Source

pub async fn try_on_command_complete_for_client( &self, client_id: ClientId, ) -> Option<ModeTransition>

Try on_command_complete with per-client state (#471, #477).

Like resolve_key_for_client, but for post-command mode transitions.

Source

pub fn execute_command_for_client( &self, client_id: ClientId, cmd_id: &CommandId, args: &CommandContext, ) -> Option<(CommandResult, StateChanges, Vec<RuntimeSignal>)>

Execute a command with per-client state (Phase #471).

This enables multi-client mode isolation by operating on per-client mode and cursor state instead of shared session state.

§Arguments
  • client_id - Client ID to execute for
  • cmd_id - Command ID to execute
  • args - Command arguments (count, register, etc.)
§Returns
  • Some((CommandResult, StateChanges)) - if command executed
  • None - if client not found, client is Following, or command not registered
§Relation Behavior
  • Independent: Uses own mode stack, windows, and extensions
  • Following: Returns None (input ignored)
  • Sharing: Uses target’s state
Source

pub fn insert_char_for_client( &self, client_id: ClientId, ch: char, target: InputTarget, ) -> Option<(BufferId, Option<Modification>)>

Insert a character for a client, checking per-client extensions first (#477).

For InputTarget::Buffer, inserts into the active buffer. For InputTarget::Extension(type_id), looks in per-client extensions first, then falls back to shared session extensions.

§Returns
  • Some((BufferId, Some(Modification))) if character was inserted into a buffer
  • None if inserted into extension or failed
Source

pub fn client_current_mode(&self, client_id: ClientId) -> Option<ModeId>

Get the current mode for a specific client (#471).

Returns the mode from the client’s per-client mode stack (if Independent/Sharing) or None for Following clients.

Source

pub fn with_client_ring_buffer<F, R>( &self, client_id: ClientId, f: F, ) -> Option<R>
where F: FnOnce(&ClientRingBuffer) -> R,

Get access to a client’s ring buffer.

Returns None if the client doesn’t exist.

Source

pub fn dump_client_ring_buffer(&self, client_id: ClientId) -> Option<String>

Dump a client’s ring buffer for debugging.

Returns None if the client doesn’t exist.

Source

pub fn get_session_register(&self, key: char) -> Option<RegisterContent>

Get a session-shared register.

Returns None if the register has not been set. Session registers are shared across all clients in this session.

Source

pub fn set_session_register(&self, key: char, content: RegisterContent)

Set a session-shared register.

The content is immediately visible to all clients in this session.

Source

pub fn get_peer_history( &self, client_id: ClientId, index: u8, ) -> Option<RegisterContent>

Read another client’s history ring entry (PeerHistory).

Returns None if the client doesn’t exist or the index is out of range. This is a read-only operation - you cannot modify another client’s history.

Source

pub fn connected_client_ids(&self) -> Vec<ClientId>

List connected client IDs (for peer history navigation).

Returns a sorted list of client IDs currently in this session.

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

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

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

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

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> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
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.
Source§

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

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

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

fn with_current_subscriber(self) -> WithDispatch<Self>

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