pub trait MultiplexerControl: Send + Sync {
Show 24 methods
// Required methods
fn list_sessions(&self) -> ControlResult<Vec<TearSession>>;
fn get_session(&self, id: SessionId) -> ControlResult<TearSession>;
fn get_window(&self, id: WindowId) -> ControlResult<(SessionId, TearWindow)>;
fn get_pane(&self, id: PaneId) -> ControlResult<TearPane>;
fn new_session_with_source_and_size(
&self,
name: &str,
shell: &str,
args: &[String],
source: SessionSource,
size_cells: (u16, u16),
) -> ControlResult<SessionId>;
fn rename_session(&self, id: SessionId, new_name: &str) -> ControlResult<()>;
fn kill_session(&self, id: SessionId) -> ControlResult<()>;
fn new_window(
&self,
session: SessionId,
name: &str,
shell: &str,
args: &[String],
) -> ControlResult<WindowId>;
fn kill_window(&self, id: WindowId) -> ControlResult<()>;
fn select_window(&self, id: WindowId) -> ControlResult<()>;
fn split_pane(
&self,
origin: PaneId,
direction: Direction,
shell: &str,
args: &[String],
) -> ControlResult<PaneId>;
fn kill_pane(&self, id: PaneId) -> ControlResult<()>;
fn select_pane(&self, id: PaneId) -> ControlResult<()>;
fn resize_pane(
&self,
id: PaneId,
direction: Direction,
delta_cells: i16,
) -> ControlResult<()>;
fn apply_layout(
&self,
window: WindowId,
kind: LayoutKind,
) -> ControlResult<()>;
fn send_keys(&self, id: PaneId, bytes: &[u8]) -> ControlResult<()>;
fn pane_subscriber_count(&self, id: PaneId) -> ControlResult<u32>;
fn set_input_policy(
&self,
id: PaneId,
policy: InputPolicy,
) -> ControlResult<()>;
// Provided methods
fn capabilities(&self) -> DaemonIdentity { ... }
fn new_session(&self, name: &str, shell: &str) -> ControlResult<SessionId> { ... }
fn new_session_with_source(
&self,
name: &str,
shell: &str,
source: SessionSource,
) -> ControlResult<SessionId> { ... }
fn pane_resize_absolute(
&self,
id: PaneId,
cols: u16,
rows: u16,
) -> ControlResult<()> { ... }
fn pane_snapshot(&self, id: PaneId) -> ControlResult<PaneSnapshot> { ... }
fn pane_cursor_keys_mode(&self, id: PaneId) -> ControlResult<bool> { ... }
}Expand description
The trait every tear backend implements. Operations are intentionally async-free at the trait level — backends that want async runtimes spin them up internally; consumers (CLI, mado) call these directly on a worker thread.
Designed for the COMMON case (one session, a few windows, a few panes). Backends that need to batch operations (e.g. tear-daemon over a slow link) wrap individual calls themselves.
Required Methods§
Sourcefn list_sessions(&self) -> ControlResult<Vec<TearSession>>
fn list_sessions(&self) -> ControlResult<Vec<TearSession>>
List every active session. Sorted by creation time (oldest
first); the CLI’s tear list renders this directly.
Sourcefn get_session(&self, id: SessionId) -> ControlResult<TearSession>
fn get_session(&self, id: SessionId) -> ControlResult<TearSession>
Look up a single session by id.
Sourcefn get_window(&self, id: WindowId) -> ControlResult<(SessionId, TearWindow)>
fn get_window(&self, id: WindowId) -> ControlResult<(SessionId, TearWindow)>
Look up a single window. Returns the window + its parent
session id (handy for rendering window paths like work:1).
Sourcefn get_pane(&self, id: PaneId) -> ControlResult<TearPane>
fn get_pane(&self, id: PaneId) -> ControlResult<TearPane>
Look up a single pane.
Sourcefn new_session_with_source_and_size(
&self,
name: &str,
shell: &str,
args: &[String],
source: SessionSource,
size_cells: (u16, u16),
) -> ControlResult<SessionId>
fn new_session_with_source_and_size( &self, name: &str, shell: &str, args: &[String], source: SessionSource, size_cells: (u16, u16), ) -> ControlResult<SessionId>
Same as Self::new_session_with_source but the first
pane is created at the given (cols, rows) size. The
child shell’s TIOCGWINSZ returns these values on first
query — TUI apps render at the correct grid from
the very first prompt, no resize-flicker on attach.
Defaults to (80, 24) when the consumer doesn’t know the
target geometry; otherwise the consumer should pass the
renderer’s exact cell grid (e.g. mado’s
TerminalRenderer::cells_for_window_phys(...)).
args is shell’s argv[1..]. It is passed to the child
as an argument vector, never through a shell — so a
consumer that wants to run nvim -u NONE file.rs passes
three elements rather than smuggling them into one command
string. Pass &[] for a bare shell.
Sourcefn rename_session(&self, id: SessionId, new_name: &str) -> ControlResult<()>
fn rename_session(&self, id: SessionId, new_name: &str) -> ControlResult<()>
Rename a session. Idempotent — renaming to the current name returns Ok(()) without side effects.
Sourcefn kill_session(&self, id: SessionId) -> ControlResult<()>
fn kill_session(&self, id: SessionId) -> ControlResult<()>
Kill a session and all its children.
Sourcefn new_window(
&self,
session: SessionId,
name: &str,
shell: &str,
args: &[String],
) -> ControlResult<WindowId>
fn new_window( &self, session: SessionId, name: &str, shell: &str, args: &[String], ) -> ControlResult<WindowId>
Create a new window in a session, spawning shell as its
first pane. args is that program’s argv[1..] — passed as a
vector, never through a shell. &[] for a bare shell.
fn kill_window(&self, id: WindowId) -> ControlResult<()>
fn select_window(&self, id: WindowId) -> ControlResult<()>
Sourcefn split_pane(
&self,
origin: PaneId,
direction: Direction,
shell: &str,
args: &[String],
) -> ControlResult<PaneId>
fn split_pane( &self, origin: PaneId, direction: Direction, shell: &str, args: &[String], ) -> ControlResult<PaneId>
Split a pane in the given direction. shell is the program
spawned in the new pane and args is its argv[1..] — passed
as a vector, never through a shell. &[] for a bare shell.
fn kill_pane(&self, id: PaneId) -> ControlResult<()>
fn select_pane(&self, id: PaneId) -> ControlResult<()>
Sourcefn resize_pane(
&self,
id: PaneId,
direction: Direction,
delta_cells: i16,
) -> ControlResult<()>
fn resize_pane( &self, id: PaneId, direction: Direction, delta_cells: i16, ) -> ControlResult<()>
Resize a pane along one axis. delta_cells is signed — negative
shrinks. tmux’s resize-pane -L/-R/-U/-D.
Sourcefn apply_layout(&self, window: WindowId, kind: LayoutKind) -> ControlResult<()>
fn apply_layout(&self, window: WindowId, kind: LayoutKind) -> ControlResult<()>
Re-arrange a window’s existing panes into a named LayoutKind
preset (tmux select-layout). The panes keep their PTYs and
scrollback — only the window’s layout tree changes, then geometry
reflows. LayoutKind::Custom (and an empty window) is a no-op:
there is no canonical arrangement to impose, so the operator’s
manual tree wins. Built on LayoutNode::from_kind.
Sourcefn send_keys(&self, id: PaneId, bytes: &[u8]) -> ControlResult<()>
fn send_keys(&self, id: PaneId, bytes: &[u8]) -> ControlResult<()>
Send keystrokes (already-bytes-encoded — caller resolved the chord) to a pane’s PTY.
Sourcefn pane_subscriber_count(&self, id: PaneId) -> ControlResult<u32>
fn pane_subscriber_count(&self, id: PaneId) -> ControlResult<u32>
How many byte-stream subscribers are currently attached to the named pane. Returns 0 if the pane has no subscribers (or doesn’t exist — wraps the typed NoSuchPane miss into a 0 count so the migration call site doesn’t have to distinguish “no subscribers” from “pane gone”).
Sourcefn set_input_policy(&self, id: PaneId, policy: InputPolicy) -> ControlResult<()>
fn set_input_policy(&self, id: PaneId, policy: InputPolicy) -> ControlResult<()>
Replace a pane’s typed crate::pane::InputPolicy. Default
behavior is Free; setting Locked causes every
subsequent send_keys for that pane to return
ControlError::Rejected. Idempotent — same policy is a
no-op.
Provided Methods§
Sourcefn capabilities(&self) -> DaemonIdentity
fn capabilities(&self) -> DaemonIdentity
What this backend can actually do, and who it is.
The default answer is this build’s own capability set,
which is correct by construction for any backend that
executes in-process: there is no other peer whose age could
differ from ours. tear-core’s InProcess takes this
default.
A backend that talks to a separate process MUST override
— its peer may be an older build, and assuming otherwise is
exactly the silent-degradation this exists to stop.
tear-client’s Client overrides with the result of the
Request::Hello probe.
Consumers holding a &dyn MultiplexerControl (mado) can
therefore gate on a capability without knowing which backend
they hold.
Sourcefn new_session(&self, name: &str, shell: &str) -> ControlResult<SessionId>
fn new_session(&self, name: &str, shell: &str) -> ControlResult<SessionId>
Create a new session. name is the operator-visible label;
the returned SessionId is the stable handle. Defaults
to SessionSource::Human — agent-driven consumers (mado
MCP, automation) should call
Self::new_session_with_source so tear list --source
can audit provenance.
Sourcefn new_session_with_source(
&self,
name: &str,
shell: &str,
source: SessionSource,
) -> ControlResult<SessionId>
fn new_session_with_source( &self, name: &str, shell: &str, source: SessionSource, ) -> ControlResult<SessionId>
Create a session with a typed [SessionSource] tag. The
daemon stores this on the TearSession so tear list
can group by provenance and operators can audit
agent-created sessions.
Pane size defaults to 80×24. For consumers that already
know the target geometry (mado, attaching renderers),
prefer Self::new_session_with_source_and_size so the
shell spawns at the right size from t=0 — no
SIGWINCH-during-first-prompt redraw.
Sourcefn pane_resize_absolute(
&self,
id: PaneId,
cols: u16,
rows: u16,
) -> ControlResult<()>
fn pane_resize_absolute( &self, id: PaneId, cols: u16, rows: u16, ) -> ControlResult<()>
Set a pane’s PTY size to an absolute (cols, rows). Used by
GPU consumers (mado at Phase 3.1) when the window the pane
is rendered in resizes — the multiplexer must SIGWINCH the
child shell so TUI apps re-layout. Distinct from
Self::resize_pane which is the tmux-style delta-on-an-axis
op for keyboard-driven splits.
Default impl returns Rejected so passthrough backends
(tear-tmux-backend) can opt out.
Sourcefn pane_snapshot(&self, id: PaneId) -> ControlResult<PaneSnapshot>
fn pane_snapshot(&self, id: PaneId) -> ControlResult<PaneSnapshot>
Return a serializable snapshot of the named pane’s currently- rendered cell grid + cursor position. Consumers (mado at Phase 4) walk the snapshot to draw pixels without holding a reference into the live parser state.
Default impl returns Rejected so backends that don’t track
rendered state (e.g. tear-tmux-backend, which passes through
to tmux) can opt out. tear-core’s InProcess overrides
with the real implementation.
Sourcefn pane_cursor_keys_mode(&self, id: PaneId) -> ControlResult<bool>
fn pane_cursor_keys_mode(&self, id: PaneId) -> ControlResult<bool>
Lightweight query for DECCKM (DEC mode 1 — cursor-keys
application mode) on a pane. Consumers translating host
keystrokes to PTY bytes — mado’s keybind::madori_key_to_ pty_bytes is the canonical caller — hit this on every
arrow-key press to decide between ESC O A/B/C/D
(application mode) and ESC [ A/B/C/D (normal mode).
Default impl falls back to the full pane_snapshot and
reads cursor_keys_mode off the returned struct. Backends
that can answer cheaply (tear-core’s InProcess reads one
bool off the live PaneGrid) override for the no-alloc
path. tear-tmux-backend reasonably returns Rejected
since tmux doesn’t expose DECCKM through its control
protocol.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".