Broke the header link wrapping out into smaller functions

This commit is contained in:
Michael Bryan 2017-06-20 11:06:30 +08:00
parent ac16d7aef1
commit fa95546988
1 changed files with 64 additions and 50 deletions

View File

@ -87,7 +87,7 @@ impl HtmlHandlebars {
Ok(()) 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<Error>> { fn render_index(&self, book: &MDBook, ch: &Chapter, destination: &Path) -> Result<(), Box<Error>> {
debug!("[*]: index.html"); debug!("[*]: index.html");
@ -399,59 +399,73 @@ fn build_header_links(html: String, filename: &str) -> String {
regex regex
.replace_all(&html, |caps: &Captures| { .replace_all(&html, |caps: &Captures| {
let level = &caps[1]; let level = caps[1].parse().expect(
let text = &caps[2]; "Regex should ensure we only ever get numbers here",
let mut id = text.to_string(); );
let repl_sub = vec![
"<em>",
"</em>",
"<code>",
"</code>",
"<strong>",
"</strong>",
"&lt;",
"&gt;",
"&amp;",
"&#39;",
"&quot;",
];
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::<String>();
let id_count = *id_counter.get(&id).unwrap_or(&0); wrap_header_with_link(level, &caps[2], &mut id_counter, filename)
id_counter.insert(id.clone(), id_count + 1);
let id = if id_count > 0 {
format!("{}-{}", id, id_count)
} else {
id
};
format!(
"<a class=\"header\" href=\"{filename}#{id}\" id=\"{id}\"><h{level}>{text}</h{level}></a>",
level = level,
id = id,
text = text,
filename = filename
)
}) })
.into_owned() .into_owned()
} }
fn wrap_header_with_link(level: usize, content: &str, id_counter: &mut HashMap<String, usize>, 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#"<a class="header" href="{filename}#{id}" id="{id}"><h{level}>{text}</h{level}></a>"#,
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![
"<em>",
"</em>",
"<code>",
"</code>",
"<strong>",
"</strong>",
"&lt;",
"&gt;",
"&amp;",
"&#39;",
"&quot;",
];
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 // anchors to the same page (href="#anchor") do not work because of
// <base href="../"> pointing to the root folder. This function *fixes* // <base href="../"> pointing to the root folder. This function *fixes*
// that in a very inelegant way // that in a very inelegant way
@ -583,4 +597,4 @@ mod tests {
assert_eq!(got, should_be); assert_eq!(got, should_be);
} }
} }
} }