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
 | 
					        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>) {
 | 
					    fn add(&mut self, attr: &'s str, val: CowStr<'s>) {
 | 
				
			||||||
        if self.0.is_none() {
 | 
					        if self.0.is_none() {
 | 
				
			||||||
            self.0 = Some(Vec::new().into());
 | 
					            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,
 | 
					    src: &'s str,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Link definitions encountered during block parse, written once.
 | 
					    /// 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.
 | 
					    /// Block tree cursor.
 | 
				
			||||||
    tree: block::Tree,
 | 
					    tree: block::Tree,
 | 
				
			||||||
| 
						 | 
					@ -347,17 +347,24 @@ impl<'s> Parser<'s> {
 | 
				
			||||||
        let link_definitions = {
 | 
					        let link_definitions = {
 | 
				
			||||||
            let mut branch = tree.clone();
 | 
					            let mut branch = tree.clone();
 | 
				
			||||||
            let mut defs = std::collections::HashMap::new();
 | 
					            let mut defs = std::collections::HashMap::new();
 | 
				
			||||||
 | 
					            let mut attr_prev: Option<Span> = None;
 | 
				
			||||||
            while let Some(e) = branch.next() {
 | 
					            while let Some(e) = branch.next() {
 | 
				
			||||||
                if let tree::EventKind::Enter(block::Node::Leaf(block::Leaf::LinkDefinition)) =
 | 
					                if let tree::EventKind::Enter(block::Node::Leaf(block::Leaf::LinkDefinition)) =
 | 
				
			||||||
                    e.kind
 | 
					                    e.kind
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    let tag = e.span.of(src);
 | 
					                    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() {
 | 
					                    let url = match branch.count_children() {
 | 
				
			||||||
                        0 => "".into(),
 | 
					                        0 => "".into(),
 | 
				
			||||||
                        1 => branch.take_inlines().next().unwrap().of(src).trim().into(),
 | 
					                        1 => branch.take_inlines().next().unwrap().of(src).trim().into(),
 | 
				
			||||||
                        _ => branch.take_inlines().map(|sp| sp.of(src).trim()).collect(),
 | 
					                        _ => 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
 | 
					            defs
 | 
				
			||||||
| 
						 | 
					@ -386,7 +393,7 @@ impl<'s> Parser<'s> {
 | 
				
			||||||
            let mut inline = parser.next();
 | 
					            let mut inline = parser.next();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let mut first_is_attr = false;
 | 
					            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 {
 | 
					                if let inline::EventKind::Attributes = inl.kind {
 | 
				
			||||||
                    first_is_attr = true;
 | 
					                    first_is_attr = true;
 | 
				
			||||||
                    attr::parse(self.inlines.slice(inl.span))
 | 
					                    attr::parse(self.inlines.slice(inl.span))
 | 
				
			||||||
| 
						 | 
					@ -433,20 +440,19 @@ impl<'s> Parser<'s> {
 | 
				
			||||||
                            },
 | 
					                            },
 | 
				
			||||||
                            SpanLinkType::Inline,
 | 
					                            SpanLinkType::Inline,
 | 
				
			||||||
                        ),
 | 
					                        ),
 | 
				
			||||||
                        inline::Container::ReferenceLink => Container::Link(
 | 
					                        inline::Container::ReferenceLink | inline::Container::ReferenceImage => {
 | 
				
			||||||
                            self.link_definitions
 | 
					                            let (url, attrs_def) = self
 | 
				
			||||||
 | 
					                                .link_definitions
 | 
				
			||||||
                                .get(self.inlines.src(inline.span).replace('\n', " ").as_str())
 | 
					                                .get(self.inlines.src(inline.span).replace('\n', " ").as_str())
 | 
				
			||||||
                                .cloned()
 | 
					                                .cloned()
 | 
				
			||||||
                                .unwrap_or_else(|| "".into()),
 | 
					                                .unwrap_or_else(|| ("".into(), Attributes::new()));
 | 
				
			||||||
                            LinkType::Span(SpanLinkType::Reference),
 | 
					                            attributes.union(attrs_def);
 | 
				
			||||||
                        ),
 | 
					                            if matches!(c, inline::Container::ReferenceLink) {
 | 
				
			||||||
                        inline::Container::ReferenceImage => Container::Image(
 | 
					                                Container::Link(url, LinkType::Span(SpanLinkType::Reference))
 | 
				
			||||||
                            self.link_definitions
 | 
					                            } else {
 | 
				
			||||||
                                .get(self.inlines.src(inline.span).replace('\n', " ").as_str())
 | 
					                                Container::Image(url, SpanLinkType::Reference)
 | 
				
			||||||
                                .cloned()
 | 
					                            }
 | 
				
			||||||
                                .unwrap_or_else(|| "".into()),
 | 
					                        }
 | 
				
			||||||
                            SpanLinkType::Reference,
 | 
					 | 
				
			||||||
                        ),
 | 
					 | 
				
			||||||
                        inline::Container::Autolink => todo!("{:?}", c),
 | 
					                        inline::Container::Autolink => todo!("{:?}", c),
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
                    if matches!(inline.kind, inline::EventKind::Enter(_)) {
 | 
					                    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]
 | 
					    #[test]
 | 
				
			||||||
    fn footnote_references() {
 | 
					    fn footnote_references() {
 | 
				
			||||||
        test_parse!(
 | 
					        test_parse!(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue