diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 8aebbce8..b933a359 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -116,7 +116,7 @@ impl HtmlHandlebars { if ctx.is_index { ctx.data.insert("path".to_owned(), json!("index.md")); ctx.data.insert("path_to_root".to_owned(), json!("")); - ctx.data.insert("is_index".to_owned(), json!("true")); + ctx.data.insert("is_index".to_owned(), json!(true)); let rendered_index = ctx.handlebars.render("index", &ctx.data)?; let rendered_index = self.post_process(rendered_index, &ctx.html_config.playground, ctx.edition); diff --git a/src/renderer/html_handlebars/helpers/toc.rs b/src/renderer/html_handlebars/helpers/toc.rs index 6ae62aa7..0884d30a 100644 --- a/src/renderer/html_handlebars/helpers/toc.rs +++ b/src/renderer/html_handlebars/helpers/toc.rs @@ -57,6 +57,11 @@ impl HelperDef for RenderToc { out.write("
    ")?; let mut current_level = 1; + // The "index" page, which has this attribute set, is supposed to alias the first chapter in + // the book, i.e. the first link. There seems to be no easy way to determine which chapter + // the "index" is aliasing from within the renderer, so this is used instead to force the + // first link to be active. See further below. + let mut is_first_chapter = ctx.data().get("is_index").is_some(); for item in chapters { // Spacer @@ -130,7 +135,8 @@ impl HelperDef for RenderToc { out.write(&tmp)?; out.write("\"")?; - if path == ¤t_path { + if path == ¤t_path || is_first_chapter { + is_first_chapter = false; out.write(" class=\"active\"")?; } diff --git a/tests/rendered_output.rs b/tests/rendered_output.rs index 24d3427b..9750a35e 100644 --- a/tests/rendered_output.rs +++ b/tests/rendered_output.rs @@ -15,7 +15,7 @@ use select::predicate::{Class, Name, Predicate}; use std::collections::HashMap; use std::ffi::OsStr; use std::fs; -use std::io::{Read, Write}; +use std::io::Write; use std::path::{Component, Path, PathBuf}; use std::str::FromStr; use tempfile::Builder as TempFileBuilder; @@ -476,23 +476,10 @@ fn first_chapter_is_copied_as_index_even_if_not_first_elem() { let md = MDBook::load_with_config(temp.path(), cfg).unwrap(); md.build().unwrap(); - // In theory, just reading the entire files into memory and comparing is sufficient for *testing*, - // but since the files are temporary and get deleted when the test completes, we'll want to print - // the differences on failure. - // We could invoke `diff` on the files on failure, but that may not be portable (hi, Windows...) - // so we'll do the job ourselves—potentially a bit sloppily, but that can always be piped into - // `diff` manually afterwards. - let book_path = temp.path().join("book"); - let read_file = |path: &str| { - let mut buf = String::new(); - fs::File::open(book_path.join(path)) - .with_context(|| format!("Failed to read {}", path)) - .unwrap() - .read_to_string(&mut buf) - .unwrap(); - buf - }; - pretty_assertions::assert_eq!(read_file("chapter_1.html"), read_file("index.html")); + let root = temp.path().join("book"); + let chapter = fs::read_to_string(root.join("chapter_1.html")).expect("read chapter 1"); + let index = fs::read_to_string(root.join("index.html")).expect("read index"); + pretty_assertions::assert_eq!(chapter, index); } #[test]