git_igitt/util/
syntax_highlight.rs1use 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)); 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 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}