aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2022-09-26 15:16:05 +0200
committermetamuffin <metamuffin@disroot.org>2022-09-26 15:16:05 +0200
commita5ee9b1edd25f698813ebdc52404ec19fa479718 (patch)
tree7d428ca9b2b0059e39f78bc096bf57b94f1d8a3d
parent15d78464ba9a717a71e1dc47a4101c8b13ec6581 (diff)
downloadmetamuffin-blog-a5ee9b1edd25f698813ebdc52404ec19fa479718.tar
metamuffin-blog-a5ee9b1edd25f698813ebdc52404ec19fa479718.tar.bz2
metamuffin-blog-a5ee9b1edd25f698813ebdc52404ec19fa479718.tar.zst
new renderer
-rw-r--r--code/grammar/markdown.pest20
-rw-r--r--code/src/atom.rs2
-rw-r--r--code/src/html.rs15
-rw-r--r--code/src/markdown/mod.rs41
-rw-r--r--code/src/markdown/parser.rs167
-rw-r--r--code/src/markdown/render.rs8
-rw-r--r--code/src/syntax_highlight/mod.rs4
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("&", "&amp;")
+ .replace("<", "&lt;")
+ .replace(">", "&gt;")
+ .replace("'", "&#8217;")
+ .replace("\"", "&quot;")
+}
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("&", "&amp;")
- .replace("<", "&lt;")
- .replace(">", "&gt;")
- .replace("'", "&#8217;")
- .replace("\"", "&quot;")
-}
-
// 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();