Skip to content

Commit

Permalink
feat: decouple public API from dependencies
Browse files Browse the repository at this point in the history
passcod committed Jan 1, 2025

Unverified

No user is associated with the committer email.
1 parent dd1430a commit 165fe96
Showing 1 changed file with 75 additions and 21 deletions.
96 changes: 75 additions & 21 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -683,34 +683,85 @@ pub fn is_windows_10() -> bool {
#[derive(Debug, Error)]
pub enum Error {
/// Any I/O error.
#[error(transparent)]
#[error("io: {0}")]
Io(#[from] io::Error),

/// A non-success exit status from a command.
#[error("{0}: {1}")]
#[error("command: {0}: {1}")]
Command(&'static str, ExitStatus),

/// Any nix (libc) error.
#[cfg(unix)]
#[error(transparent)]
Nix(#[from] nix::Error),
#[error("unix: {0}")]
Nix(#[from] NixError),

/// Any terminfo error.
#[error(transparent)]
Terminfo(#[from] terminfo::Error),
#[error("terminfo: {0}")]
Terminfo(#[from] TerminfoError),

/// A missing terminfo capability.
#[error("required terminfo capability not available: {0}")]
#[error("terminfo: capability not available: {0}")]
TerminfoCap(&'static str),

/// A null-pointer error.
#[error("encountered a null pointer while reading {0}")]
#[error("ffi: encountered a null pointer while reading {0}")]
NullPtr(&'static str),
}

/// Nix error type.
///
/// This wraps a [`nix::Error`] to avoid directly exposing the type in the public API, which
/// required a breaking change every time `clearscreen` updated its `nix` version.
///
/// To obtain a nix error, convert this error to an `i32` then use [`nix::Error::from_raw`]:
///
/// Creating a [`NixError`] is explicitly not possible from the public API.
///
/// ```no_compile
/// let nix_error = nix::Error::from_raw(error.into());
/// assert_eq!(nix_error, nix::Error::EINVAL);
/// ```
#[cfg(unix)]
#[derive(Debug, Error)]
#[error(transparent)]
pub struct NixError(nix::Error);

#[cfg(unix)]
impl From<NixError> for i32 {
fn from(err: NixError) -> Self {
err.0 as _
}
}

/// Terminfo error type.
///
/// This wraps a [`terminfo::Error`] to avoid directly exposing the type in the public API, which
/// required a breaking change every time `clearscreen` updated its `terminfo` version.
#[derive(Debug, Error)]
#[error("{description}")]
pub struct TerminfoError {
inner: terminfo::Error,
description: String,
}

impl From<terminfo::Error> for TerminfoError {
fn from(inner: terminfo::Error) -> Self {
Self {
description: inner.to_string(),
inner,
}
}
}

impl From<terminfo::Error> for Error {
fn from(err: terminfo::Error) -> Self {
Self::Terminfo(TerminfoError::from(err))
}
}

#[cfg(unix)]
mod unix {
use super::Error;
use super::{Error, NixError};

use nix::{
sys::termios::{
@@ -726,8 +777,10 @@ mod unix {
write_termios(|t| {
t.input_flags.insert(
InputFlags::BRKINT
| InputFlags::ICRNL | InputFlags::IGNPAR
| InputFlags::ISTRIP | InputFlags::IXON,
| InputFlags::ICRNL
| InputFlags::IGNPAR
| InputFlags::ISTRIP
| InputFlags::IXON,
);
t.output_flags.insert(OutputFlags::OPOST);
t.local_flags.insert(LocalFlags::ICANON | LocalFlags::ISIG);
@@ -736,11 +789,12 @@ mod unix {

pub(crate) fn vt_well_done() -> Result<(), Error> {
write_termios(|t| {
let mut inserts =
InputFlags::BRKINT
| InputFlags::ICRNL | InputFlags::IGNPAR
| InputFlags::IMAXBEL
| InputFlags::ISTRIP | InputFlags::IXON;
let mut inserts = InputFlags::BRKINT
| InputFlags::ICRNL
| InputFlags::IGNPAR
| InputFlags::IMAXBEL
| InputFlags::ISTRIP
| InputFlags::IXON;

#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
{
@@ -763,19 +817,19 @@ mod unix {
}

fn write_termios(f: impl Fn(&mut Termios)) -> Result<(), Error> {
if isatty(stdin().as_raw_fd())? {
let mut t = tcgetattr(stdin().as_fd())?;
if isatty(stdin().as_raw_fd()).map_err(NixError)? {
let mut t = tcgetattr(stdin().as_fd()).map_err(NixError)?;
reset_termios(&mut t);
f(&mut t);
tcsetattr(stdin().as_fd(), TCSANOW, &t)?;
tcsetattr(stdin().as_fd(), TCSANOW, &t).map_err(NixError)?;
} else {
let tty = OpenOptions::new().read(true).write(true).open("/dev/tty")?;
let fd = tty.as_fd();

let mut t = tcgetattr(fd)?;
let mut t = tcgetattr(fd).map_err(NixError)?;
reset_termios(&mut t);
f(&mut t);
tcsetattr(fd, TCSANOW, &t)?;
tcsetattr(fd, TCSANOW, &t).map_err(NixError)?;
}

Ok(())

0 comments on commit 165fe96

Please sign in to comment.