inline: word attributes

This commit is contained in:
Noah Hellman 2023-01-15 23:48:55 +01:00
parent 5f9a72545b
commit 161dfec96d
2 changed files with 84 additions and 6 deletions

View file

@ -56,6 +56,7 @@ pub enum EventKind {
Exit(Container), Exit(Container),
Atom(Atom), Atom(Atom),
Str, Str,
Whitespace,
Attributes, Attributes,
AttributesDummy, AttributesDummy,
} }
@ -108,11 +109,16 @@ 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_attributes(&first))
.or_else(|| self.parse_autolink(&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 {
kind: EventKind::Str, kind: if first.kind == lex::Kind::Whitespace {
EventKind::Whitespace
} else {
EventKind::Str
},
span: self.span, span: self.span,
}) })
}) })
@ -225,6 +231,58 @@ impl<I: Iterator<Item = char> + Clone> Parser<I> {
}) })
} }
fn parse_attributes(&mut self, first: &lex::Token) -> Option<Event> {
if first.kind == lex::Kind::Open(Delimiter::Brace)
&& self
.events
.back()
.map_or(false, |e| e.kind == EventKind::Str)
{
let mut ahead = self.lexer.inner().clone();
let mut attr_len = attr::valid(std::iter::once('{').chain(&mut ahead)) - 1;
if attr_len > 0 {
while attr_len > 0 {
self.lexer = lex::Lexer::new(ahead.clone());
self.span = self.span.extend(attr_len);
attr_len = attr::valid(&mut ahead);
}
let i = self
.events
.iter()
.rposition(|e| e.kind != EventKind::Str)
.map_or(0, |i| i + 1);
let span_str = Span::new(
self.events[i].span.start(),
self.events[self.events.len() - 1].span.end(),
);
self.events.drain(i..);
self.events.push_back(Event {
kind: EventKind::Attributes,
span: self.span,
});
self.events.push_back(Event {
kind: EventKind::Enter(Container::Span),
span: Span::empty_at(span_str.start()),
});
self.events.push_back(Event {
kind: EventKind::Str,
span: span_str,
});
Some(Event {
kind: EventKind::Exit(Container::Span),
span: Span::empty_at(span_str.end()),
})
} else {
None
}
} else {
None
}
}
fn parse_autolink(&mut self, first: &lex::Token) -> Option<Event> { fn parse_autolink(&mut self, first: &lex::Token) -> Option<Event> {
if first.kind == lex::Kind::Sym(Symbol::Lt) { if first.kind == lex::Kind::Sym(Symbol::Lt) {
let mut ahead = self.lexer.inner().clone(); let mut ahead = self.lexer.inner().clone();
@ -482,10 +540,12 @@ impl<I: Iterator<Item = char> + Clone> Iterator for Parser<I> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while self.events.is_empty() while self.events.is_empty()
|| !self.openers.is_empty() || !self.openers.is_empty()
|| self // for merge || self // for merge or attributes
.events .events
.back() .back()
.map_or(false, |ev| matches!(ev.kind, EventKind::Str)) .map_or(false, |ev| {
matches!(ev.kind, EventKind::Str | EventKind::Whitespace)
})
{ {
if let Some(ev) = self.parse_event() { if let Some(ev) = self.parse_event() {
self.events.push_back(ev); self.events.push_back(ev);
@ -496,11 +556,14 @@ impl<I: Iterator<Item = char> + Clone> Iterator for Parser<I> {
self.events.pop_front().and_then(|e| { self.events.pop_front().and_then(|e| {
match e.kind { match e.kind {
EventKind::Str => { EventKind::Str | EventKind::Whitespace => {
// merge str events // merge str events
let mut span = e.span; let mut span = e.span;
while self.events.front().map_or(false, |e| { while self.events.front().map_or(false, |e| {
matches!(e.kind, EventKind::Str | EventKind::AttributesDummy) matches!(
e.kind,
EventKind::Str | EventKind::Whitespace | EventKind::AttributesDummy
)
}) { }) {
let ev = self.events.pop_front().unwrap(); let ev = self.events.pop_front().unwrap();
assert_eq!(span.end(), ev.span.start()); assert_eq!(span.end(), ev.span.start());
@ -864,4 +927,17 @@ mod test {
(Str, " {.d}"), (Str, " {.d}"),
); );
} }
#[test]
fn attr() {
test_parse!(
"some word{.a}{.b} with attrs",
(Str, "some "),
(Attributes, "{.a}{.b}"),
(Enter(Span), ""),
(Str, "word"),
(Exit(Span), ""),
(Str, " with attrs"),
);
}
} }

View file

@ -357,7 +357,9 @@ impl<'s> Parser<'s> {
inline::Atom::Escape => Event::Atom(Atom::Escape), inline::Atom::Escape => Event::Atom(Atom::Escape),
}, },
inline::EventKind::Str => Event::Str(self.inlines.src(inline.span)), inline::EventKind::Str => Event::Str(self.inlines.src(inline.span)),
inline::EventKind::Attributes | inline::EventKind::AttributesDummy => { inline::EventKind::Whitespace
| inline::EventKind::Attributes
| inline::EventKind::AttributesDummy => {
panic!("{:?}", inline) panic!("{:?}", inline)
} }
}) })