Skip to main content

SessionState

Struct SessionState 

Source
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: Session

Driver-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:

FieldStatusUse Instead
mode_stackDEPRECATEDClient::Owner.state.mode_stack
pending_keysDEPRECATEDClient::Owner.state.pending_keys
windowsShared (layout)Per-client cursor in EditingState.cursor
extensionsSharedModule state is inherently shared
active_bufferSharedAll 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: AppState

Application 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: ModeRegistry

Registry of mode metadata and behavior.

§command_registry: CommandRegistry

Registry of command handlers.

§keymap_registry: KeymapRegistry

Registry of keybindings.

§resolver_registry: ResolverRegistry

Registry 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

Source

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 session
  • initial_mode - The home mode for new clients joining this session
  • vfs - The virtual filesystem driver for file operations
Source

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.

Source

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.

Source

pub const fn driver_session(&self) -> &DriverSession

Get a reference to the driver session (SSOT for session state).

Source

pub fn driver_session_mut(&mut self) -> &mut DriverSession

Get a mutable reference to the driver session.

Source

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.

Source

pub fn lookup_keys(&self, mode: &ModeId, keys: &KeySequence) -> KeyLookupResult

Look up a key sequence in the current mode’s keymap.

Source

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 execute
  • args - Command arguments (count, register, etc.)
Source

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.

Source

pub const fn is_running(&self) -> bool

Check if the session should continue running.

Source

pub fn request_quit(&mut self)

Request the session to quit.

Source

pub fn request_detach(&mut self)

Request clients to detach (server continues running).

Source

pub const fn resolver_registry(&self) -> &ResolverRegistry

Get the resolver registry.

Source

pub fn buffer(&self, id: BufferId) -> Option<Arc<RwLock<Buffer>>>

Get a buffer by ID.

Source

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.

Source

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 key
  • None - if no resolver is registered for the current mode
Source

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-level EditingState)
  • client_windows - Per-client window layout
  • client_extensions - Per-client extensions
  • key - The key event to resolve
§Returns
  • Some((ResolveResult, StateChanges)) - if a resolver handled the key
  • None - 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);
Source

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
  1. Key press → resolver returns Execute(motion-command)
  2. Runner executes the motion → cursor moves
  3. This method → resolver reads end position, returns ModeTransition::Pop { ExecuteCommand { operator, range } }
  4. Runner pops the operator mode and executes the operator command
Source

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-level EditingState)
§Returns

A ModeTransition if the resolver wants to change modes.

Source§

impl SessionState

Source

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§

Source§

impl Default for SessionState

Source§

fn default() -> Self

Returns the “default value” for a type. 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
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