tui_syntax_highlight/
convert.rs

1#[cfg(feature = "termprofile")]
2use termprofile::TermProfile;
3
4/// Converts between [`syntect`] styles and [`ratatui`] styles.
5#[derive(Clone, Copy, Debug, PartialEq, Eq)]
6pub struct Converter {
7    #[cfg(feature = "termprofile")]
8    profile: TermProfile,
9}
10
11impl Default for Converter {
12    fn default() -> Self {
13        Self::new()
14    }
15}
16
17impl Converter {
18    /// Creates a new [`Converter`].
19    pub fn new() -> Self {
20        Self {
21            #[cfg(feature = "termprofile")]
22            profile: TermProfile::TrueColor,
23        }
24    }
25
26    /// Creates a new [`Converter`] with the given [`TermProfile`].
27    #[cfg(feature = "termprofile")]
28    pub fn with_profile(profile: TermProfile) -> Self {
29        Self { profile }
30    }
31
32    /// Converts the syntect [`Style`](syntect::highlighting::Style) to a ratatui
33    /// [`Style`](ratatui::style::Style).
34    pub fn syntect_style_to_tui(
35        &self,
36        style: syntect::highlighting::Style,
37    ) -> ratatui::style::Style {
38        #[cfg(feature = "termprofile")]
39        if self.profile == termprofile::TermProfile::NoTty {
40            return ratatui::style::Style::new();
41        }
42        let mut tui_style = ratatui::style::Style::new();
43        if let Some(fg) = self.syntect_color_to_tui(style.foreground) {
44            tui_style = tui_style.fg(fg);
45        }
46        if let Some(bg) = self.syntect_color_to_tui(style.background) {
47            tui_style = tui_style.bg(bg);
48        }
49        tui_style.add_modifier(syntect_modifiers_to_tui(&style.font_style))
50    }
51
52    /// Converts the syntect [`Color`](ratatui::style::Color) to a ratatui
53    /// [`Color`](ratatui::style::Color).
54    pub fn syntect_color_to_tui(
55        &self,
56        color: syntect::highlighting::Color,
57    ) -> Option<ratatui::style::Color> {
58        if color.a == 0 {
59            Some(match color.r {
60                0x00 => ratatui::style::Color::Black,
61                0x01 => ratatui::style::Color::Red,
62                0x02 => ratatui::style::Color::Green,
63                0x03 => ratatui::style::Color::Yellow,
64                0x04 => ratatui::style::Color::Blue,
65                0x05 => ratatui::style::Color::Magenta,
66                0x06 => ratatui::style::Color::Cyan,
67                0x07 => ratatui::style::Color::Gray,
68                0x08 => ratatui::style::Color::DarkGray,
69                0x09 => ratatui::style::Color::LightRed,
70                0x0A => ratatui::style::Color::LightGreen,
71                0x0B => ratatui::style::Color::LightYellow,
72                0x0C => ratatui::style::Color::LightBlue,
73                0x0D => ratatui::style::Color::LightMagenta,
74                0x0E => ratatui::style::Color::LightCyan,
75                0x0F => ratatui::style::Color::White,
76                c => ratatui::style::Color::Indexed(c),
77            })
78        } else if color.a == 1 {
79            None
80        } else {
81            #[cfg(feature = "termprofile")]
82            return self
83                .profile
84                .adapt_color(ratatui::style::Color::Rgb(color.r, color.g, color.b));
85            #[cfg(not(feature = "termprofile"))]
86            return Some(ratatui::style::Color::Rgb(color.r, color.g, color.b));
87        }
88    }
89}
90
91fn syntect_modifiers_to_tui(style: &syntect::highlighting::FontStyle) -> ratatui::style::Modifier {
92    let mut modifier = ratatui::style::Modifier::empty();
93    if style.intersects(syntect::highlighting::FontStyle::BOLD) {
94        modifier |= ratatui::style::Modifier::BOLD;
95    }
96    if style.intersects(syntect::highlighting::FontStyle::ITALIC) {
97        modifier |= ratatui::style::Modifier::ITALIC;
98    }
99    if style.intersects(syntect::highlighting::FontStyle::UNDERLINE) {
100        modifier |= ratatui::style::Modifier::UNDERLINED;
101    }
102    modifier
103}