1
Fork 0

Use custom header IDs if present (#40)

Co-authored-by: Jan-Erik Rediger <janerik@fnordig.de>
This commit is contained in:
Dominik Nakamura 2023-08-01 21:59:27 +09:00 committed by GitHub
parent e897dbffcc
commit 113362a944
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 20 deletions

View file

@ -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,10 +179,15 @@ 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 slug = if let Some(slug) = fragment {
// 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 mut slug = mdbook::utils::normalize_id(&header);
let id_count = id_counter.entry(slug.clone()).or_insert(0); let id_count = id_counter.entry(slug.clone()).or_insert(0);
@ -193,6 +198,8 @@ fn add_toc(content: &str, cfg: &Config) -> Result<String> {
} }
*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
View 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
View 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}

View file

@ -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");
}