Upgrade mdx parser
This commit is contained in:
@@ -9,7 +9,7 @@ use std::str::FromStr;
|
||||
|
||||
use crate::components::fa::FAIcon;
|
||||
use crate::components::mangle::{MangledBetaEmail, MangledGoogleEmail};
|
||||
use crate::components::misc::Backlinks;
|
||||
use crate::components::misc::{Backlinks, FarLink};
|
||||
|
||||
lazy_static! {
|
||||
static ref MdParser: MarkdownIt = {
|
||||
@@ -159,6 +159,10 @@ impl NodeValue for InlineMdx {
|
||||
return;
|
||||
}
|
||||
|
||||
if mdx_external(&self.0, node, fmt) {
|
||||
return;
|
||||
}
|
||||
|
||||
fmt.open("code", &[]);
|
||||
fmt.text(&self.0);
|
||||
fmt.close("code");
|
||||
@@ -200,78 +204,83 @@ impl InlineRule for InlineMdx {
|
||||
}
|
||||
|
||||
fn mdx_style(mdx: &str, _node: &Node, fmt: &mut dyn Renderer) -> bool {
|
||||
// Parse inside of mdx: `style(<style>) <content>`
|
||||
let (style, content) = {
|
||||
let mdx = mdx.trim();
|
||||
if !mdx.starts_with("style(") {
|
||||
return false;
|
||||
// Parse inside of mdx: `color(value, "text")`
|
||||
let mdx = mdx
|
||||
.trim()
|
||||
.trim_start_matches('{')
|
||||
.trim_end_matches('}')
|
||||
.trim();
|
||||
|
||||
// Find the function name (everything before the opening parenthesis)
|
||||
let paren_pos = match mdx.find('(') {
|
||||
Some(x) => x,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
if mdx[..paren_pos].trim() != "color" {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Find matching closing parenthesis
|
||||
let skip = paren_pos + 1;
|
||||
let mut balance = 1;
|
||||
let mut end = skip;
|
||||
for i in mdx[skip..].bytes() {
|
||||
match i {
|
||||
b')' => balance -= 1,
|
||||
b'(' => balance += 1,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let skip = 6;
|
||||
let mut balance = 1;
|
||||
let mut end = skip;
|
||||
for i in mdx[skip..].bytes() {
|
||||
match i {
|
||||
b')' => balance -= 1,
|
||||
b'(' => balance += 1,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if balance == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
end += 1;
|
||||
if balance == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
if balance != 0 {
|
||||
return false;
|
||||
}
|
||||
end += 1;
|
||||
}
|
||||
|
||||
let style = mdx[skip..end].trim();
|
||||
let content = mdx[end + 1..].trim();
|
||||
if balance != 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
(style, content)
|
||||
let args = mdx[skip..end].trim();
|
||||
|
||||
// Parse arguments: should be "value, text" or "value, \"text\""
|
||||
let comma_pos = match args.find(',') {
|
||||
Some(x) => x,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let value = args[..comma_pos].trim();
|
||||
let text = args[comma_pos + 1..].trim();
|
||||
|
||||
// Strip quotes from text if present
|
||||
let text = if (text.starts_with('"') && text.ends_with('"'))
|
||||
|| (text.starts_with('\'') && text.ends_with('\''))
|
||||
{
|
||||
&text[1..text.len() - 1]
|
||||
} else {
|
||||
text
|
||||
};
|
||||
|
||||
let mut style_str = String::new();
|
||||
|
||||
for kv in style.split(";") {
|
||||
let mut s = kv.split(":");
|
||||
let k = s.next();
|
||||
let v = s.next();
|
||||
|
||||
if k.is_none() || v.is_none() || s.next().is_some() {
|
||||
return false;
|
||||
}
|
||||
|
||||
#[expect(clippy::unwrap_used)] // Checked previously
|
||||
let k = k.unwrap().trim();
|
||||
|
||||
#[expect(clippy::unwrap_used)] // Checked previously
|
||||
let v = v.unwrap().trim();
|
||||
|
||||
match k {
|
||||
"color" => {
|
||||
style_str.push_str("color:");
|
||||
style_str.push_str(v);
|
||||
style_str.push(';');
|
||||
}
|
||||
|
||||
"color_var" => {
|
||||
style_str.push_str("color:var(--");
|
||||
style_str.push_str(v);
|
||||
style_str.push_str(");");
|
||||
}
|
||||
|
||||
_ => continue,
|
||||
}
|
||||
if value.starts_with("#") {
|
||||
style_str.push_str("color:");
|
||||
style_str.push_str(value);
|
||||
style_str.push(';');
|
||||
} else if value.starts_with("--") {
|
||||
style_str.push_str("color:var(");
|
||||
style_str.push_str(value);
|
||||
style_str.push_str(");");
|
||||
} else {
|
||||
style_str.push_str("color:");
|
||||
style_str.push_str(value);
|
||||
style_str.push(';');
|
||||
}
|
||||
|
||||
// Only works with text, could be reworked to do basic md styling
|
||||
// (italics, bold, tab, code)
|
||||
fmt.open("span", &[("style", style_str)]);
|
||||
fmt.text(content);
|
||||
fmt.text(text);
|
||||
fmt.close("span");
|
||||
|
||||
return true;
|
||||
@@ -280,7 +289,12 @@ fn mdx_style(mdx: &str, _node: &Node, fmt: &mut dyn Renderer) -> bool {
|
||||
fn mdx_include(mdx: &str, _node: &Node, fmt: &mut dyn Renderer) -> bool {
|
||||
// Parse inside of mdx: `include(<args>)`
|
||||
let args = {
|
||||
let mdx = mdx.trim();
|
||||
let mdx = mdx
|
||||
.trim()
|
||||
.trim_start_matches('{')
|
||||
.trim_end_matches('}')
|
||||
.trim();
|
||||
|
||||
if !mdx.starts_with("include(") {
|
||||
return false;
|
||||
}
|
||||
@@ -326,6 +340,105 @@ fn mdx_include(mdx: &str, _node: &Node, fmt: &mut dyn Renderer) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn mdx_external(mdx: &str, _node: &Node, fmt: &mut dyn Renderer) -> bool {
|
||||
// Parse inside of mdx: `external("text", "link")`
|
||||
let args = {
|
||||
let mdx = mdx
|
||||
.trim()
|
||||
.trim_start_matches('{')
|
||||
.trim_end_matches('}')
|
||||
.trim();
|
||||
|
||||
if !mdx.starts_with("external(") {
|
||||
return false;
|
||||
}
|
||||
|
||||
let skip = 9;
|
||||
let mut balance = 1;
|
||||
let mut end = skip;
|
||||
for i in mdx[skip..].bytes() {
|
||||
match i {
|
||||
b')' => balance -= 1,
|
||||
b'(' => balance += 1,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if balance == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
end += 1;
|
||||
}
|
||||
|
||||
if balance != 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let args = mdx[skip..end].trim();
|
||||
let trail = mdx[end + 1..].trim();
|
||||
if !trail.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
args
|
||||
};
|
||||
|
||||
// TODO: better parsing, handle , in string
|
||||
let mut split = args.split(",");
|
||||
|
||||
let title = match split.next() {
|
||||
Some(mut x) => {
|
||||
x = x.trim();
|
||||
|
||||
if &x[0..1] == "\"" {
|
||||
x = &x[1..]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if &x[x.len() - 1..] == "\"" {
|
||||
x = &x[0..x.len() - 1]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
x
|
||||
}
|
||||
|
||||
None => return false,
|
||||
};
|
||||
|
||||
let link = match split.next() {
|
||||
Some(mut x) => {
|
||||
x = x.trim();
|
||||
|
||||
if &x[0..1] == "\"" {
|
||||
x = &x[1..]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if &x[x.len() - 1..] == "\"" {
|
||||
x = &x[0..x.len() - 1]
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
x
|
||||
}
|
||||
|
||||
None => return false,
|
||||
};
|
||||
|
||||
if split.next().is_some() {
|
||||
return false;
|
||||
}
|
||||
|
||||
fmt.text_raw(&FarLink(link, title).render().0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// MARK: yaml frontmatter
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user