diff --git a/src/builder.rs b/src/builder.rs index 5e5ebd4..d5da847 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -4,7 +4,6 @@ use std::{collections::HashMap, path::PathBuf}; use eyre::{eyre, Context, OptionExt}; use lol_html::{element, html_content::ContentType, HtmlRewriter, Settings}; -use pulldown_cmark::{Options, Parser}; use rayon::prelude::*; use serde::Serialize; use syntect::{highlighting::ThemeSet, parsing::SyntaxSet}; @@ -399,49 +398,7 @@ impl SiteBuilder { .with_context(|| format!("Failed to read page at {}", page_path.display()))?; let page = crate::frontmatter::FrontMatter::parse(input)?; - let mut language = None; - let parser = Parser::new_ext(&page.content, Options::all()).filter_map(|event| { - // syntax highlighting for code blocks - match event { - pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock( - pulldown_cmark::CodeBlockKind::Fenced(name), - )) => { - language = Some(name); - None - } - pulldown_cmark::Event::Text(code) => { - if let Some(language) = language.take() { - let syntax_reference = self - .syntax_set - .find_syntax_by_token(&language) - .unwrap_or_else(|| self.syntax_set.find_syntax_plain_text()); - let html = format!( - r#"
- - {} -
"#, - syntect::html::highlighted_html_for_string( - &code, - &self.syntax_set, - syntax_reference, - self.theme_set - .themes - .get(&self.site.config.code_theme) - .as_ref() - .expect("should never fail"), - ) - .expect("failed to highlight syntax") - ); - Some(pulldown_cmark::Event::Html(html.into())) - } else { - Some(pulldown_cmark::Event::Text(code)) - } - } - _ => Some(event), - } - }); - let mut page_html = String::new(); - pulldown_cmark::html::push_html(&mut page_html, parser); + let page_html = util::render_markdown(self, &page.content)?; let out = self.build_page_raw(page.data.unwrap_or_default(), &page_html, ())?; diff --git a/src/resource.rs b/src/resource.rs index d4d5bf1..433584c 100644 --- a/src/resource.rs +++ b/src/resource.rs @@ -5,14 +5,13 @@ use std::{ use eyre::Context; use itertools::Itertools; -use pulldown_cmark::{Options, Parser}; use rss::{validation::Validate, ChannelBuilder, ItemBuilder}; use serde::{Deserialize, Serialize}; use time::{format_description::well_known::Rfc2822, OffsetDateTime}; use crate::{ builder::SiteBuilder, frontmatter::FrontMatterRequired, link_list::Link, - util::format_timestamp, PageMetadata, + util::{self, format_timestamp}, PageMetadata, }; /// Metadata for resources. @@ -182,10 +181,7 @@ impl ResourceBuilder { let mut page = FrontMatterRequired::::parse(input) .wrap_err_with(|| eyre::eyre!("Failed to parse resource front matter"))?; - let parser = Parser::new_ext(&page.content, Options::all()); - let mut html = String::new(); - pulldown_cmark::html::push_html(&mut html, parser); - *page.content_mut() = html; + *page.content_mut() = util::render_markdown(builder, &page.content)?; let data = page.data_mut(); if let Some(cdn_file) = &data.cdn_file { diff --git a/src/util.rs b/src/util.rs index d8ebf18..0f42680 100644 --- a/src/util.rs +++ b/src/util.rs @@ -2,8 +2,11 @@ use std::path::Path; +use pulldown_cmark::{Options, Parser}; use time::OffsetDateTime; +use crate::builder::SiteBuilder; + /// Simple helper to remove the contents of a directory without removing the directory itself. pub fn remove_dir_contents(path: &Path) -> eyre::Result<()> { for entry in path.read_dir()? { @@ -24,3 +27,52 @@ pub fn format_timestamp(ts: OffsetDateTime, format: &str) -> eyre::Result(format)?; Ok(ts.format(&fmt)?) } + +/// Helper to render markdown. +pub fn render_markdown(builder: &SiteBuilder, input: &str) -> eyre::Result { + let mut language = None; + let parser = Parser::new_ext(input, Options::all()).filter_map(|event| { + // syntax highlighting for code blocks + match event { + pulldown_cmark::Event::Start(pulldown_cmark::Tag::CodeBlock( + pulldown_cmark::CodeBlockKind::Fenced(name), + )) => { + language = Some(name); + None + } + pulldown_cmark::Event::Text(code) => { + if let Some(language) = language.take() { + let syntax_reference = builder + .syntax_set + .find_syntax_by_token(&language) + .unwrap_or_else(|| builder.syntax_set.find_syntax_plain_text()); + let html = format!( + r#"
+ + {} +
"#, + syntect::html::highlighted_html_for_string( + &code, + &builder.syntax_set, + syntax_reference, + builder.theme_set + .themes + .get(&builder.site.config.code_theme) + .as_ref() + .expect("should never fail"), + ) + .expect("failed to highlight syntax") + ); + Some(pulldown_cmark::Event::Html(html.into())) + } else { + Some(pulldown_cmark::Event::Text(code)) + } + } + _ => Some(event), + } + }); + let mut page_html = String::new(); + pulldown_cmark::html::push_html(&mut page_html, parser); + + Ok(page_html) +}