use crossterm::tty::IsTty;
use std::io;
use vtcode_commons::color_policy::no_color_env_active;
pub trait TtyExt {
fn is_tty_ext(&self) -> bool;
fn supports_color(&self) -> bool;
fn is_interactive(&self) -> bool;
}
impl TtyExt for io::Stdout {
fn is_tty_ext(&self) -> bool {
self.is_tty()
}
fn supports_color(&self) -> bool {
if !self.is_tty() {
return false;
}
if no_color_env_active() {
return false;
}
if std::env::var_os("FORCE_COLOR").is_some() {
return true;
}
true
}
fn is_interactive(&self) -> bool {
self.is_tty() && self.supports_color()
}
}
impl TtyExt for io::Stderr {
fn is_tty_ext(&self) -> bool {
self.is_tty()
}
fn supports_color(&self) -> bool {
if !self.is_tty() {
return false;
}
if no_color_env_active() {
return false;
}
if std::env::var_os("FORCE_COLOR").is_some() {
return true;
}
true
}
fn is_interactive(&self) -> bool {
self.is_tty() && self.supports_color()
}
}
impl TtyExt for io::Stdin {
fn is_tty_ext(&self) -> bool {
self.is_tty()
}
fn supports_color(&self) -> bool {
self.is_tty()
}
fn is_interactive(&self) -> bool {
self.is_tty()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TtyCapabilities {
pub color: bool,
pub cursor: bool,
pub bracketed_paste: bool,
pub focus_events: bool,
pub mouse: bool,
pub keyboard_enhancement: bool,
}
impl TtyCapabilities {
pub fn detect() -> Option<Self> {
let stderr = io::stderr();
if !stderr.is_tty() {
return None;
}
Some(Self {
color: stderr.supports_color(),
cursor: true, bracketed_paste: true, focus_events: true, mouse: true, keyboard_enhancement: true, })
}
pub fn is_fully_featured(&self) -> bool {
self.color
&& self.cursor
&& self.bracketed_paste
&& self.focus_events
&& self.mouse
&& self.keyboard_enhancement
}
pub fn is_basic_tui(&self) -> bool {
self.color && self.cursor
}
}
pub fn is_interactive_session() -> bool {
io::stderr().is_tty() && io::stdin().is_tty()
}
pub fn terminal_size() -> Option<(u16, u16)> {
crossterm::terminal::size().ok()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tty_detection() {
let stdout = io::stdout();
let stderr = io::stderr();
let stdin = io::stdin();
let _ = stdout.is_tty();
let _ = stderr.is_tty();
let _ = stdin.is_tty();
}
#[test]
fn test_capabilities_detection() {
let caps = TtyCapabilities::detect();
let _ = caps.is_some() || caps.is_none();
}
#[test]
fn test_interactive_session() {
let _ = is_interactive_session();
}
}