Skip to main content

Session

Struct Session 

Source
pub struct Session<T: AsyncReadExt + AsyncWriteExt + Unpin + Send> { /* private fields */ }
Expand description

A session handle for interacting with a spawned process.

The session provides methods to send input, expect patterns in output, and manage the lifecycle of the process.

Implementations§

Source§

impl<T: AsyncReadExt + AsyncWriteExt + Unpin + Send> Session<T>

Source

pub fn new(transport: T, config: SessionConfig) -> Self

Create a new session with the given transport.

Source

pub fn add_output_tap<F>(&mut self, f: F) -> TapId
where F: Fn(&[u8]) + Send + Sync + 'static,

Register a callback that will be invoked with every chunk of bytes read from the transport.

Taps observe the raw byte stream as it arrives — they receive bytes in the same form the underlying process produced them, including any ANSI escape sequences. Taps are invoked synchronously inside the read loop after the bytes are appended to the matcher buffer; they should be cheap and non-blocking. Use a channel if expensive work is required.

Multiple taps may be registered; they are invoked in registration order. Taps are dropped when the session is dropped.

§Example
use std::sync::Arc;
use std::sync::Mutex;
let captured: Arc<Mutex<Vec<u8>>> = Arc::new(Mutex::new(Vec::new()));
let buf = captured.clone();
session.add_output_tap(move |chunk| {
    buf.lock().unwrap().extend_from_slice(chunk);
});
Source

pub fn remove_output_tap(&mut self, id: TapId) -> bool

Remove a previously registered output tap by its TapId. Returns true if a tap was removed, false if the id was not registered (already removed, or never existed).

Source

pub fn output_tap_callbacks(&self) -> impl Iterator<Item = &OutputTap>

Iterate the callbacks for all currently registered output taps.

Exposed for instrumentation and inspection only — the read loops in expect and interact invoke these themselves. Returns the callback Arcs in registration order; ids are intentionally omitted (use add_output_tap’s return value if you need the id).

Source

pub const fn id(&self) -> &SessionId

Get the session ID.

Source

pub const fn state(&self) -> SessionState

Get the current session state.

Source

pub const fn config(&self) -> &SessionConfig

Get the session configuration.

Source

pub const fn is_eof(&self) -> bool

Check if EOF has been detected.

Source

pub fn buffer(&mut self) -> String

Get the current buffer contents.

Source

pub fn clear_buffer(&mut self)

Clear the buffer.

Source

pub const fn pattern_manager(&self) -> &PatternManager

Get the pattern manager for before/after patterns.

Source

pub const fn pattern_manager_mut(&mut self) -> &mut PatternManager

Get mutable access to the pattern manager.

Source

pub const fn set_state(&mut self, state: SessionState)

Set the session state.

Source

pub async fn send(&mut self, data: &[u8]) -> Result<()>

Send bytes to the process.

§Errors

Returns an error if the write fails.

Source

pub async fn send_str(&mut self, s: &str) -> Result<()>

Send a string to the process.

§Errors

Returns an error if the write fails.

Source

pub async fn send_line(&mut self, line: &str) -> Result<()>

Send a line to the process (appends newline based on config).

§Errors

Returns an error if the write fails.

Source

pub async fn send_control(&mut self, ctrl: ControlChar) -> Result<()>

Send a control character to the process.

§Errors

Returns an error if the write fails.

Source

pub async fn send_shift_tab(&mut self) -> Result<()>

Send a Shift+Tab keystroke.

Sends the xterm “back tab” sequence \x1b[Z (CSI Z). Most TUIs use this to cycle a focused-element ring backwards or, in Claude Code’s case, to cycle permission modes. Compatible with both plain xterm and the kitty keyboard protocol’s CSI-u fallback mode.

§Errors

Returns an error if the write fails.

Source

pub async fn send_paste(&mut self, text: &str) -> Result<()>

Send text using bracketed paste mode (DECSET 2004).

Wraps the content in \x1b[200~ and \x1b[201~ markers. Applications that have enabled bracketed paste treat the enclosed content as pasted input rather than typed input — this suppresses autocomplete, command-history scanning, and per-character interpretation such as a leading / triggering a slash-command popup. Safe to call even when the receiver hasn’t enabled bracketed paste: most terminals ignore the markers and deliver the inner text as-is.

§Errors

Returns an error if the write fails or if text contains the closing paste marker \x1b[201~, which would let the receiver drop out of paste mode mid-payload. Callers that want to send such bytes should write them through the regular send path.

Source

pub async fn expect(&mut self, pattern: impl Into<Pattern>) -> Result<Match>

Expect a pattern in the output.

Blocks until the pattern is matched, EOF is detected, or timeout occurs.

§Errors

Returns an error on timeout, EOF (if not expected), or I/O error.

Source

pub async fn expect_any(&mut self, patterns: &PatternSet) -> Result<Match>

Expect any of the given patterns.

§Errors

Returns an error on timeout, EOF (if not expected), or I/O error.

Source

pub async fn expect_timeout( &mut self, pattern: impl Into<Pattern>, timeout: Duration, ) -> Result<Match>

Expect with a specific timeout.

§Errors

Returns an error on timeout, EOF, or I/O error.

Source

pub async fn wait(&mut self) -> Result<ProcessExitStatus>

Wait for the process to exit.

This method blocks until EOF is detected on the session, which typically happens when the child process terminates.

§Warning

This method has no timeout and may block indefinitely if the process does not exit. Consider using wait_timeout or expect_eof_timeout for bounded waits.

§Errors

Returns an error if waiting fails due to I/O error.

Source

pub async fn wait_timeout( &mut self, timeout: Duration, ) -> Result<ProcessExitStatus>

Wait for the process to exit with a timeout.

Like wait, but with a maximum duration to wait.

§Errors

Returns an error if:

  • The timeout expires before the process exits
  • An I/O error occurs while waiting
Source

pub fn check(&mut self, pattern: &Pattern) -> Option<MatchResult>

Check if a pattern matches immediately without blocking.

Source

pub const fn transport(&self) -> &Arc<Mutex<T>>

Get the underlying transport.

Use with caution as direct access bypasses session management.

Source

pub fn interact(&self) -> InteractBuilder<'_, T>
where T: 'static,

Start an interactive session with pattern hooks.

This returns a builder that allows you to configure pattern-based callbacks that fire when patterns match in the output or input.

§Example
use rust_expect::{Session, InteractAction};

#[tokio::main]
async fn main() -> Result<(), rust_expect::ExpectError> {
    let mut session = Session::spawn("/bin/bash", &[]).await?;

    session.interact()
        .on_output("password:", |ctx| {
            ctx.send("my_password\n")
        })
        .on_output("logout", |_| {
            InteractAction::Stop
        })
        .start()
        .await?;

    Ok(())
}
Source

pub async fn run_dialog(&mut self, dialog: &Dialog) -> Result<DialogResult>

Run a dialog on this session.

A dialog is a predefined sequence of expect/send operations. This method executes the dialog and returns the result.

§Example
use rust_expect::{Session, Dialog, DialogStep};

#[tokio::main]
async fn main() -> Result<(), rust_expect::ExpectError> {
    let mut session = Session::spawn("/bin/bash", &[]).await?;

    let dialog = Dialog::named("shell_test")
        .step(DialogStep::new("prompt")
            .with_expect("$")
            .with_send("echo hello\n"))
        .step(DialogStep::new("verify")
            .with_expect("hello"));

    let result = session.run_dialog(&dialog).await?;
    assert!(result.success);
    Ok(())
}
§Errors

Returns an error if I/O fails. Step-level timeouts are reported in the DialogResult rather than as errors.

Source

pub async fn run_dialog_with( &mut self, dialog: &Dialog, executor: &DialogExecutor, ) -> Result<DialogResult>

Run a dialog with a custom executor.

This allows customizing the executor settings (max steps, default timeout).

§Errors

Returns an error if I/O fails.

Source

pub async fn expect_eof(&mut self) -> Result<Match>

Expect end-of-file (process termination).

This is a convenience method for waiting until the process terminates and closes its output stream.

§Example
use rust_expect::Session;

#[tokio::main]
async fn main() -> Result<(), rust_expect::ExpectError> {
    let mut session = Session::spawn("echo", &["hello"]).await?;
    session.expect("hello").await?;
    session.expect_eof().await?;
    Ok(())
}
§Errors

Returns an error if the session times out before EOF or an I/O error occurs.

Source

pub async fn expect_eof_timeout(&mut self, timeout: Duration) -> Result<Match>

Expect end-of-file with a specific timeout.

§Errors

Returns an error if the session times out before EOF or an I/O error occurs.

Source

pub async fn run_script<I, S>( &mut self, commands: I, prompt: Pattern, ) -> Result<Vec<Match>>
where I: IntoIterator<Item = S>, S: AsRef<str>,

Run a batch of commands, waiting for the prompt after each.

This is a convenience method for executing multiple shell commands in sequence. For each command, it sends the command line and waits for the prompt pattern to appear.

§Example
use rust_expect::{Session, Pattern};

#[tokio::main]
async fn main() -> Result<(), rust_expect::ExpectError> {
    let mut session = Session::spawn("/bin/bash", &[]).await?;
    session.expect(Pattern::shell_prompt()).await?;

    // Run a batch of commands
    let results = session.run_script(
        &["pwd", "whoami", "date"],
        Pattern::shell_prompt(),
    ).await?;

    for result in &results {
        println!("Output: {}", result.before.trim());
    }

    Ok(())
}
§Errors

Returns an error if any command times out or I/O fails. On error, partial results are lost; consider using Self::run_script_with_results if you need to capture partial results on failure.

Source

pub async fn run_script_timeout<I, S>( &mut self, commands: I, prompt: Pattern, timeout: Duration, ) -> Result<Vec<Match>>
where I: IntoIterator<Item = S>, S: AsRef<str>,

Run a batch of commands with a specific timeout per command.

Like run_script, but applies the given timeout to each command individually.

§Errors

Returns an error if any command times out or I/O fails.

Source

pub async fn run_script_with_results<I, S>( &mut self, commands: I, prompt: Pattern, ) -> (Vec<Match>, Option<ExpectError>)
where I: IntoIterator<Item = S>, S: AsRef<str>,

Run a batch of commands, collecting results even on failure.

Unlike run_script, this method continues collecting results and returns them along with any error that occurred.

§Returns

A tuple of (results, error) where:

  • results contains the matches for successfully completed commands
  • error is Some(err) if an error occurred, None if all commands succeeded
§Example
use rust_expect::{Session, Pattern};

#[tokio::main]
async fn main() -> Result<(), rust_expect::ExpectError> {
    let mut session = Session::spawn("/bin/bash", &[]).await?;
    session.expect(Pattern::shell_prompt()).await?;

    let (results, error) = session.run_script_with_results(
        &["pwd", "bad_command", "date"],
        Pattern::shell_prompt(),
    ).await;

    println!("Completed {} commands", results.len());
    if let Some(e) = error {
        eprintln!("Script failed at command {}: {}", results.len(), e);
    }

    Ok(())
}
Source§

impl Session<AsyncPty>

Source

pub async fn spawn(command: &str, args: &[&str]) -> Result<Self>

Spawn a new process with the given command.

This creates a new PTY, forks a child process, and returns a Session connected to the child’s terminal.

§Example
use rust_expect::Session;

#[tokio::main]
async fn main() -> Result<(), rust_expect::ExpectError> {
    let mut session = Session::spawn("/bin/bash", &[]).await?;
    session.expect("$").await?;
    session.send_line("echo hello").await?;
    session.expect("hello").await?;
    Ok(())
}
§Errors

Returns an error if:

  • The command contains null bytes
  • PTY allocation fails
  • Fork fails
  • The command cannot be executed
Source

pub async fn spawn_with_config( command: &str, args: &[&str], config: SessionConfig, ) -> Result<Self>

Spawn a new process with custom configuration.

§Errors

Returns an error if spawning fails.

Source

pub fn pid(&self) -> u32

Get the child process ID.

Source

pub async fn resize_pty(&mut self, cols: u16, rows: u16) -> Result<()>

Resize the terminal.

Also resizes the attached screen (if any) so it stays consistent with the PTY. Without this, screen-aware assertions would drift after a resize.

§Errors

Returns an error if the resize ioctl fails.

Source

pub fn signal(&self, signal: i32) -> Result<()>

Send a signal to the child process.

§Errors

Returns an error if sending the signal fails.

Source

pub fn kill(&self) -> Result<()>

Kill the child process.

§Errors

Returns an error if killing the process fails.

Trait Implementations§

Source§

impl<T: AsyncReadExt + AsyncWriteExt + Unpin + Send> Debug for Session<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<T> Freeze for Session<T>

§

impl<T> !RefUnwindSafe for Session<T>

§

impl<T> Send for Session<T>

§

impl<T> Sync for Session<T>

§

impl<T> Unpin for Session<T>

§

impl<T> UnsafeUnpin for Session<T>

§

impl<T> !UnwindSafe for Session<T>

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