#[cfg(unix)]
use crate::tui::terminal_lib_backends::{TERMINAL_LIB_BACKEND, TerminalLibBackend};
use crate::{ColWidth, Size, height, width};
use miette::IntoDiagnostic;
use std::io::IsTerminal;
pub const DEFAULT_WIDTH: u16 = 80;
#[cfg(unix)]
fn is_tty_stdin() -> bool {
match TERMINAL_LIB_BACKEND {
TerminalLibBackend::Crossterm => std::io::stdin().is_terminal(),
TerminalLibBackend::DirectToAnsi => rustix::termios::isatty(std::io::stdin()),
}
}
#[cfg(not(unix))]
fn is_tty_stdin() -> bool { std::io::stdin().is_terminal() }
#[cfg(unix)]
fn is_tty_stdout() -> bool {
match TERMINAL_LIB_BACKEND {
TerminalLibBackend::Crossterm => std::io::stdout().is_terminal(),
TerminalLibBackend::DirectToAnsi => rustix::termios::isatty(std::io::stdout()),
}
}
#[cfg(not(unix))]
fn is_tty_stdout() -> bool { std::io::stdout().is_terminal() }
#[cfg(unix)]
fn is_tty_stderr() -> bool {
match TERMINAL_LIB_BACKEND {
TerminalLibBackend::Crossterm => std::io::stderr().is_terminal(),
TerminalLibBackend::DirectToAnsi => rustix::termios::isatty(std::io::stderr()),
}
}
#[cfg(not(unix))]
fn is_tty_stderr() -> bool { std::io::stderr().is_terminal() }
#[must_use]
pub fn get_terminal_width_no_default() -> Option<ColWidth> {
match get_size() {
Ok(size) => Some(size.col_width),
Err(_) => None,
}
}
#[must_use]
pub fn get_terminal_width() -> ColWidth {
match get_size() {
Ok(size) => size.col_width,
Err(_) => width(DEFAULT_WIDTH),
}
}
#[cfg(unix)]
pub fn get_size() -> miette::Result<Size> {
match TERMINAL_LIB_BACKEND {
TerminalLibBackend::Crossterm => {
let (columns, rows) = crossterm::terminal::size().into_diagnostic()?;
Ok(width(columns) + height(rows))
}
TerminalLibBackend::DirectToAnsi => {
let winsize = rustix::termios::tcgetwinsize(std::io::stdout())
.map_err(|e| miette::miette!("tcgetwinsize failed: {}", e))?;
Ok(width(winsize.ws_col) + height(winsize.ws_row))
}
}
}
#[cfg(not(unix))]
pub fn get_size() -> miette::Result<Size> {
let (columns, rows) = crossterm::terminal::size().into_diagnostic()?;
Ok(width(columns) + height(rows))
}
#[derive(Debug)]
pub enum StdinIsPipedResult {
StdinIsPiped,
StdinIsNotPiped,
}
#[derive(Debug)]
pub enum StdoutIsPipedResult {
StdoutIsPiped,
StdoutIsNotPiped,
}
#[must_use]
pub fn is_stdin_piped() -> StdinIsPipedResult {
if is_tty_stdin() {
StdinIsPipedResult::StdinIsNotPiped
} else {
StdinIsPipedResult::StdinIsPiped
}
}
#[must_use]
pub fn is_stdout_piped() -> StdoutIsPipedResult {
if is_tty_stdout() {
StdoutIsPipedResult::StdoutIsNotPiped
} else {
StdoutIsPipedResult::StdoutIsPiped
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum TTYResult {
IsInteractive,
IsNotInteractive,
}
#[must_use]
pub fn is_stdin_interactive() -> TTYResult {
if is_tty_stdin() {
TTYResult::IsInteractive
} else {
TTYResult::IsNotInteractive
}
}
#[must_use]
pub fn is_headless() -> TTYResult {
#[cfg(target_os = "windows")]
if std::env::var("CARGO").is_ok() || std::env::var("CARGO_PKG_NAME").is_ok() {
return TTYResult::IsInteractive;
}
if !is_tty_stdin() && !is_tty_stdout() && !is_tty_stderr() {
TTYResult::IsNotInteractive
} else {
TTYResult::IsInteractive
}
}
#[must_use]
pub fn is_output_interactive() -> TTYResult {
if !is_tty_stdout() || !is_tty_stderr() {
TTYResult::IsNotInteractive
} else {
TTYResult::IsInteractive
}
}