vt100/
attrs.rs

1use tui::style::Modifier;
2
3use crate::term::BufWrite as _;
4
5/// Represents a foreground or background color for cells.
6#[derive(Eq, PartialEq, Debug, Copy, Clone)]
7pub enum Color {
8  /// The default terminal color.
9  Default,
10
11  /// An indexed terminal color.
12  Idx(u8),
13
14  /// An RGB terminal color. The parameters are (red, green, blue).
15  Rgb(u8, u8, u8),
16}
17
18impl Default for Color {
19  fn default() -> Self {
20    Self::Default
21  }
22}
23
24impl Color {
25  pub fn to_tui(self) -> tui::style::Color {
26    match self {
27      Color::Default => tui::style::Color::Reset,
28      Color::Idx(index) => tui::style::Color::Indexed(index),
29      Color::Rgb(r, g, b) => tui::style::Color::Rgb(r, g, b),
30    }
31  }
32}
33
34impl From<termwiz::color::ColorSpec> for Color {
35  fn from(value: termwiz::color::ColorSpec) -> Self {
36    match value {
37      termwiz::color::ColorSpec::Default => Self::Default,
38      termwiz::color::ColorSpec::PaletteIndex(idx) => Self::Idx(idx),
39      termwiz::color::ColorSpec::TrueColor(srgba) => {
40        let (r, g, b, _) = srgba.to_srgb_u8();
41        Self::Rgb(r, g, b)
42      }
43    }
44  }
45}
46
47const TEXT_MODE_BOLD: u8 = 0b0000_0001;
48const TEXT_MODE_ITALIC: u8 = 0b0000_0010;
49const TEXT_MODE_UNDERLINE: u8 = 0b0000_0100;
50const TEXT_MODE_INVERSE: u8 = 0b0000_1000;
51
52#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
53pub struct Attrs {
54  pub fgcolor: Color,
55  pub bgcolor: Color,
56  pub mode: u8,
57}
58
59impl Attrs {
60  pub fn bold(&self) -> bool {
61    self.mode & TEXT_MODE_BOLD != 0
62  }
63
64  pub fn set_bold(&mut self, bold: bool) {
65    if bold {
66      self.mode |= TEXT_MODE_BOLD;
67    } else {
68      self.mode &= !TEXT_MODE_BOLD;
69    }
70  }
71
72  pub fn italic(&self) -> bool {
73    self.mode & TEXT_MODE_ITALIC != 0
74  }
75
76  pub fn set_italic(&mut self, italic: bool) {
77    if italic {
78      self.mode |= TEXT_MODE_ITALIC;
79    } else {
80      self.mode &= !TEXT_MODE_ITALIC;
81    }
82  }
83
84  pub fn underline(&self) -> bool {
85    self.mode & TEXT_MODE_UNDERLINE != 0
86  }
87
88  pub fn set_underline(&mut self, underline: bool) {
89    if underline {
90      self.mode |= TEXT_MODE_UNDERLINE;
91    } else {
92      self.mode &= !TEXT_MODE_UNDERLINE;
93    }
94  }
95
96  pub fn inverse(&self) -> bool {
97    self.mode & TEXT_MODE_INVERSE != 0
98  }
99
100  pub fn set_inverse(&mut self, inverse: bool) {
101    if inverse {
102      self.mode |= TEXT_MODE_INVERSE;
103    } else {
104      self.mode &= !TEXT_MODE_INVERSE;
105    }
106  }
107
108  pub fn write_escape_code_diff(&self, contents: &mut Vec<u8>, other: &Self) {
109    if self != other && self == &Self::default() {
110      crate::term::ClearAttrs::default().write_buf(contents);
111      return;
112    }
113
114    let attrs = crate::term::Attrs::default();
115
116    let attrs = if self.fgcolor == other.fgcolor {
117      attrs
118    } else {
119      attrs.fgcolor(self.fgcolor)
120    };
121    let attrs = if self.bgcolor == other.bgcolor {
122      attrs
123    } else {
124      attrs.bgcolor(self.bgcolor)
125    };
126    let attrs = if self.bold() == other.bold() {
127      attrs
128    } else {
129      attrs.bold(self.bold())
130    };
131    let attrs = if self.italic() == other.italic() {
132      attrs
133    } else {
134      attrs.italic(self.italic())
135    };
136    let attrs = if self.underline() == other.underline() {
137      attrs
138    } else {
139      attrs.underline(self.underline())
140    };
141    let attrs = if self.inverse() == other.inverse() {
142      attrs
143    } else {
144      attrs.inverse(self.inverse())
145    };
146
147    attrs.write_buf(contents);
148  }
149}
150
151impl Attrs {
152  pub fn mods_to_tui(&self) -> tui::style::Modifier {
153    let mut mods = Modifier::empty();
154    mods.set(Modifier::BOLD, self.bold());
155    mods.set(Modifier::ITALIC, self.italic());
156    mods.set(Modifier::UNDERLINED, self.underline());
157    mods.set(Modifier::REVERSED, self.inverse());
158    mods
159  }
160}