inline: apply word attribute when flushing event buf

fixes issue with e.g `[text]({.cls})` where attributes get immediately
applied to `[text](` where link should have priority.
This commit is contained in:
Noah Hellman 2023-02-19 18:28:00 +01:00
parent 08ef15655b
commit 9454a2e393
2 changed files with 59 additions and 31 deletions

View file

@ -63,7 +63,7 @@ pub enum EventKind {
Atom(Atom), Atom(Atom),
Str, Str,
Whitespace, Whitespace,
Attributes, Attributes { container: bool },
Placeholder, Placeholder,
} }
@ -273,7 +273,7 @@ impl<'s> Parser<'s> {
if non_empty { if non_empty {
let e_attr = event_opener - 1; let e_attr = event_opener - 1;
self.events[e_attr] = Event { self.events[e_attr] = Event {
kind: EventKind::Attributes, kind: EventKind::Attributes { container: true },
span: span_attr, span: span_attr,
}; };
} }
@ -360,20 +360,7 @@ impl<'s> Parser<'s> {
.map_or(false, |e| e.kind == EventKind::Str); .map_or(false, |e| e.kind == EventKind::Str);
if set_attr { if set_attr {
let i = self self.push(EventKind::Attributes { container: false });
.events
.iter()
.rposition(|e| e.kind != EventKind::Str)
.map_or(0, |i| i + 1);
let span_str = self.events[i]
.span
.union(self.events[self.events.len() - 1].span);
self.events.drain(i..);
self.push(EventKind::Attributes);
self.push_sp(EventKind::Enter(Span), span_str.empty_before());
self.push_sp(EventKind::Str, span_str);
self.push_sp(EventKind::Exit(Span), span_str.empty_after());
} else { } else {
self.push_sp(EventKind::Placeholder, self.input.span.empty_before()); self.push_sp(EventKind::Placeholder, self.input.span.empty_before());
} }
@ -573,7 +560,7 @@ impl<'s> Parser<'s> {
if let Some((non_empty, span)) = self.input.ahead_attributes() { if let Some((non_empty, span)) = self.input.ahead_attributes() {
if non_empty { if non_empty {
self.events[e_attr] = Event { self.events[e_attr] = Event {
kind: EventKind::Attributes, kind: EventKind::Attributes { container: true },
span, span,
}; };
} }
@ -697,6 +684,13 @@ impl<'s> Parser<'s> {
let ev = self.events.pop_front().unwrap(); let ev = self.events.pop_front().unwrap();
span = span.union(ev.span); span = span.union(ev.span);
} }
if matches!(
self.events.front().map(|ev| &ev.kind),
Some(EventKind::Attributes { container: false })
) {
self.apply_word_attributes(span)
} else {
Event { Event {
kind: EventKind::Str, kind: EventKind::Str,
span, span,
@ -704,6 +698,41 @@ impl<'s> Parser<'s> {
} }
} }
fn apply_word_attributes(&mut self, span_str: Span) -> Event {
if let Some(i) = span_str
.of(self.input.src)
.bytes()
.rposition(|c| c.is_ascii_whitespace())
{
let before = span_str.with_len(i + 1);
let word = span_str.skip(i + 1);
self.events.push_front(Event {
kind: EventKind::Str,
span: word,
});
Event {
kind: EventKind::Str,
span: before,
}
} else {
let attr = self.events.pop_front().unwrap();
self.events.push_front(Event {
kind: EventKind::Exit(Span),
span: span_str.empty_after(),
});
self.events.push_front(Event {
kind: EventKind::Str,
span: span_str,
});
self.events.push_front(Event {
kind: EventKind::Enter(Span),
span: span_str.empty_before(),
});
attr
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Directionality { enum Directionality {
Uni, Uni,
@ -883,7 +912,7 @@ impl<'s> Iterator for Parser<'s> {
self.events.pop_front().and_then(|e| match e.kind { self.events.pop_front().and_then(|e| match e.kind {
EventKind::Str if e.span.is_empty() => self.next(), EventKind::Str if e.span.is_empty() => self.next(),
EventKind::Str | EventKind::Whitespace => Some(self.merge_str_events(e.span)), EventKind::Str | EventKind::Whitespace => Some(self.merge_str_events(e.span)),
EventKind::Placeholder => self.next(), EventKind::Placeholder | EventKind::Attributes { container: false } => self.next(),
_ => Some(e), _ => Some(e),
}) })
} }
@ -967,7 +996,7 @@ mod test {
test_parse!( test_parse!(
"pre `raw`{#id} post", "pre `raw`{#id} post",
(Str, "pre "), (Str, "pre "),
(Attributes, "{#id}"), (Attributes { container: true }, "{#id}"),
(Enter(Verbatim), "`"), (Enter(Verbatim), "`"),
(Str, "raw"), (Str, "raw"),
(Exit(Verbatim), "`"), (Exit(Verbatim), "`"),
@ -1152,14 +1181,13 @@ mod test {
fn span_url_attr_unclosed() { fn span_url_attr_unclosed() {
test_parse!( test_parse!(
"[text]({.cls}", "[text]({.cls}",
(Attributes, "{.cls}"), (Attributes { container: false }, "{.cls}"),
(Enter(Span), ""), (Enter(Span), ""),
(Str, "[text]("), (Str, "[text]("),
(Exit(Span), ""), (Exit(Span), ""),
); );
} }
#[ignore = "broken"]
#[test] #[test]
fn span_url_attr_closed() { fn span_url_attr_closed() {
test_parse!( test_parse!(
@ -1196,7 +1224,7 @@ mod test {
fn span_attr() { fn span_attr() {
test_parse!( test_parse!(
"[abc]{.def}", "[abc]{.def}",
(Attributes, "{.def}"), (Attributes { container: true }, "{.def}"),
(Enter(Span), "["), (Enter(Span), "["),
(Str, "abc"), (Str, "abc"),
(Exit(Span), "]"), (Exit(Span), "]"),
@ -1301,7 +1329,7 @@ mod test {
fn container_attr() { fn container_attr() {
test_parse!( test_parse!(
"_abc def_{.attr}", "_abc def_{.attr}",
(Attributes, "{.attr}"), (Attributes { container: true }, "{.attr}"),
(Enter(Emphasis), "_"), (Enter(Emphasis), "_"),
(Str, "abc def"), (Str, "abc def"),
(Exit(Emphasis), "_"), (Exit(Emphasis), "_"),
@ -1329,7 +1357,7 @@ mod test {
fn container_attr_multiple() { fn container_attr_multiple() {
test_parse!( test_parse!(
"_abc def_{.a}{.b}{.c} {.d}", "_abc def_{.a}{.b}{.c} {.d}",
(Attributes, "{.a}{.b}{.c}"), (Attributes { container: true }, "{.a}{.b}{.c}"),
(Enter(Emphasis), "_"), (Enter(Emphasis), "_"),
(Str, "abc def"), (Str, "abc def"),
(Exit(Emphasis), "_"), (Exit(Emphasis), "_"),
@ -1341,7 +1369,7 @@ mod test {
fn attr() { fn attr() {
test_parse!( test_parse!(
"word{a=b}", "word{a=b}",
(Attributes, "{a=b}"), (Attributes { container: false }, "{a=b}"),
(Enter(Span), ""), (Enter(Span), ""),
(Str, "word"), (Str, "word"),
(Exit(Span), ""), (Exit(Span), ""),
@ -1349,7 +1377,7 @@ mod test {
test_parse!( test_parse!(
"some word{.a}{.b} with attrs", "some word{.a}{.b} with attrs",
(Str, "some "), (Str, "some "),
(Attributes, "{.a}{.b}"), (Attributes { container: false }, "{.a}{.b}"),
(Enter(Span), ""), (Enter(Span), ""),
(Str, "word"), (Str, "word"),
(Exit(Span), ""), (Exit(Span), ""),

View file

@ -799,7 +799,7 @@ impl<'s> Parser<'s> {
let mut first_is_attr = false; let mut first_is_attr = false;
let mut attributes = inline.as_ref().map_or_else(Attributes::new, |inl| { let mut attributes = inline.as_ref().map_or_else(Attributes::new, |inl| {
if let inline::EventKind::Attributes = inl.kind { if let inline::EventKind::Attributes { .. } = inl.kind {
first_is_attr = true; first_is_attr = true;
attr::parse(inl.span.of(self.src)) attr::parse(inl.span.of(self.src))
} else { } else {
@ -911,7 +911,7 @@ impl<'s> Parser<'s> {
}, },
inline::EventKind::Str => Event::Str(inline.span.of(self.src).into()), inline::EventKind::Str => Event::Str(inline.span.of(self.src).into()),
inline::EventKind::Whitespace inline::EventKind::Whitespace
| inline::EventKind::Attributes | inline::EventKind::Attributes { .. }
| inline::EventKind::Placeholder => { | inline::EventKind::Placeholder => {
panic!("{:?}", inline) panic!("{:?}", inline)
} }