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
impl Session
Sourcepub fn from_state(id: SessionId, state: SessionState) -> Self
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);Sourcepub fn subscribe_notifications(&self) -> Receiver<Notification>
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.
Sourcepub fn emit_notification(&self, notification: Notification)
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.
Sourcepub const fn capture_tracker(&self) -> &CaptureTracker
pub const fn capture_tracker(&self) -> &CaptureTracker
Get the capture tracker for CLI→Server→TUI→Server→CLI relay (gRPC only).
Sourcepub const fn presence(&self) -> &PresenceMap
pub const fn presence(&self) -> &PresenceMap
Get the presence map for multi-client tracking (Phase 14, gRPC only).
Sourcepub fn add_client(&self, client_id: ClientId)
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.
Sourcepub fn add_client_with_metadata(
&self,
client_id: ClientId,
metadata: ClientMetadata,
)
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.
Sourcepub fn add_client_with_state(&self, client: Client)
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.
Sourcepub fn remove_client(&self, client_id: ClientId) -> Option<Client>
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.
Sourcepub fn get_client(&self, client_id: ClientId) -> Option<Client>
pub fn get_client(&self, client_id: ClientId) -> Option<Client>
Get a client’s role (immutable).
Sourcepub fn set_client_relation(
&self,
client_id: ClientId,
relation: Option<ClientRelation>,
) -> Result<(), TransitionResult>
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)
Sourcepub fn set_client_relation_unchecked(
&self,
client_id: ClientId,
relation: Option<ClientRelation>,
) -> bool
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.
Sourcepub fn sync_and_set_relation(
&self,
client_id: ClientId,
target_id: ClientId,
relation: Option<ClientRelation>,
) -> Result<(), TransitionResult>
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)
Sourcepub fn client_state(&self, client_id: ClientId) -> Option<EditingState>
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.
Sourcepub fn update_client_state<F>(&self, client_id: ClientId, f: F) -> boolwhere
F: FnOnce(&mut EditingState),
pub fn update_client_state<F>(&self, client_id: ClientId, f: F) -> boolwhere
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.
Sourcepub fn with_clients<F, R>(&self, f: F) -> R
pub fn with_clients<F, R>(&self, f: F) -> R
Execute a closure with read access to the clients map.
Sourcepub fn with_clients_mut<F, R>(&self, f: F) -> R
pub fn with_clients_mut<F, R>(&self, f: F) -> R
Execute a closure with write access to the clients map.
Sourcepub fn with_client_extensions<F, R>(
&self,
client_id: ClientId,
f: F,
) -> Option<R>where
F: FnOnce(&ExtensionMap) -> R,
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().
Sourcepub fn with_client_extensions_mut<F, R>(
&self,
client_id: ClientId,
f: F,
) -> Option<R>where
F: FnOnce(&mut ExtensionMap) -> R,
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).
Sourcepub fn with_tick_mut<F, R>(&self, client_id: ClientId, f: F) -> Option<R>
pub fn with_tick_mut<F, R>(&self, client_id: ClientId, f: F) -> Option<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.
Sourcepub fn client_count(&self) -> usize
pub fn client_count(&self) -> usize
Get count of connected clients.
Sourcepub fn has_client(&self, client_id: ClientId) -> bool
pub fn has_client(&self, client_id: ClientId) -> bool
Check if a client is connected.
Sourcepub async fn with_state<F, R>(&self, f: F) -> Rwhere
F: FnOnce(&SessionState) -> R,
pub async fn with_state<F, R>(&self, f: F) -> Rwhere
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.
Sourcepub async fn with_state_mut<F, R>(&self, f: F) -> Rwhere
F: FnOnce(&mut SessionState) -> R,
pub async fn with_state_mut<F, R>(&self, f: F) -> Rwhere
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.
Sourcepub fn with_state_sync<F, R>(&self, f: F) -> Rwhere
F: FnOnce(&SessionState) -> R,
pub fn with_state_sync<F, R>(&self, f: F) -> Rwhere
F: FnOnce(&SessionState) -> R,
Synchronous read access (for contexts where async isn’t needed).
Sourcepub fn with_state_mut_sync<F, R>(&self, f: F) -> Rwhere
F: FnOnce(&mut SessionState) -> R,
pub fn with_state_mut_sync<F, R>(&self, f: F) -> Rwhere
F: FnOnce(&mut SessionState) -> R,
Synchronous write access.
Sourcepub fn with_bridge_context<F, R>(&self, client_id: ClientId, f: F) -> Option<R>
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.
Sourcepub async fn resolve_key_for_client(
&self,
client_id: ClientId,
key: &KeyEvent,
) -> Option<(ResolveResult, StateChanges)>
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 forkey- Key event to resolve
§Returns
Some((ResolveResult, StateChanges))- if key was resolvedNone- 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
Sourcepub async fn try_on_command_complete_for_client(
&self,
client_id: ClientId,
) -> Option<ModeTransition>
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.
Sourcepub fn execute_command_for_client(
&self,
client_id: ClientId,
cmd_id: &CommandId,
args: &CommandContext,
) -> Option<(CommandResult, StateChanges, Vec<RuntimeSignal>)>
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 forcmd_id- Command ID to executeargs- Command arguments (count, register, etc.)
§Returns
Some((CommandResult, StateChanges))- if command executedNone- 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
Sourcepub fn insert_char_for_client(
&self,
client_id: ClientId,
ch: char,
target: InputTarget,
) -> Option<(BufferId, Option<Modification>)>
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 bufferNoneif inserted into extension or failed
Sourcepub fn client_current_mode(&self, client_id: ClientId) -> Option<ModeId>
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.
Sourcepub fn with_client_ring_buffer<F, R>(
&self,
client_id: ClientId,
f: F,
) -> Option<R>where
F: FnOnce(&ClientRingBuffer) -> R,
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.
Sourcepub fn dump_client_ring_buffer(&self, client_id: ClientId) -> Option<String>
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.
Sourcepub fn get_session_register(&self, key: char) -> Option<RegisterContent>
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.
Sourcepub fn set_session_register(&self, key: char, content: RegisterContent)
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.
Sourcepub fn get_peer_history(
&self,
client_id: ClientId,
index: u8,
) -> Option<RegisterContent>
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.
Sourcepub fn connected_client_ids(&self) -> Vec<ClientId>
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§
impl !Freeze for Session
impl !RefUnwindSafe for Session
impl Send for Session
impl Sync for Session
impl Unpin for Session
impl UnsafeUnpin for Session
impl !UnwindSafe for Session
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
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request