From 6c5fcbf57d3039ebd780b2730ea193c68bb99640 Mon Sep 17 00:00:00 2001 From: Noah Hellman Date: Mon, 16 Jan 2023 23:22:44 +0100 Subject: [PATCH] parser: impl link references --- src/lib.rs | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1bc2185..2105091 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -268,16 +268,36 @@ pub struct Parser<'s> { tree: block::Tree, inlines: span::InlineSpans<'s>, inline_parser: Option>>, + link_definitions: std::collections::HashMap<&'s str, String>, } impl<'s> Parser<'s> { #[must_use] pub fn new(src: &'s str) -> Self { + let tree = block::parse(src); + + let link_definitions = { + let mut tree = tree.clone(); // TODO avoid clone + let mut defs = std::collections::HashMap::new(); + while let Some(e) = tree.next() { + if let tree::EventKind::Enter(block::Node::Leaf(block::Leaf::LinkDefinition)) = + e.kind + { + let tag = e.span.of(src); + // TODO borrow url string if single inline + let url = tree.inlines().map(|sp| sp.of(src)).collect(); + defs.insert(tag, url); + } + } + defs + }; + Self { src, - tree: block::parse(src), + tree, inlines: span::InlineSpans::new(src), inline_parser: None, + link_definitions, } } } @@ -337,8 +357,28 @@ impl<'s> Parser<'s> { }, SpanLinkType::Inline, ), - inline::Container::ReferenceLink => todo!("{:?}", c), - inline::Container::ReferenceImage => todo!("{:?}", c), + inline::Container::ReferenceLink => Container::Link( + if let Some(url) = self + .link_definitions + .get(self.inlines.src(inline.span).as_ref()) + { + url.clone().into() + } else { + "".into() + }, + LinkType::Span(SpanLinkType::Reference), + ), + inline::Container::ReferenceImage => Container::Image( + if let Some(url) = self + .link_definitions + .get(self.inlines.src(inline.span).as_ref()) + { + url.clone().into() + } else { + "".into() + }, + SpanLinkType::Reference, + ), inline::Container::Autolink => todo!("{:?}", c), }; if matches!(inline.kind, inline::EventKind::Enter(_)) { @@ -368,7 +408,7 @@ impl<'s> Parser<'s> { fn block(&mut self) -> Option> { let mut attributes = Attributes::new(); - for ev in &mut self.tree { + while let Some(ev) = &mut self.tree.next() { let content = ev.span.of(self.src); let event = match ev.kind { tree::EventKind::Atom(a) => match a { @@ -379,6 +419,13 @@ impl<'s> Parser<'s> { continue; } }, + tree::EventKind::Enter(c) | tree::EventKind::Exit(c) + if matches!(c, block::Node::Leaf(block::Leaf::LinkDefinition)) => + { + // ignore link definitions + self.tree.inlines().last(); + continue; + } tree::EventKind::Enter(c) => match c { block::Node::Leaf(l) => { self.inlines.set_spans(self.tree.inlines()); @@ -608,6 +655,42 @@ mod test { ); } + #[test] + fn link_reference() { + test_parse!( + concat!( + "[text][tag]\n", + "\n", + "[tag]: url\n" // + ), + Start(Paragraph, Attributes::new()), + Start( + Link("url".into(), LinkType::Span(SpanLinkType::Reference)), + Attributes::new() + ), + Str("text".into()), + End(Link("url".into(), LinkType::Span(SpanLinkType::Reference))), + End(Paragraph), + Atom(Blankline), + ); + test_parse!( + concat!( + "![text][tag]\n", + "\n", + "[tag]: url\n" // + ), + Start(Paragraph, Attributes::new()), + Start( + Image("url".into(), SpanLinkType::Reference), + Attributes::new() + ), + Str("text".into()), + End(Image("url".into(), SpanLinkType::Reference)), + End(Paragraph), + Atom(Blankline), + ); + } + #[test] fn attr_block() { test_parse!(