use super::Color;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Style {
foreground: Option<Color>,
background: Option<Color>,
attributes: u8,
}
const BOLD_BIT: u8 = 1;
const DIM_BIT: u8 = 1 << 1;
const ITALIC_BIT: u8 = 1 << 2;
const UNDERLINE_BIT: u8 = 1 << 3;
const STRIKETHROUGH_BIT: u8 = 1 << 4;
impl Style {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn fg(mut self, color: Color) -> Self {
self.foreground = Some(color);
self
}
#[must_use]
pub fn bg(mut self, color: Color) -> Self {
self.background = Some(color);
self
}
#[must_use]
pub fn bold(mut self) -> Self {
self.attributes |= BOLD_BIT;
self
}
#[must_use]
pub fn dim(mut self) -> Self {
self.attributes |= DIM_BIT;
self
}
#[must_use]
pub fn italic(mut self) -> Self {
self.attributes |= ITALIC_BIT;
self
}
#[must_use]
pub fn underline(mut self) -> Self {
self.attributes |= UNDERLINE_BIT;
self
}
#[must_use]
pub fn strikethrough(mut self) -> Self {
self.attributes |= STRIKETHROUGH_BIT;
self
}
#[must_use]
pub fn is_plain(&self) -> bool {
*self == Self::default()
}
#[must_use]
pub fn paint(&self, text: &str) -> String {
if self.is_plain() {
return text.to_string();
}
let mut codes: Vec<String> = Vec::new();
for (bit, code) in [
(BOLD_BIT, "1"),
(DIM_BIT, "2"),
(ITALIC_BIT, "3"),
(UNDERLINE_BIT, "4"),
(STRIKETHROUGH_BIT, "9"),
] {
if self.attributes & bit != 0 {
codes.push(code.to_string());
}
}
codes.extend(self.foreground.map(|color| color.sgr(false)));
codes.extend(self.background.map(|color| color.sgr(true)));
format!("\u{1b}[{}m{text}\u{1b}[0m", codes.join(";"))
}
}
#[cfg(test)]
#[path = "style.test.rs"]
mod tests;
#[cfg(test)]
#[path = "style.spec.rs"]
mod spec;