112 lines
2.4 KiB
Rust
112 lines
2.4 KiB
Rust
use nom::branch::alt;
|
|
use nom::bytes::complete::tag;
|
|
use nom::character::complete::alphanumeric1;
|
|
use nom::character::complete::line_ending;
|
|
use nom::character::complete::space1;
|
|
use nom::combinator::eof;
|
|
use nom::combinator::map;
|
|
use nom::combinator::recognize;
|
|
use nom::multi::many1;
|
|
use nom::multi::many_till;
|
|
use nom::sequence::tuple;
|
|
use nom::IResult;
|
|
|
|
use super::error::CustomError;
|
|
|
|
pub type Res<T, U> = IResult<T, U, CustomError<T>>;
|
|
|
|
#[derive(Debug)]
|
|
pub enum TextElement<'a> {
|
|
Span(Span<'a>),
|
|
Space(Space<'a>),
|
|
LineBreak(LineBreak<'a>),
|
|
Symbol(Symbol<'a>),
|
|
Bold(Bold<'a>),
|
|
Link(Link<'a>),
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Span<'a> {
|
|
contents: &'a str,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Space<'a> {
|
|
contents: &'a str,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct LineBreak<'a> {
|
|
contents: &'a str,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Symbol<'a> {
|
|
contents: &'a str,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct BlankLine<'a> {
|
|
contents: &'a str,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Sequence<'a> {
|
|
pub contents: &'a str,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Bold<'a> {
|
|
pub contents: &'a str,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Link<'a> {
|
|
pub contents: &'a str,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct Paragraph<'a> {
|
|
pub contents: Vec<TextElement<'a>>,
|
|
pub paragraph_end: &'a str,
|
|
}
|
|
|
|
pub fn line_break(input: &str) -> Res<&str, LineBreak> {
|
|
map(line_ending, |s: &str| LineBreak { contents: s })(input)
|
|
}
|
|
|
|
pub fn space(input: &str) -> Res<&str, Space> {
|
|
map(space1, |s: &str| Space { contents: s })(input)
|
|
}
|
|
|
|
pub fn span(input: &str) -> Res<&str, Span> {
|
|
map(alphanumeric1, |s: &str| Span { contents: s })(input)
|
|
}
|
|
|
|
pub fn symbol(symbol_tag: &'static str) -> impl for<'a> Fn(&'a str) -> Res<&'a str, Symbol<'a>> {
|
|
move |i: &str| map(tag(symbol_tag), |s: &str| Symbol { contents: s })(i)
|
|
}
|
|
|
|
/// A line containing only whitespace and then a line break
|
|
///
|
|
/// It is up to the caller to ensure this is called at the start of a line.
|
|
fn blank_line(input: &str) -> Res<&str, BlankLine> {
|
|
map(
|
|
recognize(many_till(
|
|
map(space, TextElement::Space),
|
|
map(line_break, TextElement::LineBreak),
|
|
)),
|
|
|contents| BlankLine { contents },
|
|
)(input)
|
|
}
|
|
|
|
pub fn paragraph_end(input: &str) -> Res<&str, &str> {
|
|
alt((
|
|
recognize(tuple((
|
|
map(line_break, TextElement::LineBreak),
|
|
many1(blank_line),
|
|
))),
|
|
eof,
|
|
))(input)
|
|
}
|