impl automatic heading identifiers
This commit is contained in:
		
					parent
					
						
							
								b726580724
							
						
					
				
			
			
				commit
				
					
						60dcf09c1a
					
				
			
		
					 5 changed files with 323 additions and 102 deletions
				
			
		| 
						 | 
					@ -100,6 +100,11 @@ impl<'s> Attributes<'s> {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn get(&self, key: &str) -> Option<&str> {
 | 
				
			||||||
 | 
					        self.iter().find(|(k, _)| *k == key).map(|(_, v)| v)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn iter(&self) -> impl Iterator<Item = (&'s str, &str)> + '_ {
 | 
					    pub fn iter(&self) -> impl Iterator<Item = (&'s str, &str)> + '_ {
 | 
				
			||||||
        self.0
 | 
					        self.0
 | 
				
			||||||
            .iter()
 | 
					            .iter()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										64
									
								
								src/block.rs
									
										
									
									
									
								
							
							
						
						
									
										64
									
								
								src/block.rs
									
										
									
									
									
								
							| 
						 | 
					@ -59,7 +59,9 @@ pub enum Leaf {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Span is `#` characters.
 | 
					    /// Span is `#` characters.
 | 
				
			||||||
    /// Each inline is a line.
 | 
					    /// Each inline is a line.
 | 
				
			||||||
    Heading,
 | 
					    Heading {
 | 
				
			||||||
 | 
					        has_section: bool,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Span is '|'.
 | 
					    /// Span is '|'.
 | 
				
			||||||
    /// Has zero or one inline for the cell contents.
 | 
					    /// Has zero or one inline for the cell contents.
 | 
				
			||||||
| 
						 | 
					@ -254,7 +256,7 @@ impl<'s> TreeParser<'s> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn parse_leaf(
 | 
					    fn parse_leaf(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        leaf: Leaf,
 | 
					        mut leaf: Leaf,
 | 
				
			||||||
        k: &Kind,
 | 
					        k: &Kind,
 | 
				
			||||||
        span: Span,
 | 
					        span: Span,
 | 
				
			||||||
        lines: &mut [Span],
 | 
					        lines: &mut [Span],
 | 
				
			||||||
| 
						 | 
					@ -300,6 +302,10 @@ impl<'s> TreeParser<'s> {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Leaf::Heading { has_section } = &mut leaf {
 | 
				
			||||||
 | 
					            *has_section = top_level;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.tree.enter(Node::Leaf(leaf), span);
 | 
					        self.tree.enter(Node::Leaf(leaf), span);
 | 
				
			||||||
        lines
 | 
					        lines
 | 
				
			||||||
            .iter()
 | 
					            .iter()
 | 
				
			||||||
| 
						 | 
					@ -573,7 +579,7 @@ impl From<&Kind> for Block {
 | 
				
			||||||
        match kind {
 | 
					        match kind {
 | 
				
			||||||
            Kind::Atom(a) => Self::Atom(*a),
 | 
					            Kind::Atom(a) => Self::Atom(*a),
 | 
				
			||||||
            Kind::Paragraph => Self::Leaf(Paragraph),
 | 
					            Kind::Paragraph => Self::Leaf(Paragraph),
 | 
				
			||||||
            Kind::Heading { .. } => Self::Leaf(Heading),
 | 
					            Kind::Heading { .. } => Self::Leaf(Heading { has_section: false }),
 | 
				
			||||||
            Kind::Fenced {
 | 
					            Kind::Fenced {
 | 
				
			||||||
                kind: FenceKind::CodeBlock(..),
 | 
					                kind: FenceKind::CodeBlock(..),
 | 
				
			||||||
                ..
 | 
					                ..
 | 
				
			||||||
| 
						 | 
					@ -983,13 +989,13 @@ mod test {
 | 
				
			||||||
                "## b\n", //
 | 
					                "## b\n", //
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            (Enter(Container(Section)), "#"),
 | 
					            (Enter(Container(Section)), "#"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "#"),
 | 
					            (Enter(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Inline, "a"),
 | 
					            (Inline, "a"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "#"),
 | 
					            (Exit(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Enter(Container(Section)), "##"),
 | 
					            (Enter(Container(Section)), "##"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "##"),
 | 
					            (Enter(Leaf(Heading { has_section: true })), "##"),
 | 
				
			||||||
            (Inline, "b"),
 | 
					            (Inline, "b"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "##"),
 | 
					            (Exit(Leaf(Heading { has_section: true })), "##"),
 | 
				
			||||||
            (Exit(Container(Section)), "##"),
 | 
					            (Exit(Container(Section)), "##"),
 | 
				
			||||||
            (Exit(Container(Section)), "#"),
 | 
					            (Exit(Container(Section)), "#"),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
| 
						 | 
					@ -1003,9 +1009,9 @@ mod test {
 | 
				
			||||||
                "heading\n", //
 | 
					                "heading\n", //
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            (Enter(Container(Section)), "#"),
 | 
					            (Enter(Container(Section)), "#"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "#"),
 | 
					            (Enter(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Inline, "heading"),
 | 
					            (Inline, "heading"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "#"),
 | 
					            (Exit(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Exit(Container(Section)), "#"),
 | 
					            (Exit(Container(Section)), "#"),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1021,17 +1027,17 @@ mod test {
 | 
				
			||||||
                "15\n", //
 | 
					                "15\n", //
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            (Enter(Container(Section)), "#"),
 | 
					            (Enter(Container(Section)), "#"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "#"),
 | 
					            (Enter(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Inline, "2"),
 | 
					            (Inline, "2"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "#"),
 | 
					            (Exit(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Atom(Blankline), "\n"),
 | 
					            (Atom(Blankline), "\n"),
 | 
				
			||||||
            (Exit(Container(Section)), "#"),
 | 
					            (Exit(Container(Section)), "#"),
 | 
				
			||||||
            (Enter(Container(Section)), "#"),
 | 
					            (Enter(Container(Section)), "#"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "#"),
 | 
					            (Enter(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Inline, "8\n"),
 | 
					            (Inline, "8\n"),
 | 
				
			||||||
            (Inline, "12\n"),
 | 
					            (Inline, "12\n"),
 | 
				
			||||||
            (Inline, "15"),
 | 
					            (Inline, "15"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "#"),
 | 
					            (Exit(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Exit(Container(Section)), "#"),
 | 
					            (Exit(Container(Section)), "#"),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1045,11 +1051,11 @@ mod test {
 | 
				
			||||||
                "c\n", //
 | 
					                "c\n", //
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            (Enter(Container(Section)), "#"),
 | 
					            (Enter(Container(Section)), "#"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "#"),
 | 
					            (Enter(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Inline, "a\n"),
 | 
					            (Inline, "a\n"),
 | 
				
			||||||
            (Inline, "b\n"),
 | 
					            (Inline, "b\n"),
 | 
				
			||||||
            (Inline, "c"),
 | 
					            (Inline, "c"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "#"),
 | 
					            (Exit(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Exit(Container(Section)), "#"),
 | 
					            (Exit(Container(Section)), "#"),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1071,39 +1077,39 @@ mod test {
 | 
				
			||||||
                "# b\n",
 | 
					                "# b\n",
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            (Enter(Container(Section)), "#"),
 | 
					            (Enter(Container(Section)), "#"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "#"),
 | 
					            (Enter(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Inline, "a"),
 | 
					            (Inline, "a"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "#"),
 | 
					            (Exit(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Atom(Blankline), "\n"),
 | 
					            (Atom(Blankline), "\n"),
 | 
				
			||||||
            (Enter(Container(Section)), "##"),
 | 
					            (Enter(Container(Section)), "##"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "##"),
 | 
					            (Enter(Leaf(Heading { has_section: true })), "##"),
 | 
				
			||||||
            (Inline, "aa"),
 | 
					            (Inline, "aa"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "##"),
 | 
					            (Exit(Leaf(Heading { has_section: true })), "##"),
 | 
				
			||||||
            (Atom(Blankline), "\n"),
 | 
					            (Atom(Blankline), "\n"),
 | 
				
			||||||
            (Enter(Container(Section)), "####"),
 | 
					            (Enter(Container(Section)), "####"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "####"),
 | 
					            (Enter(Leaf(Heading { has_section: true })), "####"),
 | 
				
			||||||
            (Inline, "aaaa"),
 | 
					            (Inline, "aaaa"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "####"),
 | 
					            (Exit(Leaf(Heading { has_section: true })), "####"),
 | 
				
			||||||
            (Atom(Blankline), "\n"),
 | 
					            (Atom(Blankline), "\n"),
 | 
				
			||||||
            (Exit(Container(Section)), "####"),
 | 
					            (Exit(Container(Section)), "####"),
 | 
				
			||||||
            (Exit(Container(Section)), "##"),
 | 
					            (Exit(Container(Section)), "##"),
 | 
				
			||||||
            (Enter(Container(Section)), "##"),
 | 
					            (Enter(Container(Section)), "##"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "##"),
 | 
					            (Enter(Leaf(Heading { has_section: true })), "##"),
 | 
				
			||||||
            (Inline, "ab"),
 | 
					            (Inline, "ab"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "##"),
 | 
					            (Exit(Leaf(Heading { has_section: true })), "##"),
 | 
				
			||||||
            (Atom(Blankline), "\n"),
 | 
					            (Atom(Blankline), "\n"),
 | 
				
			||||||
            (Enter(Container(Section)), "###"),
 | 
					            (Enter(Container(Section)), "###"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "###"),
 | 
					            (Enter(Leaf(Heading { has_section: true })), "###"),
 | 
				
			||||||
            (Inline, "aba"),
 | 
					            (Inline, "aba"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "###"),
 | 
					            (Exit(Leaf(Heading { has_section: true })), "###"),
 | 
				
			||||||
            (Atom(Blankline), "\n"),
 | 
					            (Atom(Blankline), "\n"),
 | 
				
			||||||
            (Exit(Container(Section)), "###"),
 | 
					            (Exit(Container(Section)), "###"),
 | 
				
			||||||
            (Exit(Container(Section)), "##"),
 | 
					            (Exit(Container(Section)), "##"),
 | 
				
			||||||
            (Exit(Container(Section)), "#"),
 | 
					            (Exit(Container(Section)), "#"),
 | 
				
			||||||
            (Enter(Container(Section)), "#"),
 | 
					            (Enter(Container(Section)), "#"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "#"),
 | 
					            (Enter(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Inline, "b"),
 | 
					            (Inline, "b"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "#"),
 | 
					            (Exit(Leaf(Heading { has_section: true })), "#"),
 | 
				
			||||||
            (Exit(Container(Section)), "#"),
 | 
					            (Exit(Container(Section)), "#"),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1141,9 +1147,9 @@ mod test {
 | 
				
			||||||
            (Inline, "a"),
 | 
					            (Inline, "a"),
 | 
				
			||||||
            (Exit(Leaf(Paragraph)), ""),
 | 
					            (Exit(Leaf(Paragraph)), ""),
 | 
				
			||||||
            (Atom(Blankline), "\n"),
 | 
					            (Atom(Blankline), "\n"),
 | 
				
			||||||
            (Enter(Leaf(Heading)), "##"),
 | 
					            (Enter(Leaf(Heading { has_section: false })), "##"),
 | 
				
			||||||
            (Inline, "hl"),
 | 
					            (Inline, "hl"),
 | 
				
			||||||
            (Exit(Leaf(Heading)), "##"),
 | 
					            (Exit(Leaf(Heading { has_section: false })), "##"),
 | 
				
			||||||
            (Atom(Blankline), "\n"),
 | 
					            (Atom(Blankline), "\n"),
 | 
				
			||||||
            (Enter(Leaf(Paragraph)), ""),
 | 
					            (Enter(Leaf(Paragraph)), ""),
 | 
				
			||||||
            (Inline, "para"),
 | 
					            (Inline, "para"),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/html.rs
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								src/html.rs
									
										
									
									
									
								
							| 
						 | 
					@ -148,7 +148,7 @@ impl<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write> Writer<'s, I, W> {
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        Container::Table => self.out.write_str("<table")?,
 | 
					                        Container::Table => self.out.write_str("<table")?,
 | 
				
			||||||
                        Container::TableRow { .. } => self.out.write_str("<tr")?,
 | 
					                        Container::TableRow { .. } => self.out.write_str("<tr")?,
 | 
				
			||||||
                        Container::Section => self.out.write_str("<section")?,
 | 
					                        Container::Section { .. } => self.out.write_str("<section")?,
 | 
				
			||||||
                        Container::Div { .. } => self.out.write_str("<div")?,
 | 
					                        Container::Div { .. } => self.out.write_str("<div")?,
 | 
				
			||||||
                        Container::Paragraph => {
 | 
					                        Container::Paragraph => {
 | 
				
			||||||
                            if matches!(self.list_tightness.last(), Some(true)) {
 | 
					                            if matches!(self.list_tightness.last(), Some(true)) {
 | 
				
			||||||
| 
						 | 
					@ -156,7 +156,7 @@ impl<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write> Writer<'s, I, W> {
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            self.out.write_str("<p")?;
 | 
					                            self.out.write_str("<p")?;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        Container::Heading { level } => write!(self.out, "<h{}", level)?,
 | 
					                        Container::Heading { level, .. } => write!(self.out, "<h{}", level)?,
 | 
				
			||||||
                        Container::TableCell { head: false, .. } => self.out.write_str("<td")?,
 | 
					                        Container::TableCell { head: false, .. } => self.out.write_str("<td")?,
 | 
				
			||||||
                        Container::TableCell { head: true, .. } => self.out.write_str("<th")?,
 | 
					                        Container::TableCell { head: true, .. } => self.out.write_str("<th")?,
 | 
				
			||||||
                        Container::Caption => self.out.write_str("<caption")?,
 | 
					                        Container::Caption => self.out.write_str("<caption")?,
 | 
				
			||||||
| 
						 | 
					@ -196,6 +196,18 @@ impl<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write> Writer<'s, I, W> {
 | 
				
			||||||
                        write!(self.out, r#" {}="{}""#, a, v)?;
 | 
					                        write!(self.out, r#" {}="{}""#, a, v)?;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if let Container::Heading {
 | 
				
			||||||
 | 
					                        id,
 | 
				
			||||||
 | 
					                        has_section: false,
 | 
				
			||||||
 | 
					                        ..
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    | Container::Section { id } = &c
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        if !attrs.iter().any(|(a, _)| a == "id") {
 | 
				
			||||||
 | 
					                            write!(self.out, r#" id="{}""#, id)?;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if attrs.iter().any(|(a, _)| a == "class")
 | 
					                    if attrs.iter().any(|(a, _)| a == "class")
 | 
				
			||||||
                        || matches!(
 | 
					                        || matches!(
 | 
				
			||||||
                            c,
 | 
					                            c,
 | 
				
			||||||
| 
						 | 
					@ -312,7 +324,7 @@ impl<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write> Writer<'s, I, W> {
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        Container::Table => self.out.write_str("</table>")?,
 | 
					                        Container::Table => self.out.write_str("</table>")?,
 | 
				
			||||||
                        Container::TableRow { .. } => self.out.write_str("</tr>")?,
 | 
					                        Container::TableRow { .. } => self.out.write_str("</tr>")?,
 | 
				
			||||||
                        Container::Section => self.out.write_str("</section>")?,
 | 
					                        Container::Section { .. } => self.out.write_str("</section>")?,
 | 
				
			||||||
                        Container::Div { .. } => self.out.write_str("</div>")?,
 | 
					                        Container::Div { .. } => self.out.write_str("</div>")?,
 | 
				
			||||||
                        Container::Paragraph => {
 | 
					                        Container::Paragraph => {
 | 
				
			||||||
                            if matches!(self.list_tightness.last(), Some(true)) {
 | 
					                            if matches!(self.list_tightness.last(), Some(true)) {
 | 
				
			||||||
| 
						 | 
					@ -333,7 +345,7 @@ impl<'s, I: Iterator<Item = Event<'s>>, W: std::fmt::Write> Writer<'s, I, W> {
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            self.out.write_str("</p>")?;
 | 
					                            self.out.write_str("</p>")?;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        Container::Heading { level } => write!(self.out, "</h{}>", level)?,
 | 
					                        Container::Heading { level, .. } => write!(self.out, "</h{}>", level)?,
 | 
				
			||||||
                        Container::TableCell { head: false, .. } => self.out.write_str("</td>")?,
 | 
					                        Container::TableCell { head: false, .. } => self.out.write_str("</td>")?,
 | 
				
			||||||
                        Container::TableCell { head: true, .. } => self.out.write_str("</th>")?,
 | 
					                        Container::TableCell { head: true, .. } => self.out.write_str("</th>")?,
 | 
				
			||||||
                        Container::Caption => self.out.write_str("</caption>")?,
 | 
					                        Container::Caption => self.out.write_str("</caption>")?,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										334
									
								
								src/lib.rs
									
										
									
									
									
								
							
							
						
						
									
										334
									
								
								src/lib.rs
									
										
									
									
									
								
							| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					use std::fmt::Write;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod html;
 | 
					pub mod html;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod attr;
 | 
					mod attr;
 | 
				
			||||||
| 
						 | 
					@ -49,13 +51,17 @@ pub enum Container<'s> {
 | 
				
			||||||
    /// A row element of a table.
 | 
					    /// A row element of a table.
 | 
				
			||||||
    TableRow { head: bool },
 | 
					    TableRow { head: bool },
 | 
				
			||||||
    /// A section belonging to a top level heading.
 | 
					    /// A section belonging to a top level heading.
 | 
				
			||||||
    Section,
 | 
					    Section { id: CowStr<'s> },
 | 
				
			||||||
    /// A block-level divider element.
 | 
					    /// A block-level divider element.
 | 
				
			||||||
    Div { class: Option<&'s str> },
 | 
					    Div { class: Option<&'s str> },
 | 
				
			||||||
    /// A paragraph.
 | 
					    /// A paragraph.
 | 
				
			||||||
    Paragraph,
 | 
					    Paragraph,
 | 
				
			||||||
    /// A heading.
 | 
					    /// A heading.
 | 
				
			||||||
    Heading { level: u16 },
 | 
					    Heading {
 | 
				
			||||||
 | 
					        level: u16,
 | 
				
			||||||
 | 
					        has_section: bool,
 | 
				
			||||||
 | 
					        id: CowStr<'s>,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    /// A cell element of row within a table.
 | 
					    /// A cell element of row within a table.
 | 
				
			||||||
    TableCell { alignment: Alignment, head: bool },
 | 
					    TableCell { alignment: Alignment, head: bool },
 | 
				
			||||||
    /// A caption within a table.
 | 
					    /// A caption within a table.
 | 
				
			||||||
| 
						 | 
					@ -107,7 +113,7 @@ impl<'s> Container<'s> {
 | 
				
			||||||
            | Self::Footnote { .. }
 | 
					            | Self::Footnote { .. }
 | 
				
			||||||
            | Self::Table
 | 
					            | Self::Table
 | 
				
			||||||
            | Self::TableRow { .. }
 | 
					            | Self::TableRow { .. }
 | 
				
			||||||
            | Self::Section
 | 
					            | Self::Section { .. }
 | 
				
			||||||
            | Self::Div { .. }
 | 
					            | Self::Div { .. }
 | 
				
			||||||
            | Self::Paragraph
 | 
					            | Self::Paragraph
 | 
				
			||||||
            | Self::Heading { .. }
 | 
					            | Self::Heading { .. }
 | 
				
			||||||
| 
						 | 
					@ -144,7 +150,7 @@ impl<'s> Container<'s> {
 | 
				
			||||||
            | Self::Footnote { .. }
 | 
					            | Self::Footnote { .. }
 | 
				
			||||||
            | Self::Table
 | 
					            | Self::Table
 | 
				
			||||||
            | Self::TableRow { .. }
 | 
					            | Self::TableRow { .. }
 | 
				
			||||||
            | Self::Section
 | 
					            | Self::Section { .. }
 | 
				
			||||||
            | Self::Div { .. } => true,
 | 
					            | Self::Div { .. } => true,
 | 
				
			||||||
            Self::Paragraph
 | 
					            Self::Paragraph
 | 
				
			||||||
            | Self::Heading { .. }
 | 
					            | Self::Heading { .. }
 | 
				
			||||||
| 
						 | 
					@ -321,15 +327,12 @@ impl OrderedListStyle {
 | 
				
			||||||
pub struct Parser<'s> {
 | 
					pub struct Parser<'s> {
 | 
				
			||||||
    src: &'s str,
 | 
					    src: &'s str,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Link definitions encountered during block parse, written once.
 | 
					    /// Block tree parsed at first.
 | 
				
			||||||
    link_definitions: std::collections::HashMap<&'s str, (CowStr<'s>, attr::Attributes<'s>)>,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /// Block tree cursor.
 | 
					 | 
				
			||||||
    tree: block::Tree,
 | 
					    tree: block::Tree,
 | 
				
			||||||
    /// Spans to the inlines in the block currently being parsed.
 | 
					
 | 
				
			||||||
    inlines: span::InlineSpans<'s>,
 | 
					    /// Contents obtained by the prepass.
 | 
				
			||||||
    /// Inline parser, recreated for each new inline.
 | 
					    pre_pass: PrePass<'s>,
 | 
				
			||||||
    inline_parser: Option<inline::Parser<span::InlineCharsIter<'s>>>,
 | 
					
 | 
				
			||||||
    /// Last parsed block attributes
 | 
					    /// Last parsed block attributes
 | 
				
			||||||
    block_attributes: Attributes<'s>,
 | 
					    block_attributes: Attributes<'s>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -344,47 +347,168 @@ pub struct Parser<'s> {
 | 
				
			||||||
    footnote_index: usize,
 | 
					    footnote_index: usize,
 | 
				
			||||||
    /// Currently within a footnote.
 | 
					    /// Currently within a footnote.
 | 
				
			||||||
    footnote_active: bool,
 | 
					    footnote_active: bool,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Spans to the inlines in the leaf block currently being parsed.
 | 
				
			||||||
 | 
					    inlines: span::InlineSpans<'s>,
 | 
				
			||||||
 | 
					    /// Inline parser, recreated for each new inline.
 | 
				
			||||||
 | 
					    inline_parser: Option<inline::Parser<span::InlineCharsIter<'s>>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Heading {
 | 
				
			||||||
 | 
					    /// Location of heading in src.
 | 
				
			||||||
 | 
					    location: usize,
 | 
				
			||||||
 | 
					    /// Automatically generated id from heading text.
 | 
				
			||||||
 | 
					    id_auto: String,
 | 
				
			||||||
 | 
					    /// Overriding id from an explicit attribute on the heading.
 | 
				
			||||||
 | 
					    id_override: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Because of potential future references, an initial pass is required to obtain all definitions.
 | 
				
			||||||
 | 
					struct PrePass<'s> {
 | 
				
			||||||
 | 
					    /// Link definitions and their attributes.
 | 
				
			||||||
 | 
					    link_definitions: std::collections::HashMap<&'s str, (CowStr<'s>, attr::Attributes<'s>)>,
 | 
				
			||||||
 | 
					    /// Cache of all heading ids.
 | 
				
			||||||
 | 
					    headings: Vec<Heading>,
 | 
				
			||||||
 | 
					    /// Indices to headings sorted lexicographically.
 | 
				
			||||||
 | 
					    headings_lex: Vec<usize>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'s> PrePass<'s> {
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    fn new(src: &'s str, mut tree: block::Tree) -> Self {
 | 
				
			||||||
 | 
					        let mut link_definitions = std::collections::HashMap::new();
 | 
				
			||||||
 | 
					        let mut headings: Vec<Heading> = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut inlines = span::InlineSpans::new(src);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut attr_prev: Option<Span> = None;
 | 
				
			||||||
 | 
					        while let Some(e) = tree.next() {
 | 
				
			||||||
 | 
					            match e.kind {
 | 
				
			||||||
 | 
					                tree::EventKind::Enter(block::Node::Leaf(block::Leaf::LinkDefinition)) => {
 | 
				
			||||||
 | 
					                    // All link definition tags have to be obtained initially, as references can
 | 
				
			||||||
 | 
					                    // appear before the definition.
 | 
				
			||||||
 | 
					                    let tag = e.span.of(src);
 | 
				
			||||||
 | 
					                    let attrs =
 | 
				
			||||||
 | 
					                        attr_prev.map_or_else(Attributes::new, |sp| attr::parse(sp.of(src)));
 | 
				
			||||||
 | 
					                    let url = match tree.count_children() {
 | 
				
			||||||
 | 
					                        0 => "".into(),
 | 
				
			||||||
 | 
					                        1 => tree.take_inlines().next().unwrap().of(src).trim().into(),
 | 
				
			||||||
 | 
					                        _ => tree.take_inlines().map(|sp| sp.of(src).trim()).collect(),
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    link_definitions.insert(tag, (url, attrs));
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                tree::EventKind::Enter(block::Node::Leaf(block::Leaf::Heading { .. })) => {
 | 
				
			||||||
 | 
					                    // All headings ids have to be obtained initially, as references can appear
 | 
				
			||||||
 | 
					                    // before the heading. Additionally, determining the id requires inline parsing
 | 
				
			||||||
 | 
					                    // as formatting must be removed.
 | 
				
			||||||
 | 
					                    //
 | 
				
			||||||
 | 
					                    // We choose to parse all headers twice instead of caching them.
 | 
				
			||||||
 | 
					                    let attrs = attr_prev.map(|sp| attr::parse(sp.of(src)));
 | 
				
			||||||
 | 
					                    let id_override = attrs
 | 
				
			||||||
 | 
					                        .as_ref()
 | 
				
			||||||
 | 
					                        .and_then(|attrs| attrs.get("id"))
 | 
				
			||||||
 | 
					                        .map(ToString::to_string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    inlines.set_spans(tree.take_inlines());
 | 
				
			||||||
 | 
					                    let mut id_auto = String::new();
 | 
				
			||||||
 | 
					                    inline::Parser::new(inlines.chars()).for_each(|ev| match ev.kind {
 | 
				
			||||||
 | 
					                        inline::EventKind::Str => {
 | 
				
			||||||
 | 
					                            let mut chars = inlines.slice(ev.span).chars().peekable();
 | 
				
			||||||
 | 
					                            while let Some(c) = chars.next() {
 | 
				
			||||||
 | 
					                                if c.is_whitespace() {
 | 
				
			||||||
 | 
					                                    while chars.peek().map_or(false, |c| c.is_whitespace()) {
 | 
				
			||||||
 | 
					                                        chars.next();
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                    if !id_auto.is_empty() {
 | 
				
			||||||
 | 
					                                        id_auto.push('-');
 | 
				
			||||||
 | 
					                                    }
 | 
				
			||||||
 | 
					                                } else if !c.is_ascii_punctuation() || matches!(c, '-' | '_') {
 | 
				
			||||||
 | 
					                                    id_auto.push(c);
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        inline::EventKind::Atom(inline::Atom::Softbreak) => {
 | 
				
			||||||
 | 
					                            id_auto.push('-');
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        _ => {}
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                    id_auto.drain(id_auto.trim_end_matches('-').len()..);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // ensure id unique
 | 
				
			||||||
 | 
					                    if headings.iter().any(|h| h.id_auto == id_auto) || id_auto.is_empty() {
 | 
				
			||||||
 | 
					                        if id_auto.is_empty() {
 | 
				
			||||||
 | 
					                            id_auto.push('s');
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        let mut num = 1;
 | 
				
			||||||
 | 
					                        id_auto.push('-');
 | 
				
			||||||
 | 
					                        let i_num = id_auto.len();
 | 
				
			||||||
 | 
					                        write!(id_auto, "{}", num).unwrap();
 | 
				
			||||||
 | 
					                        while headings.iter().any(|h| h.id_auto == id_auto) {
 | 
				
			||||||
 | 
					                            num += 1;
 | 
				
			||||||
 | 
					                            id_auto.drain(i_num..);
 | 
				
			||||||
 | 
					                            write!(id_auto, "{}", num).unwrap();
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    headings.push(Heading {
 | 
				
			||||||
 | 
					                        location: e.span.start(),
 | 
				
			||||||
 | 
					                        id_auto,
 | 
				
			||||||
 | 
					                        id_override,
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                tree::EventKind::Atom(block::Atom::Attributes) => {
 | 
				
			||||||
 | 
					                    attr_prev = Some(e.span);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                tree::EventKind::Enter(..)
 | 
				
			||||||
 | 
					                | tree::EventKind::Exit(block::Node::Container(block::Container::Section {
 | 
				
			||||||
 | 
					                    ..
 | 
				
			||||||
 | 
					                })) => {}
 | 
				
			||||||
 | 
					                _ => {
 | 
				
			||||||
 | 
					                    attr_prev = None;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut headings_lex = (0..headings.len()).collect::<Vec<_>>();
 | 
				
			||||||
 | 
					        headings_lex.sort_by_key(|i| &headings[*i].id_auto);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            link_definitions,
 | 
				
			||||||
 | 
					            headings,
 | 
				
			||||||
 | 
					            headings_lex,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn heading_id(&self, i: usize) -> &str {
 | 
				
			||||||
 | 
					        let h = &self.headings[i];
 | 
				
			||||||
 | 
					        h.id_override.as_ref().unwrap_or(&h.id_auto)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn heading_id_by_location(&self, location: usize) -> Option<&str> {
 | 
				
			||||||
 | 
					        self.headings
 | 
				
			||||||
 | 
					            .binary_search_by_key(&location, |h| h.location)
 | 
				
			||||||
 | 
					            .ok()
 | 
				
			||||||
 | 
					            .map(|i| self.heading_id(i))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn heading_id_by_tag(&self, tag: &str) -> Option<&str> {
 | 
				
			||||||
 | 
					        self.headings_lex
 | 
				
			||||||
 | 
					            .binary_search_by_key(&tag, |i| &self.headings[*i].id_auto)
 | 
				
			||||||
 | 
					            .ok()
 | 
				
			||||||
 | 
					            .map(|i| self.heading_id(i))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'s> Parser<'s> {
 | 
					impl<'s> Parser<'s> {
 | 
				
			||||||
    #[must_use]
 | 
					    #[must_use]
 | 
				
			||||||
    pub fn new(src: &'s str) -> Self {
 | 
					    pub fn new(src: &'s str) -> Self {
 | 
				
			||||||
        let tree = block::parse(src);
 | 
					        let tree = block::parse(src);
 | 
				
			||||||
 | 
					        let pre_pass = PrePass::new(src, tree.clone());
 | 
				
			||||||
        // All link definition tags have to be obtained initially, as references can appear before
 | 
					 | 
				
			||||||
        // the definition.
 | 
					 | 
				
			||||||
        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, attrs));
 | 
					 | 
				
			||||||
                } else if let tree::EventKind::Atom(block::Atom::Attributes) = e.kind {
 | 
					 | 
				
			||||||
                    attr_prev = Some(e.span);
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    attr_prev = None;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            defs
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let branch = tree.clone();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            src,
 | 
					            src,
 | 
				
			||||||
            link_definitions,
 | 
					            tree,
 | 
				
			||||||
            tree: branch,
 | 
					            pre_pass,
 | 
				
			||||||
            block_attributes: Attributes::new(),
 | 
					            block_attributes: Attributes::new(),
 | 
				
			||||||
            table_head_row: false,
 | 
					            table_head_row: false,
 | 
				
			||||||
            footnote_references: Vec::new(),
 | 
					            footnote_references: Vec::new(),
 | 
				
			||||||
| 
						 | 
					@ -453,12 +577,18 @@ impl<'s> Parser<'s> {
 | 
				
			||||||
                                CowStr::Owned(s) => s.replace('\n', " ").into(),
 | 
					                                CowStr::Owned(s) => s.replace('\n', " ").into(),
 | 
				
			||||||
                                s @ CowStr::Borrowed(_) => s,
 | 
					                                s @ CowStr::Borrowed(_) => s,
 | 
				
			||||||
                            };
 | 
					                            };
 | 
				
			||||||
                            let (url, attrs_def) = self
 | 
					                            let link_def =
 | 
				
			||||||
                                .link_definitions
 | 
					                                self.pre_pass.link_definitions.get(tag.as_ref()).cloned();
 | 
				
			||||||
                                .get(tag.as_ref())
 | 
					
 | 
				
			||||||
                                .cloned()
 | 
					                            let url = if let Some((url, attrs_def)) = link_def {
 | 
				
			||||||
                                .unwrap_or_else(|| ("".into(), Attributes::new()));
 | 
					                                attributes.union(attrs_def);
 | 
				
			||||||
                            attributes.union(attrs_def);
 | 
					                                url
 | 
				
			||||||
 | 
					                            } else {
 | 
				
			||||||
 | 
					                                self.pre_pass
 | 
				
			||||||
 | 
					                                    .heading_id_by_tag(tag.as_ref())
 | 
				
			||||||
 | 
					                                    .map_or_else(|| "".into(), |id| format!("#{}", id).into())
 | 
				
			||||||
 | 
					                            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            if matches!(c, inline::Container::ReferenceLink) {
 | 
					                            if matches!(c, inline::Container::ReferenceLink) {
 | 
				
			||||||
                                Container::Link(url, LinkType::Span(SpanLinkType::Reference))
 | 
					                                Container::Link(url, LinkType::Span(SpanLinkType::Reference))
 | 
				
			||||||
                            } else {
 | 
					                            } else {
 | 
				
			||||||
| 
						 | 
					@ -561,8 +691,15 @@ impl<'s> Parser<'s> {
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            match l {
 | 
					                            match l {
 | 
				
			||||||
                                block::Leaf::Paragraph => Container::Paragraph,
 | 
					                                block::Leaf::Paragraph => Container::Paragraph,
 | 
				
			||||||
                                block::Leaf::Heading => Container::Heading {
 | 
					                                block::Leaf::Heading { has_section } => Container::Heading {
 | 
				
			||||||
                                    level: content.len().try_into().unwrap(),
 | 
					                                    level: content.len().try_into().unwrap(),
 | 
				
			||||||
 | 
					                                    has_section,
 | 
				
			||||||
 | 
					                                    id: self
 | 
				
			||||||
 | 
					                                        .pre_pass
 | 
				
			||||||
 | 
					                                        .heading_id_by_location(ev.span.start())
 | 
				
			||||||
 | 
					                                        .unwrap_or_default()
 | 
				
			||||||
 | 
					                                        .to_string()
 | 
				
			||||||
 | 
					                                        .into(),
 | 
				
			||||||
                                },
 | 
					                                },
 | 
				
			||||||
                                block::Leaf::CodeBlock => {
 | 
					                                block::Leaf::CodeBlock => {
 | 
				
			||||||
                                    if let Some(format) = content.strip_prefix('=') {
 | 
					                                    if let Some(format) = content.strip_prefix('=') {
 | 
				
			||||||
| 
						 | 
					@ -631,7 +768,14 @@ impl<'s> Parser<'s> {
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                                Container::TableRow { head }
 | 
					                                Container::TableRow { head }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            block::Container::Section => Container::Section,
 | 
					                            block::Container::Section => Container::Section {
 | 
				
			||||||
 | 
					                                id: self
 | 
				
			||||||
 | 
					                                    .pre_pass
 | 
				
			||||||
 | 
					                                    .heading_id_by_location(ev.span.start())
 | 
				
			||||||
 | 
					                                    .unwrap_or_default()
 | 
				
			||||||
 | 
					                                    .to_string()
 | 
				
			||||||
 | 
					                                    .into(),
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
                    if enter {
 | 
					                    if enter {
 | 
				
			||||||
| 
						 | 
					@ -751,20 +895,49 @@ mod test {
 | 
				
			||||||
    fn heading() {
 | 
					    fn heading() {
 | 
				
			||||||
        test_parse!(
 | 
					        test_parse!(
 | 
				
			||||||
            "#\n",
 | 
					            "#\n",
 | 
				
			||||||
            Start(Section, Attributes::new()),
 | 
					            Start(Section { id: "s-1".into() }, Attributes::new()),
 | 
				
			||||||
            Start(Heading { level: 1 }, Attributes::new()),
 | 
					            Start(
 | 
				
			||||||
            End(Heading { level: 1 }),
 | 
					                Heading {
 | 
				
			||||||
            End(Section),
 | 
					                    level: 1,
 | 
				
			||||||
 | 
					                    has_section: true,
 | 
				
			||||||
 | 
					                    id: "s-1".into()
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                Attributes::new()
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            End(Heading {
 | 
				
			||||||
 | 
					                level: 1,
 | 
				
			||||||
 | 
					                has_section: true,
 | 
				
			||||||
 | 
					                id: "s-1".into()
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            End(Section { id: "s-1".into() }),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        test_parse!(
 | 
					        test_parse!(
 | 
				
			||||||
            "# abc\ndef\n",
 | 
					            "# abc\ndef\n",
 | 
				
			||||||
            Start(Section, Attributes::new()),
 | 
					            Start(
 | 
				
			||||||
            Start(Heading { level: 1 }, Attributes::new()),
 | 
					                Section {
 | 
				
			||||||
 | 
					                    id: "abc-def".into()
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                Attributes::new()
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            Start(
 | 
				
			||||||
 | 
					                Heading {
 | 
				
			||||||
 | 
					                    level: 1,
 | 
				
			||||||
 | 
					                    has_section: true,
 | 
				
			||||||
 | 
					                    id: "abc-def".into()
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                Attributes::new()
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
            Str("abc".into()),
 | 
					            Str("abc".into()),
 | 
				
			||||||
            Atom(Softbreak),
 | 
					            Atom(Softbreak),
 | 
				
			||||||
            Str("def".into()),
 | 
					            Str("def".into()),
 | 
				
			||||||
            End(Heading { level: 1 }),
 | 
					            End(Heading {
 | 
				
			||||||
            End(Section),
 | 
					                level: 1,
 | 
				
			||||||
 | 
					                has_section: true,
 | 
				
			||||||
 | 
					                id: "abc-def".into(),
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            End(Section {
 | 
				
			||||||
 | 
					                id: "abc-def".into()
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -776,16 +949,41 @@ mod test {
 | 
				
			||||||
                "{a=b}\n",
 | 
					                "{a=b}\n",
 | 
				
			||||||
                "# def\n", //
 | 
					                "# def\n", //
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            Start(Section, Attributes::new()),
 | 
					            Start(Section { id: "abc".into() }, Attributes::new()),
 | 
				
			||||||
            Start(Heading { level: 1 }, Attributes::new()),
 | 
					            Start(
 | 
				
			||||||
 | 
					                Heading {
 | 
				
			||||||
 | 
					                    level: 1,
 | 
				
			||||||
 | 
					                    has_section: true,
 | 
				
			||||||
 | 
					                    id: "abc".into()
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                Attributes::new()
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
            Str("abc".into()),
 | 
					            Str("abc".into()),
 | 
				
			||||||
            End(Heading { level: 1 }),
 | 
					            End(Heading {
 | 
				
			||||||
            End(Section),
 | 
					                level: 1,
 | 
				
			||||||
            Start(Section, [("a", "b")].into_iter().collect(),),
 | 
					                has_section: true,
 | 
				
			||||||
            Start(Heading { level: 1 }, Attributes::new(),),
 | 
					                id: "abc".into(),
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            End(Section { id: "abc".into() }),
 | 
				
			||||||
 | 
					            Start(
 | 
				
			||||||
 | 
					                Section { id: "def".into() },
 | 
				
			||||||
 | 
					                [("a", "b")].into_iter().collect(),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            Start(
 | 
				
			||||||
 | 
					                Heading {
 | 
				
			||||||
 | 
					                    level: 1,
 | 
				
			||||||
 | 
					                    has_section: true,
 | 
				
			||||||
 | 
					                    id: "def".into()
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                Attributes::new(),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
            Str("def".into()),
 | 
					            Str("def".into()),
 | 
				
			||||||
            End(Heading { level: 1 }),
 | 
					            End(Heading {
 | 
				
			||||||
            End(Section),
 | 
					                level: 1,
 | 
				
			||||||
 | 
					                has_section: true,
 | 
				
			||||||
 | 
					                id: "def".into(),
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					            End(Section { id: "def".into() }),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -302,7 +302,7 @@ impl<'s, 'i> DiscontinuousString<'s> for InlineSpansSlice<'s, 'i> {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type InlineSpansSliceIter<'i> = std::iter::Chain<
 | 
					pub type InlineSpansSliceIter<'i> = std::iter::Chain<
 | 
				
			||||||
    std::iter::Chain<std::iter::Once<Span>, std::iter::Copied<std::slice::Iter<'i, Span>>>,
 | 
					    std::iter::Chain<std::iter::Once<Span>, std::iter::Copied<std::slice::Iter<'i, Span>>>,
 | 
				
			||||||
    std::iter::Once<Span>,
 | 
					    std::iter::Once<Span>,
 | 
				
			||||||
>;
 | 
					>;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue