From ec1c4bcf8f94f973ddf05d35956a40f0c42b5d9d Mon Sep 17 00:00:00 2001 From: sigoden Date: Wed, 8 Mar 2023 07:25:32 +0800 Subject: refactor: theme and code color (#32) --- src/render/markdown.rs | 110 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/render/markdown.rs b/src/render/markdown.rs index 5316653..f0cb64a 100644 --- a/src/render/markdown.rs +++ b/src/render/markdown.rs @@ -1,37 +1,37 @@ -use syntect::highlighting::Theme; +// use colored::{Color, Colorize}; +use crossterm::style::{Color, Stylize}; +use syntect::highlighting::{Color as SyntectColor, FontStyle, Style, Theme}; use syntect::parsing::SyntaxSet; -use syntect::util::as_24_bit_terminal_escaped; use syntect::{easy::HighlightLines, parsing::SyntaxReference}; -/// Comms from https://github.com/jonschlinkert/sublime-monokai-extended/tree/0ca4e75291515c4d47e2d455e598e03e0dc53745 -const THEME: &[u8] = include_bytes!("../../assets/theme.yaml"); +/// Monokai Extended +const MD_THEME: &[u8] = include_bytes!("../../assets/monokai-extended.theme.bin"); /// Comes from https://github.com/sharkdp/bat/raw/5e77ca37e89c873e4490b42ff556370dc5c6ba4f/assets/syntaxes.bin const SYNTAXES: &[u8] = include_bytes!("../../assets/syntaxes.bin"); pub struct MarkdownRender { syntax_set: SyntaxSet, - theme: Theme, + md_theme: Theme, + code_color: Color, md_syntax: SyntaxReference, - txt_syntax: SyntaxReference, - code_syntax: SyntaxReference, + code_syntax: Option, line_type: LineType, } impl MarkdownRender { pub fn new() -> Self { let syntax_set: SyntaxSet = - bincode::deserialize_from(SYNTAXES).expect("invalid syntaxes.bin"); - let theme: Theme = serde_yaml::from_slice(THEME).unwrap(); + bincode::deserialize_from(SYNTAXES).expect("invalid syntaxes binary"); + let md_theme: Theme = bincode::deserialize_from(MD_THEME).expect("invalid md_theme binary"); + let code_color = get_code_color(&md_theme); let md_syntax = syntax_set.find_syntax_by_extension("md").unwrap().clone(); - let txt_syntax = syntax_set.find_syntax_by_extension("txt").unwrap().clone(); - let code_syntax = txt_syntax.clone(); let line_type = LineType::Normal; Self { syntax_set, - theme, + md_theme, + code_color, md_syntax, - code_syntax, - txt_syntax, + code_syntax: None, line_type, } } @@ -49,16 +49,14 @@ impl MarkdownRender { LineType::Normal | LineType::CodeEnd => { self.line_type = LineType::CodeBegin; self.code_syntax = if lang.is_empty() { - self.txt_syntax.clone() + None } else { - self.find_syntax(&lang) - .cloned() - .unwrap_or_else(|| self.txt_syntax.clone()) + self.find_syntax(&lang).cloned() }; } LineType::CodeBegin | LineType::CodeInner => { self.line_type = LineType::CodeEnd; - self.code_syntax = self.txt_syntax.clone(); + self.code_syntax = None; } } self.render_line_inner(line, &self.md_syntax) @@ -71,9 +69,9 @@ impl MarkdownRender { } LineType::CodeBegin => { self.line_type = LineType::CodeInner; - self.render_line_inner(line, &self.code_syntax) + self.render_code_line(line) } - LineType::CodeInner => self.render_line_inner(line, &self.code_syntax), + LineType::CodeInner => self.render_code_line(line), } } } @@ -86,7 +84,7 @@ impl MarkdownRender { LineType::Normal | LineType::CodeEnd => { self.render_line_inner(line, &self.md_syntax) } - _ => self.render_line_inner(line, &self.code_syntax), + _ => self.render_code_line(line), } }; @@ -94,9 +92,16 @@ impl MarkdownRender { } fn render_line_inner(&self, line: &str, syntax: &SyntaxReference) -> Option { - let mut highlighter = HighlightLines::new(syntax, &self.theme); + let mut highlighter = HighlightLines::new(syntax, &self.md_theme); let ranges = highlighter.highlight_line(line, &self.syntax_set).ok()?; - Some(as_24_bit_terminal_escaped(&ranges[..], false)) + Some(as_terminal_escaped(&ranges)) + } + + fn render_code_line(&self, line: &str) -> Option { + self.code_syntax + .as_ref() + .map(|syntax| self.render_line_inner(line, syntax)) + .unwrap_or_else(|| Some(format!("{}", line.with(self.code_color)))) } fn find_syntax(&self, lang: &str) -> Option<&SyntaxReference> { @@ -114,6 +119,46 @@ enum LineType { CodeEnd, } +fn as_terminal_escaped(ranges: &[(Style, &str)]) -> String { + let mut output = String::new(); + for (style, text) in ranges { + let fg = blend_fg_color(style.foreground, style.background); + let mut text = text.with(convert_color(fg)); + if style.font_style.contains(FontStyle::BOLD) { + text = text.bold() + } + if style.font_style.contains(FontStyle::UNDERLINE) { + text = text.underlined() + } + output.push_str(&text.to_string()); + } + output +} + +fn convert_color(c: SyntectColor) -> Color { + Color::Rgb { + r: c.r, + g: c.g, + b: c.b, + } +} + +fn blend_fg_color(fg: SyntectColor, bg: SyntectColor) -> SyntectColor { + if fg.a == 0xff { + return fg; + } + let ratio = fg.a as u32; + let r = (fg.r as u32 * ratio + bg.r as u32 * (255 - ratio)) / 255; + let g = (fg.g as u32 * ratio + bg.g as u32 * (255 - ratio)) / 255; + let b = (fg.b as u32 * ratio + bg.b as u32 * (255 - ratio)) / 255; + SyntectColor { + r: r as u8, + g: g as u8, + b: b as u8, + a: 255, + } +} + fn detect_code_block(line: &str) -> Option { if !line.starts_with("```") { return None; @@ -126,8 +171,23 @@ fn detect_code_block(line: &str) -> Option { Some(lang) } +fn get_code_color(theme: &Theme) -> Color { + let scope = theme.scopes.iter().find(|v| { + v.scope + .selectors + .iter() + .any(|v| v.path.scopes.iter().any(|v| v.to_string() == "string")) + }); + scope + .and_then(|v| v.style.foreground) + .map(convert_color) + .unwrap_or_else(|| Color::Yellow) +} + #[test] -fn feature() { +fn test_assets() { let syntax_set: SyntaxSet = bincode::deserialize_from(SYNTAXES).expect("invalid syntaxes.bin"); assert!(syntax_set.find_syntax_by_extension("md").is_some()); + let md_theme: Theme = bincode::deserialize_from(MD_THEME).expect("invalid md_theme binary"); + assert_eq!(md_theme.name, Some("Monokai Extended".into())); } -- cgit v1.2.3