Skip to main content

SessionRuntime

Struct SessionRuntime 

Source
pub struct SessionRuntime<'a> { /* private fields */ }
Expand description

Runtime that implements all session API traits.

Bundles Session + KernelContext + CommandExecutor. Changes accumulate internally; runner takes at end via take_changes.

§Compositor Integration

The compositor is accessed via session.compositor. When present, CompositorApi methods delegate to it. When absent, they return errors.

§Per-Client State (#471, #477)

SessionRuntime ALWAYS operates on per-client state. The per-client fields are required (no Option wrappers, no fallback to shared state):

  • mode_stack (#471): Per-client mode (INSERT, NORMAL, etc.)
  • windows (#471): Per-client cursor positions
  • extensions (#477): Per-client module state (VimSessionState, etc.)

This enforces multi-client isolation at compile time - you cannot create a SessionRuntime without providing per-client state.

§Client Binding (#471)

The owner field tracks which client this runtime is bound to. When present, it makes explicit which client’s state we’re operating on. This is useful for:

  • Debugging and logging
  • Assertions in tests
  • Future multi-client coordination

Implementations§

Source§

impl<'a> SessionRuntime<'a>

Source

pub fn new( session: &'a mut Session, client: ClientContext<'a>, kernel: &'a KernelContext, executor: &'a dyn CommandExecutor, ) -> Self

Create a new runtime with per-client state (#471, #477).

All per-client state is required. There are no fallbacks to shared session state. This enforces multi-client isolation at compile time.

§Arguments
  • session - Shared session state (compositor, home mode)
  • mode_stack - Per-client mode stack (source of truth for mode)
  • windows - Per-client window layout with cursors
  • extensions - Per-client module extensions
  • kernel - Kernel context (buffers, registers, marks)
  • executor - Command executor
§Multi-Client Isolation

Each client has independent:

  • Mode state (Client A in INSERT while Client B in NORMAL)
  • Cursor positions (Client A at line 5, Client B at line 10)
  • Module state (Client A’s pending_count doesn’t affect Client B)
§Example
// From server level, get per-client EditingState
let editing_state = session.client_state_mut(client_id)?;

// Create runtime with per-client state bundle
let client = editing_state.client_context();
let mut runtime = SessionRuntime::new(
    &mut driver_session,
    client,
    &kernel,
    &executor,
);

// All operations use per-client state
runtime.push_mode(insert_mode, ctx);     // Only affects this client
runtime.windows().active();              // This client's active window
runtime.ext_mut::<VimSessionState>();    // This client's vim state
Source

pub fn with_owner( owner: ClientId, session: &'a mut Session, client: ClientContext<'a>, kernel: &'a KernelContext, executor: &'a dyn CommandExecutor, ) -> Self

Create a runtime with explicit client binding (#471).

Like new, but also records which client this runtime is bound to. The owner field can be retrieved via owner().

§Arguments
  • owner - The ClientId this runtime is bound to
  • session - Shared session infrastructure
  • client - Per-client state bundle (mode, windows, extensions, registers, etc.)
  • kernel - Kernel context (buffers, global marks)
  • executor - Command executor
§Example
let client = editing_state.client_context();
let mut runtime = SessionRuntime::with_owner(
    client_id,
    &mut driver_session,
    client,
    &kernel,
    &executor,
);

// Query which client owns this runtime
assert_eq!(runtime.owner(), Some(client_id));
Source

pub const fn owner(&self) -> Option<ClientId>

Get the client ID this runtime is bound to (#471).

Returns Some(ClientId) if created with with_owner, None otherwise. Use this for debugging, logging, or assertions about which client owns this runtime.

§Example
let runtime = SessionRuntime::with_owner(client_id, ...);
assert_eq!(runtime.owner(), Some(client_id));

let shared_runtime = SessionRuntime::new(...);
assert_eq!(shared_runtime.owner(), None);
Source

pub const fn with_shared_extensions( self, extensions: &'a mut ExtensionMap, ) -> Self

Set shared extensions for session-wide state access (#543).

Called by server code that has access to AppState.extensions. Enables shared_ext() / shared_ext_mut() in commands.

Source

pub fn signal(&mut self, signal: RuntimeSignal)

Push a lifecycle signal onto the queue (#547).

Commands call this during execution. The server drains the queue after the command returns and acts on the signals. Same pattern as StateChanges — accumulate during execution, drain after.

Source

pub fn take_signals(&mut self) -> Vec<RuntimeSignal>

Drain the signal queue, returning all accumulated signals (#547).

Called by the server after command execution completes. Returns the signals and empties the queue.

Source

pub fn has_compositor(&self) -> bool

Check if compositor is available.

Source

pub const fn session(&self) -> &Session

Get direct access to the session.

Source

pub const fn session_mut(&mut self) -> &mut Session

Get mutable access to the session.

Source

pub const fn kernel(&self) -> &KernelContext

Get direct access to the kernel context.

Source

pub fn with_buffer_read<F, R>(&self, buffer: BufferId, f: F) -> Option<R>
where F: FnOnce(&Buffer) -> R,

Execute a read-only operation on a buffer.

This method provides temporary read access to a buffer for complex calculations that need the full buffer interface (e.g., motion calculations, text object matching).

§Arguments
  • buffer - The buffer ID to access
  • f - A function that receives a read guard to the buffer
§Returns

Some(R) with the function’s return value if the buffer exists, None if the buffer doesn’t exist.

§Example
let target = runtime.with_buffer_read(buffer_id, |buffer| {
    MotionEngine::calculate(buffer, &cursor, motion, count)
});
Source

pub fn record_global_option_change( &mut self, name: impl Into<String>, value: OptionValue, )

Record a global option change for notification emission.

Call this after setting a global option via kernel.options.set(). The change will be emitted as an OPTION_CHANGED notification.

Source

pub fn record_window_option_change( &mut self, name: impl Into<String>, value: OptionValue, window_id: WindowId, )

Record a window-scoped option change for notification emission.

Call this after setting a window option via kernel.options.set(). The change will be emitted as an OPTION_CHANGED notification.

Source

pub fn record_buffer_modified(&mut self, buffer: BufferId)

Record that a buffer was modified for notification emission.

Call this after modifying buffer content directly (e.g., via OperatorContext which bypasses SessionRuntime’s BufferApi methods like delete_range()).

Source

pub const fn windows(&self) -> &WindowLayout

Get the per-client windows.

Phase #471: Direct access to per-client windows. No fallback, no Option. Commands use this to access the active window’s cursor position.

§Example
let Some(window) = runtime.windows().active() else {
    return CommandResult::error("No active window");
};
let pos = Position::new(window.cursor.line, window.cursor.column);
Source

pub fn windows_mut(&mut self) -> &mut WindowLayout

Get the per-client windows mutably.

Phase #471: Direct access to per-client windows for cursor/selection updates.

§Example
if let Some(window) = runtime.windows_mut().active_mut() {
    window.cursor = new_pos.into();
    window.selection = Some(Selection::new(start, end, mode));
}
Source

pub const fn registers(&self) -> &RegisterBank

Get per-client registers (#515).

Source

pub fn registers_mut(&mut self) -> &mut RegisterBank

Get per-client registers mutably (#515).

Source

pub const fn clipboard_history(&self) -> &HistoryRing

Get per-client clipboard history (#515).

Source

pub fn clipboard_history_mut(&mut self) -> &mut HistoryRing

Get per-client clipboard history mutably (#515).

Source

pub const fn kernel_and_registers( &mut self, ) -> (&KernelContext, &mut RegisterBank, &mut HistoryRing)

Get kernel, registers, and clipboard history together (#515).

Splits the borrow so the caller can hold &KernelContext and &mut RegisterBank / &mut HistoryRing simultaneously, which isn’t possible through separate accessor calls.

Source

pub const fn local_marks(&self) -> &MarkBank

Get per-client local marks (#515).

Source

pub fn local_marks_mut(&mut self) -> &mut MarkBank

Get per-client local marks mutably (#515).

Source

pub const fn jumplist(&self) -> &Jumplist

Get per-client jump list (#654).

Source

pub fn jumplist_mut(&mut self) -> &mut Jumplist

Get per-client jump list mutably (#654).

Source§

impl SessionRuntime<'_>

Source

pub fn push_to_clipboard_history(&mut self, content: RegisterContent)

Push content to the per-client clipboard history (#515).

Should be called after every yank/delete operation to populate numbered registers (0-9). This is an inherent method because history is per-client state, not a shared service.

Source

pub fn store_register_with_sync( &mut self, register: Option<char>, content: RegisterContent, )

Store content to register with clipboard sync (#515 Phase 4).

Coordinates RegisterApi and ClipboardApi:

  1. Stores content in per-client register via RegisterApi
  2. Syncs to OS clipboard for +/* registers via ClipboardApi
  3. Pushes to clipboard history for numbered register rotation

Use this from commands that operate on SessionRuntime directly (visual mode operators, editor commands). Vim operators that hold separate borrows via OperatorContext use registers::store_and_sync instead.

Source

pub fn get_register_with_clipboard( &self, register: Option<char>, ) -> Option<RegisterContent>

Get register content with clipboard fallback for +/* (#515 Phase 4).

For system clipboard registers:

  • +: reads from OS clipboard, falls back to per-client register
  • *: reads from OS selection, falls back to per-client register
  • All others: reads directly from per-client RegisterBank

Trait Implementations§

Source§

impl BufferApi for SessionRuntime<'_>

Source§

fn active_buffer(&self) -> Option<BufferId>

Get the active buffer ID.
Source§

fn set_active_buffer(&mut self, id: Option<BufferId>)

Set the active buffer ID. Read more
Source§

fn buffer_line(&self, buffer: BufferId, line: usize) -> Option<String>

Get a line from a buffer. Read more
Source§

fn buffer_line_count(&self, buffer: BufferId) -> Option<usize>

Get the line count of a buffer. Read more
Source§

fn buffer_line_len(&self, buffer: BufferId, line: usize) -> Option<usize>

Get the length of a line in characters. Read more
Source§

fn buffer_text_range( &self, buffer: BufferId, start: Position, end: Position, ) -> Option<String>

Extract text from a range in the buffer. Read more
Source§

fn buffer_content(&self, buffer: BufferId) -> Option<String>

Get full buffer content as a string. Read more
Source§

fn buffer_file_path(&self, buffer: BufferId) -> Option<String>

Get buffer’s file path. Read more
Source§

fn is_buffer_modified(&self, buffer: BufferId) -> Option<bool>

Check if buffer has been modified since last save. Read more
Source§

fn set_buffer_modified(&mut self, buffer: BufferId, modified: bool)

Set buffer’s modified flag. Read more
Source§

fn insert_text(&mut self, buffer: BufferId, pos: Position, text: &str)

Insert text at a position.
Source§

fn delete_range(&mut self, buffer: BufferId, start: Position, end: Position)

Delete a range.
Source§

fn replace_content(&mut self, buffer: BufferId, content: &str)

Replace entire buffer content. Read more
Source§

fn create_buffer(&mut self, name: Option<&str>, content: &str) -> BufferId

Create a new buffer. Read more
Source§

fn delete_buffer(&mut self, buffer: BufferId) -> Result<(), BufferError>

Delete a buffer. Read more
Source§

fn rename_buffer(&mut self, buffer: BufferId, new_name: &str)

Rename a buffer.
Source§

impl ChangeTracker for SessionRuntime<'_>

Source§

fn take_changes(&mut self) -> StateChanges

Take all accumulated changes, resetting internal state.
Source§

fn record_cursor_move(&mut self, buffer: BufferId)

Record that the cursor moved in a buffer. Read more
Source§

fn record_selection_change(&mut self, buffer: BufferId)

Record that the selection changed in a buffer (#474). Read more
Source§

impl ClipboardApi for SessionRuntime<'_>

Source§

fn copy_to_clipboard(&self, text: &str) -> bool

Copy text to the system clipboard (+ register). Read more
Source§

fn paste_from_clipboard(&self) -> Option<String>

Paste text from the system clipboard (+ register). Read more
Source§

fn copy_to_selection(&self, text: &str) -> bool

Copy text to the selection clipboard (* register). Read more
Source§

fn paste_from_selection(&self) -> Option<String>

Paste text from the selection clipboard (* register). Read more
Source§

impl CommandApi for SessionRuntime<'_>

Source§

fn execute_command( &mut self, cmd: CommandId, ctx: CommandContext, ) -> CommandResult

Execute a command directly. Read more
Source§

impl CompositorApi for SessionRuntime<'_>

Source§

fn navigate( &self, direction: NavigateDirection, ) -> Result<WindowId, CompositorError>

Navigate in direction from the current window. Read more
Source§

fn split( &mut self, direction: SplitDirection, ) -> Result<WindowId, CompositorError>

Split the current window. Read more
Source§

fn close_current_window(&mut self) -> Result<WindowId, CompositorError>

Close the current window. Read more
Source§

fn close_others(&mut self) -> Result<(), CompositorError>

Close all windows except the current one. Read more
Source§

fn resize( &mut self, direction: NavigateDirection, delta: i16, ) -> Result<(), CompositorError>

Resize the current window. Read more
Source§

fn equalize(&mut self) -> Result<(), CompositorError>

Equalize all windows in the current layer. Read more
Source§

fn cycle(&self, forward: bool) -> Result<WindowId, CompositorError>

Cycle to next/previous window. Read more
Source§

fn focus(&mut self, window: WindowId) -> Result<(), CompositorError>

Set focus to a specific window. Read more
Source§

fn focused_window(&self) -> Option<WindowId>

Get the currently focused window. Read more
Source§

fn compositor_window_count(&self) -> usize

Get window count in the active layer.
Source§

fn arrange(&self, screen: Rect) -> Vec<WindowPlacement>

Get all window placements (for rendering). Read more
Source§

fn active_layer(&self) -> Option<LayerId>

Get the active layer ID.
Source§

fn set_screen(&mut self, screen: Rect)

Update screen size (on terminal resize).
Source§

fn toggle_float(&mut self) -> Result<(), CompositorError>

Toggle the current window between tiled and float zones. Read more
Source§

fn raise_float(&mut self) -> Result<(), CompositorError>

Raise the current float window to the front. Read more
Source§

fn lower_float(&mut self) -> Result<(), CompositorError>

Lower the current float window to the back. Read more
Source§

fn show_overlay( &mut self, constraints: OverlayConstraints, ) -> Result<WindowId, CompositorError>

Show an overlay with constraints. Read more
Source§

fn hide_overlay(&mut self, window: WindowId) -> Result<(), CompositorError>

Hide (remove) an overlay. Read more
Source§

fn resize_overlay( &mut self, window: WindowId, width: u16, height: u16, ) -> Result<(), CompositorError>

Resize an overlay. Read more
Source§

fn hide_all_overlays(&mut self) -> Result<(), CompositorError>

Hide all overlays in the active layer. Read more
Source§

fn set_active_layer_opacity( &mut self, opacity: f32, ) -> Result<(), CompositorError>

Set the opacity of the active layer. Read more
Source§

fn active_layer_opacity(&self) -> Result<f32, CompositorError>

Get the opacity of the active layer. Read more
Source§

fn adjust_active_layer_opacity( &mut self, delta: f32, ) -> Result<f32, CompositorError>

Adjust the active layer’s opacity by a delta. Read more
Source§

fn tab_new(&mut self) -> Result<TabId, CompositorError>

Create a new tab page after the active tab. Read more
Source§

fn tab_close(&mut self) -> Result<(), CompositorError>

Close the active tab page. Read more
Source§

fn tab_next(&mut self) -> Result<TabId, CompositorError>

Switch to the next tab page (wraps around). Read more
Source§

fn tab_prev(&mut self) -> Result<TabId, CompositorError>

Switch to the previous tab page (wraps around). Read more
Source§

fn tab_goto(&mut self, index: usize) -> Result<TabId, CompositorError>

Switch to a tab page by 0-based index. Read more
Source§

fn tab_count(&self) -> usize

Get the number of tab pages.
Source§

fn active_tab_id(&self) -> Option<TabId>

Get the active tab page’s ID.
Source§

impl ExtensionApi for SessionRuntime<'_>

Per-client extensions (#477, #471 Phase 0).

Extensions are now ALWAYS per-client (no fallback to shared session). This enforces complete module state isolation between clients. For example, VimSessionState.pending_count is per-client, so Client A pressing 5 doesn’t affect Client B’s motions.

Source§

fn ext<T: SessionExtension>(&self) -> Option<&T>

Get per-client extension by type (immutable). Read more
Source§

fn ext_mut<T: SessionExtension>(&mut self) -> &mut T

Get per-client extension by type (mutable), creating if needed. Read more
Source§

fn shared_ext<T: SessionExtension>(&self) -> Option<&T>

Get shared (session-wide) extension by type (immutable). Read more
Source§

fn shared_ext_mut<T: SessionExtension>(&mut self) -> Option<&mut T>

Get shared (session-wide) extension by type (mutable), creating if needed. Read more
Source§

impl ModeApi for SessionRuntime<'_>

Per-client state (#471): Mode operations use the per-client mode stack directly.

Since per-client state is now required (no Option), all mode operations directly access self.mode_stack without fallback to session.

Source§

fn current_mode(&self) -> &ModeId

Get the current mode (top of stack).
Source§

fn home_mode(&self) -> &ModeId

Get the home mode (bottom of stack, cannot be popped).
Source§

fn mode_depth(&self) -> usize

Get the mode stack depth.
Source§

fn is_mode_active(&self, mode: &ModeId) -> bool

Check if a mode is anywhere on the stack.
Source§

fn mode_stack(&self) -> Vec<ModeId>

Get the full mode stack as a snapshot (bottom to top).
Source§

fn push_mode(&mut self, mode: ModeId, _ctx: TransitionContext)

Push a mode onto the stack. Read more
Source§

fn pop_mode(&mut self, _result: Option<PopResult>) -> Result<(), ModeError>

Pop the current mode from the stack. Read more
Source§

fn set_mode(&mut self, mode: ModeId, _ctx: TransitionContext)

Replace the current mode (pop + push atomically). Read more
Source§

impl RegisterApi for SessionRuntime<'_>

Source§

fn get_register(&self, name: Option<char>) -> Option<RegisterContent>

Get register contents. Read more
Source§

fn set_register(&mut self, name: Option<char>, content: RegisterContent)

Set register contents. Read more
Source§

impl UndoApi for SessionRuntime<'_>

Source§

fn undo(&mut self, buffer: BufferId) -> Option<UndoResult>

Undo the last change for a buffer. Read more
Source§

fn redo(&mut self, buffer: BufferId) -> Option<UndoResult>

Redo the last undone change for a buffer. Read more
Source§

fn record_edit( &mut self, buffer: BufferId, edits: Vec<Edit>, cursor_before: Position, cursor_after: Position, )

Record edits for undo history. Read more
Source§

fn can_undo(&self, buffer: BufferId) -> bool

Check if undo is available for a buffer.
Source§

fn can_redo(&self, buffer: BufferId) -> bool

Check if redo is available for a buffer.
Source§

fn undo_mine(&mut self, buffer: BufferId) -> Option<UndoResult>

Undo the last change made by the current client. Read more
Source§

fn redo_mine(&mut self, buffer: BufferId) -> Option<UndoResult>

Redo the last undone change made by the current client. Read more
Source§

fn record_edit_mine( &mut self, buffer: BufferId, edits: Vec<Edit>, cursor_before: Position, cursor_after: Position, )

Record edits for undo history with client origin tagging. Read more
Source§

impl WindowApi for SessionRuntime<'_>

Source§

fn active_window(&self) -> Option<WindowId>

Get the active window ID.
Source§

fn cursor_position(&self) -> Option<Position>

Get cursor position from the active window. Read more
Source§

fn window_count(&self) -> usize

Get the window count.
Source§

fn window_buffer(&self, window: WindowId) -> Option<BufferId>

Get the buffer displayed in a window.
Source§

fn create_window(&mut self, buffer: Option<BufferId>) -> WindowId

Create a new window. Read more
Source§

fn close_window(&mut self, window: WindowId) -> Result<(), WindowError>

Close a window. Read more
Source§

fn focus_window(&mut self, window: WindowId) -> Result<(), WindowError>

Focus a window. Read more
Source§

fn set_window_buffer( &mut self, window: WindowId, buffer: BufferId, ) -> Result<(), WindowError>

Set the buffer displayed in a window. Read more
Source§

fn set_active_selection(&mut self, selection: Option<Selection>)

Set or clear the selection on the active window. Read more
Source§

fn active_selection(&self) -> Option<&Selection>

Get the selection on the active window, if any.

Auto Trait Implementations§

§

impl<'a> Freeze for SessionRuntime<'a>

§

impl<'a> !RefUnwindSafe for SessionRuntime<'a>

§

impl<'a> Send for SessionRuntime<'a>

§

impl<'a> Sync for SessionRuntime<'a>

§

impl<'a> Unpin for SessionRuntime<'a>

§

impl<'a> UnsafeUnpin for SessionRuntime<'a>

§

impl<'a> !UnwindSafe for SessionRuntime<'a>

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

impl<T> SessionApi for T

Source§

impl<T> SessionApiDyn for T