aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2022-09-26 17:08:20 +0200
committermetamuffin <metamuffin@disroot.org>2022-09-26 17:08:20 +0200
commit5316b954323a4d7bee492a3997bae35dd107e44a (patch)
tree428b550f419d1ceab1f3e54df5bfeb79a17384d1
parentb14edcc66993a3e84bbfa0606bff04d0fe271e48 (diff)
downloadmetamuffin-blog-5316b954323a4d7bee492a3997bae35dd107e44a.tar
metamuffin-blog-5316b954323a4d7bee492a3997bae35dd107e44a.tar.bz2
metamuffin-blog-5316b954323a4d7bee492a3997bae35dd107e44a.tar.zst
hyperlinks
-rw-r--r--code/src/markdown/mod.rs50
-rw-r--r--code/src/markdown/parser.pest (renamed from code/grammar/markdown.pest)16
-rw-r--r--code/src/markdown/parser.rs26
3 files changed, 52 insertions, 40 deletions
diff --git a/code/src/markdown/mod.rs b/code/src/markdown/mod.rs
index dee923c..7ee18a2 100644
--- a/code/src/markdown/mod.rs
+++ b/code/src/markdown/mod.rs
@@ -7,7 +7,7 @@ use pest_derive::Parser;
use crate::{html::escape, syntax_highlight::syntax_highlight};
#[derive(Parser)]
-#[grammar = "grammar/markdown.pest"]
+#[grammar = "src/markdown/parser.pest"]
struct Grammar;
pub fn render(s: &str) -> String {
@@ -27,16 +27,28 @@ pub fn render_pairs(p: Pairs<Rule>) -> String {
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::header => {
+ let mut level = 0;
+ while p.as_str()[level..].starts_with("#") {
+ level += 1
+ }
+ format!("<h{level}>{}</h{level}>", render_pairs(p.into_inner()))
+ }
Rule::paragraph => format!("<p>{}</p>", render_pairs(p.into_inner())),
+ Rule::style_italic => format!("<i>{}</i>", render_pairs(p.into_inner())),
+ Rule::style_bold => format!("<b>{}</b>", render_pairs(p.into_inner())),
+ Rule::style_code => format!("<code>{}</code>", p.into_inner().next().unwrap().as_str()),
Rule::unordered_list => format!("<ul>{}</ul>", render_pairs(p.into_inner())),
Rule::ordered_list => format!("<ol>{}</ol>", render_pairs(p.into_inner())),
Rule::unordered_list_item | Rule::ordered_list_item => {
format!("<li>{}</li>", render_pairs(p.into_inner()))
}
- Rule::style_italic => format!("<i>{}</i>", render_pairs(p.into_inner())),
- Rule::style_bold => format!("<b>{}</b>", render_pairs(p.into_inner())),
- Rule::style_code => format!("<code>{}</code>", p.into_inner().next().unwrap().as_str()),
+ Rule::hyperlink => {
+ let k = p.into_inner().collect::<Vec<_>>();
+ let label = k[0].as_str();
+ let target = k[1].as_str();
+ format!("<a href=\"{}\">{}</a>", escape(target), escape(label))
+ }
Rule::span => render_pairs(p.into_inner()),
Rule::EOI => "".to_string(),
Rule::code_block => {
@@ -48,11 +60,35 @@ pub fn render_ast(p: Pair<Rule>) -> String {
syntax_highlight(lang, &inner).unwrap_or_else(|| escape(&inner))
)
}
- Rule::inline_latex => format!("<span>TODO: Inline latex</span>"),
- Rule::latex_block => format!("<p>TODO: Latex block</p>"),
+ Rule::inline_latex => fix_katex(
+ &katex::render_with_opts(
+ &p.into_inner().as_str(),
+ &katex::OptsBuilder::default().build().unwrap(),
+ )
+ .unwrap(),
+ ),
+ Rule::latex_block => fix_katex(
+ &katex::render_with_opts(
+ &p.into_inner().as_str(),
+ &katex::OptsBuilder::default()
+ .display_mode(true)
+ .build()
+ .unwrap(),
+ )
+ .unwrap(),
+ ),
Rule::text => escape(p.as_str()),
_ => todo!("{:?}", p.as_rule()),
}
}
+
+// TODO this is *really* bad fix
+fn fix_katex<'a>(s: &str) -> String {
+ let e = s.find("<span class=\"katex-html\"").unwrap();
+ s[0..e].replace(
+ "<mspace linebreak=\"newline\"></mspace>",
+ "</mrow></semantics></math><math xmlns=\"http://www.w3.org/1998/Math/MathML\" display=\"block\"><semantics><mrow>",
+ )
+}
diff --git a/code/grammar/markdown.pest b/code/src/markdown/parser.pest
index e387182..22563d4 100644
--- a/code/grammar/markdown.pest
+++ b/code/src/markdown/parser.pest
@@ -1,9 +1,7 @@
-// WHITESPACE = _{ " " | "\t" | NEWLINE }
-
file = _{ SOI ~ NEWLINE* ~ (block ~ NEWLINE*)* ~ EOI }
block = { code_block | latex_block | header | unordered_list | ordered_list | paragraph }
- header = { "#"+ ~ span }
+ header = { "#"{1,6} ~ span }
unordered_list = { unordered_list_item+ }
unordered_list_item = { "-" ~ span ~ NEWLINE }
ordered_list = { ordered_list_item+ }
@@ -14,14 +12,18 @@ block = { code_block | latex_block | header | unordered_list | ordered_list | pa
code_block_inner = { (!"```" ~ ANY)* }
latex_block = { "$$" ~ latex_block_inner ~ "$$" }
latex_block_inner = { (!"$$" ~ ANY)* }
+
-span = { (style_bold | style_italic | style_code | inline_latex | text)+ }
- style_bold = { "**" ~ text ~ "**" }
- style_italic = { "_" ~ text ~ "_" }
+span = { (style_bold | style_italic | style_code | inline_latex | hyperlink | text)+ }
+ style_bold = { "**" ~ span ~ "**" }
+ style_italic = { "_" ~ span ~ "_" }
style_code = { "`" ~ code_inner ~ "`" }
code_inner = { (!"`" ~ ANY)+ }
inline_latex = { "$" ~ latex_inner ~ "$" }
latex_inner = { (!"$" ~ ANY)+ }
+ hyperlink = { "[" ~ hyperlink_label ~ "](" ~ hyperlink_location ~ ")" }
+ hyperlink_label = { span }
+ hyperlink_location = { (!")" ~ANY)+ }
- text = { (!("\n" ~ forbidden_span_wrap | "*" | "_" | "`" | "$") ~ ANY)+ }
+ text = { (!("[" | "]" | "*" | "_" | "`" | "$" | ("\n" ~ forbidden_span_wrap)) ~ ANY)+ }
forbidden_span_wrap = _{ "\n" | "-" | ASCII_DIGIT+ ~ "." }
diff --git a/code/src/markdown/parser.rs b/code/src/markdown/parser.rs
deleted file mode 100644
index 8876335..0000000
--- a/code/src/markdown/parser.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use pest::Parser;
-use pest_derive::Parser;
-
-#[derive(Debug, Clone)]
-pub enum Block {
- Header(usize, Vec<Span>),
- Paragraph(Vec<Span>),
- Blockquote(Vec<Block>),
- CodeBlock(Option<String>, String),
- LatexBlock(String),
- OrderedList(Vec<Vec<Block>>),
- UnorderedList(Vec<Vec<Block>>),
- Raw(String),
- Hr,
-}
-#[derive(Debug, Clone)]
-pub enum Span {
- Break,
- Text(String),
- Code(String),
- Link(String, String),
- Image(String, String),
- Emphasis(Vec<Span>),
- Strong(Vec<Span>),
- Latex(String),
-}