Use custom header IDs if present (#40)
Co-authored-by: Jan-Erik Rediger <janerik@fnordig.de>
This commit is contained in:
parent
e897dbffcc
commit
113362a944
35
src/lib.rs
35
src/lib.rs
|
@ -140,11 +140,11 @@ fn add_toc(content: &str, cfg: &Config) -> Result<String> {
|
||||||
let mut current_header_level: Option<u32> = None;
|
let mut current_header_level: Option<u32> = None;
|
||||||
let mut id_counter = HashMap::new();
|
let mut id_counter = HashMap::new();
|
||||||
|
|
||||||
let mut opts = Options::empty();
|
let opts = Options::ENABLE_TABLES
|
||||||
opts.insert(Options::ENABLE_TABLES);
|
| Options::ENABLE_FOOTNOTES
|
||||||
opts.insert(Options::ENABLE_FOOTNOTES);
|
| Options::ENABLE_STRIKETHROUGH
|
||||||
opts.insert(Options::ENABLE_STRIKETHROUGH);
|
| Options::ENABLE_TASKLISTS
|
||||||
opts.insert(Options::ENABLE_TASKLISTS);
|
| Options::ENABLE_HEADING_ATTRIBUTES;
|
||||||
|
|
||||||
let mark: Vec<Event> = Parser::new(&cfg.marker).collect();
|
let mark: Vec<Event> = Parser::new(&cfg.marker).collect();
|
||||||
log::trace!("Marker: {mark:?}");
|
log::trace!("Marker: {mark:?}");
|
||||||
|
@ -179,20 +179,27 @@ fn add_toc(content: &str, cfg: &Config) -> Result<String> {
|
||||||
current_header_level = Some(lvl as u32);
|
current_header_level = Some(lvl as u32);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Event::End(Heading(..)) = e {
|
if let Event::End(Heading(_, fragment, _)) = e {
|
||||||
// Skip if this header is nested too deeply.
|
// Skip if this header is nested too deeply.
|
||||||
if let Some(level) = current_header_level.take() {
|
if let Some(level) = current_header_level.take() {
|
||||||
let header = current_header.clone();
|
let header = current_header.clone();
|
||||||
let mut slug = mdbook::utils::normalize_id(&header);
|
let slug = if let Some(slug) = fragment {
|
||||||
let id_count = id_counter.entry(slug.clone()).or_insert(0);
|
// If a fragment is defined, take it as is, not trying to append an extra ID
|
||||||
|
// in case of duplicates (same behavior as mdBook)
|
||||||
|
slug.to_owned()
|
||||||
|
} else {
|
||||||
|
let mut slug = mdbook::utils::normalize_id(&header);
|
||||||
|
let id_count = id_counter.entry(slug.clone()).or_insert(0);
|
||||||
|
|
||||||
// Append unique ID if multiple headers with the same name exist
|
// Append unique ID if multiple headers with the same name exist
|
||||||
// to follow what mdBook does
|
// to follow what mdBook does
|
||||||
if *id_count > 0 {
|
if *id_count > 0 {
|
||||||
write!(slug, "-{id_count}").unwrap();
|
write!(slug, "-{id_count}").unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
*id_count += 1;
|
*id_count += 1;
|
||||||
|
slug
|
||||||
|
};
|
||||||
|
|
||||||
if level <= cfg.max_level {
|
if level <= cfg.max_level {
|
||||||
toc_content.push((level, header, slug));
|
toc_content.push((level, header, slug));
|
||||||
|
|
11
tests/attributes.in.md
Normal file
11
tests/attributes.in.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# Chapter
|
||||||
|
|
||||||
|
<!-- toc -->
|
||||||
|
|
||||||
|
# Header 1
|
||||||
|
|
||||||
|
## Header {#header-1-sub}
|
||||||
|
|
||||||
|
# Header 2
|
||||||
|
|
||||||
|
## Header {#header-2-sub .class1 .class2}
|
14
tests/attributes.out.md
Normal file
14
tests/attributes.out.md
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Chapter
|
||||||
|
|
||||||
|
* [Header 1](#header-1)
|
||||||
|
* [Header](#header-1-sub)
|
||||||
|
* [Header 2](#header-2)
|
||||||
|
* [Header](#header-2-sub)
|
||||||
|
|
||||||
|
# Header 1
|
||||||
|
|
||||||
|
## Header {#header-1-sub}
|
||||||
|
|
||||||
|
# Header 2
|
||||||
|
|
||||||
|
## Header {#header-2-sub .class1 .class2}
|
19
tests/it.rs
19
tests/it.rs
|
@ -7,15 +7,17 @@ fn default<T: Default>() -> T {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_marker<S: Into<String>>(marker: S) -> Config {
|
fn with_marker<S: Into<String>>(marker: S) -> Config {
|
||||||
let mut cfg = Config::default();
|
Config {
|
||||||
cfg.marker = marker.into();
|
marker: marker.into(),
|
||||||
cfg
|
..Config::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_max_level(level: u32) -> Config {
|
fn with_max_level(level: u32) -> Config {
|
||||||
let mut cfg = Config::default();
|
Config {
|
||||||
cfg.max_level = level;
|
max_level: level,
|
||||||
cfg
|
..Config::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait FromContent {
|
trait FromContent {
|
||||||
|
@ -169,3 +171,8 @@ fn empty_document() {
|
||||||
fn crlf() {
|
fn crlf() {
|
||||||
assert_toc!("crlf");
|
assert_toc!("crlf");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn attributes() {
|
||||||
|
assert_toc!("attributes");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue