From f767167808b10149c5523c5a6dc9a1d869c67567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Haudebourg?= Date: Fri, 25 Jun 2021 21:51:43 +0200 Subject: [PATCH] Add `--auto-summary` option. Add a `Summary::from_source` function to generate the book's summary from the sources directory structure. --- src/book/book.rs | 73 ++++++++++---- src/book/init.rs | 2 +- src/book/mod.rs | 11 ++- src/book/summary.rs | 177 +++++++++++++++++++++++++++------- src/cmd/build.rs | 6 +- src/cmd/clean.rs | 6 +- src/cmd/serve.rs | 8 +- src/cmd/test.rs | 6 +- src/cmd/watch.rs | 8 +- src/config.rs | 5 + src/lib.rs | 2 +- src/preprocess/cmd.rs | 2 +- tests/custom_preprocessors.rs | 4 +- tests/init.rs | 2 +- tests/rendered_output.rs | 48 ++++----- tests/testing.rs | 4 +- 16 files changed, 266 insertions(+), 98 deletions(-) diff --git a/src/book/book.rs b/src/book/book.rs index da2a0a3c..1e45b448 100644 --- a/src/book/book.rs +++ b/src/book/book.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::collections::VecDeque; use std::fmt::{self, Display, Formatter}; use std::fs::{self, File}; @@ -11,19 +12,27 @@ use crate::errors::*; /// Load a book into memory from its `src/` directory. pub fn load_book>(src_dir: P, cfg: &BuildConfig) -> Result { let src_dir = src_dir.as_ref(); - let summary_md = src_dir.join("SUMMARY.md"); - let mut summary_content = String::new(); - File::open(&summary_md) - .with_context(|| format!("Couldn't open SUMMARY.md in {:?} directory", src_dir))? - .read_to_string(&mut summary_content)?; + let summary = if !cfg.auto_summary { + let summary_md = src_dir.join("SUMMARY.md"); - let summary = parse_summary(&summary_content) - .with_context(|| format!("Summary parsing failed for file={:?}", summary_md))?; + let mut summary_content = String::new(); + File::open(&summary_md) + .with_context(|| format!("Couldn't open SUMMARY.md in {:?} directory", src_dir))? + .read_to_string(&mut summary_content)?; - if cfg.create_missing { - create_missing(src_dir, &summary).with_context(|| "Unable to create missing chapters")?; - } + let summary = parse_summary(&summary_content) + .with_context(|| format!("Summary parsing failed for file={:?}", summary_md))?; + + if cfg.create_missing { + create_missing(src_dir, &summary) + .with_context(|| "Unable to create missing chapters")?; + } + + summary + } else { + Summary::from_sources(src_dir)? + }; load_book_from_disk(&summary, src_dir) } @@ -53,7 +62,10 @@ fn create_missing(src_dir: &Path, summary: &Summary) -> Result<()> { let mut f = File::create(&filename).with_context(|| { format!("Unable to create missing file: {}", filename.display()) })?; - writeln!(f, "# {}", link.name)?; + + if let Some(name) = &link.name { + writeln!(f, "# {}", name)?; + } } } @@ -253,7 +265,7 @@ fn load_chapter>( let src_dir = src_dir.as_ref(); let mut ch = if let Some(ref link_location) = link.location { - debug!("Loading {} ({})", link.name, link_location.display()); + debug!("Loading {}", link); let location = if link_location.is_absolute() { link_location.clone() @@ -265,9 +277,8 @@ fn load_chapter>( .with_context(|| format!("Chapter file not found, {}", link_location.display()))?; let mut content = String::new(); - f.read_to_string(&mut content).with_context(|| { - format!("Unable to read \"{}\" ({})", link.name, location.display()) - })?; + f.read_to_string(&mut content) + .with_context(|| format!("Unable to read {}", link))?; if content.as_bytes().starts_with(b"\xef\xbb\xbf") { content.replace_range(..3, ""); @@ -277,16 +288,21 @@ fn load_chapter>( .strip_prefix(&src_dir) .expect("Chapters are always inside a book"); - Chapter::new(&link.name, content, stripped, parent_names.clone()) + let name = match &link.name { + Some(name) => Cow::Borrowed(name.as_str()), + None => Cow::Owned(read_chapter_title(&content)), + }; + + Chapter::new(&name, content, stripped, parent_names.clone()) } else { - Chapter::new_draft(&link.name, parent_names.clone()) + Chapter::new_draft(link.name.as_ref().unwrap().as_str(), parent_names.clone()) }; let mut sub_item_parents = parent_names; ch.number = link.number.clone(); - sub_item_parents.push(link.name.clone()); + sub_item_parents.push(ch.name.clone()); let sub_items = link .nested_items .iter() @@ -298,6 +314,23 @@ fn load_chapter>( Ok(ch) } +/// Read a chapter title from its source file. +fn read_chapter_title(content: &str) -> String { + let mut pulldown_parser = pulldown_cmark::Parser::new(content); + + while let Some(event) = pulldown_parser.next() { + if let pulldown_cmark::Event::Start(pulldown_cmark::Tag::Heading(1)) = event { + if let Some(pulldown_cmark::Event::Text(title)) = pulldown_parser.next() { + return title.to_string(); + } else { + break; + } + } + } + + "Untitled".to_string() +} + /// A depth-first iterator over the items in a book. /// /// # Note @@ -604,7 +637,7 @@ And here is some \ let (_, temp) = dummy_link(); let summary = Summary { numbered_chapters: vec![SummaryItem::Link(Link { - name: String::from("Empty"), + name: Some(String::from("Empty")), location: Some(PathBuf::from("")), ..Default::default() })], @@ -624,7 +657,7 @@ And here is some \ let summary = Summary { numbered_chapters: vec![SummaryItem::Link(Link { - name: String::from("nested"), + name: Some(String::from("nested")), location: Some(dir), ..Default::default() })], diff --git a/src/book/init.rs b/src/book/init.rs index 264c113d..07c60fa4 100644 --- a/src/book/init.rs +++ b/src/book/init.rs @@ -81,7 +81,7 @@ impl BookBuilder { self.write_book_toml()?; - match MDBook::load(&self.root) { + match MDBook::load(&self.root, false) { Ok(book) => Ok(book), Err(e) => { error!("{}", e); diff --git a/src/book/mod.rs b/src/book/mod.rs index df140797..50e05ba7 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -47,7 +47,10 @@ pub struct MDBook { impl MDBook { /// Load a book from its root directory on disk. - pub fn load>(book_root: P) -> Result { + /// + /// If `auto_summary` is set, the book's summary is automatically generated + /// from the root directory structure. + pub fn load>(book_root: P, auto_summary: bool) -> Result { let book_root = book_root.into(); let config_location = book_root.join("book.toml"); @@ -68,6 +71,10 @@ impl MDBook { Config::default() }; + if auto_summary { + config.build.auto_summary = true; + } + config.update_from_env(); if log_enabled!(log::Level::Trace) { @@ -128,7 +135,7 @@ impl MDBook { /// ```no_run /// # use mdbook::MDBook; /// # use mdbook::book::BookItem; - /// # let book = MDBook::load("mybook").unwrap(); + /// # let book = MDBook::load("mybook", false).unwrap(); /// for item in book.iter() { /// match *item { /// BookItem::Chapter(ref chapter) => {}, diff --git a/src/book/summary.rs b/src/book/summary.rs index 981e1079..ca3224e7 100644 --- a/src/book/summary.rs +++ b/src/book/summary.rs @@ -66,6 +66,91 @@ pub struct Summary { pub suffix_chapters: Vec, } +impl Summary { + /// Create a summary from the book's sources directory. + /// + /// Each file is imported as a book chapter. + /// Each folder is imported as a book chapter and must contain + /// a `README.md` file defining the chapter's title and content. + /// Any file/folder inside the directory is imported as a sub-chapter. + /// The file/folder name is used to compose the chapter's link. + /// + /// Chapters are added to the book in alphabetical order, using the file/folder name. + pub fn from_sources>(src_dir: P) -> std::io::Result { + let mut summary = Summary { + title: None, + prefix_chapters: Vec::new(), + numbered_chapters: Vec::new(), + suffix_chapters: Vec::new(), + }; + + // Checks if the given path must be considered. + fn include_path(path: &Path) -> bool { + if let Some(name) = path.file_name() { + if name == "README.md" || name == "SUMMARY.md" { + return false; + } + } + + true + } + + // Read a directory recursively and return the found summary items. + fn read_dir>(dir: P) -> std::io::Result> { + let mut links = Vec::new(); + + for entry in std::fs::read_dir(dir)? { + let entry = entry?; + let entry_path = entry.path(); + + if include_path(&entry_path) { + let metadata = std::fs::metadata(&entry_path)?; + + if metadata.is_file() { + links.push(Link::new_unnamed(entry_path)) + } else { + let chapter_path = entry_path.join("README.md"); + if chapter_path.is_file() { + let mut link = Link::new_unnamed(chapter_path); + link.nested_items = read_dir(entry_path)?; + links.push(link) + } + } + } + } + + // Items are sorted by name. + links.sort_by(|a, b| { + a.location + .as_ref() + .unwrap() + .cmp(b.location.as_ref().unwrap()) + }); + + Ok(links.into_iter().map(SummaryItem::Link).collect()) + } + + // Associate the correct section number to each summary item. + fn number_items(items: &mut [SummaryItem], number: &[u32]) { + let mut n = 1; + for item in items { + if let SummaryItem::Link(link) = item { + let mut entry_number = number.to_vec(); + entry_number.push(n); + n += 1; + number_items(&mut link.nested_items, &entry_number); + link.number = Some(SectionNumber(entry_number)) + } + } + } + + summary.numbered_chapters = read_dir(src_dir)?; + number_items(&mut summary.numbered_chapters, &[]); + + Ok(summary) + } +} + /// A struct representing an entry in the `SUMMARY.md`, possibly with nested /// entries. /// @@ -73,7 +158,7 @@ pub struct Summary { #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Link { /// The name of the chapter. - pub name: String, + pub name: Option, /// The location of the chapter's source file, taking the book's `src` /// directory as the root. pub location: Option, @@ -87,7 +172,17 @@ impl Link { /// Create a new link with no nested items. pub fn new, P: AsRef>(name: S, location: P) -> Link { Link { - name: name.into(), + name: Some(name.into()), + location: Some(location.as_ref().to_path_buf()), + number: None, + nested_items: Vec::new(), + } + } + + /// Create a new unnamed link with no nested items. + pub fn new_unnamed>(location: P) -> Link { + Link { + name: None, location: Some(location.as_ref().to_path_buf()), number: None, nested_items: Vec::new(), @@ -98,7 +193,7 @@ impl Link { impl Default for Link { fn default() -> Self { Link { - name: String::new(), + name: None, location: Some(PathBuf::new()), number: None, nested_items: Vec::new(), @@ -106,6 +201,22 @@ impl Default for Link { } } +impl fmt::Display for Link { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.name { + Some(name) => write!(f, "\"{}\"", name)?, + None => write!(f, "unnamed chapter")?, + } + + match &self.location { + Some(location) => write!(f, " ({})", location.display())?, + None => write!(f, " [draft]")?, + } + + Ok(()) + } +} + /// An item in `SUMMARY.md` which could be either a separator or a `Link`. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum SummaryItem { @@ -344,7 +455,7 @@ impl<'a> SummaryParser<'a> { }; Link { - name, + name: Some(name), location: path, number: None, nested_items: Vec::new(), @@ -489,15 +600,7 @@ impl<'a> SummaryParser<'a> { let mut number = parent.clone(); number.0.push(num_existing_items as u32 + 1); - trace!( - "Found chapter: {} {} ({})", - number, - link.name, - link.location - .as_ref() - .map(|p| p.to_str().unwrap_or("")) - .unwrap_or("[draft]") - ); + trace!("Found chapter: {} {}", number, link); link.number = Some(number); @@ -676,12 +779,12 @@ mod tests { let should_be = vec![ SummaryItem::Link(Link { - name: String::from("First"), + name: Some(String::from("First")), location: Some(PathBuf::from("./first.md")), ..Default::default() }), SummaryItem::Link(Link { - name: String::from("Second"), + name: Some(String::from("Second")), location: Some(PathBuf::from("./second.md")), ..Default::default() }), @@ -717,7 +820,7 @@ mod tests { fn parse_a_link() { let src = "[First](./first.md)"; let should_be = Link { - name: String::from("First"), + name: Some(String::from("First")), location: Some(PathBuf::from("./first.md")), ..Default::default() }; @@ -738,7 +841,7 @@ mod tests { fn parse_a_numbered_chapter() { let src = "- [First](./first.md)\n"; let link = Link { - name: String::from("First"), + name: Some(String::from("First")), location: Some(PathBuf::from("./first.md")), number: Some(SectionNumber(vec![1])), ..Default::default() @@ -759,18 +862,18 @@ mod tests { let should_be = vec![ SummaryItem::Link(Link { - name: String::from("First"), + name: Some(String::from("First")), location: Some(PathBuf::from("./first.md")), number: Some(SectionNumber(vec![1])), nested_items: vec![SummaryItem::Link(Link { - name: String::from("Nested"), + name: Some(String::from("Nested")), location: Some(PathBuf::from("./nested.md")), number: Some(SectionNumber(vec![1, 1])), nested_items: Vec::new(), })], }), SummaryItem::Link(Link { - name: String::from("Second"), + name: Some(String::from("Second")), location: Some(PathBuf::from("./second.md")), number: Some(SectionNumber(vec![2])), nested_items: Vec::new(), @@ -791,13 +894,13 @@ mod tests { let should_be = vec![ SummaryItem::Link(Link { - name: String::from("First"), + name: Some(String::from("First")), location: Some(PathBuf::from("./first.md")), number: Some(SectionNumber(vec![1])), nested_items: Vec::new(), }), SummaryItem::Link(Link { - name: String::from("Second"), + name: Some(String::from("Second")), location: Some(PathBuf::from("./second.md")), number: Some(SectionNumber(vec![2])), nested_items: Vec::new(), @@ -819,24 +922,24 @@ mod tests { let should_be = vec![ SummaryItem::Link(Link { - name: String::from("First"), + name: Some(String::from("First")), location: Some(PathBuf::from("./first.md")), number: Some(SectionNumber(vec![1])), nested_items: Vec::new(), }), SummaryItem::Link(Link { - name: String::from("Second"), + name: Some(String::from("Second")), location: Some(PathBuf::from("./second.md")), number: Some(SectionNumber(vec![2])), nested_items: Vec::new(), }), SummaryItem::PartTitle(String::from("Title 2")), SummaryItem::Link(Link { - name: String::from("Third"), + name: Some(String::from("Third")), location: Some(PathBuf::from("./third.md")), number: Some(SectionNumber(vec![3])), nested_items: vec![SummaryItem::Link(Link { - name: String::from("Fourth"), + name: Some(String::from("Fourth")), location: Some(PathBuf::from("./fourth.md")), number: Some(SectionNumber(vec![3, 1])), nested_items: Vec::new(), @@ -859,13 +962,13 @@ mod tests { let src = "- [First](./first.md)\n\n## Subheading\n\n- [Second](./second.md)\n"; let should_be = vec![ SummaryItem::Link(Link { - name: String::from("First"), + name: Some(String::from("First")), location: Some(PathBuf::from("./first.md")), number: Some(SectionNumber(vec![1])), nested_items: Vec::new(), }), SummaryItem::Link(Link { - name: String::from("Second"), + name: Some(String::from("Second")), location: Some(PathBuf::from("./second.md")), number: Some(SectionNumber(vec![2])), nested_items: Vec::new(), @@ -887,7 +990,7 @@ mod tests { let got = parser.parse_numbered(&mut 0, &mut SectionNumber::default()); let should_be = vec![SummaryItem::Link(Link { - name: String::from("Empty"), + name: Some(String::from("Empty")), location: None, number: Some(SectionNumber(vec![1])), nested_items: Vec::new(), @@ -905,21 +1008,21 @@ mod tests { "- [First](./first.md)\n---\n- [Second](./second.md)\n---\n- [Third](./third.md)\n"; let should_be = vec![ SummaryItem::Link(Link { - name: String::from("First"), + name: Some(String::from("First")), location: Some(PathBuf::from("./first.md")), number: Some(SectionNumber(vec![1])), nested_items: Vec::new(), }), SummaryItem::Separator, SummaryItem::Link(Link { - name: String::from("Second"), + name: Some(String::from("Second")), location: Some(PathBuf::from("./second.md")), number: Some(SectionNumber(vec![2])), nested_items: Vec::new(), }), SummaryItem::Separator, SummaryItem::Link(Link { - name: String::from("Third"), + name: Some(String::from("Third")), location: Some(PathBuf::from("./third.md")), number: Some(SectionNumber(vec![3])), nested_items: Vec::new(), @@ -940,7 +1043,7 @@ mod tests { fn add_space_for_multi_line_chapter_names() { let src = "- [Chapter\ntitle](./chapter.md)"; let should_be = vec![SummaryItem::Link(Link { - name: String::from("Chapter title"), + name: Some(String::from("Chapter title")), location: Some(PathBuf::from("./chapter.md")), number: Some(SectionNumber(vec![1])), nested_items: Vec::new(), @@ -959,13 +1062,13 @@ mod tests { let src = "- [test1](./test%20link1.md)\n- [test2](<./test link2.md>)"; let should_be = vec![ SummaryItem::Link(Link { - name: String::from("test1"), + name: Some(String::from("test1")), location: Some(PathBuf::from("./test link1.md")), number: Some(SectionNumber(vec![1])), nested_items: Vec::new(), }), SummaryItem::Link(Link { - name: String::from("test2"), + name: Some(String::from("test2")), location: Some(PathBuf::from("./test link2.md")), number: Some(SectionNumber(vec![2])), nested_items: Vec::new(), @@ -1030,7 +1133,7 @@ mod tests { let new_affix_item = |name, location| { SummaryItem::Link(Link { - name: String::from(name), + name: Some(String::from(name)), location: Some(PathBuf::from(location)), ..Default::default() }) @@ -1048,7 +1151,7 @@ mod tests { let new_numbered_item = |name, location, numbers: &[u32], nested_items| { SummaryItem::Link(Link { - name: String::from(name), + name: Some(String::from(name)), location: Some(PathBuf::from(location)), number: Some(SectionNumber(numbers.to_vec())), nested_items, diff --git a/src/cmd/build.rs b/src/cmd/build.rs index d1c66302..1cd8de6f 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -17,12 +17,16 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { (Defaults to the Current Directory when omitted)'", ) .arg_from_usage("-o, --open 'Opens the compiled book in a web browser'") + .arg_from_usage( + "--auto-summary 'Automatically generate the book's summary{n}\ + from the sources directory structure.'", + ) } // Build command implementation pub fn execute(args: &ArgMatches) -> Result<()> { let book_dir = get_book_dir(args); - let mut book = MDBook::load(&book_dir)?; + let mut book = MDBook::load(&book_dir, args.is_present("auto-summary"))?; if let Some(dest_dir) = args.value_of("dest-dir") { book.config.build.build_dir = dest_dir.into(); diff --git a/src/cmd/clean.rs b/src/cmd/clean.rs index b58f937e..34a22638 100644 --- a/src/cmd/clean.rs +++ b/src/cmd/clean.rs @@ -18,12 +18,16 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { "[dir] 'Root directory for the book{n}\ (Defaults to the Current Directory when omitted)'", ) + .arg_from_usage( + "--auto-summary 'Automatically generate the book's summary{n}\ + from the sources directory structure.'", + ) } // Clean command implementation pub fn execute(args: &ArgMatches) -> mdbook::errors::Result<()> { let book_dir = get_book_dir(args); - let book = MDBook::load(&book_dir)?; + let book = MDBook::load(&book_dir, args.is_present("auto-summary"))?; let dir_to_remove = match args.value_of("dest-dir") { Some(dest_dir) => dest_dir.into(), diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index c5394f8a..6165ca3f 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -49,12 +49,16 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { .help("Port to use for HTTP connections"), ) .arg_from_usage("-o, --open 'Opens the book server in a web browser'") + .arg_from_usage( + "--auto-summary 'Automatically generate the book's summary{n}\ + from the sources directory structure.'", + ) } // Serve command implementation pub fn execute(args: &ArgMatches) -> Result<()> { let book_dir = get_book_dir(args); - let mut book = MDBook::load(&book_dir)?; + let mut book = MDBook::load(&book_dir, args.is_present("auto-summary"))?; let port = args.value_of("port").unwrap(); let hostname = args.value_of("hostname").unwrap(); @@ -110,7 +114,7 @@ pub fn execute(args: &ArgMatches) -> Result<()> { info!("Building book..."); // FIXME: This area is really ugly because we need to re-set livereload :( - let result = MDBook::load(&book_dir).and_then(|mut b| { + let result = MDBook::load(&book_dir, args.is_present("auto-summary")).and_then(|mut b| { update_config(&mut b); b.build() }); diff --git a/src/cmd/test.rs b/src/cmd/test.rs index f6d97aa6..78b87850 100644 --- a/src/cmd/test.rs +++ b/src/cmd/test.rs @@ -25,6 +25,10 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { .multiple(true) .empty_values(false) .help("A comma-separated list of directories to add to {n}the crate search path when building tests")) + .arg_from_usage( + "--auto-summary 'Automatically generate the book's summary{n}\ + from the sources directory structure.'" + ) } // test command implementation @@ -34,7 +38,7 @@ pub fn execute(args: &ArgMatches) -> Result<()> { .map(std::iter::Iterator::collect) .unwrap_or_default(); let book_dir = get_book_dir(args); - let mut book = MDBook::load(&book_dir)?; + let mut book = MDBook::load(&book_dir, args.is_present("auto-summary"))?; if let Some(dest_dir) = args.value_of("dest-dir") { book.config.build.build_dir = dest_dir.into(); diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs index b27516b0..411dccd4 100644 --- a/src/cmd/watch.rs +++ b/src/cmd/watch.rs @@ -23,12 +23,16 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { (Defaults to the Current Directory when omitted)'", ) .arg_from_usage("-o, --open 'Open the compiled book in a web browser'") + .arg_from_usage( + "--auto-summary 'Automatically generate the book's summary{n}\ + from the sources directory structure.'", + ) } // Watch command implementation pub fn execute(args: &ArgMatches) -> Result<()> { let book_dir = get_book_dir(args); - let mut book = MDBook::load(&book_dir)?; + let mut book = MDBook::load(&book_dir, args.is_present("auto-summary"))?; let update_config = |book: &mut MDBook| { if let Some(dest_dir) = args.value_of("dest-dir") { @@ -44,7 +48,7 @@ pub fn execute(args: &ArgMatches) -> Result<()> { trigger_on_change(&book, |paths, book_dir| { info!("Files changed: {:?}\nBuilding book...\n", paths); - let result = MDBook::load(&book_dir).and_then(|mut b| { + let result = MDBook::load(&book_dir, args.is_present("auto-summary")).and_then(|mut b| { update_config(&mut b); b.build() }); diff --git a/src/config.rs b/src/config.rs index bf4aabbb..69123a5e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -444,6 +444,8 @@ pub struct BuildConfig { /// Should the default preprocessors always be used when they are /// compatible with the renderer? pub use_default_preprocessors: bool, + /// Automatically build the book's summary from the directory structure. + pub auto_summary: bool, } impl Default for BuildConfig { @@ -452,6 +454,7 @@ impl Default for BuildConfig { build_dir: PathBuf::from("book"), create_missing: true, use_default_preprocessors: true, + auto_summary: false, } } } @@ -769,6 +772,7 @@ mod tests { build_dir: PathBuf::from("outputs"), create_missing: false, use_default_preprocessors: true, + auto_summary: false, }; let rust_should_be = RustConfig { edition: None }; let playground_should_be = Playground { @@ -962,6 +966,7 @@ mod tests { build_dir: PathBuf::from("my-book"), create_missing: true, use_default_preprocessors: true, + auto_summary: false, }; let html_should_be = HtmlConfig { diff --git a/src/lib.rs b/src/lib.rs index 82d9b6f7..cc812735 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,7 @@ //! //! let root_dir = "/path/to/book/root"; //! -//! let mut md = MDBook::load(root_dir) +//! let mut md = MDBook::load(root_dir, false) //! .expect("Unable to load the book"); //! md.build().expect("Building failed"); //! ``` diff --git a/src/preprocess/cmd.rs b/src/preprocess/cmd.rs index c47fd5d2..63031191 100644 --- a/src/preprocess/cmd.rs +++ b/src/preprocess/cmd.rs @@ -183,7 +183,7 @@ mod tests { fn guide() -> MDBook { let example = Path::new(env!("CARGO_MANIFEST_DIR")).join("guide"); - MDBook::load(example).unwrap() + MDBook::load(example, false).unwrap() } #[test] diff --git a/tests/custom_preprocessors.rs b/tests/custom_preprocessors.rs index 8237602d..7e49a061 100644 --- a/tests/custom_preprocessors.rs +++ b/tests/custom_preprocessors.rs @@ -33,7 +33,7 @@ fn example_doesnt_support_not_supported() { fn ask_the_preprocessor_to_blow_up() { let dummy_book = DummyBook::new(); let temp = dummy_book.build().unwrap(); - let mut md = MDBook::load(temp.path()).unwrap(); + let mut md = MDBook::load(temp.path(), false).unwrap(); md.with_preprocessor(example()); md.config @@ -49,7 +49,7 @@ fn ask_the_preprocessor_to_blow_up() { fn process_the_dummy_book() { let dummy_book = DummyBook::new(); let temp = dummy_book.build().unwrap(); - let mut md = MDBook::load(temp.path()).unwrap(); + let mut md = MDBook::load(temp.path(), false).unwrap(); md.with_preprocessor(example()); md.build().unwrap(); diff --git a/tests/init.rs b/tests/init.rs index 4deb8401..eea9a8a9 100644 --- a/tests/init.rs +++ b/tests/init.rs @@ -95,7 +95,7 @@ fn run_mdbook_init_with_custom_book_and_src_locations() { let contents = fs::read_to_string(temp.path().join("book.toml")).unwrap(); assert_eq!( contents, - "[book]\nauthors = []\nlanguage = \"en\"\nmultilingual = false\nsrc = \"in\"\n\n[build]\nbuild-dir = \"out\"\ncreate-missing = true\nuse-default-preprocessors = true\n" + "[book]\nauthors = []\nlanguage = \"en\"\nmultilingual = false\nsrc = \"in\"\n\n[build]\nauto-summary = false\nbuild-dir = \"out\"\ncreate-missing = true\nuse-default-preprocessors = true\n" ); } diff --git a/tests/rendered_output.rs b/tests/rendered_output.rs index 5ec6e64b..77c887ed 100644 --- a/tests/rendered_output.rs +++ b/tests/rendered_output.rs @@ -42,7 +42,7 @@ const TOC_SECOND_LEVEL: &[&str] = &[ #[test] fn build_the_dummy_book() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); } @@ -50,7 +50,7 @@ fn build_the_dummy_book() { #[test] fn by_default_mdbook_generates_rendered_content_in_the_book_directory() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); assert!(!temp.path().join("book").exists()); md.build().unwrap(); @@ -63,7 +63,7 @@ fn by_default_mdbook_generates_rendered_content_in_the_book_directory() { #[test] fn make_sure_bottom_level_files_contain_links_to_chapters() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let dest = temp.path().join("book"); @@ -85,7 +85,7 @@ fn make_sure_bottom_level_files_contain_links_to_chapters() { #[test] fn check_correct_cross_links_in_nested_dir() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let first = temp.path().join("book").join("first"); @@ -117,7 +117,7 @@ fn check_correct_cross_links_in_nested_dir() { #[test] fn check_correct_relative_links_in_print_page() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let first = temp.path().join("book"); @@ -138,7 +138,7 @@ fn check_correct_relative_links_in_print_page() { #[test] fn rendered_code_has_playground_stuff() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let nested = temp.path().join("book/first/nested.html"); @@ -153,7 +153,7 @@ fn rendered_code_has_playground_stuff() { #[test] fn anchors_include_text_between_but_not_anchor_comments() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let nested = temp.path().join("book/first/nested.html"); @@ -167,7 +167,7 @@ fn anchors_include_text_between_but_not_anchor_comments() { #[test] fn rustdoc_include_hides_the_unspecified_part_of_the_file() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let nested = temp.path().join("book/first/nested.html"); @@ -191,7 +191,7 @@ fn chapter_content_appears_in_rendered_document() { ]; let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let destination = temp.path().join("book"); @@ -251,7 +251,7 @@ fn root_index_html() -> Result { let temp = DummyBook::new() .build() .with_context(|| "Couldn't create the dummy book")?; - MDBook::load(temp.path())? + MDBook::load(temp.path(), false)? .build() .with_context(|| "Book building failed")?; @@ -350,7 +350,7 @@ fn create_missing_file_with_config() { #[test] fn able_to_include_playground_files_in_chapters() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let second = temp.path().join("book/second.html"); @@ -368,7 +368,7 @@ fn able_to_include_playground_files_in_chapters() { #[test] fn able_to_include_files_in_chapters() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let includes = temp.path().join("book/first/includes.html"); @@ -386,7 +386,7 @@ fn able_to_include_files_in_chapters() { #[test] fn recursive_includes_are_capped() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let recursive = temp.path().join("book/first/recursive.html"); @@ -400,7 +400,7 @@ Around the world, around the world"]; fn example_book_can_build() { let example_book_dir = dummy_book::new_copy_of_example_book().unwrap(); - let md = MDBook::load(example_book_dir.path()).unwrap(); + let md = MDBook::load(example_book_dir.path(), false).unwrap(); md.build().unwrap(); } @@ -418,7 +418,7 @@ fn book_with_a_reserved_filename_does_not_build() { let mut summary_file = fs::File::create(summary_path).unwrap(); writeln!(summary_file, "[print](print.md)").unwrap(); - let md = MDBook::load(tmp_dir.path()).unwrap(); + let md = MDBook::load(tmp_dir.path(), false).unwrap(); let got = md.build(); assert!(got.is_err()); } @@ -457,7 +457,7 @@ fn theme_dir_overrides_work_correctly() { write_file(&theme_dir, "index.hbs", &index).unwrap(); - let md = MDBook::load(book_dir).unwrap(); + let md = MDBook::load(book_dir, false).unwrap(); md.build().unwrap(); let built_index = book_dir.join("book").join("index.html"); @@ -467,7 +467,7 @@ fn theme_dir_overrides_work_correctly() { #[test] fn no_index_for_print_html() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let print_html = temp.path().join("book/print.html"); @@ -480,7 +480,7 @@ fn no_index_for_print_html() { #[test] fn markdown_options() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let path = temp.path().join("book/first/markdown.html"); @@ -516,7 +516,7 @@ fn markdown_options() { #[test] fn redirects_are_emitted_correctly() { let temp = DummyBook::new().build().unwrap(); - let mut md = MDBook::load(temp.path()).unwrap(); + let mut md = MDBook::load(temp.path(), false).unwrap(); // override the "outputs.html.redirect" table let redirects: HashMap = vec![ @@ -555,7 +555,7 @@ fn edit_url_has_default_src_dir_edit_url() { write_file(temp.path(), "book.toml", book_toml.as_bytes()).unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let index_html = temp.path().join("book").join("index.html"); @@ -581,7 +581,7 @@ fn edit_url_has_configured_src_dir_edit_url() { write_file(temp.path(), "book.toml", book_toml.as_bytes()).unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let index_html = temp.path().join("book").join("index.html"); @@ -619,7 +619,7 @@ mod search { #[allow(clippy::float_cmp)] fn book_creates_reasonable_search_index() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let index = read_book_index(temp.path()); @@ -671,7 +671,7 @@ mod search { fn get_fixture() -> serde_json::Value { if GENERATE_FIXTURE { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let src = read_book_index(temp.path()); @@ -699,7 +699,7 @@ mod search { #[test] fn search_index_hasnt_changed_accidentally() { let temp = DummyBook::new().build().unwrap(); - let md = MDBook::load(temp.path()).unwrap(); + let md = MDBook::load(temp.path(), false).unwrap(); md.build().unwrap(); let book_index = read_book_index(temp.path()); diff --git a/tests/testing.rs b/tests/testing.rs index 2b2c0fd0..0e750bc7 100644 --- a/tests/testing.rs +++ b/tests/testing.rs @@ -7,7 +7,7 @@ use mdbook::MDBook; #[test] fn mdbook_can_correctly_test_a_passing_book() { let temp = DummyBook::new().with_passing_test(true).build().unwrap(); - let mut md = MDBook::load(temp.path()).unwrap(); + let mut md = MDBook::load(temp.path(), false).unwrap(); let result = md.test(vec![]); assert!( @@ -20,7 +20,7 @@ fn mdbook_can_correctly_test_a_passing_book() { #[test] fn mdbook_detects_book_with_failing_tests() { let temp = DummyBook::new().with_passing_test(false).build().unwrap(); - let mut md = MDBook::load(temp.path()).unwrap(); + let mut md = MDBook::load(temp.path(), false).unwrap(); assert!(md.test(vec![]).is_err()); }