From 9d17aba0dfbdf29e70a6d2a9a04540a5ea1f638c Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Tue, 21 Nov 2023 06:43:16 -0800 Subject: [PATCH] Pull in all of bat's syntect themes --- Cargo.lock | 1 + Cargo.toml | 1 + bat/themes.bin | Bin 0 -> 40606 bytes bat/update.sh | 1 + src/builder.rs | 6 +- src/export.rs | 2 +- src/main.rs | 2 +- src/render/highlighting.rs | 128 +++++++++++++++++++++++++++++++++---- themes/light.yaml | 2 +- 9 files changed, 123 insertions(+), 20 deletions(-) create mode 100644 bat/themes.bin diff --git a/Cargo.lock b/Cargo.lock index 74559fad..c96b79ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -903,6 +903,7 @@ dependencies = [ "clap", "comrak", "crossterm", + "flate2", "hex", "image", "itertools", diff --git a/Cargo.toml b/Cargo.toml index 0664d481..556b6df8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ clap = { version = "4.4", features = ["derive", "string"] } comrak = { version = "0.19", default-features = false } crossterm = { version = "0.27", features = ["serde"] } hex = "0.4" +flate2 = "1.0" image = "0.24" merge-struct = "0.1.0" itertools = "0.11" diff --git a/bat/themes.bin b/bat/themes.bin new file mode 100644 index 0000000000000000000000000000000000000000..c9dfcde10ba797b3038418cf9c26aa3a30bd42ca GIT binary patch literal 40606 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 PresentationBuilder<'a> { let mut code_highlighter = self.highlighter.language_highlighter(&code.language); let padding_style = { let mut highlighter = self.highlighter.language_highlighter(&CodeLanguage::Rust); - highlighter.style_line("//").first().expect("no styles").style + highlighter.style_line("//").next().expect("no styles").style }; let groups = match self.options.allow_mutations { true => code.attributes.highlight_groups.clone(), @@ -669,8 +669,6 @@ impl CodeLine { fn highlight(&self, padding_style: &Style, code_highlighter: &mut LanguageHighlighter) -> String { let mut output = StyledTokens { style: *padding_style, tokens: &self.prefix }.apply_style(); output.push_str(&code_highlighter.highlight_line(&self.code)); - // Remove newline - output.pop(); output.push_str(&StyledTokens { style: *padding_style, tokens: &self.suffix }.apply_style()); output } @@ -1147,7 +1145,7 @@ mod test { } fn try_build_presentation(elements: Vec) -> Result { - let highlighter = CodeHighlighter::new("base16-ocean.dark").unwrap(); + let highlighter = CodeHighlighter::default(); let theme = PresentationTheme::default(); let mut resources = Resources::new("/tmp"); let options = PresentationBuilderOptions::default(); diff --git a/src/export.rs b/src/export.rs index 3fe668a7..72607262 100644 --- a/src/export.rs +++ b/src/export.rs @@ -172,7 +172,7 @@ mod test { let arena = Arena::new(); let parser = MarkdownParser::new(&arena); let theme = Default::default(); - let highlighter = CodeHighlighter::new("base16-ocean.dark").unwrap(); + let highlighter = CodeHighlighter::default(); let resources = Resources::new("examples"); let mut exporter = Exporter::new(parser, &theme, highlighter, resources); exporter.extract_metadata(content, Path::new(path)).expect("metadata extraction failed") diff --git a/src/main.rs b/src/main.rs index 999ff9d3..8bd52838 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,7 +74,7 @@ fn run(cli: Cli) -> Result<(), Box> { }; let arena = Arena::new(); let parser = MarkdownParser::new(&arena); - let default_highlighter = CodeHighlighter::new("base16-ocean.dark")?; + let default_highlighter = CodeHighlighter::default(); if cli.acknowledgements { display_acknowledgements(); return Ok(()); diff --git a/src/render/highlighting.rs b/src/render/highlighting.rs index 13799675..78b20701 100644 --- a/src/render/highlighting.rs +++ b/src/render/highlighting.rs @@ -1,28 +1,76 @@ use crate::markdown::elements::CodeLanguage; +use crossterm::{ + style::{SetBackgroundColor, SetForegroundColor}, + QueueableCommand, +}; +use flate2::read::ZlibDecoder; use once_cell::sync::Lazy; +use serde::Deserialize; +use std::{ + collections::BTreeMap, + io::{self, Write}, + sync::{Arc, Mutex}, +}; use syntect::{ easy::HighlightLines, highlighting::{Style, Theme, ThemeSet}, parsing::SyntaxSet, - util::as_24_bit_terminal_escaped, }; static SYNTAX_SET: Lazy = Lazy::new(|| { let contents = include_bytes!("../../bat/syntaxes.bin"); bincode::deserialize(contents).expect("syntaxes are broken") }); -static THEMES: Lazy = Lazy::new(ThemeSet::load_defaults); + +static THEMES: Lazy = Lazy::new(|| { + let contents = include_bytes!("../../bat/themes.bin"); + let theme_set: LazyThemeSet = bincode::deserialize(contents).expect("syntaxes are broken"); + let default_themes = ThemeSet::load_defaults(); + theme_set.merge(default_themes); + theme_set +}); + +// This structure mimic's `bat`'s serialized theme set's. +#[derive(Debug, Deserialize)] +struct LazyThemeSet { + serialized_themes: BTreeMap>, + #[serde(skip)] + themes: Mutex>>, +} + +impl LazyThemeSet { + fn merge(&self, themes: ThemeSet) { + let mut all_themes = self.themes.lock().unwrap(); + for (name, theme) in themes.themes { + if !self.serialized_themes.contains_key(&name) { + all_themes.insert(name, theme.into()); + } + } + } + + fn get(&self, theme_name: &str) -> Option> { + let mut themes = self.themes.lock().unwrap(); + if let Some(theme) = themes.get(theme_name) { + return Some(theme.clone()); + } + let serialized = self.serialized_themes.get(theme_name)?; + let decoded: Theme = bincode::deserialize_from(ZlibDecoder::new(serialized.as_slice())).ok()?; + let decoded = Arc::new(decoded); + themes.insert(theme_name.to_string(), decoded); + themes.get(theme_name).cloned() + } +} /// A code highlighter. #[derive(Clone)] pub struct CodeHighlighter { - theme: &'static Theme, + theme: Arc, } impl CodeHighlighter { /// Construct a new highlighted using the given [syntect] theme name. pub fn new(theme: &str) -> Result { - let theme = THEMES.themes.get(theme).ok_or(ThemeNotFound)?; + let theme = THEMES.get(theme).ok_or(ThemeNotFound)?; Ok(Self { theme }) } @@ -30,7 +78,7 @@ impl CodeHighlighter { pub(crate) fn language_highlighter(&self, language: &CodeLanguage) -> LanguageHighlighter { let extension = Self::language_extension(language); let syntax = SYNTAX_SET.find_syntax_by_extension(extension).unwrap(); - let highlighter = HighlightLines::new(syntax, self.theme); + let highlighter = HighlightLines::new(syntax, &self.theme); LanguageHighlighter { highlighter } } @@ -90,23 +138,28 @@ impl CodeHighlighter { } } } -pub(crate) struct LanguageHighlighter { - highlighter: HighlightLines<'static>, + +impl Default for CodeHighlighter { + fn default() -> Self { + Self::new("base16-eighties.dark").expect("default theme not found") + } +} + +pub(crate) struct LanguageHighlighter<'a> { + highlighter: HighlightLines<'a>, } -impl LanguageHighlighter { +impl<'a> LanguageHighlighter<'a> { pub(crate) fn highlight_line(&mut self, line: &str) -> String { - let ranges = self.highlighter.highlight_line(line, &SYNTAX_SET).unwrap(); - as_24_bit_terminal_escaped(&ranges, true) + self.style_line(line).map(|s| s.apply_style()).collect() } - pub(crate) fn style_line<'a>(&mut self, line: &'a str) -> Vec> { + pub(crate) fn style_line<'b>(&mut self, line: &'b str) -> impl Iterator> { self.highlighter .highlight_line(line, &SYNTAX_SET) .unwrap() .into_iter() .map(|(style, tokens)| StyledTokens { style, tokens }) - .collect() } } @@ -117,7 +170,29 @@ pub(crate) struct StyledTokens<'a> { impl<'a> StyledTokens<'a> { pub(crate) fn apply_style(&self) -> String { - as_24_bit_terminal_escaped(&[(self.style, self.tokens)], true) + let background = to_ansi_color(self.style.background); + let foreground = to_ansi_color(self.style.foreground); + + // We do this conversion manually as crossterm will reset the color after styling, and we + // want to "keep it open" so that padding also uses this background color. + // + // Note: these unwraps shouldn't happen as this is an in-memory writer so there's no + // fallible IO here. + let mut cursor = io::BufWriter::new(Vec::new()); + if let Some(color) = background { + cursor.queue(SetBackgroundColor(color)).unwrap(); + } + if let Some(color) = foreground { + cursor.queue(SetForegroundColor(color)).unwrap(); + } + // syntect likes its input to contain \n but we don't want them as we pad text with extra + // " " at the end so we get rid of them here. + for chunk in self.tokens.split('\n') { + cursor.write_all(chunk.as_bytes()).unwrap(); + } + + cursor.flush().unwrap(); + String::from_utf8(cursor.into_inner().unwrap()).unwrap() } } @@ -126,6 +201,28 @@ impl<'a> StyledTokens<'a> { #[error("theme not found")] pub struct ThemeNotFound; +// This code has been adapted from bat's: https://github.com/sharkdp/bat +fn to_ansi_color(color: syntect::highlighting::Color) -> Option { + use crossterm::style::Color; + if color.a == 0 { + Some(match color.r { + 0x00 => Color::Black, + 0x01 => Color::DarkRed, + 0x02 => Color::DarkGreen, + 0x03 => Color::DarkYellow, + 0x04 => Color::DarkBlue, + 0x05 => Color::DarkMagenta, + 0x06 => Color::DarkCyan, + 0x07 => Color::Grey, + n => Color::AnsiValue(n), + }) + } else if color.a == 1 { + None + } else { + Some(Color::Rgb { r: color.r, g: color.g, b: color.b }) + } +} + #[cfg(test)] mod test { use super::*; @@ -139,4 +236,9 @@ mod test { assert!(syntax.is_some(), "extension {extension} for {language:?} not found"); } } + + #[test] + fn default_highlighter() { + CodeHighlighter::default(); + } } diff --git a/themes/light.yaml b/themes/light.yaml index c3b5d16d..d09c2c95 100644 --- a/themes/light.yaml +++ b/themes/light.yaml @@ -17,7 +17,7 @@ code: minimum_size: 50 minimum_margin: percent: 8 - theme_name: InspiredGitHub + theme_name: GitHub padding: horizontal: 2 vertical: 1