From 9454a2e393800dcd27029c41c6502297b03c0a95 Mon Sep 17 00:00:00 2001 From: Noah Hellman Date: Sun, 19 Feb 2023 18:28:00 +0100 Subject: [PATCH] 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. --- src/inline.rs | 86 ++++++++++++++++++++++++++++++++++----------------- src/lib.rs | 4 +-- 2 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/inline.rs b/src/inline.rs index a473d6c..947288c 100644 --- a/src/inline.rs +++ b/src/inline.rs @@ -63,7 +63,7 @@ pub enum EventKind { Atom(Atom), Str, Whitespace, - Attributes, + Attributes { container: bool }, Placeholder, } @@ -273,7 +273,7 @@ impl<'s> Parser<'s> { if non_empty { let e_attr = event_opener - 1; self.events[e_attr] = Event { - kind: EventKind::Attributes, + kind: EventKind::Attributes { container: true }, span: span_attr, }; } @@ -360,20 +360,7 @@ impl<'s> Parser<'s> { .map_or(false, |e| e.kind == EventKind::Str); if set_attr { - let i = self - .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()); + self.push(EventKind::Attributes { container: false }); } else { 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 non_empty { self.events[e_attr] = Event { - kind: EventKind::Attributes, + kind: EventKind::Attributes { container: true }, span, }; } @@ -697,9 +684,51 @@ impl<'s> Parser<'s> { let ev = self.events.pop_front().unwrap(); span = span.union(ev.span); } - Event { - kind: EventKind::Str, - span, + + if matches!( + self.events.front().map(|ev| &ev.kind), + Some(EventKind::Attributes { container: false }) + ) { + self.apply_word_attributes(span) + } else { + Event { + kind: EventKind::Str, + span, + } + } + } + + 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 } } } @@ -883,7 +912,7 @@ impl<'s> Iterator for Parser<'s> { self.events.pop_front().and_then(|e| match e.kind { EventKind::Str if e.span.is_empty() => self.next(), 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), }) } @@ -967,7 +996,7 @@ mod test { test_parse!( "pre `raw`{#id} post", (Str, "pre "), - (Attributes, "{#id}"), + (Attributes { container: true }, "{#id}"), (Enter(Verbatim), "`"), (Str, "raw"), (Exit(Verbatim), "`"), @@ -1152,14 +1181,13 @@ mod test { fn span_url_attr_unclosed() { test_parse!( "[text]({.cls}", - (Attributes, "{.cls}"), + (Attributes { container: false }, "{.cls}"), (Enter(Span), ""), (Str, "[text]("), (Exit(Span), ""), ); } - #[ignore = "broken"] #[test] fn span_url_attr_closed() { test_parse!( @@ -1196,7 +1224,7 @@ mod test { fn span_attr() { test_parse!( "[abc]{.def}", - (Attributes, "{.def}"), + (Attributes { container: true }, "{.def}"), (Enter(Span), "["), (Str, "abc"), (Exit(Span), "]"), @@ -1301,7 +1329,7 @@ mod test { fn container_attr() { test_parse!( "_abc def_{.attr}", - (Attributes, "{.attr}"), + (Attributes { container: true }, "{.attr}"), (Enter(Emphasis), "_"), (Str, "abc def"), (Exit(Emphasis), "_"), @@ -1329,7 +1357,7 @@ mod test { fn container_attr_multiple() { test_parse!( "_abc def_{.a}{.b}{.c} {.d}", - (Attributes, "{.a}{.b}{.c}"), + (Attributes { container: true }, "{.a}{.b}{.c}"), (Enter(Emphasis), "_"), (Str, "abc def"), (Exit(Emphasis), "_"), @@ -1341,7 +1369,7 @@ mod test { fn attr() { test_parse!( "word{a=b}", - (Attributes, "{a=b}"), + (Attributes { container: false }, "{a=b}"), (Enter(Span), ""), (Str, "word"), (Exit(Span), ""), @@ -1349,7 +1377,7 @@ mod test { test_parse!( "some word{.a}{.b} with attrs", (Str, "some "), - (Attributes, "{.a}{.b}"), + (Attributes { container: false }, "{.a}{.b}"), (Enter(Span), ""), (Str, "word"), (Exit(Span), ""), diff --git a/src/lib.rs b/src/lib.rs index 99e0000..e02f78f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -799,7 +799,7 @@ impl<'s> Parser<'s> { let mut first_is_attr = false; 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; attr::parse(inl.span.of(self.src)) } else { @@ -911,7 +911,7 @@ impl<'s> Parser<'s> { }, inline::EventKind::Str => Event::Str(inline.span.of(self.src).into()), inline::EventKind::Whitespace - | inline::EventKind::Attributes + | inline::EventKind::Attributes { .. } | inline::EventKind::Placeholder => { panic!("{:?}", inline) }