termal_core 5.0.0

This library contains implementation for the termal library
Documentation
use std::time::Duration;

use crate::{Error, Result};

#[cfg(unix)]
mod unix;
#[cfg(windows)]
mod windows;

#[cfg(unix)]
pub use unix::MAX_STDIN_WAIT;
#[cfg(windows)]
pub use windows::MAX_STDIN_WAIT;
/// Waiting for stdin is not supported on this plarform so this is `0`.
#[cfg(all(not(unix), not(windows)))]
pub const MAX_STDIN_WAIT: Duration = Duration::ZERO;

/// Unprocessed system event.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub enum SysEvent {
    #[default]
    Timeout,
    StdinReady,
    WindowResize,
}

/// Size of terminal.
#[derive(Clone, Debug)]
pub struct TermSize {
    /// Width in characters.
    pub char_width: usize,
    /// Height in charaters.
    pub char_height: usize,
    /// Width in pixels. Not supported on windows (always 0).
    pub pixel_width: usize,
    /// Height in pixels. Not supported on windows (always 0).
    pub pixel_height: usize,
}

/// Enables raw terminal.
///
/// # Support
/// - Unix (Linux)
/// - Windows (not tested)
///
/// # Errors
/// - [`Error::NotSupportedOnPlatform`] when used on unsupported platform.
///   Supported is linux and windows.
/// - [`Error::Io`] on io error.
pub fn enable_raw_mode() -> Result<()> {
    #[cfg(unix)]
    return unix::enable_raw_mode();

    #[cfg(windows)]
    return windows::enable_raw_mode();

    #[allow(unreachable_code)]
    Err(Error::NotSupportedOnPlatform("raw mode"))
}

/// Disables raw terminal.
///
/// # Support
/// - Unix (Linux)
/// - Windows (not tested)
///
/// # Errors
/// - [`Error::NotSupportedOnPlatform`] when used on  unsupported platform.
/// - [`Error::Io`] on io error.
pub fn disable_raw_mode() -> Result<()> {
    #[cfg(unix)]
    return unix::disable_raw_mode();

    #[cfg(windows)]
    return windows::disable_raw_mode();

    #[allow(unreachable_code)]
    Err(Error::NotSupportedOnPlatform("raw mode"))
}

/// Enable special events handling.
///
/// On windows this is noop. On linux this blocks the signal WINCHG to allow
/// proper handling of the window resize.
pub fn init_events() -> Result<()> {
    #[cfg(unix)]
    return unix::init_events();

    #[allow(unreachable_code)]
    Ok(())
}

/// Checks if raw mode is enabled.
///
/// # Support
/// - Unix (Linux)
/// - Windows (not tested)
///
/// This will conservatively return false (e.g. on unsupported or when fails)
pub fn is_raw_mode_enabled() -> bool {
    #[cfg(unix)]
    return unix::is_raw_mode_enabled();

    #[cfg(windows)]
    return windows::is_raw_mode_enabled().unwrap_or_default();

    #[allow(unreachable_code)]
    false
}

/// Gets the terminal size.
///
/// # Support
/// - Unix (Linux)
/// - Windows (not tested)
///   - Doesn't support size in pixels. (will be set to 0)
///
/// # Errors
/// - [`Error::NotSupportedOnPlatform`] when used on unsupported platform.
/// - [`Error::Io`] on io error.
pub fn term_size() -> Result<TermSize> {
    #[cfg(unix)]
    return unix::window_size();

    #[cfg(windows)]
    return windows::term_size();

    #[allow(unreachable_code)]
    Err(Error::NotSupportedOnPlatform("terminal size"))
}

/// Wait for any event on stdin, but not longer than the timeout.
///
/// If timeout is [`Duration::MAX`], this will wait indefinitely.
///
/// # Returns
/// `true` if there is event on stdin. If this returns due to timeout or
/// interrupt, returns `false`.
///
/// # Support
/// - Unix (Linux)
/// - Windows (not tested)
///
/// # Errors
/// - [`Error::NotSupportedOnPlatform`] on unsupported platforms.
/// - [`Error::Io`] on io error.
/// - [`Error::WaitAbandoned`] when unexpected state happens. See error
///   description.
/// - [`Error::IntConvert`] when timeout value is too large (but not
///   [`Duration::MAX`])
pub fn wait_for_stdin(timeout: Duration) -> Result<bool> {
    #[cfg(unix)]
    return unix::wait_for_stdin(timeout);

    #[cfg(windows)]
    return windows::wait_for_stdin(timeout);

    #[allow(unreachable_code)]
    {
        _ = timeout;
        Err(Error::NotSupportedOnPlatform("stdin timeout"))
    }
}

/// Wait for any event on stdin or other supported event, but not longer than
/// the timeout.
///
/// If timeout is [`Duration::MAX`], this will wait indefinitely.
///
/// # Returns
/// The kind of event detected or `SysEvent::Timeout` if timeout was reached.
///
/// # Support
/// - Unix (Linux)
///     - `SysEvent::Stdin`
///     - `SysEvent::Resize`
/// - Windows (not tested)
///     - `SysEvent::Stdin`
///
/// # Errors
/// - [`Error::NotSupportedOnPlatform`] on unsupported platforms.
/// - [`Error::Io`] on io error.
/// - [`Error::WaitAbandoned`] when unexpected state happens. See error
///   description.
/// - [`Error::IntConvert`] when timeout value is too large (but not
///   [`Duration::MAX`])
pub fn wait_for_event(timeout: Duration) -> Result<SysEvent> {
    #[cfg(unix)]
    return unix::wait_for_event(timeout);

    #[cfg(windows)]
    return windows::wait_for_stdin(timeout).map(|b| {
        if b {
            SysEvent::StdinReady
        } else {
            SysEvent::Timeout
        }
    });

    #[allow(unreachable_code)]
    {
        _ = timeout;
        Err(Error::NotSupportedOnPlatform("stdin timeout"))
    }
}