refactor: theme and code color (#32)

pull/33/head
sigoden 1 year ago committed by GitHub
parent 360264121c
commit ec1c4bcf8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

Binary file not shown.

File diff suppressed because it is too large Load Diff

@ -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<SyntaxReference>,
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<String> {
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<String> {
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<String> {
if !line.starts_with("```") {
return None;
@ -126,8 +171,23 @@ fn detect_code_block(line: &str) -> Option<String> {
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()));
}

Loading…
Cancel
Save