ailloli_ui_terminal_core/style.rs
1//! Provider-neutral terminal colors and SGR text attributes.
2
3use serde::{Deserialize, Serialize};
4
5/// Terminal foreground/background color selection.
6///
7/// `Ansi` normally carries one of the 16 base palette indices, but all `u8`
8/// values are representable. `Indexed` covers the full 0–255 extended palette.
9/// RGB components are unpremultiplied 0–255 channel values.
10///
11/// # Examples
12///
13/// ```
14/// use ailloli_ui_terminal_core::TerminalColor;
15/// let red = TerminalColor::Rgb(255, 0, 0);
16/// assert_ne!(red, TerminalColor::DefaultFg);
17/// ```
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
19pub enum TerminalColor {
20 /// Renderer/theme default foreground.
21 DefaultFg,
22 /// Renderer/theme default background.
23 DefaultBg,
24 /// Base ANSI palette index, conventionally 0–15 but not validated.
25 Ansi(u8),
26 /// Extended 256-color palette index, 0–255.
27 Indexed(u8),
28 /// Explicit red, green, and blue channels, each 0–255.
29 Rgb(u8, u8, u8),
30}
31
32/// Complete style attached to a terminal cell.
33///
34/// Flags are independent; no normalization prevents combinations such as
35/// `bold && dim` or foreground/background defaults used in either field.
36///
37/// # Examples
38///
39/// ```
40/// use ailloli_ui_terminal_core::{TerminalColor, TerminalStyle};
41/// let style = TerminalStyle::default();
42/// assert_eq!((style.fg, style.bg), (TerminalColor::DefaultFg, TerminalColor::DefaultBg));
43/// assert!(!style.bold && !style.inverse);
44/// ```
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
46pub struct TerminalStyle {
47 /// Foreground color selection.
48 pub fg: TerminalColor,
49 /// Background color selection.
50 pub bg: TerminalColor,
51 /// Bold/intensified text request.
52 pub bold: bool,
53 /// Italic text request.
54 pub italic: bool,
55 /// Underline text request.
56 pub underline: bool,
57 /// Swap effective foreground and background at rendering time.
58 pub inverse: bool,
59 /// Dim/faint text request.
60 pub dim: bool,
61 /// Strikethrough text request.
62 pub strike: bool,
63}
64
65impl TerminalStyle {
66 /// Returns the default SGR style with every flag disabled.
67 ///
68 /// # Examples
69 ///
70 /// ```
71 /// use ailloli_ui_terminal_core::{TerminalColor, TerminalStyle};
72 /// assert_eq!(TerminalStyle::reset().fg, TerminalColor::DefaultFg);
73 /// assert_eq!(TerminalStyle::reset(), TerminalStyle::default());
74 /// ```
75 pub const fn reset() -> Self {
76 Self {
77 fg: TerminalColor::DefaultFg,
78 bg: TerminalColor::DefaultBg,
79 bold: false,
80 italic: false,
81 underline: false,
82 inverse: false,
83 dim: false,
84 strike: false,
85 }
86 }
87
88 /// Replaces this value with [`Self::reset`].
89 ///
90 /// # Examples
91 ///
92 /// ```
93 /// use ailloli_ui_terminal_core::TerminalStyle;
94 /// let mut style = TerminalStyle { bold: true, ..TerminalStyle::default() };
95 /// style.reset_sgr();
96 /// assert!(!style.bold);
97 /// ```
98 pub fn reset_sgr(&mut self) {
99 *self = Self::reset();
100 }
101}
102
103impl Default for TerminalStyle {
104 fn default() -> Self {
105 Self::reset()
106 }
107}