diff --git a/Cargo.toml b/Cargo.toml index 6218d5f7..1c74008a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ ws = { version = "0.7", optional = true} error-chain = "0.11" [dev-dependencies] -pretty_assertions = "0.2.1" +pretty_assertions = "0.2" [features] default = ["output", "watch", "serve"] diff --git a/src/bin/build.rs b/src/bin/build.rs index 0fe950f0..6e311e51 100644 --- a/src/bin/build.rs +++ b/src/bin/build.rs @@ -24,9 +24,7 @@ pub fn execute(args: &ArgMatches) -> Result<()> { None => book, }; - if args.is_present("create") { - book.create_missing = true; - } + book.create_missing = args.is_present("create"); if args.is_present("curly-quotes") { book = book.with_curly_quotes(true); diff --git a/src/book/mod.rs b/src/book/mod.rs index 60b583dd..75319b02 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -13,7 +13,7 @@ use std::process::Command; use tempdir::TempDir; use {theme, utils}; -use renderer::{Renderer, HtmlHandlebars}; +use renderer::{HtmlHandlebars, Renderer}; use preprocess; use errors::*; @@ -23,7 +23,10 @@ use config::htmlconfig::HtmlConfig; use config::jsonconfig::JsonConfig; -/// A helper for managing the `Book`, its configuration, and the rendering +const STUB_SUMMARY_CONTENTS: &'static str = "# Summary\n\n- [Chapter 1](./chapter_1.md)]"; +const STUB_CHAPTER_1: &'static str = "# Chapter 1\n"; + +/// A helper for managing the `Book`, its configuration, and the rendering /// process. pub struct MDBook { config: BookConfig, @@ -67,7 +70,6 @@ impl MDBook { /// [`set_dest()`](#method.set_dest) pub fn new>(root: P) -> MDBook { - let root = root.into(); if !root.exists() || !root.is_dir() { warn!("{:?} No directory with that name", root); @@ -114,8 +116,10 @@ impl MDBook { /// ``` pub fn iter(&self) -> BookItems { - self.content.as_ref().expect("Trying to iterate over a book before it is loaded. This is a bug") - .iter() + self.content + .as_ref() + .expect("Trying to iterate over a book before it is loaded. This is a bug") + .iter() } /// `init()` creates some boilerplate files and directories @@ -132,64 +136,73 @@ impl MDBook { /// It uses the paths given as source and output directories /// and adds a `SUMMARY.md` and a /// `chapter_1.md` to the source directory. - pub fn init(&mut self) -> Result<()> { - debug!("[fn]: init"); - { - let root = self.config.get_root(); - let dest = self.get_destination(); - let src = self.config.get_source(); + self.create_book_directories()?; + self.create_stub_files()?; - let necessary_folders = &[root, dest, src]; - - for folder in necessary_folders { - if !folder.exists() { - fs::create_dir_all(folder)?; - debug!("{} created", folder.display()); - } - } + self.parse_summary() + .chain_err(|| "Couldn't parse the SUMMARY.md file")?; - let summary = src.join("SUMMARY.md"); + debug!("[*]: init done"); + Ok(()) + } - if !summary.exists() { - debug!("[*]: Creating SUMMARY.md"); + fn create_book_directories(&self) -> Result<()> { + debug!("[*] Creating directories"); - let mut f = File::create(&summary)?; + let root = self.config.get_root(); + let dest = self.get_destination(); + let src = self.config.get_source(); - writeln!(f, "# Summary")?; - writeln!(f)?; - writeln!(f, "- [Chapter 1](./chapter_1.md)")?; - } + let necessary_folders = &[root, dest, src]; - let ch_1 = src.join("chapter_1.md"); - if !ch_1.exists() { - debug!("[*] Creating {}", ch_1.display()); - - let mut f = File::create(&ch_1)?; - writeln!(f, "# Chapter 1")?; + for folder in necessary_folders { + if !folder.exists() { + fs::create_dir_all(folder)?; + debug!("{} created", folder.display()); } } - // parse SUMMARY.md and load the newly created files into memory - self.parse_summary().chain_err(|| "Couldn't parse the SUMMARY.md file")?; + Ok(()) + } + + fn create_stub_files(&self) -> Result<()> { + debug!("[*] Creating stub files"); + + let src = self.config.get_source(); + let summary = src.join("SUMMARY.md"); + + if !summary.exists() { + debug!("[*]: Creating SUMMARY.md"); + let mut f = File::create(&summary)?; + writeln!(f, "{}", STUB_SUMMARY_CONTENTS)?; + } + + let ch_1 = src.join("chapter_1.md"); + if !ch_1.exists() { + debug!("[*] Creating {}", ch_1.display()); + + let mut f = File::create(&ch_1)?; + writeln!(f, "{}", STUB_CHAPTER_1)?; + } - debug!("[*]: init done"); Ok(()) } pub fn create_gitignore(&self) { let gitignore = self.get_gitignore(); - let destination = self.config.get_html_config() - .get_destination(); + let destination = self.config.get_html_config().get_destination(); - // Check that the gitignore does not extist and that the destination path begins with the root path - // We assume tha if it does begin with the root path it is contained within. This assumption - // will not hold true for paths containing double dots to go back up e.g. `root/../destination` + // Check that the gitignore does not exist and that the destination path + // begins with the root path + // We assume tha if it does begin with the root path it is contained within. + // This assumption + // will not hold true for paths containing double dots to go back up e.g. + // `root/../destination` if !gitignore.exists() && destination.starts_with(self.config.get_root()) { - let relative = destination .strip_prefix(self.config.get_root()) .expect("Could not strip the root prefix, path is not relative to root") @@ -223,7 +236,6 @@ impl MDBook { self.renderer.render(self) } - pub fn get_gitignore(&self) -> PathBuf { self.config.get_root().join(".gitignore") } @@ -265,8 +277,7 @@ impl MDBook { } pub fn write_file>(&self, filename: P, content: &[u8]) -> Result<()> { - let path = self.get_destination() - .join(filename); + let path = self.get_destination().join(filename); utils::fs::create_file(&path)? .write_all(content) @@ -279,7 +290,6 @@ impl MDBook { /// The root directory is the one specified when creating a new `MDBook` pub fn read_config(mut self) -> Result { - let toml = self.get_root().join("book.toml"); let json = self.get_root().join("book.json"); @@ -335,31 +345,33 @@ impl MDBook { pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> { // read in the chapters self.parse_summary().chain_err(|| "Couldn't parse summary")?; - let library_args: Vec<&str> = (0..library_paths.len()).map(|_| "-L") - .zip(library_paths.into_iter()) - .flat_map(|x| vec![x.0, x.1]) - .collect(); + let library_args: Vec<&str> = (0..library_paths.len()) + .map(|_| "-L") + .zip(library_paths.into_iter()) + .flat_map(|x| vec![x.0, x.1]) + .collect(); let temp_dir = TempDir::new("mdbook")?; for item in self.iter() { - if let BookItem::Chapter(ref ch) = *item { if ch.path != PathBuf::new() { - let path = self.get_source().join(&ch.path); - let base = path.parent().ok_or_else( - || String::from("Invalid bookitem path!"), - )?; + let base = path.parent() + .ok_or_else(|| String::from("Invalid bookitem path!"))?; let content = utils::fs::file_to_string(&path)?; // Parse and expand links let content = preprocess::links::replace_all(&content, base)?; println!("[*]: Testing file: {:?}", path); - //write preprocessed file to tempdir + // write preprocessed file to tempdir let path = temp_dir.path().join(&ch.path); let mut tmpf = utils::fs::create_file(&path)?; tmpf.write_all(content.as_bytes())?; - let output = Command::new("rustdoc").arg(&path).arg("--test").args(&library_args).output()?; + let output = Command::new("rustdoc") + .arg(&path) + .arg("--test") + .args(&library_args) + .output()?; if !output.status.success() { bail!(ErrorKind::Subprocess("Rustdoc returned an error".to_string(), output)); @@ -377,15 +389,15 @@ impl MDBook { pub fn with_destination>(mut self, destination: T) -> Self { let root = self.config.get_root().to_owned(); - self.config.get_mut_html_config() + self.config + .get_mut_html_config() .set_destination(&root, &destination.into()); self } pub fn get_destination(&self) -> &Path { - self.config.get_html_config() - .get_destination() + self.config.get_html_config().get_destination() } pub fn with_source>(mut self, source: T) -> Self { diff --git a/src/book/summary.rs b/src/book/summary.rs index 009b33e1..79f4e0f3 100644 --- a/src/book/summary.rs +++ b/src/book/summary.rs @@ -322,6 +322,11 @@ impl<'a> SummaryParser<'a> { let section_number = self.push_numbered_section(SummaryItem::Link(it)); trace!("[*] Section number is {}", section_number); }, + Event::End(Tag::Rule) => { + debug!("[*] Found a numbered chapter separator"); + self.summary.numbered_chapters.push(SummaryItem::Separator); + self.state = State::NumberedChapters(0); + }, Event::Start(Tag::List(_)) => { if let State::NumberedChapters(n) = self.state { self.state = State::NumberedChapters(n + 1);