| 1 | use std::io::Cursor; |
| 2 | use syntect::highlighting::{Theme, ThemeSet}; |
| 3 | use syntect::html::highlighted_html_for_string; |
| 4 | use syntect::parsing::SyntaxSet; |
| 5 | |
| 6 | pub struct Highlighter { |
| 7 | syntax_set: SyntaxSet, |
| 8 | theme: Theme, |
| 9 | } |
| 10 | |
| 11 | impl Highlighter { |
| 12 | pub fn new() -> Self { |
| 13 | let theme_data = include_bytes!("darkmatter.tmTheme"); |
| 14 | let theme = ThemeSet::load_from_reader(&mut Cursor::new(&theme_data[..])) |
| 15 | .expect("failed to load darkmatter theme"); |
| 16 | Self { |
| 17 | syntax_set: SyntaxSet::load_defaults_newlines(), |
| 18 | theme, |
| 19 | } |
| 20 | } |
| 21 | |
| 22 | pub fn highlight(&self, name: &str, content: &str) -> String { |
| 23 | let raw_ext = name.rsplit('.').next().unwrap_or(""); |
| 24 | let ext = match raw_ext { |
| 25 | "ts" | "tsx" | "jsx" => "js", |
| 26 | other => other, |
| 27 | }; |
| 28 | let syntax = self |
| 29 | .syntax_set |
| 30 | .find_syntax_by_extension(ext) |
| 31 | .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text()); |
| 32 | highlighted_html_for_string(content, &self.syntax_set, syntax, &self.theme) |
| 33 | .unwrap_or_else(|_| { |
| 34 | let escaped = content |
| 35 | .replace('&', "&") |
| 36 | .replace('<', "<") |
| 37 | .replace('>', ">"); |
| 38 | format!("<pre>{}</pre>", escaped) |
| 39 | }) |
| 40 | } |
| 41 | } |