tastty-driver 0.1.0

Terminal automation driver built on tastty
use crate::{ParseColorError, ParseInputError, Signal, WaitError};

/// Opaque carrier for an underlying regex-compile diagnostic.
///
/// Used as the `source` payload on
/// [`WaitError::InvalidRegex`](crate::WaitError::InvalidRegex) and
/// [`SearchError::InvalidRegex`](crate::SearchError::InvalidRegex). The
/// stored string is the [`regex::Error`] message captured at the failure
/// site; the original typed error is intentionally not exposed so a future
/// major bump of the `regex` crate cannot become a public semver hazard
/// for this crate.
#[derive(Clone, Debug, thiserror::Error)]
#[error("{0}")]
pub struct InvalidRegexSource(String);

impl From<regex::Error> for InvalidRegexSource {
    fn from(err: regex::Error) -> Self {
        Self(err.to_string())
    }
}

/// Errors produced by terminal driver operations.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
    /// No command was configured before spawning.
    #[error("no command configured")]
    MissingCommand,
    /// Spawning a `tastty` terminal failed.
    #[error(transparent)]
    Spawn(tastty::Error),
    /// Sending raw bytes failed.
    #[error(transparent)]
    Send(tastty::Error),
    /// Sending a key event failed.
    #[error(transparent)]
    SendKey(tastty::Error),
    /// Sending a paste frame failed.
    #[error(transparent)]
    SendPaste(tastty::Error),
    /// Resizing the terminal failed.
    #[error(transparent)]
    Resize(tastty::Error),
    /// Polling the child exit status failed.
    #[error(transparent)]
    ExitStatus(tastty::Error),
    /// Force-killing the child failed.
    #[error(transparent)]
    Kill(tastty::Error),
    /// Waiting for a screen condition failed.
    #[error(transparent)]
    Wait(Box<WaitError>),
    /// Parsing input failed.
    #[error(transparent)]
    ParseInput(#[from] ParseInputError),
    /// Parsing a color failed.
    #[error(transparent)]
    ParseColor(#[from] ParseColorError),
    /// The session has no child process id to signal.
    #[error("terminal session has no child process id")]
    MissingProcessId,
    /// Signaling is not supported on this platform.
    #[error("signals are not supported on this platform")]
    UnsupportedSignal,
    /// Sending a signal failed.
    #[error("failed to send signal {signal}: {source}")]
    Signal {
        /// Signal that was requested.
        signal: Signal,
        /// Underlying OS error.
        #[source]
        source: std::io::Error,
    },
    /// Spawning a background thread failed.
    #[error("failed to spawn thread '{name}': {source}")]
    ThreadSpawn {
        /// Name assigned to the thread.
        name: &'static str,
        /// Underlying OS error.
        #[source]
        source: std::io::Error,
    },
}

/// Convenient result alias for driver operations.
pub type Result<T> = std::result::Result<T, Error>;

impl From<WaitError> for Error {
    fn from(error: WaitError) -> Self {
        Self::Wait(Box::new(error))
    }
}