Add `--auto-summary` option.

Add a `Summary::from_source` function to generate the book's
summary from the sources directory structure.
This commit is contained in:
Timothée Haudebourg 2021-06-25 21:51:43 +02:00
parent ffa8284743
commit f767167808
16 changed files with 266 additions and 98 deletions

View File

@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::collections::VecDeque;
use std::fmt::{self, Display, Formatter};
use std::fs::{self, File};
@ -11,6 +12,8 @@ use crate::errors::*;
/// Load a book into memory from its `src/` directory.
pub fn load_book<P: AsRef<Path>>(src_dir: P, cfg: &BuildConfig) -> Result<Book> {
let src_dir = src_dir.as_ref();
let summary = if !cfg.auto_summary {
let summary_md = src_dir.join("SUMMARY.md");
let mut summary_content = String::new();
@ -22,9 +25,15 @@ pub fn load_book<P: AsRef<Path>>(src_dir: P, cfg: &BuildConfig) -> Result<Book>
.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")?;
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<P: AsRef<Path>>(
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<P: AsRef<Path>>(
.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<P: AsRef<Path>>(
.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<P: AsRef<Path>>(
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()
})],

View File

@ -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);

View File

@ -47,7 +47,10 @@ pub struct MDBook {
impl MDBook {
/// Load a book from its root directory on disk.
pub fn load<P: Into<PathBuf>>(book_root: P) -> Result<MDBook> {
///
/// If `auto_summary` is set, the book's summary is automatically generated
/// from the root directory structure.
pub fn load<P: Into<PathBuf>>(book_root: P, auto_summary: bool) -> Result<MDBook> {
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) => {},

View File

@ -66,6 +66,91 @@ pub struct Summary {
pub suffix_chapters: Vec<SummaryItem>,
}
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<P: AsRef<Path>>(src_dir: P) -> std::io::Result<Summary> {
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<P: AsRef<Path>>(dir: P) -> std::io::Result<Vec<SummaryItem>> {
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<String>,
/// The location of the chapter's source file, taking the book's `src`
/// directory as the root.
pub location: Option<PathBuf>,
@ -87,7 +172,17 @@ impl Link {
/// Create a new link with no nested items.
pub fn new<S: Into<String>, P: AsRef<Path>>(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<P: AsRef<Path>>(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,

View File

@ -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();

View File

@ -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(),

View File

@ -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()
});

View File

@ -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();

View File

@ -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()
});

View File

@ -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 {

View File

@ -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");
//! ```

View File

@ -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]

View File

@ -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();

View File

@ -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"
);
}

View File

@ -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<Document> {
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<PathBuf, String> = 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());

View File

@ -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());
}