parser: apply link def attrs to link
This commit is contained in:
		
					parent
					
						
							
								9fdd402d07
							
						
					
				
			
			
				commit
				
					
						2e4a9147aa
					
				
			
		
					 2 changed files with 63 additions and 15 deletions
				
			
		
							
								
								
									
										15
									
								
								src/attr.rs
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								src/attr.rs
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -58,6 +58,21 @@ impl<'s> Attributes<'s> {
 | 
			
		|||
        true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Combine all attributes from both objects, prioritizing self on conflicts.
 | 
			
		||||
    pub fn union(&mut self, other: Self) {
 | 
			
		||||
        if let Some(attrs0) = &mut self.0 {
 | 
			
		||||
            if let Some(mut attrs1) = other.0 {
 | 
			
		||||
                for (attr, val) in attrs1.drain(..) {
 | 
			
		||||
                    if !attrs0.iter().any(|(a, _)| *a == attr) {
 | 
			
		||||
                        attrs0.push((attr, val));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            self.0 = other.0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn add(&mut self, attr: &'s str, val: CowStr<'s>) {
 | 
			
		||||
        if self.0.is_none() {
 | 
			
		||||
            self.0 = Some(Vec::new().into());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										63
									
								
								src/lib.rs
									
										
									
									
									
								
							
							
						
						
									
										63
									
								
								src/lib.rs
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -318,7 +318,7 @@ pub struct Parser<'s> {
 | 
			
		|||
    src: &'s str,
 | 
			
		||||
 | 
			
		||||
    /// Link definitions encountered during block parse, written once.
 | 
			
		||||
    link_definitions: std::collections::HashMap<&'s str, CowStr<'s>>,
 | 
			
		||||
    link_definitions: std::collections::HashMap<&'s str, (CowStr<'s>, attr::Attributes<'s>)>,
 | 
			
		||||
 | 
			
		||||
    /// Block tree cursor.
 | 
			
		||||
    tree: block::Tree,
 | 
			
		||||
| 
						 | 
				
			
			@ -347,17 +347,24 @@ impl<'s> Parser<'s> {
 | 
			
		|||
        let link_definitions = {
 | 
			
		||||
            let mut branch = tree.clone();
 | 
			
		||||
            let mut defs = std::collections::HashMap::new();
 | 
			
		||||
            let mut attr_prev: Option<Span> = None;
 | 
			
		||||
            while let Some(e) = branch.next() {
 | 
			
		||||
                if let tree::EventKind::Enter(block::Node::Leaf(block::Leaf::LinkDefinition)) =
 | 
			
		||||
                    e.kind
 | 
			
		||||
                {
 | 
			
		||||
                    let tag = e.span.of(src);
 | 
			
		||||
                    let attrs =
 | 
			
		||||
                        attr_prev.map_or_else(Attributes::new, |sp| attr::parse(sp.of(src)));
 | 
			
		||||
                    let url = match branch.count_children() {
 | 
			
		||||
                        0 => "".into(),
 | 
			
		||||
                        1 => branch.take_inlines().next().unwrap().of(src).trim().into(),
 | 
			
		||||
                        _ => branch.take_inlines().map(|sp| sp.of(src).trim()).collect(),
 | 
			
		||||
                    };
 | 
			
		||||
                    defs.insert(tag, url);
 | 
			
		||||
                    defs.insert(tag, (url, attrs));
 | 
			
		||||
                } else if let tree::EventKind::Atom(block::Atom::Attributes) = e.kind {
 | 
			
		||||
                    attr_prev = Some(e.span);
 | 
			
		||||
                } else {
 | 
			
		||||
                    attr_prev = None;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            defs
 | 
			
		||||
| 
						 | 
				
			
			@ -386,7 +393,7 @@ impl<'s> Parser<'s> {
 | 
			
		|||
            let mut inline = parser.next();
 | 
			
		||||
 | 
			
		||||
            let mut first_is_attr = false;
 | 
			
		||||
            let 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 {
 | 
			
		||||
                    first_is_attr = true;
 | 
			
		||||
                    attr::parse(self.inlines.slice(inl.span))
 | 
			
		||||
| 
						 | 
				
			
			@ -433,20 +440,19 @@ impl<'s> Parser<'s> {
 | 
			
		|||
                            },
 | 
			
		||||
                            SpanLinkType::Inline,
 | 
			
		||||
                        ),
 | 
			
		||||
                        inline::Container::ReferenceLink => Container::Link(
 | 
			
		||||
                            self.link_definitions
 | 
			
		||||
                        inline::Container::ReferenceLink | inline::Container::ReferenceImage => {
 | 
			
		||||
                            let (url, attrs_def) = self
 | 
			
		||||
                                .link_definitions
 | 
			
		||||
                                .get(self.inlines.src(inline.span).replace('\n', " ").as_str())
 | 
			
		||||
                                .cloned()
 | 
			
		||||
                                .unwrap_or_else(|| "".into()),
 | 
			
		||||
                            LinkType::Span(SpanLinkType::Reference),
 | 
			
		||||
                        ),
 | 
			
		||||
                        inline::Container::ReferenceImage => Container::Image(
 | 
			
		||||
                            self.link_definitions
 | 
			
		||||
                                .get(self.inlines.src(inline.span).replace('\n', " ").as_str())
 | 
			
		||||
                                .cloned()
 | 
			
		||||
                                .unwrap_or_else(|| "".into()),
 | 
			
		||||
                            SpanLinkType::Reference,
 | 
			
		||||
                        ),
 | 
			
		||||
                                .unwrap_or_else(|| ("".into(), Attributes::new()));
 | 
			
		||||
                            attributes.union(attrs_def);
 | 
			
		||||
                            if matches!(c, inline::Container::ReferenceLink) {
 | 
			
		||||
                                Container::Link(url, LinkType::Span(SpanLinkType::Reference))
 | 
			
		||||
                            } else {
 | 
			
		||||
                                Container::Image(url, SpanLinkType::Reference)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        inline::Container::Autolink => todo!("{:?}", c),
 | 
			
		||||
                    };
 | 
			
		||||
                    if matches!(inline.kind, inline::EventKind::Enter(_)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -921,6 +927,33 @@ mod test {
 | 
			
		|||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn link_reference_attrs() {
 | 
			
		||||
        test_parse!(
 | 
			
		||||
            concat!(
 | 
			
		||||
                "[text][tag]{b=c}\n",
 | 
			
		||||
                "\n",
 | 
			
		||||
                "{a=b}\n",
 | 
			
		||||
                "[tag]: url\n",
 | 
			
		||||
                "\n",
 | 
			
		||||
                "para\n",
 | 
			
		||||
            ),
 | 
			
		||||
            Start(Paragraph, Attributes::new()),
 | 
			
		||||
            Start(
 | 
			
		||||
                Link("url".into(), LinkType::Span(SpanLinkType::Reference)),
 | 
			
		||||
                [("b", "c"), ("a", "b")].into_iter().collect(),
 | 
			
		||||
            ),
 | 
			
		||||
            Str("text".into()),
 | 
			
		||||
            End(Link("url".into(), LinkType::Span(SpanLinkType::Reference))),
 | 
			
		||||
            End(Paragraph),
 | 
			
		||||
            Atom(Blankline),
 | 
			
		||||
            Atom(Blankline),
 | 
			
		||||
            Start(Paragraph, Attributes::new()),
 | 
			
		||||
            Str("para".into()),
 | 
			
		||||
            End(Paragraph),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn footnote_references() {
 | 
			
		||||
        test_parse!(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue