From a5ee9b1edd25f698813ebdc52404ec19fa479718 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Mon, 26 Sep 2022 15:16:05 +0200 Subject: new renderer --- code/src/markdown/mod.rs | 41 ++++++++++- code/src/markdown/parser.rs | 167 +------------------------------------------- code/src/markdown/render.rs | 8 --- 3 files changed, 42 insertions(+), 174 deletions(-) (limited to 'code/src/markdown') 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) -> String { + p.map(|p| render_ast(p)).collect::>().join("") +} + +pub fn render_ast(p: Pair) -> String { + match p.as_rule() { + Rule::block => render_pairs(p.into_inner()), + Rule::header => format!("

{}

", render_pairs(p.into_inner())), + Rule::paragraph => format!("

{}

", render_pairs(p.into_inner())), + Rule::list => format!("
    {}
", render_pairs(p.into_inner())), + Rule::list_item => format!("
  • {}
  • ", 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), @@ -21,167 +24,3 @@ pub enum Span { Strong(Vec), Latex(String), } - -pub fn parse(mut s: &str) -> Vec { - 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::>() - .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 { - 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) -> 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("