scosh-core 0.1.0

Portable session state and terminal event core for scosh
Documentation
//! Portable session state and terminal event semantics for scosh hosts.
//!
//! The crate deliberately contains no transport, process, PTY, or terminal
//! renderer code.  Desktop and mobile adapters own those boundaries.
//!
//! See the repository's [host examples](https://github.com/dyxushuai/scosh/tree/main/examples)
//! for the event loop used by Apple, Android, and Rust hosts.

pub mod bootstrap;
pub mod errors;
pub mod events;
pub mod input;
pub mod lifecycle;
pub mod recovery;
pub mod types;

mod session;

pub use errors::{ErrorCategory, SdkError};
pub use events::{
    AcknowledgeResult, CommitReceipt, SessionEvent, SessionStatus, SnapshotRequiredReason,
    TerminalEffect,
};
pub use input::{InputId, InputOutcome, InputRequest, InputResult};
pub use session::{Session, SessionOptions};
pub use types::{
    Dimensions, PrimaryScrollRow, StateRevision, TerminalCell, TerminalCellStyle, TerminalColor,
    TerminalCursor, TerminalDelta, TerminalSnapshot, TerminalState, TerminalStateDelta,
    TerminalStateRow,
};

use std::fmt;

/// Stable, transport-neutral errors exposed by the portable core.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum CoreError {
    InvalidDimensions {
        columns: u16,
        rows: u16,
    },
    InvalidCellCount {
        expected: usize,
        actual: usize,
    },
    InvalidCursor {
        column: u16,
        row: u16,
    },
    InvalidRow {
        expected: u16,
        actual: usize,
    },
    InvalidStateDelta,
    InvalidUtf8,
    CellTextTooLarge {
        size: usize,
    },
    StateTooLarge {
        cells: usize,
    },
    TooManyScrollRows {
        size: usize,
    },
    RevisionGap {
        expected: StateRevision,
        got: StateRevision,
    },
    NoSnapshot,
    DimensionsMismatch,
    ConsumerStalled,
    UnknownReceipt,
    StaleReceipt,
    InputTooLarge {
        size: usize,
    },
    NotLive,
}

impl fmt::Display for CoreError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::InvalidDimensions { columns, rows } => {
                write!(f, "invalid terminal dimensions {columns}x{rows}")
            }
            Self::InvalidCellCount { expected, actual } => {
                write!(
                    f,
                    "invalid terminal cell count: expected {expected}, got {actual}"
                )
            }
            Self::InvalidCursor { column, row } => write!(f, "invalid cursor {column},{row}"),
            Self::InvalidRow { expected, actual } => {
                write!(
                    f,
                    "invalid row cell count: expected {expected}, got {actual}"
                )
            }
            Self::InvalidStateDelta => f.write_str("invalid terminal state delta"),
            Self::InvalidUtf8 => f.write_str("terminal cell is not UTF-8"),
            Self::CellTextTooLarge { size } => write!(f, "terminal cell is too large: {size}"),
            Self::StateTooLarge { cells } => {
                write!(f, "terminal state is too large: {cells} cells")
            }
            Self::TooManyScrollRows { size } => write!(f, "too many primary scroll rows: {size}"),
            Self::RevisionGap { expected, got } => {
                write!(
                    f,
                    "state revision gap: expected {}, got {}",
                    expected.get(),
                    got.get()
                )
            }
            Self::NoSnapshot => f.write_str("no terminal snapshot installed"),
            Self::DimensionsMismatch => {
                f.write_str("terminal dimensions changed without a snapshot")
            }
            Self::ConsumerStalled => f.write_str("host event consumer is stalled"),
            Self::UnknownReceipt => f.write_str("unknown commit receipt"),
            Self::StaleReceipt => f.write_str("stale commit receipt"),
            Self::InputTooLarge { size } => write!(f, "input is too large: {size}"),
            Self::NotLive => f.write_str("session is not live"),
        }
    }
}

impl std::error::Error for CoreError {}