diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/blog/mod.rs | 96 |
1 files changed, 83 insertions, 13 deletions
diff --git a/src/blog/mod.rs b/src/blog/mod.rs index b301171..49fbd4b 100644 --- a/src/blog/mod.rs +++ b/src/blog/mod.rs @@ -8,8 +8,14 @@ use crate::uri; use anyhow::anyhow; pub use atom::r_blog_atom; use atom::rocket_uri_macro_r_blog_atom; +use latex2mathml::DisplayStyle; +use markdown::mdast::Node; +use markup::{raw, DynRender}; use rocket::{get, response::Redirect}; use std::{path::PathBuf, str::FromStr}; +use syntect::highlighting::ThemeSet; +use syntect::html::highlighted_html_for_string; +use syntect::parsing::SyntaxSet; use tokio::fs::read_to_string; pub const ARTICLE_ROOT: &'static str = "./blog/articles"; @@ -49,28 +55,92 @@ pub async fn r_blog_article(name: &str) -> MyResult<DynScaffold<'static>> { .join(PathBuf::new().with_file_name(name).with_extension("md")); let a = article_metadata(apath.clone()).await?; let text = read_to_string(apath).await?; - let html = markdown::to_html_with_options( + let ast = markdown::to_mdast( &text, - &markdown::Options { - parse: markdown::ParseOptions { - constructs: markdown::Constructs { - math_flow: true, - math_text: true, - ..Default::default() - }, - ..Default::default() - }, - compile: markdown::CompileOptions { + &markdown::ParseOptions { + constructs: markdown::Constructs { + math_flow: true, + math_text: true, ..Default::default() }, + ..Default::default() }, ) - .map_err(|e| anyhow!("the server had trouble compiling markdown: {e}"))?; + .map_err(|e| anyhow!("the server had trouble parsing markdown: {e}"))?; + Ok(Scaffold { title: a.title, content: markup::new! { - @markup::raw(&html) + @node_to_render(&ast) p{i{ "Article written by metamuffin, text licenced under CC BY-ND 4.0, non-trivial code blocks under GPL-3.0-only except where indicated otherwise" }} }, }) } + +fn node_to_render<'a>(node: &'a Node) -> DynRender<'a> { + match node { + Node::Text(s) => markup::new!(@s.value), + Node::Paragraph(el) => markup::new!(p { @for e in &el.children { @node_to_render(e) } }), + Node::List(list) => markup::new!(ul { @for e in &list.children { @node_to_render(e) } }), + Node::Root(el) => markup::new!(article { @for e in &el.children { @node_to_render(e) } }), + Node::ListItem(el) => markup::new!(li { @for e in &el.children { @node_to_render(e) } }), + Node::Emphasis(el) => markup::new!(i { @for e in &el.children { @node_to_render(e) } }), + Node::Strong(el) => markup::new!(strong { @for e in &el.children { @node_to_render(e) } }), + Node::Html(html) => markup::new!(@raw(&html.value)), + Node::Link(l) => { + markup::new!(a[href=&l.url, alt=&l.title] { @for e in &l.children { @node_to_render(e) } }) + } + Node::Break(_) => markup::new!(br;), + Node::InlineCode(s) => markup::new!(code { @s.value }), + Node::Delete(_) => markup::new!("todo1"), + Node::FootnoteReference(_) => markup::new!("todo3"), + Node::FootnoteDefinition(_) => markup::new!("todo4"), + Node::Image(_) => markup::new!("todo5"), + Node::ImageReference(_) => markup::new!("todo6"), + Node::LinkReference(_) => markup::new!("todo8"), + Node::BlockQuote(_) => markup::new!("todo10"), + Node::Table(_) => markup::new!("todo12"), + Node::ThematicBreak(_) => markup::new!("todo13"), + Node::TableRow(_) => markup::new!("todo14"), + Node::TableCell(_) => markup::new!("todo15"), + Node::Definition(_) => markup::new!("todo16"), + Node::Toml(_) + | Node::Yaml(_) + | Node::MdxjsEsm(_) + | Node::MdxJsxFlowElement(_) + | Node::MdxJsxTextElement(_) + | Node::MdxTextExpression(_) + | Node::MdxFlowExpression(_) => markup::new!("unsupported"), + Node::Heading(h) => { + let inner = markup::new!(@for e in &h.children { @node_to_render(e) }); + match h.depth { + 1 => markup::new!(h2{@inner}), + 2 => markup::new!(h3{@inner}), + 3 => markup::new!(h4{@inner}), + 4 => markup::new!(h5{@inner}), + 5 => markup::new!(h6{@inner}), + 6 => markup::new!(h6{@inner}), + _ => unreachable!(), + } + } + Node::Code(code) => { + let theme = &ThemeSet::load_defaults().themes["base16-ocean.dark"]; + let syntax = &SyntaxSet::load_defaults_newlines(); + let lang = syntax + .find_syntax_by_extension(&code.lang.to_owned().unwrap_or("txt".to_owned())) + .unwrap_or_else(|| syntax.find_syntax_by_extension("txt").unwrap()); + let html = highlighted_html_for_string(&code.value, syntax, lang, theme).unwrap(); + markup::new!(@raw(&html)) + } + Node::Math(s) => { + let mathml = latex2mathml::latex_to_mathml(&s.value, DisplayStyle::Block) + .expect("invalid block math"); + markup::new!(@raw(&mathml)) + } + Node::InlineMath(s) => { + let mathml = latex2mathml::latex_to_mathml(&s.value, DisplayStyle::Inline) + .expect("invalid inline math"); + markup::new!(@raw(&mathml)) + } + } +} |