pub struct SessionState {
pub driver_session: Session,
pub app: AppState,
pub vfs: Arc<dyn VfsDriver>,
pub mode_registry: ModeRegistry,
pub command_registry: CommandRegistry,
pub keymap_registry: KeymapRegistry,
pub resolver_registry: ResolverRegistry,
pub session_registers: HashMap<char, RegisterContent>,
}Expand description
Session state combining application state with registries.
This is the complete state for a single editing session. Each session
(like tmux sessions) has its own SessionState with independent:
- Driver-layer session (SSOT for
mode_stack,pending_keys,extensions, etc.) - Kernel context (buffers, events, options)
- Mode/command/keymap registries
§SSOT Architecture
driver_session is the Single Source of Truth for per-session state.
AppState provides server-specific state that doesn’t belong in the driver.
§Thread Safety
SessionState is NOT Sync by itself. The Session wrapper provides
thread-safe access via RwLock<SessionState>.
Fields§
§driver_session: SessionDriver-layer session state (SSOT for buffers and shared resources).
§Multi-Client Warning (#471)
This contains SHARED state used by ALL clients. In multi-client scenarios:
| Field | Status | Use Instead |
|---|---|---|
mode_stack | DEPRECATED | Client::Owner.state.mode_stack |
pending_keys | DEPRECATED | Client::Owner.state.pending_keys |
windows | Shared (layout) | Per-client cursor in EditingState.cursor |
extensions | Shared | Module state is inherently shared |
active_buffer | Shared | All clients see same buffers |
DO NOT access driver_session.mode_stack directly for key resolution.
Use Session::resolve_key_for_client() which routes through per-client state.
app: AppStateApplication state (kernel + server-specific state).
Contains: kernel context, running flag, windows, cmdline.
NOTE: mode_stack, pending_keys, extensions, active_buffer, and
terminal_size in AppState are DEPRECATED - use driver_session instead.
vfs: Arc<dyn VfsDriver>Virtual filesystem driver for file operations.
Commands access files through this VFS abstraction rather than
using std::fs directly.
mode_registry: ModeRegistryRegistry of mode metadata and behavior.
command_registry: CommandRegistryRegistry of command handlers.
keymap_registry: KeymapRegistryRegistry of keybindings.
resolver_registry: ResolverRegistryRegistry of mode key resolvers.
Resolvers implement mode-specific key handling policy:
- Operator interception (keys that enter operator-pending mode)
- Motion handling (keys that compute cursor ranges)
- Line-operator detection (repeated operator keys)
session_registers: HashMap<char, RegisterContent>Session-scoped shared registers (A-Z) (#515 Phase 5).
All clients in the session read/write from this shared storage.
Accessed via Register::Session('A') through Register::Session('Z').
Provides cross-client register sharing within a single session.
Implementations§
Source§impl SessionState
impl SessionState
Sourcepub fn new(
kernel: KernelContext,
initial_mode: ModeId,
vfs: Arc<dyn VfsDriver>,
) -> Self
pub fn new( kernel: KernelContext, initial_mode: ModeId, vfs: Arc<dyn VfsDriver>, ) -> Self
Create a new session state.
§Arguments
kernel- The kernel context for this sessioninitial_mode- The home mode for new clients joining this sessionvfs- The virtual filesystem driver for file operations
Sourcepub fn with_registries(
kernel: KernelContext,
initial_mode: ModeId,
vfs: Arc<dyn VfsDriver>,
mode_registry: ModeRegistry,
command_registry: CommandRegistry,
keymap_registry: KeymapRegistry,
resolver_registry: ResolverRegistry,
compositor: Option<Box<dyn RootCompositor>>,
) -> Self
pub fn with_registries( kernel: KernelContext, initial_mode: ModeId, vfs: Arc<dyn VfsDriver>, mode_registry: ModeRegistry, command_registry: CommandRegistry, keymap_registry: KeymapRegistry, resolver_registry: ResolverRegistry, compositor: Option<Box<dyn RootCompositor>>, ) -> Self
Create session state with existing registries.
Used when modules need to populate registries before creating the session state.
Sourcepub fn ensure_initial_compositor_window(&mut self)
pub fn ensure_initial_compositor_window(&mut self)
Ensure the compositor has at least one tiled window.
Called after scratch buffer creation to handle the case where
with_registries() ran before any buffers existed.
Sourcepub const fn driver_session(&self) -> &DriverSession
pub const fn driver_session(&self) -> &DriverSession
Get a reference to the driver session (SSOT for session state).
Sourcepub fn driver_session_mut(&mut self) -> &mut DriverSession
pub fn driver_session_mut(&mut self) -> &mut DriverSession
Get a mutable reference to the driver session.
Sourcepub const fn home_mode(&self) -> &ModeId
pub const fn home_mode(&self) -> &ModeId
Get the home mode for initializing new clients (#491).
When a new client connects, their mode stack is initialized with
this mode at the bottom. This is stored in SessionShared.
Sourcepub fn lookup_keys(&self, mode: &ModeId, keys: &KeySequence) -> KeyLookupResult
pub fn lookup_keys(&self, mode: &ModeId, keys: &KeySequence) -> KeyLookupResult
Look up a key sequence in the current mode’s keymap.
Sourcepub fn execute_command_for_client(
&mut self,
client_id: usize,
client: ClientContext<'_>,
id: &CommandId,
args: &CommandContext,
) -> Option<(CommandResult, StateChanges, Vec<RuntimeSignal>)>
pub fn execute_command_for_client( &mut self, client_id: usize, client: ClientContext<'_>, id: &CommandId, args: &CommandContext, ) -> Option<(CommandResult, StateChanges, Vec<RuntimeSignal>)>
Execute a command with per-client state (#471, #477).
This enables multi-client isolation by operating on per-client mode, cursor, and extension state instead of shared session state.
§Arguments
client_mode_stack- Per-client mode stack (source of truth for mode)client_windows- Per-client window layout (source of truth for cursor)client_extensions- Per-client module extensions (#477)id- The command ID to executeargs- Command arguments (count, register, etc.)
Sourcepub fn mode_accepts_char_input(&self) -> bool
pub fn mode_accepts_char_input(&self) -> bool
Check if the home mode accepts character input.
NOTE (#491): This uses home_mode() since per-client mode lives in EditingState.
For per-client mode checking, use the per-client state directly.
Sourcepub const fn is_running(&self) -> bool
pub const fn is_running(&self) -> bool
Check if the session should continue running.
Sourcepub fn request_quit(&mut self)
pub fn request_quit(&mut self)
Request the session to quit.
Sourcepub fn request_detach(&mut self)
pub fn request_detach(&mut self)
Request clients to detach (server continues running).
Sourcepub const fn resolver_registry(&self) -> &ResolverRegistry
pub const fn resolver_registry(&self) -> &ResolverRegistry
Get the resolver registry.
Sourcepub fn create_buffer(&mut self, content: &str) -> BufferId
pub fn create_buffer(&mut self, content: &str) -> BufferId
Create a new buffer with the given content.
Returns the buffer ID. Per-client active_buffer is managed by
EditingState — callers must set it there if needed.
Uses Buffer::from_string so buffers start with modified = false.
Sourcepub fn resolve_key(
&mut self,
key: &KeyEvent,
) -> Option<(ResolveResult, StateChanges)>
pub fn resolve_key( &mut self, key: &KeyEvent, ) -> Option<(ResolveResult, StateChanges)>
Resolve a key event using the resolver registry.
This is the primary key resolution method that handles:
- Operator interception (entering operator-pending mode)
- Mode-specific key handling (via registered resolvers)
- Extension access for module state
§Returns
Some(ResolveResult)- if a resolver handled the keyNone- if no resolver is registered for the current mode
Sourcepub fn resolve_key_for_client(
&mut self,
client_id: usize,
client: ClientContext<'_>,
key: &KeyEvent,
) -> Option<(ResolveResult, StateChanges)>
pub fn resolve_key_for_client( &mut self, client_id: usize, client: ClientContext<'_>, key: &KeyEvent, ) -> Option<(ResolveResult, StateChanges)>
Resolve a key event with per-client mode stack (#471).
Like resolve_key(), but uses a provided per-client mode stack instead
of the shared session mode stack. This enables multi-client mode isolation
where each client has independent mode state.
§Arguments
client_id- The client ID for undo origin tracking (#471 Phase 5)client_mode_stack- Per-client mode stack (from server-levelEditingState)client_windows- Per-client window layoutclient_extensions- Per-client extensionskey- The key event to resolve
§Returns
Some((ResolveResult, StateChanges))- if a resolver handled the keyNone- if no resolver is registered for the current mode
§Example
// Get per-client EditingState
let editing_state = session.client_state_mut(client_id)?;
// Resolve key with per-client state
let client = editing_state.client_context();
let result = session_state.resolve_key_for_client(client_id, client, &key);Sourcepub fn try_on_command_complete(&mut self) -> Option<ModeTransition>
pub fn try_on_command_complete(&mut self) -> Option<ModeTransition>
Try to call on_command_complete on the current mode’s resolver.
Called after executing a command from ResolveResult::Execute.
For operator-pending modes, this is where the resolver reads
the post-motion cursor position and builds the final command.
§Flow
- Key press → resolver returns
Execute(motion-command) - Runner executes the motion → cursor moves
- This method → resolver reads end position, returns
ModeTransition::Pop { ExecuteCommand { operator, range } } - Runner pops the operator mode and executes the operator command
Sourcepub fn try_on_command_complete_for_client(
&mut self,
client_id: usize,
client: ClientContext<'_>,
) -> Option<ModeTransition>
pub fn try_on_command_complete_for_client( &mut self, client_id: usize, client: ClientContext<'_>, ) -> Option<ModeTransition>
Try to call on_command_complete with per-client state (#471, #477).
Like try_on_command_complete(), but uses per-client mode stack, windows,
and extensions instead of the shared session state.
§Arguments
client- Per-client state bundle (from server-levelEditingState)
§Returns
A ModeTransition if the resolver wants to change modes.
Source§impl SessionState
impl SessionState
Sourcepub fn with_kernel(kernel: KernelContext) -> Self
pub fn with_kernel(kernel: KernelContext) -> Self
Create a session state with a custom kernel context.
Useful for testing with non-default buffer managers.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for SessionState
impl !RefUnwindSafe for SessionState
impl Send for SessionState
impl Sync for SessionState
impl Unpin for SessionState
impl UnsafeUnpin for SessionState
impl !UnwindSafe for SessionState
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