tui_markup/generator/crossterm/
span.rs

1use crossterm::{
2    style::{Attributes, Color, ContentStyle, Print, PrintStyledContent, Stylize},
3    Command,
4};
5
6use crate::generator::{
7    helper::{FlattenableSpan, FlattenableStyle},
8    Tag, TagConvertor,
9};
10
11impl<'a, C> From<Tag<'a, C>> for ContentStyle
12where
13    C: TagConvertor<'a, Color = Color, Modifier = Attributes, Custom = ContentStyle>,
14{
15    fn from(t: Tag<'a, C>) -> Self {
16        match t {
17            Tag::Fg(c) => ContentStyle::new().with(c),
18            Tag::Bg(c) => ContentStyle::new().on(c),
19            Tag::Modifier(m) => {
20                let mut c = ContentStyle::new();
21                c.attributes = m;
22                c
23            }
24            Tag::Custom(style) => style,
25        }
26    }
27}
28
29impl FlattenableStyle for ContentStyle {
30    fn patch(mut self, other: Self) -> Self {
31        if let Some(c) = other.foreground_color {
32            self = self.with(c);
33        }
34
35        if let Some(c) = other.background_color {
36            self = self.on(c);
37        }
38
39        self.attributes.extend(other.attributes);
40
41        self
42    }
43}
44
45/// Span is a crossterm Command for print raw or styled text.
46#[derive(Debug)]
47pub enum Span<'a> {
48    /// Print raw text
49    NoStyle(Print<&'a str>),
50    /// Print styled text
51    Styled(PrintStyledContent<&'a str>),
52}
53
54impl<'a> FlattenableSpan<'a, ContentStyle> for Span<'a> {
55    fn with_style(s: &'a str, style: Option<ContentStyle>) -> Self {
56        match style {
57            Some(style) => Span::Styled(PrintStyledContent(style.apply(s))),
58            None => Span::NoStyle(Print(s)),
59        }
60    }
61}
62
63impl<'a> Command for Span<'a> {
64    fn write_ansi(&self, f: &mut impl std::fmt::Write) -> std::fmt::Result {
65        match self {
66            Self::NoStyle(p) => p.write_ansi(f),
67            Self::Styled(p) => p.write_ansi(f),
68        }
69    }
70
71    #[cfg(windows)]
72    fn execute_winapi(&self) -> std::io::Result<()> {
73        match self {
74            Self::NoStyle(p) => p.execute_winapi(),
75            Self::Styled(p) => p.execute_winapi(),
76        }
77    }
78
79    #[cfg(windows)]
80    fn is_ansi_code_supported(&self) -> bool {
81        match self {
82            Self::NoStyle(p) => p.is_ansi_code_supported(),
83            Self::Styled(p) => p.is_ansi_code_supported(),
84        }
85    }
86}