ratatui/text/
grapheme.rs

1use crate::style::{Style, Styled};
2
3const NBSP: &str = "\u{00a0}";
4const ZWSP: &str = "\u{200b}";
5
6/// A grapheme associated to a style.
7/// Note that, although `StyledGrapheme` is the smallest divisible unit of text,
8/// it actually is not a member of the text type hierarchy (`Text` -> `Line` -> `Span`).
9/// It is a separate type used mostly for rendering purposes. A `Span` consists of components that
10/// can be split into `StyledGrapheme`s, but it does not contain a collection of `StyledGrapheme`s.
11#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
12pub struct StyledGrapheme<'a> {
13    pub symbol: &'a str,
14    pub style: Style,
15}
16
17impl<'a> StyledGrapheme<'a> {
18    /// Creates a new `StyledGrapheme` with the given symbol and style.
19    ///
20    /// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
21    /// your own type that implements [`Into<Style>`]).
22    ///
23    /// [`Color`]: crate::style::Color
24    pub fn new<S: Into<Style>>(symbol: &'a str, style: S) -> Self {
25        Self {
26            symbol,
27            style: style.into(),
28        }
29    }
30
31    pub(crate) fn is_whitespace(&self) -> bool {
32        let symbol = self.symbol;
33        symbol == ZWSP || symbol.chars().all(char::is_whitespace) && symbol != NBSP
34    }
35}
36
37impl<'a> Styled for StyledGrapheme<'a> {
38    type Item = Self;
39
40    fn style(&self) -> Style {
41        self.style
42    }
43
44    fn set_style<S: Into<Style>>(mut self, style: S) -> Self::Item {
45        self.style = style.into();
46        self
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use crate::style::Stylize;
54
55    #[test]
56    fn new() {
57        let style = Style::new().yellow();
58        let sg = StyledGrapheme::new("a", style);
59        assert_eq!(sg.symbol, "a");
60        assert_eq!(sg.style, style);
61    }
62
63    #[test]
64    fn style() {
65        let style = Style::new().yellow();
66        let sg = StyledGrapheme::new("a", style);
67        assert_eq!(sg.style(), style);
68    }
69
70    #[test]
71    fn set_style() {
72        let style = Style::new().yellow().on_red();
73        let style2 = Style::new().green();
74        let sg = StyledGrapheme::new("a", style).set_style(style2);
75        assert_eq!(sg.style, style2);
76    }
77
78    #[test]
79    fn stylize() {
80        let style = Style::new().yellow().on_red();
81        let sg = StyledGrapheme::new("a", style).green();
82        assert_eq!(sg.style, Style::new().green().on_red());
83    }
84}