use std::ops::Range; /// An RGB colour, the same shape wherever this crate names one -- no alpha, /// because the one place that needs partial transparency (dimming) says so /// with a separate flag rather than baking it into the colour. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Rgb { pub r: u8, pub g: u8, pub b: u8, } impl Rgb { pub const fn new(r: u8, g: u8, b: u8) -> Self { Self { r, g, b } } } #[derive(Debug, Clone)] pub struct AnsiPalette { pub colours: [Rgb; 16], pub foreground: Rgb, pub background: Rgb, } /// One span's worth of styling. `None` means unspecified. #[derive(Debug, Clone, Copy, PartialEq, Default)] pub struct Style { pub color: Option, /// How much of `color`'s alpha survives, 0.0-1.0; `None` is opaque. pub alpha: Option, pub background: Option, pub bold: bool, pub italic: bool, pub underline: bool, pub strikethrough: bool, } #[derive(Debug, Clone, PartialEq, Default)] pub struct StyledText { pub text: String, pub spans: Vec<(Range, Style)>, } impl StyledText { fn plain(text: String) -> Self { Self { text, spans: Vec::new(), } } } const ESC: char = '\u{1B}'; const BELL: char = '\u{7}'; pub fn ansi_styled(text: &str, palette: &AnsiPalette) -> StyledText { if !text.contains(ESC) && !text.contains('\r') { return StyledText::plain(text.to_string()); } let chars: Vec = text.chars().collect(); let mut runs: Vec<(String, Option