git_igitt/util/
syntax_highlight.rs

1use lazy_static::lazy_static;
2use syntect::easy::HighlightLines;
3use syntect::highlighting::Color as SynColor;
4use syntect::highlighting::{Style, Theme, ThemeSet};
5use syntect::parsing::SyntaxSet;
6use tui::style::Color;
7use tui::text::{Span, Spans, Text};
8
9lazy_static! {
10    static ref SYNTAX: Syntax = Syntax {
11        syntax: SyntaxSet::load_defaults_nonewlines(),
12        themes: ThemeSet::load_defaults()
13    };
14    static ref THEME: Theme = create_custom_theme();
15}
16
17struct Syntax {
18    pub syntax: SyntaxSet,
19    pub themes: ThemeSet,
20}
21
22fn create_custom_theme() -> Theme {
23    let mut theme = SYNTAX.themes.themes["Solarized (dark)"].clone();
24    theme.settings.foreground = theme.settings.foreground.map(|color| brighter(color, 0.4)); //Some(syntect::highlighting::Color::WHITE);
25    theme
26}
27
28fn brighter(color: SynColor, factor: f32) -> SynColor {
29    SynColor {
30        r: color.r + ((255 - color.r) as f32 * factor) as u8,
31        g: color.g + ((255 - color.g) as f32 * factor) as u8,
32        b: color.b + ((255 - color.b) as f32 * factor) as u8,
33        a: color.a,
34    }
35}
36
37pub fn highlight(lines: &str, extension: &str) -> Option<Vec<Vec<(Style, String)>>> {
38    let syntax = SYNTAX.syntax.find_syntax_by_extension(extension)?;
39
40    let mut h = HighlightLines::new(syntax, &THEME);
41
42    // TODO: Due to a bug in tui-rs (?), it is necessary to trim line ends.
43    // Otherwise, artifacts of the previous buffer may occur
44    let spans: Vec<_> = lines
45        .lines()
46        .map(|line| {
47            h.highlight_line(line.trim_end(), &SYNTAX.syntax)
48                .unwrap()
49                .into_iter()
50                .map(|(s, l)| (s, l.to_string()))
51                .collect::<Vec<_>>()
52        })
53        .collect();
54
55    Some(spans)
56}
57
58pub fn as_styled(lines: &'_ [Vec<(Style, String)>]) -> Text<'_> {
59    let spans: Vec<_> = lines
60        .iter()
61        .map(|line| {
62            Spans(
63                line.iter()
64                    .map(|(style, string)| {
65                        Span::styled(
66                            string,
67                            tui::style::Style::default().fg(Color::Rgb(
68                                style.foreground.r,
69                                style.foreground.g,
70                                style.foreground.b,
71                            )),
72                        )
73                    })
74                    .collect(),
75            )
76        })
77        .collect();
78
79    Text::from(spans)
80}