Implement links in section headers.
This project already had a transitive dependency on regex; let's use it. This isn't the most efficient solution, but it should be fine. It ends up doing five full scans of the text. There's probably an easier way but I'm mostly just trying to get this to work for now. This also implements the same algorithm that rustdoc does for generating the name for the link. Fixes #204
This commit is contained in:
parent
d609988264
commit
38b3516b60
|
@ -24,6 +24,7 @@ log = "0.3"
|
||||||
env_logger = "0.3"
|
env_logger = "0.3"
|
||||||
toml = { version = "0.2", features = ["serde"] }
|
toml = { version = "0.2", features = ["serde"] }
|
||||||
open = "1.1"
|
open = "1.1"
|
||||||
|
regex = "0.1.80"
|
||||||
|
|
||||||
# Watch feature
|
# Watch feature
|
||||||
notify = { version = "3.0", optional = true }
|
notify = { version = "3.0", optional = true }
|
||||||
|
|
|
@ -74,6 +74,7 @@ extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate handlebars;
|
extern crate handlebars;
|
||||||
extern crate pulldown_cmark;
|
extern crate pulldown_cmark;
|
||||||
|
extern crate regex;
|
||||||
|
|
||||||
#[macro_use] extern crate log;
|
#[macro_use] extern crate log;
|
||||||
pub mod book;
|
pub mod book;
|
||||||
|
|
|
@ -3,7 +3,9 @@ use renderer::Renderer;
|
||||||
use book::MDBook;
|
use book::MDBook;
|
||||||
use book::bookitem::BookItem;
|
use book::bookitem::BookItem;
|
||||||
use {utils, theme};
|
use {utils, theme};
|
||||||
|
use regex::{Regex, Captures};
|
||||||
|
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -91,6 +93,9 @@ impl Renderer for HtmlHandlebars {
|
||||||
// Render the handlebars template with the data
|
// Render the handlebars template with the data
|
||||||
debug!("[*]: Render template");
|
debug!("[*]: Render template");
|
||||||
let rendered = try!(handlebars.render("index", &data));
|
let rendered = try!(handlebars.render("index", &data));
|
||||||
|
|
||||||
|
// create links for headers
|
||||||
|
let rendered = build_header_links(rendered);
|
||||||
|
|
||||||
// Write to file
|
// Write to file
|
||||||
let filename = Path::new(&ch.path).with_extension("html");
|
let filename = Path::new(&ch.path).with_extension("html");
|
||||||
|
@ -208,3 +213,37 @@ fn make_data(book: &MDBook) -> Result<serde_json::Map<String, serde_json::Value>
|
||||||
debug!("[*]: JSON constructed");
|
debug!("[*]: JSON constructed");
|
||||||
Ok(data)
|
Ok(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_header_links(mut html: String) -> String {
|
||||||
|
for header in &["h1", "h2", "h3", "h4", "h5"] {
|
||||||
|
let regex = Regex::new(&format!("<{h}>(.*?)</{h}>", h=header)).unwrap();
|
||||||
|
|
||||||
|
html = regex.replace_all(&html, |caps: &Captures| {
|
||||||
|
let text = &caps[1];
|
||||||
|
let mut id = text.to_string();
|
||||||
|
let repl_sub = vec!["<em>", "</em>", "<code>", "</code>",
|
||||||
|
"<strong>", "</strong>",
|
||||||
|
"<", ">", "&", "'", """];
|
||||||
|
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>();
|
||||||
|
|
||||||
|
format!("<a class=\"header\" href=\"#{id}\" name=\"{id}\"><{h}>{text}</{h}></a>", h=header, id=id, text=text)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
html
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue