diff options
author | metamuffin <metamuffin@disroot.org> | 2022-09-26 15:16:05 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2022-09-26 15:16:05 +0200 |
commit | a5ee9b1edd25f698813ebdc52404ec19fa479718 (patch) | |
tree | 7d428ca9b2b0059e39f78bc096bf57b94f1d8a3d | |
parent | 15d78464ba9a717a71e1dc47a4101c8b13ec6581 (diff) | |
download | metamuffin-blog-a5ee9b1edd25f698813ebdc52404ec19fa479718.tar metamuffin-blog-a5ee9b1edd25f698813ebdc52404ec19fa479718.tar.bz2 metamuffin-blog-a5ee9b1edd25f698813ebdc52404ec19fa479718.tar.zst |
new renderer
-rw-r--r-- | code/grammar/markdown.pest | 20 | ||||
-rw-r--r-- | code/src/atom.rs | 2 | ||||
-rw-r--r-- | code/src/html.rs | 15 | ||||
-rw-r--r-- | code/src/markdown/mod.rs | 41 | ||||
-rw-r--r-- | code/src/markdown/parser.rs | 167 | ||||
-rw-r--r-- | code/src/markdown/render.rs | 8 | ||||
-rw-r--r-- | code/src/syntax_highlight/mod.rs | 4 |
7 files changed, 69 insertions, 188 deletions
diff --git a/code/grammar/markdown.pest b/code/grammar/markdown.pest index 43c6e7a..ebdfcd7 100644 --- a/code/grammar/markdown.pest +++ b/code/grammar/markdown.pest @@ -1,9 +1,17 @@ -file = _{SOI ~ block* ~ EOI} -block = { (header | list | span | "") ~ NEWLINE } -header = {"#"+ ~ span} -list = { list_item+ } -list_item = { "-" ~ span } -span = { (!NEWLINE ~ ANY)+ } +file = _{ SOI ~ block* ~ EOI } + +block = { (code_block | header | list | paragraph | "") ~ NEWLINE } + header = { "#"+ ~ span } + list = { list_item+ } + list_item = { "-" ~ span } + paragraph = { span } + code_block = { "```" ~ (!"```" ~ ANY) ~ "```" } + +span = { (style_bold | style_italic | style_code | text)+ } + style_bold = { "**" ~ text ~ "**" } + style_italic = { "_" ~ text ~ "_" } + style_code = { "`" ~ text ~ "`" } + text = { (!(NEWLINE | "*" | "_" | "`") ~ ANY)+ } diff --git a/code/src/atom.rs b/code/src/atom.rs index c231c94..de23265 100644 --- a/code/src/atom.rs +++ b/code/src/atom.rs @@ -1,4 +1,4 @@ -use crate::{get_articles, markdown::render::escape, Args, ArticleMeta, BLOG_BASE}; +use crate::{get_articles, Args, ArticleMeta, BLOG_BASE, html::escape}; use std::process::{Command, Stdio}; pub fn generate_atom(args: &Args) -> String { diff --git a/code/src/html.rs b/code/src/html.rs index 23ac6c8..e133528 100644 --- a/code/src/html.rs +++ b/code/src/html.rs @@ -1,10 +1,9 @@ use crate::{ article_metadata, file_history, get_articles, - markdown::{self, render::blocks_to_html}, + markdown::{self}, ArticleMeta, }; use laby::{frag, html, iter, li, ul, Render}; -use pest::Parser; use std::fs::read_to_string; pub fn scaffold(title: String, body: impl Render) -> impl Render { @@ -39,9 +38,9 @@ pub fn article(path: String) -> impl Render { scaffold( article_metadata(path.clone().into()).title, frag!( - laby::raw!(blocks_to_html(markdown::parser::parse( + laby::raw!(markdown::render( &read_to_string(&path).unwrap() - ))), + )), hr!(), p!("changes to this article (as recorded with git; visible on the git repo, that i will create soon)"), pre!(file_history(&path)) @@ -70,3 +69,11 @@ pub fn index(root: &str) -> impl Render { })), ) } + +pub fn escape(text: &str) -> String { + text.replace("&", "&") + .replace("<", "<") + .replace(">", ">") + .replace("'", "’") + .replace("\"", """) +} diff --git a/code/src/markdown/mod.rs b/code/src/markdown/mod.rs index 7bdf323..b6dfb55 100644 --- a/code/src/markdown/mod.rs +++ b/code/src/markdown/mod.rs @@ -1,2 +1,39 @@ -pub mod parser; -pub mod render; +use pest::{ + iterators::{Pair, Pairs}, + Parser, +}; +use pest_derive::Parser; + +use crate::html::escape; + +#[derive(Parser)] +#[grammar = "grammar/markdown.pest"] +struct Grammar; + +pub fn render(s: &str) -> String { + match Grammar::parse(Rule::file, s) { + Ok(pairs) => { + eprintln!("{pairs:#?}"); + render_pairs(pairs) + } + Err(e) => panic!("{e}"), + } +} + +pub fn render_pairs(p: Pairs<Rule>) -> String { + p.map(|p| render_ast(p)).collect::<Vec<_>>().join("") +} + +pub fn render_ast(p: Pair<Rule>) -> String { + match p.as_rule() { + Rule::block => render_pairs(p.into_inner()), + Rule::header => format!("<h1>{}</h1>", render_pairs(p.into_inner())), + Rule::paragraph => format!("<p>{}</p>", render_pairs(p.into_inner())), + Rule::list => format!("<ul>{}</ul>", render_pairs(p.into_inner())), + Rule::list_item => format!("<li>{}</li>", render_pairs(p.into_inner())), + Rule::span => render_pairs(p.into_inner()), + Rule::text => escape(p.as_str()), + Rule::EOI => "".to_string(), + _ => todo!("{:?}", p.as_rule()), + } +} diff --git a/code/src/markdown/parser.rs b/code/src/markdown/parser.rs index 94eab49..8876335 100644 --- a/code/src/markdown/parser.rs +++ b/code/src/markdown/parser.rs @@ -1,3 +1,6 @@ +use pest::Parser; +use pest_derive::Parser; + #[derive(Debug, Clone)] pub enum Block { Header(usize, Vec<Span>), @@ -21,167 +24,3 @@ pub enum Span { Strong(Vec<Span>), Latex(String), } - -pub fn parse(mut s: &str) -> Vec<Block> { - let mut blocks = Vec::new(); - while s.len() != 0 { - if s.starts_with("\n") { - s = &s[1..]; - continue; - } - // TODO bad code here - if let Some((block, rest)) = try_header(s) { - s = rest; - blocks.push(block); - continue; - } - if let Some((block, rest)) = try_latex_block(s) { - s = rest; - blocks.push(block); - continue; - } - if let Some((block, rest)) = try_code_block(s) { - s = rest; - blocks.push(block); - continue; - } - if let Some((block, rest)) = try_list(s) { - s = rest; - blocks.push(block); - continue; - } - let lf = [s.find("\n\n"), s.find("\n-")] - .iter() - .filter_map(|e| *e) - .min() - .unwrap_or(s.len()); - let span = Span::parse(&s[..lf]); - blocks.push(Block::Paragraph(span)); - if lf >= s.len() { - break; - } - s = &s[lf + 1..]; - } - blocks -} - -fn try_code_block(mut s: &str) -> Option<(Block, &str)> { - if !s.starts_with("```") { - return None; - } - s = &s[3..]; - let lf = s.find('\n')?; - let syntax = if lf != 0 { - Some(String::from(&s[0..lf])) - } else { - None - }; - s = &s[lf..]; - let end = s.find("\n```\n")?; - Some(( - Block::CodeBlock(syntax, String::from(&s[..end])), - &s[end + 4..], - )) -} -fn try_latex_block(mut s: &str) -> Option<(Block, &str)> { - if !s.starts_with("$$") { - return None; - } - s = &s[2..]; - let end = s.find("$$")?; - Some((Block::LatexBlock(String::from(&s[..end])), &s[end + 2..])) -} -fn try_list(mut s: &str) -> Option<(Block, &str)> { - if !s.starts_with("-") { - return None; - }; - let mut blocks = vec![]; - loop { - if !s.starts_with("-") || s.len() == 0 { - break Some((Block::UnorderedList(blocks), s)); - } - s = &s[1..]; - let mut lf = s.find("\n").unwrap(); - while s[lf + 1..].starts_with(" ") { - lf += 2 + s[lf + 2..].find("\n").unwrap(); - } - let mut k = s[..lf] - .split("\n") - .map(|l| if l.starts_with(" ") { &l[2..] } else { &l }) - .collect::<Vec<_>>() - .join("\n"); - k.push('\n'); - blocks.push(parse(&k)); - s = &s[lf + 1..]; - } -} -fn try_header(s: &str) -> Option<(Block, &str)> { - if s.starts_with("#") { - let mut u = 0; - while s.chars().nth(u)? == '#' { - u += 1; - } - let lf = s.find('\n')?; - Some((Block::Header(u, Span::parse(&s[u..lf])), &s[lf + 1..])) - } else { - None - } -} - -impl Span { - pub fn parse(mut s: &str) -> Vec<Span> { - let mut spans = Vec::new(); - while s.len() != 0 { - let nt = s.find(&['*', '_', '`', '[', '$']); - - if let Some(nt) = nt { - spans.push(Span::Text(String::from(&s[..nt]))); - s = &s[nt..]; - if s.starts_with("**") { - s = &s[2..]; - let end = s.find("**").expect("** not ended"); - spans.push(Span::Strong(Span::parse(&s[..end]))); - s = &s[end + 2..]; - continue; - } - if s.starts_with("_") { - s = &s[1..]; - let end = s.find("_").expect("_ not ended"); - spans.push(Span::Emphasis(Span::parse(&s[..end]))); - s = &s[end + 1..]; - continue; - } - if s.starts_with("`") { - s = &s[1..]; - let end = s.find("`").expect("` not ended"); - spans.push(Span::Code(String::from(&s[..end]))); - s = &s[end + 1..]; - continue; - } - if s.starts_with("$") { - s = &s[1..]; - let end = s.find("$").expect("$ not ended"); - spans.push(Span::Latex(String::from(&s[..end]))); - s = &s[end + 1..]; - continue; - } - if s.starts_with("[") { - s = &s[1..]; - let del = s.find("](").expect("]( expected"); - let end = del + s[del..].find(")").expect(") expected"); - spans.push(Span::Link( - String::from(&s[..del]), - String::from(&s[del + 2..end]), - )); - s = &s[end + 1..]; - continue; - } - panic!("{s:?}") - } else { - spans.push(Span::Text(String::from(s))); - break; - } - } - spans - } -} diff --git a/code/src/markdown/render.rs b/code/src/markdown/render.rs index 7962561..75ebe43 100644 --- a/code/src/markdown/render.rs +++ b/code/src/markdown/render.rs @@ -74,14 +74,6 @@ pub fn blocks_to_html(blocks: Vec<Block>) -> String { out } -pub fn escape(text: &str) -> String { - text.replace("&", "&") - .replace("<", "<") - .replace(">", ">") - .replace("'", "’") - .replace("\"", """) -} - // TODO this is *really* bad fix fn fix_katex<'a>(s: &str) -> String { let e = s.find("<span class=\"katex-html\"").unwrap(); diff --git a/code/src/syntax_highlight/mod.rs b/code/src/syntax_highlight/mod.rs index 86b689a..a766065 100644 --- a/code/src/syntax_highlight/mod.rs +++ b/code/src/syntax_highlight/mod.rs @@ -1,10 +1,8 @@ - -use crate::markdown::render::escape; use lazy_static::lazy_static; use syntect::easy::HighlightLines; use syntect::highlighting::{Style, ThemeSet}; use syntect::parsing::SyntaxSet; -use syntect::util::{as_24_bit_terminal_escaped, LinesWithEndings}; +use syntect::util::LinesWithEndings; lazy_static! { static ref PS: SyntaxSet = SyntaxSet::load_defaults_newlines(); |