block: specify heading pos in event

instead of using span
This commit is contained in:
Noah Hellman 2023-04-29 20:02:18 +02:00
parent 898ed90a24
commit ee9ea2e023
2 changed files with 97 additions and 57 deletions

View file

@ -58,7 +58,11 @@ pub enum Leaf<'s> {
/// Span is `#` characters. /// Span is `#` characters.
/// Each inline is a line. /// Each inline is a line.
Heading { level: u16, has_section: bool }, Heading {
level: u16,
has_section: bool,
pos: u32,
},
/// Span is empty. /// Span is empty.
DescriptionTerm, DescriptionTerm,
@ -103,7 +107,7 @@ pub enum Container<'s> {
TableRow { head: bool }, TableRow { head: bool },
/// Span is '#' characters of heading. /// Span is '#' characters of heading.
Section, Section { pos: u32 },
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -259,6 +263,7 @@ impl<'s> TreeParser<'s> {
Kind::Heading { level } => Block::Leaf(Heading { Kind::Heading { level } => Block::Leaf(Heading {
level: level.try_into().unwrap(), level: level.try_into().unwrap(),
has_section: top_level, has_section: top_level,
pos: span.start() as u32,
}), }),
Kind::Fenced { Kind::Fenced {
kind: FenceKind::CodeBlock(..), kind: FenceKind::CodeBlock(..),
@ -343,7 +348,12 @@ impl<'s> TreeParser<'s> {
self.tree.exit(); // section self.tree.exit(); // section
}); });
self.open_sections.push(*level); self.open_sections.push(*level);
self.tree.enter(Node::Container(Section), span); self.tree.enter(
Node::Container(Section {
pos: span.start() as u32,
}),
span,
);
} }
// trim '#' characters // trim '#' characters
@ -1110,11 +1120,12 @@ mod test {
"# a\n", "# a\n",
"## b\n", // "## b\n", //
), ),
(Enter(Container(Section)), "#"), (Enter(Container(Section { pos: 0 })), "#"),
( (
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 0
})), })),
"#" "#"
), ),
@ -1122,15 +1133,17 @@ mod test {
( (
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 0
})), })),
"#" "#"
), ),
(Enter(Container(Section)), "##"), (Enter(Container(Section { pos: 4 })), "##"),
( (
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 2, level: 2,
has_section: true has_section: true,
pos: 4
})), })),
"##" "##"
), ),
@ -1138,12 +1151,13 @@ mod test {
( (
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 2, level: 2,
has_section: true has_section: true,
pos: 4
})), })),
"##" "##"
), ),
(Exit(Container(Section)), "##"), (Exit(Container(Section { pos: 4 })), "##"),
(Exit(Container(Section)), "#"), (Exit(Container(Section { pos: 0 })), "#"),
); );
} }
@ -1154,11 +1168,12 @@ mod test {
"#\n", "#\n",
"heading\n", // "heading\n", //
), ),
(Enter(Container(Section)), "#"), (Enter(Container(Section { pos: 0 })), "#"),
( (
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 0
})), })),
"#" "#"
), ),
@ -1166,11 +1181,12 @@ mod test {
( (
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 0
})), })),
"#" "#"
), ),
(Exit(Container(Section)), "#"), (Exit(Container(Section { pos: 0 })), "#"),
); );
} }
@ -1184,11 +1200,12 @@ mod test {
" 12\n", " 12\n",
"15\n", // "15\n", //
), ),
(Enter(Container(Section)), "#"), (Enter(Container(Section { pos: 0 })), "#"),
( (
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 0,
})), })),
"#" "#"
), ),
@ -1196,17 +1213,19 @@ mod test {
( (
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 0,
})), })),
"#" "#"
), ),
(Atom(Blankline), "\n"), (Atom(Blankline), "\n"),
(Exit(Container(Section)), "#"), (Exit(Container(Section { pos: 0 })), "#"),
(Enter(Container(Section)), "#"), (Enter(Container(Section { pos: 6 })), "#"),
( (
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 6,
})), })),
"#" "#"
), ),
@ -1216,11 +1235,12 @@ mod test {
( (
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 6,
})), })),
"#" "#"
), ),
(Exit(Container(Section)), "#"), (Exit(Container(Section { pos: 6 })), "#"),
); );
} }
@ -1232,11 +1252,12 @@ mod test {
"# b\n", "# b\n",
"c\n", // "c\n", //
), ),
(Enter(Container(Section)), "#"), (Enter(Container(Section { pos: 0 })), "#"),
( (
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 0
})), })),
"#" "#"
), ),
@ -1246,11 +1267,12 @@ mod test {
( (
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 0
})), })),
"#" "#"
), ),
(Exit(Container(Section)), "#"), (Exit(Container(Section { pos: 0 })), "#"),
); );
} }
@ -1270,11 +1292,12 @@ mod test {
"\n", "\n",
"# b\n", "# b\n",
), ),
(Enter(Container(Section)), "#"), (Enter(Container(Section { pos: 0 })), "#"),
( (
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 0,
})), })),
"#" "#"
), ),
@ -1282,16 +1305,18 @@ mod test {
( (
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 0,
})), })),
"#" "#"
), ),
(Atom(Blankline), "\n"), (Atom(Blankline), "\n"),
(Enter(Container(Section)), "##"), (Enter(Container(Section { pos: 5 })), "##"),
( (
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 2, level: 2,
has_section: true has_section: true,
pos: 5,
})), })),
"##" "##"
), ),
@ -1299,16 +1324,18 @@ mod test {
( (
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 2, level: 2,
has_section: true has_section: true,
pos: 5,
})), })),
"##" "##"
), ),
(Atom(Blankline), "\n"), (Atom(Blankline), "\n"),
(Enter(Container(Section)), "####"), (Enter(Container(Section { pos: 12 })), "####"),
( (
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 4, level: 4,
has_section: true has_section: true,
pos: 12,
})), })),
"####" "####"
), ),
@ -1316,18 +1343,20 @@ mod test {
( (
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 4, level: 4,
has_section: true has_section: true,
pos: 12,
})), })),
"####" "####"
), ),
(Atom(Blankline), "\n"), (Atom(Blankline), "\n"),
(Exit(Container(Section)), "####"), (Exit(Container(Section { pos: 12 })), "####"),
(Exit(Container(Section)), "##"), (Exit(Container(Section { pos: 5 })), "##"),
(Enter(Container(Section)), "##"), (Enter(Container(Section { pos: 23 })), "##"),
( (
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 2, level: 2,
has_section: true has_section: true,
pos: 23,
})), })),
"##" "##"
), ),
@ -1335,16 +1364,18 @@ mod test {
( (
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 2, level: 2,
has_section: true has_section: true,
pos: 23,
})), })),
"##" "##"
), ),
(Atom(Blankline), "\n"), (Atom(Blankline), "\n"),
(Enter(Container(Section)), "###"), (Enter(Container(Section { pos: 30 })), "###"),
( (
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 3, level: 3,
has_section: true has_section: true,
pos: 30,
})), })),
"###" "###"
), ),
@ -1352,19 +1383,21 @@ mod test {
( (
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 3, level: 3,
has_section: true has_section: true,
pos: 30,
})), })),
"###" "###"
), ),
(Atom(Blankline), "\n"), (Atom(Blankline), "\n"),
(Exit(Container(Section)), "###"), (Exit(Container(Section { pos: 30 })), "###"),
(Exit(Container(Section)), "##"), (Exit(Container(Section { pos: 23 })), "##"),
(Exit(Container(Section)), "#"), (Exit(Container(Section { pos: 0 })), "#"),
(Enter(Container(Section)), "#"), (Enter(Container(Section { pos: 39 })), "#"),
( (
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 1, level: 1,
has_section: true has_section: true,
pos: 39,
})), })),
"#" "#"
), ),
@ -1373,10 +1406,11 @@ mod test {
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 1, level: 1,
has_section: true, has_section: true,
pos: 39,
})), })),
"#" "#"
), ),
(Exit(Container(Section)), "#"), (Exit(Container(Section { pos: 39 })), "#"),
); );
} }
@ -1417,6 +1451,7 @@ mod test {
Enter(Leaf(Heading { Enter(Leaf(Heading {
level: 2, level: 2,
has_section: false, has_section: false,
pos: 8,
})), })),
"##" "##"
), ),
@ -1425,6 +1460,7 @@ mod test {
Exit(Leaf(Heading { Exit(Leaf(Heading {
level: 2, level: 2,
has_section: false, has_section: false,
pos: 8,
})), })),
"##" "##"
), ),

View file

@ -576,7 +576,7 @@ pub struct Parser<'s> {
#[derive(Clone)] #[derive(Clone)]
struct Heading { struct Heading {
/// Location of heading in src. /// Location of heading in src.
location: usize, location: u32,
/// Automatically generated id from heading text. /// Automatically generated id from heading text.
id_auto: String, id_auto: String,
/// Text of heading, formatting stripped. /// Text of heading, formatting stripped.
@ -694,7 +694,7 @@ impl<'s> PrePass<'s> {
std::mem::transmute::<&str, &'static str>(id_auto.as_ref()) std::mem::transmute::<&str, &'static str>(id_auto.as_ref())
}); });
headings.push(Heading { headings.push(Heading {
location: e.span.start(), location: e.span.start() as u32,
id_auto, id_auto,
text, text,
id_override, id_override,
@ -728,7 +728,7 @@ impl<'s> PrePass<'s> {
h.id_override.as_ref().unwrap_or(&h.id_auto) h.id_override.as_ref().unwrap_or(&h.id_auto)
} }
fn heading_id_by_location(&self, location: usize) -> Option<&str> { fn heading_id_by_location(&self, location: u32) -> Option<&str> {
self.headings self.headings
.binary_search_by_key(&location, |h| h.location) .binary_search_by_key(&location, |h| h.location)
.ok() .ok()
@ -886,12 +886,16 @@ impl<'s> Parser<'s> {
self.inline_parser.reset(); self.inline_parser.reset();
match l { match l {
block::Leaf::Paragraph => Container::Paragraph, block::Leaf::Paragraph => Container::Paragraph,
block::Leaf::Heading { level, has_section } => Container::Heading { block::Leaf::Heading {
level,
has_section,
pos,
} => Container::Heading {
level, level,
has_section, has_section,
id: self id: self
.pre_pass .pre_pass
.heading_id_by_location(ev.span.start()) .heading_id_by_location(pos)
.unwrap_or_default() .unwrap_or_default()
.to_string() .to_string()
.into(), .into(),
@ -957,10 +961,10 @@ impl<'s> Parser<'s> {
} }
Container::TableRow { head } Container::TableRow { head }
} }
block::Container::Section => Container::Section { block::Container::Section { pos } => Container::Section {
id: self id: self
.pre_pass .pre_pass
.heading_id_by_location(ev.span.start()) .heading_id_by_location(pos)
.unwrap_or_default() .unwrap_or_default()
.to_string() .to_string()
.into(), .into(),