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]