use ctl_term::{ColorMode, Console, DetectOptions, Probe, Stream, Terminal};
use ctl_text::anstyle::{AnsiColor, Style};
use ctl_text::{Context, Line, Measurement, Renderable, Span};
pub(crate) const ESC: char = '\u{1b}';
pub(crate) const PIPE: Probe = Probe::Redirected;
pub(crate) const TERMINAL: Probe = Probe::terminal(Some(100));
pub(crate) type Variables = &'static [(&'static str, &'static str)];
pub(crate) fn lookup(variables: Variables) -> impl Fn(&str) -> Option<String> {
move |name| {
variables
.iter()
.find(|(key, _)| *key == name)
.map(|(_, value)| (*value).to_owned())
}
}
pub(crate) fn terminal(probe: Probe, mode: ColorMode, variables: Variables) -> Terminal {
Terminal::from_probe(probe, mode, DetectOptions::new(), &lookup(variables))
}
pub(crate) fn console(probe: Probe, mode: ColorMode, variables: Variables) -> Console {
Console::new(Stream::Stdout, terminal(probe, mode, variables))
}
#[derive(Debug)]
pub(crate) struct Rows(pub(crate) Vec<Line>);
impl Renderable for Rows {
fn measure(&self, _: &Context) -> Measurement {
Measurement::exact(self.0.iter().map(Line::width).max().unwrap_or(0))
}
fn render(&self, _: &Context) -> Vec<Line> {
self.0.clone()
}
}
pub(crate) fn line(spans: &[(&str, Style)]) -> Line {
let mut line = Line::new();
for (text, style) in spans {
line.push(Span::new(text, *style));
}
line
}
pub(crate) fn fg(color: impl Into<ctl_text::anstyle::Color>) -> Style {
Style::new().fg_color(Some(color.into()))
}
pub(crate) fn red() -> Style {
fg(AnsiColor::Red)
}
pub(crate) fn widest(text: &str) -> u16 {
text.lines().map(ctl_text::text_width).max().unwrap_or(0)
}