stuuoestnhunoestuh
This commit is contained in:
parent
d8d464902a
commit
653bd59eb5
2 changed files with 111 additions and 44 deletions
153
src/inline.rs
153
src/inline.rs
|
@ -48,7 +48,7 @@ pub enum Container {
|
||||||
/// Span is the URL.
|
/// Span is the URL.
|
||||||
InlineImage,
|
InlineImage,
|
||||||
|
|
||||||
AutoLink,
|
Autolink,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
@ -108,6 +108,7 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
||||||
self.reset_span();
|
self.reset_span();
|
||||||
self.eat().map(|first| {
|
self.eat().map(|first| {
|
||||||
self.parse_verbatim(&first)
|
self.parse_verbatim(&first)
|
||||||
|
.or_else(|| self.parse_autolink(&first))
|
||||||
.or_else(|| self.parse_container(&first))
|
.or_else(|| self.parse_container(&first))
|
||||||
.or_else(|| self.parse_atom(&first))
|
.or_else(|| self.parse_atom(&first))
|
||||||
.unwrap_or(Event {
|
.unwrap_or(Event {
|
||||||
|
@ -208,45 +209,46 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_autolink(&mut self, first: &lex::Token) -> Option<Event> {
|
||||||
|
if first.kind == lex::Kind::Sym(Symbol::Lt) {
|
||||||
|
let mut ahead = self.lexer.inner().clone();
|
||||||
|
let mut end = false;
|
||||||
|
let mut is_url = false;
|
||||||
|
let len = (&mut ahead)
|
||||||
|
.take_while(|c| {
|
||||||
|
if *c == '>' {
|
||||||
|
end = true;
|
||||||
|
};
|
||||||
|
if matches!(*c, ':' | '@') {
|
||||||
|
is_url = true;
|
||||||
|
}
|
||||||
|
!end && !c.is_whitespace()
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
(end && is_url).then(|| {
|
||||||
|
self.lexer = lex::Lexer::new(ahead);
|
||||||
|
self.events.push_back(Event {
|
||||||
|
kind: EventKind::Enter(Autolink),
|
||||||
|
span: self.span,
|
||||||
|
});
|
||||||
|
self.span = Span::by_len(self.span.end(), len);
|
||||||
|
self.events.push_back(Event {
|
||||||
|
kind: EventKind::Str,
|
||||||
|
span: self.span,
|
||||||
|
});
|
||||||
|
self.span = Span::by_len(self.span.end(), 1);
|
||||||
|
Event {
|
||||||
|
kind: EventKind::Exit(Autolink),
|
||||||
|
span: self.span,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_container(&mut self, first: &lex::Token) -> Option<Event> {
|
fn parse_container(&mut self, first: &lex::Token) -> Option<Event> {
|
||||||
enum Dir {
|
Delim::from_token(first.kind).map(|(delim, dir)| {
|
||||||
Open,
|
|
||||||
Close,
|
|
||||||
Both,
|
|
||||||
}
|
|
||||||
|
|
||||||
use Directionality::{Bi, Uni};
|
|
||||||
use SpanType::{General, Image};
|
|
||||||
|
|
||||||
match first.kind {
|
|
||||||
lex::Kind::Sym(Symbol::Asterisk) => Some((Delim::Strong(Bi), Dir::Both)),
|
|
||||||
lex::Kind::Sym(Symbol::Underscore) => Some((Delim::Emphasis(Bi), Dir::Both)),
|
|
||||||
lex::Kind::Sym(Symbol::Caret) => Some((Delim::Superscript(Bi), Dir::Both)),
|
|
||||||
lex::Kind::Sym(Symbol::Tilde) => Some((Delim::Subscript(Bi), Dir::Both)),
|
|
||||||
lex::Kind::Sym(Symbol::Quote1) => Some((Delim::SingleQuoted, Dir::Both)),
|
|
||||||
lex::Kind::Sym(Symbol::Quote2) => Some((Delim::DoubleQuoted, Dir::Both)),
|
|
||||||
lex::Kind::Sym(Symbol::ExclaimBracket) => Some((Delim::Span(Image), Dir::Open)),
|
|
||||||
lex::Kind::Open(Delimiter::Bracket) => Some((Delim::Span(General), Dir::Open)),
|
|
||||||
lex::Kind::Close(Delimiter::Bracket) => Some((Delim::Span(General), Dir::Close)),
|
|
||||||
lex::Kind::Open(Delimiter::BraceAsterisk) => Some((Delim::Strong(Uni), Dir::Open)),
|
|
||||||
lex::Kind::Close(Delimiter::BraceAsterisk) => Some((Delim::Strong(Uni), Dir::Close)),
|
|
||||||
lex::Kind::Open(Delimiter::BraceUnderscore) => Some((Delim::Emphasis(Uni), Dir::Open)),
|
|
||||||
lex::Kind::Close(Delimiter::BraceUnderscore) => {
|
|
||||||
Some((Delim::Emphasis(Uni), Dir::Close))
|
|
||||||
}
|
|
||||||
lex::Kind::Open(Delimiter::BraceCaret) => Some((Delim::Superscript(Uni), Dir::Open)),
|
|
||||||
lex::Kind::Close(Delimiter::BraceCaret) => Some((Delim::Superscript(Uni), Dir::Close)),
|
|
||||||
lex::Kind::Open(Delimiter::BraceTilde) => Some((Delim::Subscript(Uni), Dir::Open)),
|
|
||||||
lex::Kind::Close(Delimiter::BraceTilde) => Some((Delim::Subscript(Uni), Dir::Close)),
|
|
||||||
lex::Kind::Open(Delimiter::BraceEqual) => Some((Delim::Mark, Dir::Open)),
|
|
||||||
lex::Kind::Close(Delimiter::BraceEqual) => Some((Delim::Mark, Dir::Close)),
|
|
||||||
lex::Kind::Open(Delimiter::BraceHyphen) => Some((Delim::Delete, Dir::Open)),
|
|
||||||
lex::Kind::Close(Delimiter::BraceHyphen) => Some((Delim::Delete, Dir::Close)),
|
|
||||||
lex::Kind::Open(Delimiter::BracePlus) => Some((Delim::Insert, Dir::Open)),
|
|
||||||
lex::Kind::Close(Delimiter::BracePlus) => Some((Delim::Insert, Dir::Close)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
.map(|(delim, dir)| {
|
|
||||||
self.openers
|
self.openers
|
||||||
.iter()
|
.iter()
|
||||||
.rposition(|(d, _)| d.matches(delim))
|
.rposition(|(d, _)| d.matches(delim))
|
||||||
|
@ -284,11 +286,10 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
|
||||||
let mut ahead = self.lexer.inner().clone();
|
let mut ahead = self.lexer.inner().clone();
|
||||||
match ahead.next() {
|
match ahead.next() {
|
||||||
Some(opener @ ('[' | '(')) => {
|
Some(opener @ ('[' | '(')) => {
|
||||||
|
let img = ty == SpanType::Image;
|
||||||
let (closer, kind) = match opener {
|
let (closer, kind) = match opener {
|
||||||
'[' if ty == SpanType::Image => (']', ReferenceImage),
|
'[' => (']', if img { ReferenceImage } else { ReferenceLink }),
|
||||||
'[' => (']', ReferenceLink),
|
'(' => (')', if img { InlineImage } else { InlineLink }),
|
||||||
'(' if ty == SpanType::Image => (')', InlineImage),
|
|
||||||
'(' => (')', InlineLink),
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let mut end = false;
|
let mut end = false;
|
||||||
|
@ -364,6 +365,12 @@ enum Delim {
|
||||||
Insert,
|
Insert,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Dir {
|
||||||
|
Open,
|
||||||
|
Close,
|
||||||
|
Both,
|
||||||
|
}
|
||||||
|
|
||||||
impl Delim {
|
impl Delim {
|
||||||
fn matches(self, other: Delim) -> bool {
|
fn matches(self, other: Delim) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
@ -379,6 +386,40 @@ impl Delim {
|
||||||
Self::Insert => matches!(other, Self::Insert),
|
Self::Insert => matches!(other, Self::Insert),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_token(kind: lex::Kind) -> Option<(Self, Dir)> {
|
||||||
|
use Delim::*;
|
||||||
|
use Dir::{Both, Close, Open};
|
||||||
|
use Directionality::{Bi, Uni};
|
||||||
|
use SpanType::{General, Image};
|
||||||
|
|
||||||
|
match kind {
|
||||||
|
lex::Kind::Sym(Symbol::Asterisk) => Some((Strong(Bi), Both)),
|
||||||
|
lex::Kind::Sym(Symbol::Underscore) => Some((Emphasis(Bi), Both)),
|
||||||
|
lex::Kind::Sym(Symbol::Caret) => Some((Superscript(Bi), Both)),
|
||||||
|
lex::Kind::Sym(Symbol::Tilde) => Some((Subscript(Bi), Both)),
|
||||||
|
lex::Kind::Sym(Symbol::Quote1) => Some((SingleQuoted, Both)),
|
||||||
|
lex::Kind::Sym(Symbol::Quote2) => Some((DoubleQuoted, Both)),
|
||||||
|
lex::Kind::Sym(Symbol::ExclaimBracket) => Some((Span(Image), Open)),
|
||||||
|
lex::Kind::Open(Delimiter::Bracket) => Some((Span(General), Open)),
|
||||||
|
lex::Kind::Close(Delimiter::Bracket) => Some((Span(General), Close)),
|
||||||
|
lex::Kind::Open(Delimiter::BraceAsterisk) => Some((Strong(Uni), Open)),
|
||||||
|
lex::Kind::Close(Delimiter::BraceAsterisk) => Some((Strong(Uni), Close)),
|
||||||
|
lex::Kind::Open(Delimiter::BraceUnderscore) => Some((Emphasis(Uni), Open)),
|
||||||
|
lex::Kind::Close(Delimiter::BraceUnderscore) => Some((Emphasis(Uni), Close)),
|
||||||
|
lex::Kind::Open(Delimiter::BraceCaret) => Some((Superscript(Uni), Open)),
|
||||||
|
lex::Kind::Close(Delimiter::BraceCaret) => Some((Superscript(Uni), Close)),
|
||||||
|
lex::Kind::Open(Delimiter::BraceTilde) => Some((Subscript(Uni), Open)),
|
||||||
|
lex::Kind::Close(Delimiter::BraceTilde) => Some((Subscript(Uni), Close)),
|
||||||
|
lex::Kind::Open(Delimiter::BraceEqual) => Some((Mark, Open)),
|
||||||
|
lex::Kind::Close(Delimiter::BraceEqual) => Some((Mark, Close)),
|
||||||
|
lex::Kind::Open(Delimiter::BraceHyphen) => Some((Delete, Open)),
|
||||||
|
lex::Kind::Close(Delimiter::BraceHyphen) => Some((Delete, Close)),
|
||||||
|
lex::Kind::Open(Delimiter::BracePlus) => Some((Insert, Open)),
|
||||||
|
lex::Kind::Close(Delimiter::BracePlus) => Some((Insert, Close)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Delim> for Container {
|
impl TryFrom<Delim> for Container {
|
||||||
|
@ -632,6 +673,32 @@ mod test {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn autolink() {
|
||||||
|
test_parse!(
|
||||||
|
"<https://example.com>",
|
||||||
|
(Enter(Autolink), "<"),
|
||||||
|
(Str, "https://example.com"),
|
||||||
|
(Exit(Autolink), ">")
|
||||||
|
);
|
||||||
|
test_parse!(
|
||||||
|
"<a@b.c>",
|
||||||
|
(Enter(Autolink), "<"),
|
||||||
|
(Str, "a@b.c"),
|
||||||
|
(Exit(Autolink), ">"),
|
||||||
|
);
|
||||||
|
test_parse!(
|
||||||
|
"<http://a.b><http://c.d>",
|
||||||
|
(Enter(Autolink), "<"),
|
||||||
|
(Str, "http://a.b"),
|
||||||
|
(Exit(Autolink), ">"),
|
||||||
|
(Enter(Autolink), "<"),
|
||||||
|
(Str, "http://c.d"),
|
||||||
|
(Exit(Autolink), ">")
|
||||||
|
);
|
||||||
|
test_parse!("<not-a-url>", (Str, "<not-a-url>"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn typeset_basic() {
|
fn typeset_basic() {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub(crate) struct Token {
|
||||||
pub len: usize,
|
pub len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
Text,
|
Text,
|
||||||
Newline,
|
Newline,
|
||||||
|
|
Loading…
Reference in a new issue