From d6099882640931b83ad3336097f1652b502c8bf3 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 15 Feb 2017 21:00:48 -0500 Subject: [PATCH 1/5] remove js rendering --- src/theme/book.js | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/theme/book.js b/src/theme/book.js index 8731880cec..21295140d6 100644 --- a/src/theme/book.js +++ b/src/theme/book.js @@ -55,20 +55,6 @@ $( document ).ready(function() { var page_wrapper = $("#page-wrapper"); var content = $("#content"); - - // Add anchors for all content headers - content.find("h1, h2, h3, h4, h5").wrap(function(){ - var wrapper = $(""); - var header_name = $(this).text().trim().replace(/\W/g, '-') - wrapper.attr("name", header_name); - // Add so that when you click the link actually shows up in the url bar... - // Remove any existing anchor then append the new one - // ensuring eg. no spaces are present within it ie. they become %20 - wrapper.attr("href", $(location).attr('href').split("#")[0] + "#" + header_name ); - return wrapper; - }); - - // Toggle sidebar $("#sidebar-toggle").click(function(event){ if ( html.hasClass("sidebar-hidden") ) { From 38b3516b60bd839cba4efd07a9ae588bf8e4589a Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 16 Feb 2017 01:39:13 -0500 Subject: [PATCH 2/5] 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 --- Cargo.toml | 1 + src/lib.rs | 1 + src/renderer/html_handlebars/hbs_renderer.rs | 39 ++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 9451e2f275..17254dc9d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ log = "0.3" env_logger = "0.3" toml = { version = "0.2", features = ["serde"] } open = "1.1" +regex = "0.1.80" # Watch feature notify = { version = "3.0", optional = true } diff --git a/src/lib.rs b/src/lib.rs index 0a59f9e7ca..49c56facf8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,6 +74,7 @@ extern crate serde; extern crate serde_json; extern crate handlebars; extern crate pulldown_cmark; +extern crate regex; #[macro_use] extern crate log; pub mod book; diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index b122ed143e..83b65bf015 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -3,7 +3,9 @@ use renderer::Renderer; use book::MDBook; use book::bookitem::BookItem; use {utils, theme}; +use regex::{Regex, Captures}; +use std::ascii::AsciiExt; use std::path::{Path, PathBuf}; use std::fs::{self, File}; use std::error::Error; @@ -91,6 +93,9 @@ impl Renderer for HtmlHandlebars { // Render the handlebars template with the data debug!("[*]: Render template"); let rendered = try!(handlebars.render("index", &data)); + + // create links for headers + let rendered = build_header_links(rendered); // Write to file let filename = Path::new(&ch.path).with_extension("html"); @@ -208,3 +213,37 @@ fn make_data(book: &MDBook) -> Result debug!("[*]: JSON constructed"); 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=header)).unwrap(); + + html = regex.replace_all(&html, |caps: &Captures| { + let text = &caps[1]; + 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::(); + + format!("<{h}>{text}", h=header, id=id, text=text) + }); + } + + html +} From 280dabecd729ce62fbeaacc5ca11a56ed8d0da30 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 16 Feb 2017 17:11:16 -0500 Subject: [PATCH 3/5] update regex dep --- Cargo.toml | 2 +- src/renderer/html_handlebars/hbs_renderer.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 17254dc9d9..3a9e9f0988 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ log = "0.3" env_logger = "0.3" toml = { version = "0.2", features = ["serde"] } open = "1.1" -regex = "0.1.80" +regex = "0.2.1" # Watch feature notify = { version = "3.0", optional = true } diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 83b65bf015..0945b5eae0 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -242,7 +242,7 @@ fn build_header_links(mut html: String) -> String { }).collect::(); format!("<{h}>{text}", h=header, id=id, text=text) - }); + }).into_owned(); } html From aba153a2713a2fc6c7c7a0c0c2a063649db34d6c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 16 Feb 2017 17:17:26 -0500 Subject: [PATCH 4/5] update env_logger --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3a9e9f0988..7f2459772d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ serde = "0.9" serde_json = "0.9" pulldown-cmark = "0.0.8" log = "0.3" -env_logger = "0.3" +env_logger = "0.4.0" toml = { version = "0.2", features = ["serde"] } open = "1.1" regex = "0.2.1" From ec42e2f771cad73bca5158f3a2651e94c9d68d89 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 16 Feb 2017 19:29:50 -0500 Subject: [PATCH 5/5] convert to one pass thanks @burntsushi :heart: --- src/renderer/html_handlebars/hbs_renderer.rs | 55 +++++++++----------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 0945b5eae0..a8bfa8eb50 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -214,36 +214,33 @@ fn make_data(book: &MDBook) -> Result 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=header)).unwrap(); - - html = regex.replace_all(&html, |caps: &Captures| { - let text = &caps[1]; - 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('-') +fn build_header_links(html: String) -> String { + let regex = Regex::new(r"(.*?)").unwrap(); + + 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 { - None + Some(c) } - }).collect::(); - - format!("<{h}>{text}", h=header, id=id, text=text) - }).into_owned(); - } + } else if c.is_whitespace() && c.is_ascii() { + Some('-') + } else { + None + } + }).collect::(); - html + format!("{text}", level=level, id=id, text=text) + }).into_owned() }