inline cont
This commit is contained in:
parent
b2bc575e27
commit
eaea5cf95c
2 changed files with 61 additions and 69 deletions
123
src/inline.rs
123
src/inline.rs
|
@ -57,7 +57,7 @@ pub enum Container {
|
||||||
Delete,
|
Delete,
|
||||||
Emphasis,
|
Emphasis,
|
||||||
Strong,
|
Strong,
|
||||||
//Mark,
|
Mark,
|
||||||
// smart quoting
|
// smart quoting
|
||||||
SingleQuoted,
|
SingleQuoted,
|
||||||
DoubleQuoted,
|
DoubleQuoted,
|
||||||
|
@ -65,12 +65,18 @@ pub enum Container {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Enter(Container),
|
Enter(Container, OpenerState),
|
||||||
Exit(Container),
|
Exit(Container),
|
||||||
Atom(Atom),
|
Atom(Atom),
|
||||||
Node(Node),
|
Node(Node),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum OpenerState {
|
||||||
|
Unclosed,
|
||||||
|
Closed,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Dir {
|
pub enum Dir {
|
||||||
Open,
|
Open,
|
||||||
|
@ -79,9 +85,8 @@ pub enum Dir {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Parser<'s> {
|
pub struct Parser<'s> {
|
||||||
openers: Vec<Container>,
|
openers: Vec<(Container, usize)>,
|
||||||
close_containers: Option<usize>,
|
events: std::collections::VecDeque<Event>,
|
||||||
next: Option<Event>,
|
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
||||||
lexer: std::iter::Peekable<lex::Lexer<'s>>,
|
lexer: std::iter::Peekable<lex::Lexer<'s>>,
|
||||||
|
@ -91,8 +96,7 @@ impl<'s> Parser<'s> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
openers: Vec::new(),
|
openers: Vec::new(),
|
||||||
close_containers: None,
|
events: std::collections::VecDeque::new(),
|
||||||
next: None,
|
|
||||||
span: Span::new(0, 0),
|
span: Span::new(0, 0),
|
||||||
|
|
||||||
lexer: lex::Lexer::new("").peekable(),
|
lexer: lex::Lexer::new("").peekable(),
|
||||||
|
@ -206,8 +210,8 @@ impl<'s> Parser<'s> {
|
||||||
lex::Kind::Close(Delimiter::BraceAsterisk) => Some((Strong, Dir::Close)),
|
lex::Kind::Close(Delimiter::BraceAsterisk) => Some((Strong, Dir::Close)),
|
||||||
lex::Kind::Open(Delimiter::BraceCaret) => Some((Superscript, Dir::Open)),
|
lex::Kind::Open(Delimiter::BraceCaret) => Some((Superscript, Dir::Open)),
|
||||||
lex::Kind::Close(Delimiter::BraceCaret) => Some((Superscript, Dir::Close)),
|
lex::Kind::Close(Delimiter::BraceCaret) => Some((Superscript, Dir::Close)),
|
||||||
//lex::Kind::Open(Delimiter::BraceEqual) => Some((Mark, Dir::Open)),
|
lex::Kind::Open(Delimiter::BraceEqual) => Some((Mark, Dir::Open)),
|
||||||
//lex::Kind::Close(Delimiter::BraceEqual) => Some((Mark, Dir::Close)),
|
lex::Kind::Close(Delimiter::BraceEqual) => Some((Mark, Dir::Close)),
|
||||||
lex::Kind::Open(Delimiter::BraceHyphen) => Some((Delete, Dir::Open)),
|
lex::Kind::Open(Delimiter::BraceHyphen) => Some((Delete, Dir::Open)),
|
||||||
lex::Kind::Close(Delimiter::BraceHyphen) => Some((Delete, Dir::Close)),
|
lex::Kind::Close(Delimiter::BraceHyphen) => Some((Delete, Dir::Close)),
|
||||||
lex::Kind::Open(Delimiter::BracePlus) => Some((Insert, Dir::Open)),
|
lex::Kind::Open(Delimiter::BracePlus) => Some((Insert, Dir::Open)),
|
||||||
|
@ -218,16 +222,28 @@ impl<'s> Parser<'s> {
|
||||||
lex::Kind::Close(Delimiter::BraceUnderscore) => Some((Emphasis, Dir::Close)),
|
lex::Kind::Close(Delimiter::BraceUnderscore) => Some((Emphasis, Dir::Close)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
.and_then(|(cont, dir)| {
|
.map(|(cont_new, dir)| {
|
||||||
if matches!(dir, Dir::Close | Dir::Both) && self.openers.contains(&cont) {
|
self.openers
|
||||||
self.close_containers = self.openers.iter().rposition(|o| *o == cont);
|
.iter()
|
||||||
Some(Event::Exit(self.openers.pop().unwrap()))
|
.rposition(|(c, _)| *c == cont_new)
|
||||||
} else if matches!(dir, Dir::Open | Dir::Both) {
|
.and_then(|o| {
|
||||||
self.openers.push(cont);
|
matches!(dir, Dir::Close | Dir::Both).then(|| {
|
||||||
Some(Event::Enter(cont))
|
let (cont_open, e) = &mut self.openers[o];
|
||||||
} else {
|
assert_eq!(*cont_open, cont_new);
|
||||||
None
|
if let Event::Enter(cont_ev, state_ev) = &mut self.events[*e] {
|
||||||
}
|
assert_eq!(*cont_ev, cont_new);
|
||||||
|
*state_ev = OpenerState::Closed;
|
||||||
|
self.openers.drain(o..);
|
||||||
|
Event::Exit(cont_new)
|
||||||
|
} else {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
self.openers.push((cont_new, self.events.len()));
|
||||||
|
Event::Enter(cont_new, OpenerState::Unclosed)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,31 +252,16 @@ impl<'s> Iterator for Parser<'s> {
|
||||||
type Item = Event;
|
type Item = Event;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.next.take().or_else(|| {
|
while self.events.is_empty() || !self.openers.is_empty() {
|
||||||
self.close_containers
|
if let Some(ev) = self.parse_event() {
|
||||||
.and_then(|i| {
|
self.events.push_back(ev);
|
||||||
if i < self.openers.len() {
|
} else {
|
||||||
Some(Event::Exit(self.openers.pop().unwrap()))
|
break;
|
||||||
} else {
|
}
|
||||||
self.close_containers = None;
|
}
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
let mut current = self.parse_event();
|
|
||||||
|
|
||||||
if let Some(Event::Node(Node { kind: Str, span })) = &mut current {
|
// TODO merge str/unclosed enters
|
||||||
self.next = self.parse_event();
|
self.events.pop_front()
|
||||||
while let Some(Event::Node(Node { kind: Str, span: s })) = self.next {
|
|
||||||
*span = span.union(s);
|
|
||||||
self.next = self.parse_event();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current
|
|
||||||
})
|
|
||||||
.or_else(|| self.openers.pop().map(Event::Exit))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,6 +273,7 @@ mod test {
|
||||||
use super::Container::*;
|
use super::Container::*;
|
||||||
use super::Event::*;
|
use super::Event::*;
|
||||||
use super::NodeKind::*;
|
use super::NodeKind::*;
|
||||||
|
use super::OpenerState::*;
|
||||||
|
|
||||||
macro_rules! test_parse {
|
macro_rules! test_parse {
|
||||||
($($st:ident,)? $src:expr $(,$($token:expr),* $(,)?)?) => {
|
($($st:ident,)? $src:expr $(,$($token:expr),* $(,)?)?) => {
|
||||||
|
@ -317,13 +319,13 @@ mod test {
|
||||||
fn container_basic() {
|
fn container_basic() {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"_abc_",
|
"_abc_",
|
||||||
Enter(Emphasis),
|
Enter(Emphasis, Closed),
|
||||||
Node(Str.span(1, 4)),
|
Node(Str.span(1, 4)),
|
||||||
Exit(Emphasis)
|
Exit(Emphasis)
|
||||||
);
|
);
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"{_abc_}",
|
"{_abc_}",
|
||||||
Enter(Emphasis),
|
Enter(Emphasis, Closed),
|
||||||
Node(Str.span(2, 5)),
|
Node(Str.span(2, 5)),
|
||||||
Exit(Emphasis)
|
Exit(Emphasis)
|
||||||
);
|
);
|
||||||
|
@ -333,16 +335,16 @@ mod test {
|
||||||
fn container_nest() {
|
fn container_nest() {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"{_{_abc_}_}",
|
"{_{_abc_}_}",
|
||||||
Enter(Emphasis),
|
Enter(Emphasis, Closed),
|
||||||
Enter(Emphasis),
|
Enter(Emphasis, Closed),
|
||||||
Node(Str.span(4, 7)),
|
Node(Str.span(4, 7)),
|
||||||
Exit(Emphasis),
|
Exit(Emphasis),
|
||||||
Exit(Emphasis)
|
Exit(Emphasis)
|
||||||
);
|
);
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"*_abc_*",
|
"*_abc_*",
|
||||||
Enter(Strong),
|
Enter(Strong, Closed),
|
||||||
Enter(Emphasis),
|
Enter(Emphasis, Closed),
|
||||||
Node(Str.span(2, 5)),
|
Node(Str.span(2, 5)),
|
||||||
Exit(Emphasis),
|
Exit(Emphasis),
|
||||||
Exit(Strong)
|
Exit(Strong)
|
||||||
|
@ -358,31 +360,22 @@ mod test {
|
||||||
fn container_close_parent() {
|
fn container_close_parent() {
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"{*{_abc*}",
|
"{*{_abc*}",
|
||||||
Enter(Strong),
|
Enter(Strong, Closed),
|
||||||
Enter(Emphasis),
|
Enter(Emphasis, Unclosed),
|
||||||
Node(Str.span(4, 7)),
|
Node(Str.span(4, 7)),
|
||||||
Exit(Emphasis),
|
Exit(Strong),
|
||||||
Exit(Strong)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn container_close_block() {
|
fn container_close_block() {
|
||||||
test_parse!(
|
test_parse!("{_abc", Enter(Emphasis, Unclosed), Node(Str.span(2, 5)));
|
||||||
"{_abc",
|
|
||||||
Enter(Emphasis),
|
|
||||||
Node(Str.span(2, 5)),
|
|
||||||
Exit(Emphasis)
|
|
||||||
);
|
|
||||||
test_parse!(
|
test_parse!(
|
||||||
"{_{*{_abc",
|
"{_{*{_abc",
|
||||||
Enter(Emphasis),
|
Enter(Emphasis, Unclosed),
|
||||||
Enter(Strong),
|
Enter(Strong, Unclosed),
|
||||||
Enter(Emphasis),
|
Enter(Emphasis, Unclosed),
|
||||||
Node(Str.span(6, 9)),
|
Node(Str.span(6, 9)),
|
||||||
Exit(Emphasis),
|
|
||||||
Exit(Strong),
|
|
||||||
Exit(Emphasis),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub enum Delimiter {
|
||||||
Brace,
|
Brace,
|
||||||
BraceAsterisk,
|
BraceAsterisk,
|
||||||
BraceCaret,
|
BraceCaret,
|
||||||
//BraceEqual,
|
BraceEqual,
|
||||||
BraceHyphen,
|
BraceHyphen,
|
||||||
BracePlus,
|
BracePlus,
|
||||||
BraceTilde,
|
BraceTilde,
|
||||||
|
@ -149,7 +149,7 @@ impl<'s> Lexer<'s> {
|
||||||
let explicit = match self.peek() {
|
let explicit = match self.peek() {
|
||||||
'*' => Some(Open(BraceAsterisk)),
|
'*' => Some(Open(BraceAsterisk)),
|
||||||
'^' => Some(Open(BraceCaret)),
|
'^' => Some(Open(BraceCaret)),
|
||||||
//'=' => Some(Open(BraceEqual)),
|
'=' => Some(Open(BraceEqual)),
|
||||||
'-' => Some(Open(BraceHyphen)),
|
'-' => Some(Open(BraceHyphen)),
|
||||||
'+' => Some(Open(BracePlus)),
|
'+' => Some(Open(BracePlus)),
|
||||||
'~' => Some(Open(BraceTilde)),
|
'~' => Some(Open(BraceTilde)),
|
||||||
|
@ -165,7 +165,7 @@ impl<'s> Lexer<'s> {
|
||||||
}
|
}
|
||||||
'*' => self.maybe_eat_close_brace(Asterisk, BraceAsterisk),
|
'*' => self.maybe_eat_close_brace(Asterisk, BraceAsterisk),
|
||||||
'^' => self.maybe_eat_close_brace(Caret, BraceCaret),
|
'^' => self.maybe_eat_close_brace(Caret, BraceCaret),
|
||||||
//'=' => self.maybe_eat_close_brace(Equal, BraceEqual),
|
'=' => self.maybe_eat_close_brace(Equal, BraceEqual),
|
||||||
'+' => self.maybe_eat_close_brace(Plus, BracePlus),
|
'+' => self.maybe_eat_close_brace(Plus, BracePlus),
|
||||||
'~' => self.maybe_eat_close_brace(Tilde, BraceTilde),
|
'~' => self.maybe_eat_close_brace(Tilde, BraceTilde),
|
||||||
'_' => self.maybe_eat_close_brace(Underscore, BraceUnderscore),
|
'_' => self.maybe_eat_close_brace(Underscore, BraceUnderscore),
|
||||||
|
@ -178,7 +178,6 @@ impl<'s> Lexer<'s> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
'=' => Sym(Equal),
|
|
||||||
'!' => Sym(Exclaim),
|
'!' => Sym(Exclaim),
|
||||||
'%' => Sym(Percentage),
|
'%' => Sym(Percentage),
|
||||||
'<' => Sym(Lt),
|
'<' => Sym(Lt),
|
||||||
|
|
Loading…
Reference in a new issue