From bdb37ec117a05677dc9f35df7a0f619e8f768153 Mon Sep 17 00:00:00 2001 From: cetra3 Date: Wed, 11 Jul 2018 23:33:44 +1000 Subject: [PATCH] Use relative links and translate internal references (#603) * Relative links for 0.1.8 * Compat for IE11 search --- book-example/src/cli/init.md | 2 +- book-example/src/for_developers/README.md | 4 +- src/renderer/html_handlebars/hbs_renderer.rs | 67 +++++-------------- .../html_handlebars/helpers/navigation.rs | 9 +++ src/renderer/html_handlebars/helpers/toc.rs | 3 + src/theme/book.js | 6 +- src/theme/index.hbs | 51 +++++++------- src/theme/searcher/searcher.js | 11 ++- src/utils/mod.rs | 41 ++++++++++++ tests/rendered_output.rs | 19 +++--- 10 files changed, 120 insertions(+), 93 deletions(-) diff --git a/book-example/src/cli/init.md b/book-example/src/cli/init.md index 43d1ae02..8a899afb 100644 --- a/book-example/src/cli/init.md +++ b/book-example/src/cli/init.md @@ -22,7 +22,7 @@ configuration files, etc. - The `book` directory is where your book is rendered. All the output is ready to be uploaded to a server to be seen by your audience. -- The `SUMMARY.md` file is the most important file, it's the skeleton of your book and is discussed in more detail in another [chapter](format/summary.html). +- The `SUMMARY.md` file is the most important file, it's the skeleton of your book and is discussed in more detail in another [chapter](../format/summary.md) #### Tip & Trick: Hidden Feature When a `SUMMARY.md` file already exists, the `init` command will first parse it and generate the missing files according to the paths used in the `SUMMARY.md`. This allows you to think and create the whole structure of your book and then let mdBook generate it for you. diff --git a/book-example/src/for_developers/README.md b/book-example/src/for_developers/README.md index 4f173c90..ae1069fc 100644 --- a/book-example/src/for_developers/README.md +++ b/book-example/src/for_developers/README.md @@ -11,8 +11,8 @@ The *For Developers* chapters are here to show you the more advanced usage of The two main ways a developer can hook into the book's build process is via, -- [Preprocessors](for_developers/preprocessors.html) -- [Alternate Backends](for_developers/backends.html) +- [Preprocessors](preprocessors.md) +- [Alternate Backends](backends.md) ## The Build Process diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index ba5c5e43..4fad1eef 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -42,10 +42,6 @@ impl HtmlHandlebars { .to_str() .chain_err(|| "Could not convert path to str")?; let filepath = Path::new(&ch.path).with_extension("html"); - let filepathstr = filepath - .to_str() - .chain_err(|| "Could not convert HTML path to str")?; - let filepathstr = utils::fs::normalize_path(filepathstr); // "print.html" is used for the print page. if ch.path == Path::new("print.md") { @@ -75,10 +71,10 @@ impl HtmlHandlebars { debug!("Render template"); let rendered = ctx.handlebars.render("index", &ctx.data)?; - let rendered = self.post_process(rendered, &filepathstr, &ctx.html_config.playpen); + let rendered = self.post_process(rendered, &ctx.html_config.playpen); // Write to file - debug!("Creating {} ✓", filepathstr); + debug!("Creating {} ✓", filepath.display()); utils::fs::write_file(&ctx.destination, &filepath, &rendered.into_bytes())?; if ctx.is_index { @@ -120,9 +116,8 @@ impl HtmlHandlebars { } #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))] - fn post_process(&self, rendered: String, filepath: &str, playpen_config: &Playpen) -> String { - let rendered = build_header_links(&rendered, filepath); - let rendered = fix_anchor_links(&rendered, filepath); + fn post_process(&self, rendered: String, playpen_config: &Playpen) -> String { + let rendered = build_header_links(&rendered); let rendered = fix_code_blocks(&rendered); let rendered = add_playpen_pre(&rendered, playpen_config); @@ -360,7 +355,7 @@ impl Renderer for HtmlHandlebars { debug!("Render template"); let rendered = handlebars.render("index", &data)?; - let rendered = self.post_process(rendered, "print.html", &html_config.playpen); + let rendered = self.post_process(rendered, &html_config.playpen); utils::fs::write_file(&destination, "print.html", &rendered.into_bytes())?; debug!("Creating print.html ✓"); @@ -497,7 +492,7 @@ fn make_data( /// Goes through the rendered HTML, making sure all header tags are wrapped in /// an anchor so people can link to sections directly. -fn build_header_links(html: &str, filepath: &str) -> String { +fn build_header_links(html: &str) -> String { let regex = Regex::new(r"(.*?)").unwrap(); let mut id_counter = HashMap::new(); @@ -507,7 +502,7 @@ fn build_header_links(html: &str, filepath: &str) -> String { .parse() .expect("Regex should ensure we only ever get numbers here"); - wrap_header_with_link(level, &caps[2], &mut id_counter, filepath) + wrap_header_with_link(level, &caps[2], &mut id_counter) }) .into_owned() } @@ -517,8 +512,7 @@ fn build_header_links(html: &str, filepath: &str) -> String { fn wrap_header_with_link( level: usize, content: &str, - id_counter: &mut HashMap, - filepath: &str, + id_counter: &mut HashMap ) -> String { let raw_id = utils::id_from_content(content); @@ -532,35 +526,13 @@ fn wrap_header_with_link( *id_count += 1; format!( - r##"{text}"##, + r##"{text}"##, level = level, id = id, - text = content, - filepath = filepath + text = content ) } -// 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 -fn fix_anchor_links(html: &str, filepath: &str) -> String { - let regex = Regex::new(r##"]+)href="#([^"]+)"([^>]*)>"##).unwrap(); - regex - .replace_all(html, |caps: &Captures| { - let before = &caps[1]; - let anchor = &caps[2]; - let after = &caps[3]; - - format!( - "", - before = before, - filepath = filepath, - anchor = anchor, - after = after - ) - }) - .into_owned() -} // The rust book uses annotations for rustdoc to test code snippets, // like the following: @@ -660,37 +632,32 @@ mod tests { let inputs = vec![ ( "blah blah

Foo

", - r##"blah blah

Foo

"##, + r##"blah blah

Foo

"##, ), ( "

Foo

", - r##"

Foo

"##, + r##"

Foo

"##, ), ( "

Foo^bar

", - r##"

Foo^bar

"##, + r##"

Foo^bar

"##, ), ( "

", - r##"

"##, + r##"

"##, ), ( "

", - r##"

"##, + r##"

"##, ), ( "

Foo

Foo

", - r##"

Foo

Foo

"##, + r##"

Foo

Foo

"##, ), ]; for (src, should_be) in inputs { - let filepath = "./some_chapter/some_section.html"; - let got = build_header_links(&src, filepath); - assert_eq!(got, should_be); - - // This is redundant for most cases - let got = fix_anchor_links(&got, filepath); + let got = build_header_links(&src); assert_eq!(got, should_be); } } diff --git a/src/renderer/html_handlebars/helpers/navigation.rs b/src/renderer/html_handlebars/helpers/navigation.rs index 429e3dd3..5b8bfdda 100644 --- a/src/renderer/html_handlebars/helpers/navigation.rs +++ b/src/renderer/html_handlebars/helpers/navigation.rs @@ -4,6 +4,8 @@ use std::collections::BTreeMap; use serde_json; use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError, Renderable}; +use utils; + type StringMap = BTreeMap; /// Target for `find_chapter`. @@ -87,6 +89,13 @@ fn render( trace!("Creating BTreeMap to inject in context"); let mut context = BTreeMap::new(); + let base_path = rc.evaluate_absolute("path", false)? + .as_str() + .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? + .replace("\"", ""); + + context.insert("path_to_root".to_owned(), + json!(utils::fs::path_to_root(&base_path))); chapter .get("name") diff --git a/src/renderer/html_handlebars/helpers/toc.rs b/src/renderer/html_handlebars/helpers/toc.rs index f44ea2ac..174ac827 100644 --- a/src/renderer/html_handlebars/helpers/toc.rs +++ b/src/renderer/html_handlebars/helpers/toc.rs @@ -1,6 +1,8 @@ use std::path::Path; use std::collections::BTreeMap; +use utils; + use serde_json; use handlebars::{Handlebars, Helper, HelperDef, RenderContext, RenderError}; use pulldown_cmark::{html, Event, Parser, Tag}; @@ -77,6 +79,7 @@ impl HelperDef for RenderToc { .replace("\\", "/"); // Add link + rc.writer.write_all(&utils::fs::path_to_root(¤t).as_bytes())?; rc.writer.write_all(tmp.as_bytes())?; rc.writer.write_all(b"\"")?; diff --git a/src/theme/book.js b/src/theme/book.js index b0d89f33..521f1371 100644 --- a/src/theme/book.js +++ b/src/theme/book.js @@ -293,9 +293,9 @@ function playpen_text(playpen) { var themePopup = document.getElementById('theme-list'); var themeColorMetaTag = document.querySelector('meta[name="theme-color"]'); var stylesheets = { - ayuHighlight: document.querySelector("[href='ayu-highlight.css']"), - tomorrowNight: document.querySelector("[href='tomorrow-night.css']"), - highlight: document.querySelector("[href='highlight.css']"), + ayuHighlight: document.querySelector("[href$='ayu-highlight.css']"), + tomorrowNight: document.querySelector("[href$='tomorrow-night.css']"), + highlight: document.querySelector("[href$='highlight.css']"), }; function showThemes() { diff --git a/src/theme/index.hbs b/src/theme/index.hbs index 0e5fa009..45be723a 100644 --- a/src/theme/index.hbs +++ b/src/theme/index.hbs @@ -9,20 +9,18 @@ - - - + - + - - - + + + {{#each additional_css}} @@ -107,7 +105,7 @@

{{ book_title }}

@@ -144,13 +142,13 @@