Implemented MFM functions and math and center blocks
This commit is contained in:
parent
1af8f4e213
commit
46e0766a36
|
@ -2499,18 +2499,18 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.180"
|
version = "1.0.188"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed"
|
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.180"
|
version = "1.0.188"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036"
|
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
use nom::character::complete;
|
use nom::character::complete;
|
||||||
use nom::character::complete::{anychar, line_ending, not_line_ending, tab};
|
use nom::character::complete::{
|
||||||
use nom::combinator::{fail, not, opt};
|
alpha1, alphanumeric1, anychar, char as one_char, line_ending, not_line_ending, tab,
|
||||||
|
};
|
||||||
|
use nom::combinator::{fail, not, opt, recognize};
|
||||||
use nom::error::ErrorKind;
|
use nom::error::ErrorKind;
|
||||||
use nom::multi::{many1, separated_list1};
|
use nom::multi::{many0, many0_count, many1, many1_count, separated_list1};
|
||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
use nom::{IResult, Offset, Slice};
|
use nom::{IResult, Offset, Slice};
|
||||||
use nom_locate::LocatedSpan;
|
use nom_locate::LocatedSpan;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
enum Token<'a> {
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum Token<'a> {
|
||||||
PlainText(Cow<'a, str>),
|
PlainText(Cow<'a, str>),
|
||||||
Sequence(Vec<Token<'a>>),
|
Sequence(Vec<Token<'a>>),
|
||||||
Quote(Box<Token<'a>>),
|
Quote(Box<Token<'a>>),
|
||||||
|
@ -24,6 +28,16 @@ enum Token<'a> {
|
||||||
PlainTag(Cow<'a, str>),
|
PlainTag(Cow<'a, str>),
|
||||||
InlineCode(Cow<'a, str>),
|
InlineCode(Cow<'a, str>),
|
||||||
InlineMath(Cow<'a, str>),
|
InlineMath(Cow<'a, str>),
|
||||||
|
BlockCode {
|
||||||
|
lang: Option<Cow<'a, str>>,
|
||||||
|
inner: Cow<'a, str>,
|
||||||
|
},
|
||||||
|
BlockMath(Cow<'a, str>),
|
||||||
|
Function {
|
||||||
|
name: Cow<'a, str>,
|
||||||
|
params: HashMap<Cow<'a, str>, Option<Cow<'a, str>>>,
|
||||||
|
inner: Box<Token<'a>>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Token<'_> {
|
impl Token<'_> {
|
||||||
|
@ -42,6 +56,28 @@ impl Token<'_> {
|
||||||
Token::PlainTag(tag) => Token::PlainTag(Cow::Owned(tag.clone().into_owned())),
|
Token::PlainTag(tag) => Token::PlainTag(Cow::Owned(tag.clone().into_owned())),
|
||||||
Token::InlineCode(code) => Token::InlineCode(Cow::Owned(code.clone().into_owned())),
|
Token::InlineCode(code) => Token::InlineCode(Cow::Owned(code.clone().into_owned())),
|
||||||
Token::InlineMath(math) => Token::InlineMath(Cow::Owned(math.clone().into_owned())),
|
Token::InlineMath(math) => Token::InlineMath(Cow::Owned(math.clone().into_owned())),
|
||||||
|
Token::BlockCode { inner, lang } => Token::BlockCode {
|
||||||
|
lang: lang.as_ref().map(|l| Cow::Owned(l.clone().into_owned())),
|
||||||
|
inner: Cow::Owned(inner.clone().into_owned()),
|
||||||
|
},
|
||||||
|
Token::BlockMath(math) => Token::BlockMath(Cow::Owned(math.clone().into_owned())),
|
||||||
|
Token::Function {
|
||||||
|
name,
|
||||||
|
params,
|
||||||
|
inner,
|
||||||
|
} => Token::Function {
|
||||||
|
name: Cow::Owned(name.clone().into_owned()),
|
||||||
|
params: params
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| {
|
||||||
|
(
|
||||||
|
Cow::Owned(k.clone().into_owned()),
|
||||||
|
v.as_ref().map(|val| Cow::Owned(val.clone().into_owned())),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
inner: Box::new(inner.owned()),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,6 +120,7 @@ const fn collect_char_sequence<'a>(
|
||||||
fn spliced<'a>(
|
fn spliced<'a>(
|
||||||
segments: &[Span<'a>],
|
segments: &[Span<'a>],
|
||||||
func: impl Fn(Span) -> IResult<Span, Token>,
|
func: impl Fn(Span) -> IResult<Span, Token>,
|
||||||
|
output_mapper: impl Fn(Box<Token<'static>>) -> Token<'static>,
|
||||||
parent: Span<'a>,
|
parent: Span<'a>,
|
||||||
) -> IResult<Span<'a>, Token<'static>, nom::error::Error<Span<'a>>> {
|
) -> IResult<Span<'a>, Token<'static>, nom::error::Error<Span<'a>>> {
|
||||||
let combined = segments
|
let combined = segments
|
||||||
|
@ -143,7 +180,7 @@ fn spliced<'a>(
|
||||||
parent
|
parent
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((out, Token::Quote(Box::new(inner.owned()))))
|
Ok((out, output_mapper(Box::new(inner.owned()))))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn space(input: Span) -> IResult<Span, Token> {
|
fn space(input: Span) -> IResult<Span, Token> {
|
||||||
|
@ -204,13 +241,69 @@ impl Context {
|
||||||
return fail(input);
|
return fail(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (_, inner) = spliced("e_lines, space, orig_input)?;
|
let (_, inner) = spliced("e_lines, space, Token::Quote, orig_input)?;
|
||||||
|
|
||||||
let (input, _) = tuple((opt(line_ending), opt(line_ending)))(input)?;
|
let (input, _) = tuple((opt(line_ending), opt(line_ending)))(input)?;
|
||||||
|
|
||||||
Ok((input, Token::Quote(Box::new(inner))))
|
Ok((input, Token::Quote(Box::new(inner))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tag_block_center<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
|
||||||
|
let tag_start = &tag("<center>");
|
||||||
|
let tag_end = &tag("</center>");
|
||||||
|
|
||||||
|
let (input, _) = opt(line_ending)(input)?;
|
||||||
|
|
||||||
|
if input.get_column() != 0 {
|
||||||
|
return fail(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (input, _) = tag_start(input)?;
|
||||||
|
let (input, _) = opt(line_ending)(input)?;
|
||||||
|
|
||||||
|
let (input, center_seq) = many0(tuple((
|
||||||
|
not(tuple((opt(line_ending), tag_end))),
|
||||||
|
self.partial(Self::inline),
|
||||||
|
)))(input)?;
|
||||||
|
|
||||||
|
let (input, _) = opt(line_ending)(input)?;
|
||||||
|
let (input, _) = tag_end(input)?;
|
||||||
|
let (input, _) = many0(space)(input)?;
|
||||||
|
let (input, _) = not(not_line_ending)(input)?;
|
||||||
|
let (input, _) = opt(line_ending)(input)?;
|
||||||
|
|
||||||
|
let tokens = center_seq.into_iter().map(|(_, v)| v).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Ok((input, boxing_sequence(Token::Center)(tokens)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tag_block_math<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
|
||||||
|
let (input, _) = opt(line_ending)(input)?;
|
||||||
|
|
||||||
|
if input.get_column() != 0 {
|
||||||
|
return fail(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (input, _) = tag("\\[")(input)?;
|
||||||
|
let (input, _) = opt(line_ending)(input)?;
|
||||||
|
|
||||||
|
let (input, math_span) = recognize(many1_count(tuple((
|
||||||
|
not(tuple((opt(line_ending), tag("\\]")))),
|
||||||
|
not_line_ending,
|
||||||
|
))))(input)?;
|
||||||
|
|
||||||
|
let (input, _) = opt(line_ending)(input)?;
|
||||||
|
let (input, _) = tag("\\]")(input)?;
|
||||||
|
let (input, _) = many0(space)(input)?;
|
||||||
|
let (input, _) = not(not_line_ending)(input)?;
|
||||||
|
let (input, _) = opt(line_ending)(input)?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
input,
|
||||||
|
Token::BlockMath(Cow::Borrowed(math_span.into_fragment())),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
const fn tag_delimited<'a, 'b: 'a, T>(
|
const fn tag_delimited<'a, 'b: 'a, T>(
|
||||||
&'a self,
|
&'a self,
|
||||||
start: &'b str,
|
start: &'b str,
|
||||||
|
@ -252,6 +345,57 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn tag_func<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
|
||||||
|
let (input, _) = tag("$[")(input)?;
|
||||||
|
|
||||||
|
let func_ident = |input| {
|
||||||
|
recognize(tuple((
|
||||||
|
many1_count(alt((alpha1, tag("_")))),
|
||||||
|
many0_count(alt((alphanumeric1, tag("_")))),
|
||||||
|
)))(input)
|
||||||
|
};
|
||||||
|
|
||||||
|
let param_value = recognize(many1_count(alt((
|
||||||
|
alphanumeric1,
|
||||||
|
tag("."),
|
||||||
|
tag("-"),
|
||||||
|
tag("_"),
|
||||||
|
))));
|
||||||
|
|
||||||
|
let (input, func_name_span) = func_ident(input)?;
|
||||||
|
let func_name = func_name_span.into_fragment();
|
||||||
|
|
||||||
|
let arg = tuple((func_ident, opt(tuple((tag("="), param_value)))));
|
||||||
|
|
||||||
|
let (input, args) =
|
||||||
|
opt(tuple((one_char('.'), separated_list1(one_char(','), arg))))(input)?;
|
||||||
|
|
||||||
|
let args_out = args.map_or_else(HashMap::new, |(_, items)| {
|
||||||
|
items
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| {
|
||||||
|
(
|
||||||
|
Cow::from(k.into_fragment()),
|
||||||
|
v.map(|(_, val)| Cow::from(val.into_fragment())),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<HashMap<_, _>>()
|
||||||
|
});
|
||||||
|
|
||||||
|
let (input, inner) = self.partial(Self::inline)(input)?;
|
||||||
|
|
||||||
|
let (input, _) = tag("]")(input)?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
input,
|
||||||
|
Token::Function {
|
||||||
|
name: Cow::from(func_name),
|
||||||
|
params: args_out,
|
||||||
|
inner: Box::new(inner),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn tag_small<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
|
fn tag_small<'a>(&self, input: Span<'a>) -> IResult<Span<'a>, Token<'a>> {
|
||||||
self.tag_delimited(
|
self.tag_delimited(
|
||||||
"<small>",
|
"<small>",
|
||||||
|
|
Loading…
Reference in New Issue