diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index fe78c920..c5050e86 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -87,7 +87,7 @@ impl HtmlHandlebars { Ok(()) } - /// Create an index.html from the first element in SUMMARY.md + /// Create an index.html from the first element in SUMMARY.md fn render_index(&self, book: &MDBook, ch: &Chapter, destination: &Path) -> Result<(), Box> { debug!("[*]: index.html"); @@ -399,59 +399,73 @@ fn build_header_links(html: String, filename: &str) -> String { regex .replace_all(&html, |caps: &Captures| { - let level = &caps[1]; - let text = &caps[2]; - let mut id = text.to_string(); - let repl_sub = vec![ - "", - "", - "", - "", - "", - "", - "<", - ">", - "&", - "'", - """, - ]; - for sub in repl_sub { - id = id.replace(sub, ""); - } - let id = id.chars() - .filter_map(|c| if c.is_alphanumeric() || c == '-' || c == '_' { - if c.is_ascii() { - Some(c.to_ascii_lowercase()) - } else { - Some(c) - } - } else if c.is_whitespace() && c.is_ascii() { - Some('-') - } else { - None - }) - .collect::(); + let level = caps[1].parse().expect( + "Regex should ensure we only ever get numbers here", + ); - let id_count = *id_counter.get(&id).unwrap_or(&0); - id_counter.insert(id.clone(), id_count + 1); - - let id = if id_count > 0 { - format!("{}-{}", id, id_count) - } else { - id - }; - - format!( - "{text}", - level = level, - id = id, - text = text, - filename = filename - ) + wrap_header_with_link(level, &caps[2], &mut id_counter, filename) }) .into_owned() } +fn wrap_header_with_link(level: usize, content: &str, id_counter: &mut HashMap, filename: &str) + -> String { + let id = id_from_content(content); + + let id_count = *id_counter.get(&id).unwrap_or(&0); + id_counter.insert(id.clone(), id_count + 1); + + let id = if id_count > 0 { + format!("{}-{}", id, id_count) + } else { + id + }; + + format!( + r#"{text}"#, + level = level, + id = id, + text = content, + filename = filename + ) +} + +fn id_from_content(content: &str) -> String { + let mut content = content.to_string(); + + // Skip any tags or html-encoded stuff + let repl_sub = vec![ + "", + "", + "", + "", + "", + "", + "<", + ">", + "&", + "'", + """, + ]; + for sub in repl_sub { + content = content.replace(sub, ""); + } + + content.chars() + .filter_map(|c| if c.is_alphanumeric() || c == '-' || c == '_' { + if c.is_ascii() { + Some(c.to_ascii_lowercase()) + } else { + Some(c) + } + } else if c.is_whitespace() && c.is_ascii() { + Some('-') + } else { + None + }) + .collect() +} + // anchors to the same page (href="#anchor") do not work because of // pointing to the root folder. This function *fixes* // that in a very inelegant way @@ -583,4 +597,4 @@ mod tests { assert_eq!(got, should_be); } } -} \ No newline at end of file +}