use std::io::IsTerminal;
pub const CODE_BG: crossterm::style::Color = crossterm::style::Color::Rgb {
r: 50,
g: 40,
b: 25,
};
pub const INPUT_BG: crossterm::style::Color = crossterm::style::Color::Rgb {
r: 60,
g: 60,
b: 60,
};
pub fn is_tty() -> bool {
static IS_TTY: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
*IS_TTY.get_or_init(|| std::io::stdout().is_terminal())
}
pub fn header_cell(text: &str) -> comfy_table::Cell {
if is_tty() {
comfy_table::Cell::new(text)
.fg(comfy_table::Color::Cyan)
.add_attribute(comfy_table::Attribute::Bold)
} else {
comfy_table::Cell::new(text)
}
}
pub fn bold_cell(text: &str) -> comfy_table::Cell {
if is_tty() {
comfy_table::Cell::new(text).add_attribute(comfy_table::Attribute::Bold)
} else {
comfy_table::Cell::new(text)
}
}
pub fn green_cell(text: &str) -> comfy_table::Cell {
if is_tty() {
comfy_table::Cell::new(text).fg(comfy_table::Color::Green)
} else {
comfy_table::Cell::new(text)
}
}
pub fn yellow_cell(text: &str) -> comfy_table::Cell {
if is_tty() {
comfy_table::Cell::new(text).fg(comfy_table::Color::Yellow)
} else {
comfy_table::Cell::new(text)
}
}
pub fn dim_cell(text: &str) -> comfy_table::Cell {
if is_tty() {
comfy_table::Cell::new(text).fg(comfy_table::Color::DarkGrey)
} else {
comfy_table::Cell::new(text)
}
}
pub fn agent_name(text: &str) -> String {
if is_tty() {
use crossterm::style::Stylize;
text.cyan().bold().to_string()
} else {
text.to_string()
}
}
pub fn code_ref(text: &str) -> String {
if is_tty() {
use crossterm::style::Stylize;
format!(" {} ", text)
.as_str()
.yellow()
.on(CODE_BG)
.to_string()
} else {
format!("`{}`", text)
}
}
pub fn input_badge(text: &str) -> String {
if is_tty() {
use crossterm::style::Stylize;
format!(" {} ", text)
.as_str()
.yellow()
.on(INPUT_BG)
.to_string()
} else {
format!("\"{}\"", text)
}
}
pub fn url(text: &str) -> String {
if is_tty() {
use crossterm::style::{Attribute, Color, ContentStyle, StyledContent};
let style = ContentStyle {
foreground_color: Some(Color::Cyan),
attributes: Attribute::Underlined.into(),
..Default::default()
};
StyledContent::new(style, text).to_string()
} else {
text.to_string()
}
}
pub fn dim(text: &str) -> String {
if is_tty() {
use crossterm::style::Stylize;
text.dark_grey().to_string()
} else {
text.to_string()
}
}
pub fn key_value(text: &str) -> String {
if is_tty() {
use crossterm::style::Stylize;
text.bold().to_string()
} else {
text.to_string()
}
}
pub fn error_prefix() -> String {
if is_tty() {
use crossterm::style::Stylize;
"error:".red().bold().to_string()
} else {
"error:".to_string()
}
}
pub fn separator(width: usize) -> String {
let line = "\u{2500}".repeat(width);
if is_tty() {
use crossterm::style::Stylize;
line.as_str().dark_grey().to_string()
} else {
line
}
}
pub fn changelog_skin() -> termimad::MadSkin {
let mut skin = termimad::MadSkin::default();
use termimad::crossterm::style::{Attribute, Color as TColor};
for h in &mut skin.headers {
h.set_fg(TColor::Magenta);
h.add_attr(Attribute::Bold);
h.compound_style.remove_attr(Attribute::Underlined);
}
skin.bullet =
termimad::StyledChar::from_fg_char(termimad::crossterm::style::Color::Magenta, '•');
skin.inline_code
.set_fg(termimad::crossterm::style::Color::Yellow);
skin.inline_code
.set_bg(termimad::crossterm::style::Color::Rgb {
r: 50,
g: 40,
b: 25,
});
skin
}
pub fn style_urls(text: &str) -> String {
use crossterm::style::{Attribute, Color, ContentStyle, StyledContent};
let url_re = regex::Regex::new(r"https?://[^\s)\]>]+").unwrap();
url_re
.replace_all(text, |caps: ®ex::Captures| {
let url_text = &caps[0];
let style = ContentStyle {
foreground_color: Some(Color::Cyan),
attributes: Attribute::Underlined.into(),
..Default::default()
};
StyledContent::new(style, url_text).to_string()
})
.into_owned()
}