From 763fdc5243e1fdde22367727565ab256a44f6031 Mon Sep 17 00:00:00 2001 From: Chris Wong Date: Thu, 22 Aug 2024 12:52:01 +1000 Subject: [PATCH] Use Comrak plugin for syntax highlighting --- docs/Cargo.toml | 2 +- docs/src/bin/build_page.rs | 54 +++----------------------------------- docs/src/highlight.rs | 44 +++++++++++++++++++++++++++++++ docs/src/lib.rs | 1 + docs/src/views.rs | 14 ++++++++-- 5 files changed, 62 insertions(+), 53 deletions(-) create mode 100644 docs/src/highlight.rs diff --git a/docs/Cargo.toml b/docs/Cargo.toml index 4fb463df..b4ece88c 100644 --- a/docs/Cargo.toml +++ b/docs/Cargo.toml @@ -11,7 +11,7 @@ description = "Documentation for Maud." edition = "2021" [dependencies] -comrak = { version = "*", default-features = false } +comrak = { version = "*", default-features = false, features = ["syntect"] } maud = { path = "../maud" } serde_json = "*" syntect = "*" diff --git a/docs/src/bin/build_page.rs b/docs/src/bin/build_page.rs index b42b4963..4533a39b 100644 --- a/docs/src/bin/build_page.rs +++ b/docs/src/bin/build_page.rs @@ -1,5 +1,5 @@ use comrak::{ - nodes::{AstNode, NodeCodeBlock, NodeHeading, NodeHtmlBlock, NodeLink, NodeValue}, + nodes::{AstNode, NodeCodeBlock, NodeHeading, NodeLink, NodeValue}, Arena, }; use docs::{ @@ -14,11 +14,6 @@ use std::{ path::Path, str, }; -use syntect::{ - highlighting::{Color, ThemeSet}, - html::highlighted_html_for_string, - parsing::SyntaxSet, -}; fn main() -> Result<(), Box> { let args = env::args().collect::>(); @@ -55,7 +50,7 @@ fn build_page( .collect::>(); let page = Page::load(&arena, input_path)?; - postprocess(page.content)?; + postprocess(page.content); let markup = views::main(slug, page, &nav, version, hash); @@ -65,12 +60,10 @@ fn build_page( Ok(()) } -fn postprocess<'a>(content: &'a AstNode<'a>) -> Result<(), Box> { +fn postprocess<'a>(content: &'a AstNode<'a>) { lower_headings(content); rewrite_md_links(content); strip_hidden_code(content); - highlight_code(content)?; - Ok(()) } fn lower_headings<'a>(root: &'a AstNode<'a>) { @@ -98,8 +91,7 @@ fn strip_hidden_code<'a>(root: &'a AstNode<'a>) { for node in root.descendants() { let mut data = node.data.borrow_mut(); if let NodeValue::CodeBlock(NodeCodeBlock { info, literal, .. }) = &mut data.value { - let info = parse_code_block_info(info); - if !info.contains(&"rust") { + if info.split(',').map(str::trim).all(|lang| lang != "rust") { continue; } *literal = strip_hidden_code_inner(literal); @@ -117,41 +109,3 @@ fn strip_hidden_code_inner(literal: &str) -> String { .collect::>(); lines.join("\n") } - -fn highlight_code<'a>(root: &'a AstNode<'a>) -> Result<(), Box> { - let ss = SyntaxSet::load_defaults_newlines(); - let ts = ThemeSet::load_defaults(); - let mut theme = ts.themes["InspiredGitHub"].clone(); - theme.settings.background = Some(Color { - r: 0xff, - g: 0xee, - b: 0xff, - a: 0xff, - }); - for node in root.descendants() { - let mut data = node.data.borrow_mut(); - if let NodeValue::CodeBlock(NodeCodeBlock { info, literal, .. }) = &mut data.value { - let info = parse_code_block_info(info); - let syntax = info - .into_iter() - .filter_map(|token| ss.find_syntax_by_token(token)) - .next() - .unwrap_or_else(|| ss.find_syntax_plain_text()); - let mut literal = std::mem::take(literal); - if !literal.ends_with('\n') { - // Syntect expects a trailing newline - literal.push('\n'); - } - let html = highlighted_html_for_string(&literal, &ss, syntax, &theme)?; - data.value = NodeValue::HtmlBlock(NodeHtmlBlock { - literal: html, - ..Default::default() - }); - } - } - Ok(()) -} - -fn parse_code_block_info(info: &str) -> Vec<&str> { - info.split(',').map(str::trim).collect() -} diff --git a/docs/src/highlight.rs b/docs/src/highlight.rs new file mode 100644 index 00000000..b297fe4a --- /dev/null +++ b/docs/src/highlight.rs @@ -0,0 +1,44 @@ +use comrak::{ + plugins::syntect::{SyntectAdapter, SyntectAdapterBuilder}, + Plugins, +}; +use std::rc::Rc; +use syntect::highlighting::{Color, ThemeSet}; + +pub struct Highlighter { + adapter: Rc, +} + +impl Highlighter { + pub fn get() -> Self { + Self { + adapter: SYNTECT_ADAPTER.with(Rc::clone), + } + } + + pub fn as_plugins(&self) -> Plugins<'_> { + let mut plugins = Plugins::default(); + plugins.render.codefence_syntax_highlighter = Some(&*self.adapter); + plugins + } +} + +thread_local! { + static SYNTECT_ADAPTER: Rc = Rc::new({ + SyntectAdapterBuilder::new() + .theme_set({ + let mut ts = ThemeSet::load_defaults(); + let mut theme = ts.themes["InspiredGitHub"].clone(); + theme.settings.background = Some(Color { + r: 0xff, + g: 0xee, + b: 0xff, + a: 0xff, + }); + ts.themes.insert("InspiredGitHub2".to_string(), theme); + ts + }) + .theme("InspiredGitHub2") + .build() + }); +} diff --git a/docs/src/lib.rs b/docs/src/lib.rs index f2e72ddf..f3d61137 100644 --- a/docs/src/lib.rs +++ b/docs/src/lib.rs @@ -1,3 +1,4 @@ +pub mod highlight; pub mod page; pub mod string_writer; pub mod views; diff --git a/docs/src/views.rs b/docs/src/views.rs index 8fe0d08c..7f21efd7 100644 --- a/docs/src/views.rs +++ b/docs/src/views.rs @@ -3,6 +3,7 @@ use maud::{html, Markup, PreEscaped, Render, DOCTYPE}; use std::str; use crate::{ + highlight::Highlighter, page::{default_comrak_options, Page}, string_writer::StringWriter, }; @@ -89,7 +90,14 @@ struct Comrak<'a>(&'a AstNode<'a>); impl<'a> Render for Comrak<'a> { fn render_to(&self, buffer: &mut String) { - comrak::format_html(self.0, &default_comrak_options(), &mut StringWriter(buffer)).unwrap(); + let highlighter = Highlighter::get(); + comrak::format_html_with_plugins( + self.0, + &default_comrak_options(), + &mut StringWriter(buffer), + &highlighter.as_plugins(), + ) + .unwrap(); } } @@ -100,10 +108,12 @@ struct ComrakRemovePTags<'a>(&'a AstNode<'a>); impl<'a> Render for ComrakRemovePTags<'a> { fn render(&self) -> Markup { let mut buffer = String::new(); - comrak::format_html( + let highlighter = Highlighter::get(); + comrak::format_html_with_plugins( self.0, &default_comrak_options(), &mut StringWriter(&mut buffer), + &highlighter.as_plugins(), ) .unwrap(); assert!(buffer.starts_with("

") && buffer.ends_with("

\n"));