diff --git a/build.rs b/build.rs index 261a7f2e..0eb63c7b 100644 --- a/build.rs +++ b/build.rs @@ -32,26 +32,23 @@ error_chain!{ } fn program_exists(program: &str) -> Result<()> { - execs::cmd(program) - .arg("-v") - .output() - .chain_err(|| format!("Please install '{}'!", program))?; + execs::cmd(program).arg("-v") + .output() + .chain_err(|| format!("Please install '{}'!", program))?; Ok(()) } fn npm_package_exists(package: &str) -> Result<()> { - let status = execs::cmd("npm") - .args(&["list", "-g"]) - .arg(package) - .output(); + let status = execs::cmd("npm").args(&["list", "-g"]) + .arg(package) + .output(); match status { Ok(ref out) if out.status.success() => Ok(()), _ => { - bail!("Missing npm package '{0}' \ - install with: 'npm -g install {0}'", + bail!("Missing npm package '{0}' install with: 'npm -g install {0}'", package) - }, + } } } @@ -59,7 +56,7 @@ pub enum Resource<'a> { Program(&'a str), Package(&'a str), } -use Resource::{Program, Package}; +use Resource::{Package, Program}; impl<'a> Resource<'a> { pub fn exists(&self) -> Result<()> { @@ -71,7 +68,6 @@ impl<'a> Resource<'a> { } fn run() -> Result<()> { - if let Ok(_) = env::var("CARGO_FEATURE_REGENERATE_CSS") { // Check dependencies Program("npm").exists()?; @@ -85,14 +81,14 @@ fn run() -> Result<()> { let theme_dir = Path::new(&manifest_dir).join("src/theme/"); let stylus_dir = theme_dir.join("stylus/book.styl"); - if !execs::cmd("stylus") - .arg(stylus_dir) - .arg("--out") - .arg(theme_dir) - .arg("--use") - .arg("nib") - .status()? - .success() { + if !execs::cmd("stylus").arg(stylus_dir) + .arg("--out") + .arg(theme_dir) + .arg("--use") + .arg("nib") + .status()? + .success() + { bail!("Stylus encoutered an error"); } } diff --git a/rustfmt.toml b/rustfmt.toml index 5ac9fa56..ceba6b26 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,16 +1,7 @@ -write_mode = "Overwrite" +array_layout = "Visual" +chain_indent = "Visual" +fn_args_layout = "Visual" +fn_call_style = "Visual" +format_strings = true +generics_indent = "Visual" -max_width = 120 -ideal_width = 120 -fn_call_width = 100 - -fn_args_density = "Compressed" - -enum_trailing_comma = true -match_block_trailing_comma = true -struct_trailing_comma = "Always" -wrap_comments = true -use_try_shorthand = true - -report_todo = "Always" -report_fixme = "Always" diff --git a/src/bin/build.rs b/src/bin/build.rs index 1a296ee5..7ad127da 100644 --- a/src/bin/build.rs +++ b/src/bin/build.rs @@ -1,4 +1,4 @@ -use clap::{ArgMatches, SubCommand, App}; +use clap::{App, ArgMatches, SubCommand}; use mdbook::MDBook; use mdbook::errors::Result; use {get_book_dir, open}; @@ -8,10 +8,21 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("build") .about("Build the book from the markdown files") .arg_from_usage("-o, --open 'Open the compiled book in a web browser'") - .arg_from_usage("-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'") - .arg_from_usage("--no-create 'Will not create non-existent files linked from SUMMARY.md'") - .arg_from_usage("--curly-quotes 'Convert straight quotes to curly quotes, except for those that occur in code blocks and code spans'") - .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'") + .arg_from_usage( + "-d, --dest-dir=[dest-dir] 'The output directory for your \ + book{n}(Defaults to ./book when omitted)'", + ) + .arg_from_usage( + "--no-create 'Will not create non-existent files linked from SUMMARY.md'", + ) + .arg_from_usage( + "--curly-quotes 'Convert straight quotes to curly quotes, except for those \ + that occur in code blocks and code spans'", + ) + .arg_from_usage( + "[dir] 'A directory for your book{n}(Defaults to Current Directory \ + when omitted)'", + ) } // Build command implementation diff --git a/src/bin/init.rs b/src/bin/init.rs index 37277fc7..83431211 100644 --- a/src/bin/init.rs +++ b/src/bin/init.rs @@ -1,6 +1,6 @@ use std::io; use std::io::Write; -use clap::{ArgMatches, SubCommand, App}; +use clap::{App, ArgMatches, SubCommand}; use mdbook::MDBook; use mdbook::errors::Result; use get_book_dir; @@ -10,14 +10,14 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("init") .about("Create boilerplate structure and files in the directory") // the {n} denotes a newline which will properly aligned in all help messages - .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'") + .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory \ + when omitted)'") .arg_from_usage("--theme 'Copies the default theme into your source folder'") .arg_from_usage("--force 'skip confirmation prompts'") } // Init command implementation pub fn execute(args: &ArgMatches) -> Result<()> { - let book_dir = get_book_dir(args); let mut book = MDBook::new(&book_dir); @@ -26,7 +26,6 @@ pub fn execute(args: &ArgMatches) -> Result<()> { // If flag `--theme` is present, copy theme to src if args.is_present("theme") { - // Skip this if `--force` is present if !args.is_present("force") { // Print warning @@ -45,7 +44,6 @@ pub fn execute(args: &ArgMatches) -> Result<()> { // Call the function that copies the theme book.copy_theme()?; println!("\nTheme copied."); - } // Because of `src/book/mdbook.rs#L37-L39`, `dest` will always start with `root` diff --git a/src/bin/mdbook.rs b/src/bin/mdbook.rs index 84503800..963189eb 100644 --- a/src/bin/mdbook.rs +++ b/src/bin/mdbook.rs @@ -1,16 +1,16 @@ -extern crate mdbook; #[macro_use] extern crate clap; -extern crate log; extern crate env_logger; +extern crate log; +extern crate mdbook; extern crate open; use std::env; use std::ffi::OsStr; use std::io::{self, Write}; use std::path::{Path, PathBuf}; -use clap::{App, ArgMatches, AppSettings}; -use log::{LogRecord, LogLevelFilter}; +use clap::{App, AppSettings, ArgMatches}; +use log::{LogLevelFilter, LogRecord}; use env_logger::LogBuilder; pub mod build; @@ -33,7 +33,10 @@ fn main() { // Get the version from our Cargo.toml using clap's crate_version!() macro .version(concat!("v",crate_version!())) .setting(AppSettings::SubcommandRequired) - .after_help("For more information about a specific command, try `mdbook --help`\nSource code for mdbook available at: https://github.com/azerupi/mdBook") + .after_help("For more information about a specific command, \ + try `mdbook --help`\n\ + Source code for mdbook available \ + at: https://github.com/azerupi/mdBook") .subcommand(init::make_subcommand()) .subcommand(build::make_subcommand()) .subcommand(test::make_subcommand()); @@ -71,7 +74,7 @@ fn init_logger() { builder.format(format).filter(None, LogLevelFilter::Info); if let Ok(var) = env::var("RUST_LOG") { - builder.parse(&var); + builder.parse(&var); } builder.init().unwrap(); diff --git a/src/bin/serve.rs b/src/bin/serve.rs index 54c0a248..c4f3a222 100644 --- a/src/bin/serve.rs +++ b/src/bin/serve.rs @@ -4,8 +4,9 @@ extern crate ws; use std; use std::path::Path; -use self::iron::{Iron, AfterMiddleware, IronResult, IronError, Request, Response, status, Set, Chain}; -use clap::{ArgMatches, SubCommand, App}; +use self::iron::{status, AfterMiddleware, Chain, Iron, IronError, IronResult, Request, Response, + Set}; +use clap::{App, ArgMatches, SubCommand}; use mdbook::MDBook; use mdbook::errors::Result; use {get_book_dir, open}; @@ -17,14 +18,33 @@ struct ErrorRecover; // Create clap subcommand arguments pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("serve") - .about("Serve the book at http://localhost:3000. Rebuild and reload on change.") - .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'") - .arg_from_usage("-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'") - .arg_from_usage("--curly-quotes 'Convert straight quotes to curly quotes, except for those that occur in code blocks and code spans'") + .about( + "Serve the book at http://localhost:3000. Rebuild and reload on change.", + ) + .arg_from_usage( + "[dir] 'A directory for your book{n}(Defaults to \ + Current Directory when omitted)'", + ) + .arg_from_usage( + "-d, --dest-dir=[dest-dir] 'The output directory for \ + your book{n}(Defaults to ./book when omitted)'", + ) + .arg_from_usage( + "--curly-quotes 'Convert straight quotes to curly quotes, except \ + for those that occur in code blocks and code spans'", + ) .arg_from_usage("-p, --port=[port] 'Use another port{n}(Defaults to 3000)'") - .arg_from_usage("-w, --websocket-port=[ws-port] 'Use another port for the websocket connection (livereload){n}(Defaults to 3001)'") - .arg_from_usage("-i, --interface=[interface] 'Interface to listen on{n}(Defaults to localhost)'") - .arg_from_usage("-a, --address=[address] 'Address that the browser can reach the websocket server from{n}(Defaults to the interface address)'") + .arg_from_usage( + "-w, --websocket-port=[ws-port] 'Use another port for the \ + websocket connection (livereload){n}(Defaults to 3001)'", + ) + .arg_from_usage( + "-i, --interface=[interface] 'Interface to listen on{n}(Defaults to localhost)'", + ) + .arg_from_usage( + "-a, --address=[address] 'Address that the browser can reach the \ + websocket server from{n}(Defaults to the interface address)'", + ) .arg_from_usage("-o, --open 'Open the book server in a web browser'") } @@ -53,7 +73,8 @@ pub fn execute(args: &ArgMatches) -> Result<()> { let address = format!("{}:{}", interface, port); let ws_address = format!("{}:{}", interface, ws_port); - book.set_livereload(format!(r#" + book.set_livereload(format!( + r#" "#, - public_address, - ws_port, - RELOAD_COMMAND)); + public_address, + ws_port, + RELOAD_COMMAND + )); book.build()?; diff --git a/src/bin/test.rs b/src/bin/test.rs index ad82d316..79a77874 100644 --- a/src/bin/test.rs +++ b/src/bin/test.rs @@ -1,4 +1,4 @@ -use clap::{ArgMatches, SubCommand, App}; +use clap::{App, ArgMatches, SubCommand}; use mdbook::MDBook; use mdbook::errors::Result; use get_book_dir; @@ -7,12 +7,16 @@ use get_book_dir; pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("test") .about("Test that code samples compile") - .arg_from_usage("-L, --library-path [DIR]... 'directory to add to crate search path'") + .arg_from_usage( + "-L, --library-path [DIR]... 'directory to add to crate search path'", + ) } // test command implementation pub fn execute(args: &ArgMatches) -> Result<()> { - let library_paths: Vec<&str> = args.values_of("library-path").map(|v| v.collect()).unwrap_or_default(); + let library_paths: Vec<&str> = args.values_of("library-path") + .map(|v| v.collect()) + .unwrap_or_default(); let book_dir = get_book_dir(args); let mut book = MDBook::new(&book_dir).read_config()?; diff --git a/src/bin/watch.rs b/src/bin/watch.rs index b4f7b4b3..132d680d 100644 --- a/src/bin/watch.rs +++ b/src/bin/watch.rs @@ -4,7 +4,7 @@ use std::path::Path; use self::notify::Watcher; use std::time::Duration; use std::sync::mpsc::channel; -use clap::{ArgMatches, SubCommand, App}; +use clap::{App, ArgMatches, SubCommand}; use mdbook::MDBook; use mdbook::errors::Result; use {get_book_dir, open}; @@ -14,9 +14,18 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("watch") .about("Watch the files for changes") .arg_from_usage("-o, --open 'Open the compiled book in a web browser'") - .arg_from_usage("-d, --dest-dir=[dest-dir] 'The output directory for your book{n}(Defaults to ./book when omitted)'") - .arg_from_usage("--curly-quotes 'Convert straight quotes to curly quotes, except for those that occur in code blocks and code spans'") - .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'") + .arg_from_usage( + "-d, --dest-dir=[dest-dir] 'The output directory for \ + your book{n}(Defaults to ./book when omitted)'", + ) + .arg_from_usage( + "--curly-quotes 'Convert straight quotes to curly quotes, except \ + for those that occur in code blocks and code spans'", + ) + .arg_from_usage( + "[dir] 'A directory for your book{n}(Defaults to \ + Current Directory when omitted)'", + ) } // Watch command implementation @@ -51,7 +60,8 @@ pub fn execute(args: &ArgMatches) -> Result<()> { // Calls the closure when a book source file is changed. This is blocking! pub fn trigger_on_change(book: &mut MDBook, closure: F) -> () - where F: Fn(&Path, &mut MDBook) -> () +where + F: Fn(&Path, &mut MDBook) -> (), { use self::notify::RecursiveMode::*; use self::notify::DebouncedEvent::*; @@ -64,7 +74,7 @@ pub fn trigger_on_change(book: &mut MDBook, closure: F) -> () Err(e) => { println!("Error while trying to watch the files:\n\n\t{:?}", e); ::std::process::exit(0); - }, + } }; // Add the source directory to the watcher @@ -74,19 +84,20 @@ pub fn trigger_on_change(book: &mut MDBook, closure: F) -> () }; // Add the theme directory to the watcher - watcher.watch(book.get_theme_path(), Recursive).unwrap_or_default(); + watcher.watch(book.get_theme_path(), Recursive) + .unwrap_or_default(); // Add the book.{json,toml} file to the watcher if it exists, because it's not // located in the source directory - if watcher - .watch(book.get_root().join("book.json"), NonRecursive) - .is_err() { + if watcher.watch(book.get_root().join("book.json"), NonRecursive) + .is_err() + { // do nothing if book.json is not found } - if watcher - .watch(book.get_root().join("book.toml"), NonRecursive) - .is_err() { + if watcher.watch(book.get_root().join("book.toml"), NonRecursive) + .is_err() + { // do nothing if book.toml is not found } @@ -96,18 +107,15 @@ pub fn trigger_on_change(book: &mut MDBook, closure: F) -> () match rx.recv() { Ok(event) => { match event { - Create(path) | - Write(path) | - Remove(path) | - Rename(_, path) => { + Create(path) | Write(path) | Remove(path) | Rename(_, path) => { closure(&path, book); - }, - _ => {}, + } + _ => {} } - }, + } Err(e) => { println!("An error occured: {:?}", e); - }, + } } } } diff --git a/src/book/bookitem.rs b/src/book/bookitem.rs index 7fe7ab55..a2ec2cb0 100644 --- a/src/book/bookitem.rs +++ b/src/book/bookitem.rs @@ -27,7 +27,6 @@ pub struct BookItems<'a> { impl Chapter { pub fn new(name: String, path: PathBuf) -> Self { - Chapter { name: name, path: path, @@ -39,7 +38,8 @@ impl Chapter { impl Serialize for Chapter { fn serialize(&self, serializer: S) -> ::std::result::Result - where S: Serializer + where + S: Serializer, { let mut struct_ = serializer.serialize_struct("Chapter", 2)?; struct_.serialize_field("name", &self.name)?; @@ -63,21 +63,20 @@ impl<'a> Iterator for BookItems<'a> { Some((parent_items, parent_idx)) => { self.items = parent_items; self.current_index = parent_idx + 1; - }, + } } } else { let cur = &self.items[self.current_index]; match *cur { - BookItem::Chapter(_, ref ch) | - BookItem::Affix(ref ch) => { + BookItem::Chapter(_, ref ch) | BookItem::Affix(ref ch) => { self.stack.push((self.items, self.current_index)); self.items = &ch.sub_items[..]; self.current_index = 0; - }, + } BookItem::Spacer => { self.current_index += 1; - }, + } } return Some(cur); diff --git a/src/book/mod.rs b/src/book/mod.rs index e8896e0a..82699a7a 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -8,8 +8,8 @@ use std::io::{Read, Write}; use std::process::Command; use tempdir::TempDir; -use {theme, parse, utils}; -use renderer::{Renderer, HtmlHandlebars}; +use {parse, theme, utils}; +use renderer::{HtmlHandlebars, Renderer}; use preprocess; use errors::*; @@ -60,7 +60,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); @@ -130,7 +129,6 @@ impl MDBook { /// `chapter_1.md` to the source directory. pub fn init(&mut self) -> Result<()> { - debug!("[fn]: init"); if !self.config.get_root().exists() { @@ -139,24 +137,25 @@ impl MDBook { } { - if !self.get_destination().exists() { - debug!("[*]: {:?} does not exist, trying to create directory", self.get_destination()); + debug!("[*]: {:?} does not exist, trying to create directory", + self.get_destination()); fs::create_dir_all(self.get_destination())?; } if !self.config.get_source().exists() { - debug!("[*]: {:?} does not exist, trying to create directory", self.config.get_source()); + debug!("[*]: {:?} does not exist, trying to create directory", + self.config.get_source()); fs::create_dir_all(self.config.get_source())?; } let summary = self.config.get_source().join("SUMMARY.md"); if !summary.exists() { - // Summary does not exist, create it - debug!("[*]: {:?} does not exist, trying to create SUMMARY.md", &summary); + debug!("[*]: {:?} does not exist, trying to create SUMMARY.md", + &summary); let mut f = File::create(&summary)?; debug!("[*]: Writing to SUMMARY.md"); @@ -175,16 +174,15 @@ impl MDBook { debug!("[*]: item: {:?}", item); let ch = match *item { BookItem::Spacer => continue, - BookItem::Chapter(_, ref ch) | - BookItem::Affix(ref ch) => ch, + BookItem::Chapter(_, ref ch) | BookItem::Affix(ref ch) => ch, }; if !ch.path.as_os_str().is_empty() { let path = self.config.get_source().join(&ch.path); if !path.exists() { if !self.create_missing { - return Err(format!("'{}' referenced from SUMMARY.md does not exist.", path.to_string_lossy()) - .into()); + return Err(format!("'{}' referenced from SUMMARY.md does not exist.", + path.to_string_lossy()).into()); } debug!("[*]: {:?} does not exist, trying to create file", path); ::std::fs::create_dir_all(path.parent().unwrap())?; @@ -203,21 +201,22 @@ impl MDBook { 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 + // 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` + // 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") + .to_str() + .expect("Could not convert to &str"); - let relative = destination - .strip_prefix(self.config.get_root()) - .expect("Could not strip the root prefix, path is not relative to root") - .to_str() - .expect("Could not convert to &str"); - - debug!("[*]: {:?} does not exist, trying to create .gitignore", gitignore); + debug!("[*]: {:?} does not exist, trying to create .gitignore", + gitignore); let mut f = File::create(&gitignore).expect("Could not create file."); @@ -254,7 +253,8 @@ impl MDBook { let themedir = self.config.get_html_config().get_theme(); if !themedir.exists() { - debug!("[*]: {:?} does not exist, trying to create directory", themedir); + debug!("[*]: {:?} does not exist, trying to create directory", + themedir); fs::create_dir(&themedir)?; } @@ -286,12 +286,10 @@ 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) - .map_err(|e| e.into()) + utils::fs::create_file(&path)?.write_all(content) + .map_err(|e| e.into()) } /// Parses the `book.json` file (if it exists) to extract @@ -300,7 +298,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"); @@ -362,14 +359,11 @@ impl MDBook { .collect(); let temp_dir = TempDir::new("mdbook")?; for item in self.iter() { - if let BookItem::Chapter(_, ref ch) = *item { if !ch.path.as_os_str().is_empty() { - 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)?; @@ -380,10 +374,14 @@ impl MDBook { 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)); + bail!(ErrorKind::Subprocess("Rustdoc returned an error".to_string(), + output)); } } } @@ -398,15 +396,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 { @@ -452,61 +450,56 @@ impl MDBook { pub fn with_theme_path>(mut self, theme_path: T) -> Self { let root = self.config.get_root().to_owned(); - self.config.get_mut_html_config() + self.config + .get_mut_html_config() .set_theme(&root, &theme_path.into()); self } pub fn get_theme_path(&self) -> &Path { - self.config.get_html_config() - .get_theme() + self.config.get_html_config().get_theme() } pub fn with_curly_quotes(mut self, curly_quotes: bool) -> Self { - self.config.get_mut_html_config() + self.config + .get_mut_html_config() .set_curly_quotes(curly_quotes); self } pub fn get_curly_quotes(&self) -> bool { - self.config.get_html_config() - .get_curly_quotes() + self.config.get_html_config().get_curly_quotes() } pub fn with_mathjax_support(mut self, mathjax_support: bool) -> Self { - self.config.get_mut_html_config() + self.config + .get_mut_html_config() .set_mathjax_support(mathjax_support); self } pub fn get_mathjax_support(&self) -> bool { - self.config.get_html_config() - .get_mathjax_support() + self.config.get_html_config().get_mathjax_support() } pub fn get_google_analytics_id(&self) -> Option { - self.config.get_html_config() - .get_google_analytics_id() + self.config.get_html_config().get_google_analytics_id() } pub fn has_additional_js(&self) -> bool { - self.config.get_html_config() - .has_additional_js() + self.config.get_html_config().has_additional_js() } pub fn get_additional_js(&self) -> &[PathBuf] { - self.config.get_html_config() - .get_additional_js() + self.config.get_html_config().get_additional_js() } pub fn has_additional_css(&self) -> bool { - self.config.get_html_config() - .has_additional_css() + self.config.get_html_config().has_additional_css() } pub fn get_additional_css(&self) -> &[PathBuf] { - self.config.get_html_config() - .get_additional_css() + self.config.get_html_config().get_additional_css() } pub fn get_html_config(&self) -> &HtmlConfig { diff --git a/src/config/bookconfig.rs b/src/config/bookconfig.rs index 5682492e..05bbfbc6 100644 --- a/src/config/bookconfig.rs +++ b/src/config/bookconfig.rs @@ -1,4 +1,4 @@ -use std::path::{PathBuf, Path}; +use std::path::{Path, PathBuf}; use super::HtmlConfig; use super::tomlconfig::TomlConfig; @@ -33,7 +33,8 @@ impl BookConfig { /// /// assert_eq!(config.get_root(), &root); /// assert_eq!(config.get_source(), PathBuf::from("directory/to/my/book/src")); - /// assert_eq!(config.get_html_config(), &HtmlConfig::new(PathBuf::from("directory/to/my/book"))); + /// assert_eq!(config.get_html_config(), + /// &HtmlConfig::new(PathBuf::from("directory/to/my/book"))); /// ``` pub fn new>(root: T) -> Self { let root: PathBuf = root.into(); @@ -86,7 +87,6 @@ impl BookConfig { } pub fn fill_from_tomlconfig(&mut self, tomlconfig: TomlConfig) -> &mut Self { - if let Some(s) = tomlconfig.source { self.set_source(s); } @@ -112,7 +112,7 @@ impl BookConfig { self.get_mut_html_config() .fill_from_tomlconfig(root, tomlhtmlconfig); } - + self } @@ -128,7 +128,6 @@ impl BookConfig { /// The JSON configuration file is **deprecated** and should not be used anymore. /// Please, migrate to the TOML configuration file. pub fn fill_from_jsonconfig(&mut self, jsonconfig: JsonConfig) -> &mut Self { - if let Some(s) = jsonconfig.src { self.set_source(s); } @@ -147,14 +146,12 @@ impl BookConfig { if let Some(d) = jsonconfig.dest { let root = self.get_root().to_owned(); - self.get_mut_html_config() - .set_destination(&root, &d); + self.get_mut_html_config().set_destination(&root, &d); } if let Some(d) = jsonconfig.theme_path { let root = self.get_root().to_owned(); - self.get_mut_html_config() - .set_theme(&root, &d); + self.get_mut_html_config().set_theme(&root, &d); } self diff --git a/src/config/htmlconfig.rs b/src/config/htmlconfig.rs index d51c5394..f2f9c42b 100644 --- a/src/config/htmlconfig.rs +++ b/src/config/htmlconfig.rs @@ -1,4 +1,4 @@ -use std::path::{PathBuf, Path}; +use std::path::{Path, PathBuf}; use super::tomlconfig::TomlHtmlConfig; use super::playpenconfig::PlaypenConfig; @@ -16,7 +16,8 @@ pub struct HtmlConfig { } impl HtmlConfig { - /// Creates a new `HtmlConfig` struct containing the configuration parameters for the HTML renderer. + /// Creates a new `HtmlConfig` struct containing + /// the configuration parameters for the HTML renderer. /// /// ``` /// # use std::path::PathBuf; @@ -42,7 +43,10 @@ impl HtmlConfig { } } - pub fn fill_from_tomlconfig>(&mut self, root: T, tomlconfig: TomlHtmlConfig) -> &mut Self { + pub fn fill_from_tomlconfig>(&mut self, + root: T, + tomlconfig: TomlHtmlConfig) + -> &mut Self { let root = root.into(); if let Some(d) = tomlconfig.destination { diff --git a/src/config/jsonconfig.rs b/src/config/jsonconfig.rs index 5e553ee3..5822bc19 100644 --- a/src/config/jsonconfig.rs +++ b/src/config/jsonconfig.rs @@ -34,8 +34,7 @@ pub struct JsonConfig { /// ``` impl JsonConfig { pub fn from_json(input: &str) -> Result { - let config: JsonConfig = serde_json::from_str(input) - .chain_err(|| "Could not parse JSON")?; + let config: JsonConfig = serde_json::from_str(input).chain_err(|| "Could not parse JSON")?; Ok(config) } diff --git a/src/config/playpenconfig.rs b/src/config/playpenconfig.rs index e2c6e891..db2ee5c2 100644 --- a/src/config/playpenconfig.rs +++ b/src/config/playpenconfig.rs @@ -1,4 +1,4 @@ -use std::path::{PathBuf, Path}; +use std::path::{Path, PathBuf}; use super::tomlconfig::TomlPlaypenConfig; @@ -28,9 +28,12 @@ impl PlaypenConfig { } } - pub fn fill_from_tomlconfig>(&mut self, root: T, tomlplaypenconfig: TomlPlaypenConfig) -> &mut Self { + pub fn fill_from_tomlconfig>(&mut self, + root: T, + tomlplaypenconfig: TomlPlaypenConfig) + -> &mut Self { let root = root.into(); - + if let Some(editor) = tomlplaypenconfig.editor { if editor.is_relative() { self.editor = root.join(editor); diff --git a/src/config/tomlconfig.rs b/src/config/tomlconfig.rs index edac4c1d..4bb11e30 100644 --- a/src/config/tomlconfig.rs +++ b/src/config/tomlconfig.rs @@ -46,16 +46,15 @@ pub struct TomlPlaypenConfig { /// let toml = r#"title="Some title" /// [output.html] /// destination = "htmlbook" "#; -/// +/// /// let config = TomlConfig::from_toml(&toml).expect("Should parse correctly"); /// assert_eq!(config.title, Some(String::from("Some title"))); /// assert_eq!(config.output.unwrap().html.unwrap().destination, Some(PathBuf::from("htmlbook"))); /// ``` impl TomlConfig { pub fn from_toml(input: &str) -> Result { - let config: TomlConfig = toml::from_str(input) - .chain_err(|| "Could not parse TOML")?; - + let config: TomlConfig = toml::from_str(input).chain_err(|| "Could not parse TOML")?; + Ok(config) } } diff --git a/src/lib.rs b/src/lib.rs index fff77bbd..247d6346 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,8 +3,8 @@ //! **mdBook** is similar to Gitbook but implemented in Rust. //! It offers a command line interface, but can also be used as a regular crate. //! -//! This is the API doc, but you can find a [less "low-level" documentation here](../index.html) that -//! contains information about the command line tool, format, structure etc. +//! This is the API doc, but you can find a [less "low-level" documentation here](../index.html) +//! that contains information about the command line tool, format, structure etc. //! It is also rendered with mdBook to showcase the features and default theme. //! //! Some reasons why you would want to use the crate (over the cli): @@ -80,9 +80,9 @@ extern crate lazy_static; extern crate log; extern crate pulldown_cmark; extern crate regex; +extern crate serde; #[macro_use] extern crate serde_derive; -extern crate serde; #[macro_use] extern crate serde_json; extern crate tempdir; diff --git a/src/parse/summary.rs b/src/parse/summary.rs index cc8452d4..1193b6f5 100644 --- a/src/parse/summary.rs +++ b/src/parse/summary.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; use std::fs::File; -use std::io::{Read, Result, Error, ErrorKind}; +use std::io::{Error, ErrorKind, Read, Result}; use book::bookitem::{BookItem, Chapter}; pub fn construct_bookitems(path: &PathBuf) -> Result> { @@ -14,7 +14,10 @@ pub fn construct_bookitems(path: &PathBuf) -> Result> { Ok(top_items) } -fn parse_level(summary: &mut Vec<&str>, current_level: i32, mut section: Vec) -> Result> { +fn parse_level(summary: &mut Vec<&str>, + current_level: i32, + mut section: Vec) + -> Result> { debug!("[fn]: parse_level"); let mut items: Vec = vec![]; @@ -36,9 +39,9 @@ fn parse_level(summary: &mut Vec<&str>, current_level: i32, mut section: Vec, current_level: i32, mut section: Vec 0 => { - return Err(Error::new(ErrorKind::Other, - "Your summary.md is messed up\n\n + BookItem::Affix(_) | BookItem::Spacer if level > 0 => { + return Err(Error::new( + ErrorKind::Other, + "Your summary.md is messed up\n\n \ - Prefix, Suffix and Spacer elements can only exist on the \ - root level.\n + Prefix, Suffix and Spacer elements \ + can only exist on the root level.\n Prefix \ - elements can only exist before any chapter and there can be \ - no chapters after suffix elements.")) - }, + elements can only exist before any chapter and \ + there can be no chapters after suffix elements.", + )) + } // error if BookItem == Chapter and section == -1 BookItem::Chapter(_, _) if section[0] == -1 => { - return Err(Error::new(ErrorKind::Other, - "Your summary.md is messed up\n\n + return Err(Error::new( + ErrorKind::Other, + "Your summary.md is messed up\n\n \ - Prefix, Suffix and Spacer elements can only exist on the \ - root level.\n + Prefix, Suffix and Spacer elements can only \ + exist on the root level.\n Prefix \ - elements can only exist before any chapter and there can be \ - no chapters after suffix elements.")) - }, + elements can only exist before any chapter and \ + there can be no chapters after suffix elements.", + )) + } // Set section = -1 after suffix BookItem::Affix(_) if section[0] > 0 => { section[0] = -1; - }, + } - _ => {}, + _ => {} } match parsed_item { @@ -102,14 +110,12 @@ fn parse_level(summary: &mut Vec<&str>, current_level: i32, mut section: Vec parsed_item, } - } else { // If parse_line does not return Some(_) continue... summary.remove(0); @@ -146,8 +152,10 @@ fn level(line: &str, spaces_in_tab: i32) -> Result { if spaces > 0 { debug!("[SUMMARY.md]:"); debug!("\t[line]: {}", line); - debug!("[*]: There is an indentation error on this line. Indentation should be {} spaces", spaces_in_tab); - return Err(Error::new(ErrorKind::Other, format!("Indentation error on line:\n\n{}", line))); + debug!("[*]: There is an indentation error on this line. Indentation should be {} spaces", + spaces_in_tab); + return Err(Error::new(ErrorKind::Other, + format!("Indentation error on line:\n\n{}", line))); } Ok(level) @@ -177,7 +185,7 @@ fn parse_line(l: &str) -> Option { } else { return None; } - }, + } // Non-list element '[' => { debug!("[*]: Line is a link element"); @@ -187,8 +195,8 @@ fn parse_line(l: &str) -> Option { } else { return None; } - }, - _ => {}, + } + _ => {} } } diff --git a/src/preprocess/links.rs b/src/preprocess/links.rs index 2eef9b38..8d10244b 100644 --- a/src/preprocess/links.rs +++ b/src/preprocess/links.rs @@ -39,7 +39,6 @@ struct Link<'a> { impl<'a> Link<'a> { fn from_capture(cap: Captures<'a>) -> Option> { - let link_type = match (cap.get(0), cap.get(1), cap.get(2)) { (_, Some(typ), Some(rest)) => { let mut path_props = rest.as_str().split_whitespace(); @@ -51,21 +50,22 @@ impl<'a> Link<'a> { ("playpen", Some(pth)) => Some(LinkType::Playpen(pth, props)), _ => None, } - }, - (Some(mat), None, None) if mat.as_str().starts_with(ESCAPE_CHAR) => Some(LinkType::Escaped), + } + (Some(mat), None, None) if mat.as_str().starts_with(ESCAPE_CHAR) => { + Some(LinkType::Escaped) + } _ => None, }; link_type.and_then(|lnk| { - cap.get(0) - .map(|mat| { - Link { - start_index: mat.start(), - end_index: mat.end(), - link: lnk, - link_text: mat.as_str(), - } - }) + cap.get(0).map(|mat| { + Link { + start_index: mat.start(), + end_index: mat.end(), + link: lnk, + link_text: mat.as_str(), + } + }) }) } @@ -75,14 +75,22 @@ impl<'a> Link<'a> { // omit the escape char LinkType::Escaped => Ok((&self.link_text[1..]).to_owned()), LinkType::Include(ref pat) => { - file_to_string(base.join(pat)).chain_err(|| format!("Could not read file for link {}", self.link_text)) - }, + file_to_string(base.join(pat)).chain_err(|| { + format!("Could not read file for \ + link {}", + self.link_text) + }) + } LinkType::Playpen(ref pat, ref attrs) => { - let contents = file_to_string(base.join(pat)) - .chain_err(|| format!("Could not read file for link {}", self.link_text))?; + let contents = file_to_string(base.join(pat)).chain_err(|| { + format!("Could not \ + read file \ + for link {}", + self.link_text) + })?; let ftype = if !attrs.is_empty() { "rust," } else { "rust" }; Ok(format!("```{}{}\n{}\n```\n", ftype, attrs.join(","), contents)) - }, + } } } } @@ -190,7 +198,8 @@ fn test_find_links_escaped_link() { #[test] fn test_find_playpens_with_properties() { - let s = "Some random text with escaped playpen {{#playpen file.rs editable }} and some more\n text {{#playpen my.rs editable no_run should_panic}} ..."; + let s = "Some random text with escaped playpen {{#playpen file.rs editable }} and some more\n \ + text {{#playpen my.rs editable no_run should_panic}} ..."; let res = find_links(s).collect::>(); println!("\nOUTPUT: {:?}\n", res); @@ -202,16 +211,19 @@ fn test_find_playpens_with_properties() { link_text: "{{#playpen file.rs editable }}", }, Link { - start_index: 90, - end_index: 137, - link: LinkType::Playpen(PathBuf::from("my.rs"), vec!["editable", "no_run", "should_panic"]), + start_index: 89, + end_index: 136, + link: LinkType::Playpen(PathBuf::from("my.rs"), + vec!["editable", "no_run", "should_panic"]), link_text: "{{#playpen my.rs editable no_run should_panic}}", }]); } #[test] fn test_find_all_link_types() { - let s = "Some random text with escaped playpen {{#include file.rs}} and \\{{#contents are insignifficant in escaped link}} some more\n text {{#playpen my.rs editable no_run should_panic}} ..."; + let s = "Some random text with escaped playpen {{#include file.rs}} and \\{{#contents are \ + insignifficant in escaped link}} some more\n text {{#playpen my.rs editable no_run \ + should_panic}} ..."; let res = find_links(s).collect::>(); println!("\nOUTPUT: {:?}\n", res); @@ -234,7 +246,8 @@ fn test_find_all_link_types() { Link { start_index: 130, end_index: 177, - link: LinkType::Playpen(PathBuf::from("my.rs"), vec!["editable", "no_run", "should_panic"]), + link: LinkType::Playpen(PathBuf::from("my.rs"), + vec!["editable", "no_run", "should_panic"]), link_text: "{{#playpen my.rs editable no_run should_panic}}", }); } diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index d2b46779..3ff914d6 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -4,10 +4,10 @@ use renderer::Renderer; use book::MDBook; use book::bookitem::{BookItem, Chapter}; use config::PlaypenConfig; -use {utils, theme}; -use theme::{Theme, playpen_editor}; +use {theme, utils}; +use theme::{playpen_editor, Theme}; use errors::*; -use regex::{Regex, Captures}; +use regex::{Captures, Regex}; use std::ascii::AsciiExt; use std::path::{Path, PathBuf}; @@ -28,18 +28,20 @@ impl HtmlHandlebars { HtmlHandlebars } - fn render_item(&self, item: &BookItem, mut ctx: RenderItemContext, print_content: &mut String) - -> Result<()> { + fn render_item(&self, + item: &BookItem, + mut ctx: RenderItemContext, + print_content: &mut String) + -> Result<()> { // FIXME: This should be made DRY-er and rely less on mutable state match *item { - BookItem::Chapter(_, ref ch) | - BookItem::Affix(ref ch) if !ch.path.as_os_str().is_empty() => { - + BookItem::Chapter(_, ref ch) | BookItem::Affix(ref ch) + if !ch.path.as_os_str().is_empty() => + { let path = ctx.book.get_source().join(&ch.path); let content = utils::fs::file_to_string(&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!"))?; // Parse and expand links let content = preprocess::links::replace_all(&content, base)?; @@ -48,34 +50,39 @@ impl HtmlHandlebars { // Update the context with data for this file let path = ch.path.to_str().ok_or_else(|| { - io::Error::new(io::ErrorKind::Other, "Could not convert path to str") - })?; + io::Error::new(io::ErrorKind::Other, + "Could not convert path \ + to str") + })?; - // Non-lexical lifetimes needed :'( + // Non-lexical lifetimes needed :'( let title: String; { - let book_title = ctx.data.get("book_title").and_then(serde_json::Value::as_str).unwrap_or(""); + let book_title = ctx.data + .get("book_title") + .and_then(serde_json::Value::as_str) + .unwrap_or(""); title = ch.name.clone() + " - " + book_title; } - + ctx.data.insert("path".to_owned(), json!(path)); ctx.data.insert("content".to_owned(), json!(content)); ctx.data.insert("chapter_title".to_owned(), json!(ch.name)); ctx.data.insert("title".to_owned(), json!(title)); - ctx.data.insert( - "path_to_root".to_owned(), - json!(utils::fs::path_to_root(&ch.path)), - ); + ctx.data.insert("path_to_root".to_owned(), + json!(utils::fs::path_to_root(&ch.path))); // Render the handlebars template with the data debug!("[*]: Render template"); let rendered = ctx.handlebars.render("index", &ctx.data)?; let filepath = Path::new(&ch.path).with_extension("html"); - let rendered = self.post_process(rendered, - &normalize_path(filepath.to_str() - .ok_or(Error::from(format!("Bad file name: {}", filepath.display())))?), - ctx.book.get_html_config().get_playpen_config() + let rendered = self.post_process( + rendered, + &normalize_path(filepath.to_str().ok_or(Error::from( + format!("Bad file name: {}", filepath.display()), + ))?), + ctx.book.get_html_config().get_playpen_config(), ); // Write to file @@ -85,8 +92,8 @@ impl HtmlHandlebars { if ctx.is_index { self.render_index(ctx.book, ch, &ctx.destination)?; } - }, - _ => {}, + } + _ => {} } Ok(()) @@ -104,24 +111,24 @@ impl HtmlHandlebars { // This could cause a problem when someone displays // code containing // on the front page, however this case should be very very rare... - content = content - .lines() - .filter(|line| !line.contains(" String { + fn post_process(&self, + rendered: String, + filepath: &str, + playpen_config: &PlaypenConfig) + -> String { let rendered = build_header_links(&rendered, &filepath); let rendered = fix_anchor_links(&rendered, &filepath); let rendered = fix_code_blocks(&rendered); @@ -136,45 +143,24 @@ impl HtmlHandlebars { book.write_file("favicon.png", &theme.favicon)?; book.write_file("jquery.js", &theme.jquery)?; book.write_file("highlight.css", &theme.highlight_css)?; - book.write_file( - "tomorrow-night.css", - &theme.tomorrow_night_css, - )?; - book.write_file( - "ayu-highlight.css", - &theme.ayu_highlight_css, - )?; + book.write_file("tomorrow-night.css", &theme.tomorrow_night_css)?; + book.write_file("ayu-highlight.css", &theme.ayu_highlight_css)?; book.write_file("highlight.js", &theme.highlight_js)?; book.write_file("clipboard.min.js", &theme.clipboard_js)?; book.write_file("store.js", &theme.store_js)?; - book.write_file( - "_FontAwesome/css/font-awesome.css", - theme::FONT_AWESOME, - )?; - book.write_file( - "_FontAwesome/fonts/fontawesome-webfont.eot", - theme::FONT_AWESOME_EOT, - )?; - book.write_file( - "_FontAwesome/fonts/fontawesome-webfont.svg", - theme::FONT_AWESOME_SVG, - )?; - book.write_file( - "_FontAwesome/fonts/fontawesome-webfont.ttf", - theme::FONT_AWESOME_TTF, - )?; - book.write_file( - "_FontAwesome/fonts/fontawesome-webfont.woff", - theme::FONT_AWESOME_WOFF, - )?; - book.write_file( - "_FontAwesome/fonts/fontawesome-webfont.woff2", - theme::FONT_AWESOME_WOFF2, - )?; - book.write_file( - "_FontAwesome/fonts/FontAwesome.ttf", - theme::FONT_AWESOME_TTF, - )?; + book.write_file("_FontAwesome/css/font-awesome.css", theme::FONT_AWESOME)?; + book.write_file("_FontAwesome/fonts/fontawesome-webfont.eot", + theme::FONT_AWESOME_EOT)?; + book.write_file("_FontAwesome/fonts/fontawesome-webfont.svg", + theme::FONT_AWESOME_SVG)?; + book.write_file("_FontAwesome/fonts/fontawesome-webfont.ttf", + theme::FONT_AWESOME_TTF)?; + book.write_file("_FontAwesome/fonts/fontawesome-webfont.woff", + theme::FONT_AWESOME_WOFF)?; + book.write_file("_FontAwesome/fonts/fontawesome-webfont.woff2", + theme::FONT_AWESOME_WOFF2)?; + book.write_file("_FontAwesome/fonts/FontAwesome.ttf", + theme::FONT_AWESOME_TTF)?; let playpen_config = book.get_html_config().get_playpen_config(); @@ -202,12 +188,11 @@ impl HtmlHandlebars { let name = match custom_file.strip_prefix(book.get_root()) { Ok(p) => p.to_str().expect("Could not convert to str"), Err(_) => { - custom_file - .file_name() - .expect("File has a file name") - .to_str() - .expect("Could not convert to str") - }, + custom_file.file_name() + .expect("File has a file name") + .to_str() + .expect("Could not convert to str") + } }; book.write_file(name, &data)?; @@ -216,14 +201,17 @@ impl HtmlHandlebars { } /// Update the context with data for this file - fn configure_print_version(&self, data: &mut serde_json::Map, print_content: &str) { + fn configure_print_version(&self, + data: &mut serde_json::Map, + print_content: &str) { // Make sure that the Print chapter does not display the title from // the last rendered chapter by removing it from its context data.remove("title"); data.insert("is_print".to_owned(), json!(true)); data.insert("path".to_owned(), json!("print.md")); data.insert("content".to_owned(), json!(print_content)); - data.insert("path_to_root".to_owned(), json!(utils::fs::path_to_root(Path::new("print.md")))); + data.insert("path_to_root".to_owned(), + json!(utils::fs::path_to_root(Path::new("print.md")))); } fn register_hbs_helpers(&self, handlebars: &mut Handlebars) { @@ -235,10 +223,9 @@ impl HtmlHandlebars { /// Copy across any additional CSS and JavaScript files which the book /// has been configured to use. fn copy_additional_css_and_js(&self, book: &MDBook) -> Result<()> { - let custom_files = book.get_additional_css().iter().chain( - book.get_additional_js() - .iter(), - ); + let custom_files = book.get_additional_css() + .iter() + .chain(book.get_additional_js().iter()); for custom_file in custom_files { self.write_custom_file(custom_file, book)?; @@ -257,10 +244,7 @@ impl Renderer for HtmlHandlebars { let theme = theme::Theme::new(book.get_theme_path()); debug!("[*]: Register handlebars template"); - handlebars.register_template_string( - "index", - String::from_utf8(theme.index.clone())?, - )?; + handlebars.register_template_string("index", String::from_utf8(theme.index.clone())?)?; debug!("[*]: Register handlebars helpers"); self.register_hbs_helpers(&mut handlebars); @@ -297,13 +281,12 @@ impl Renderer for HtmlHandlebars { let rendered = handlebars.render("index", &data)?; - let rendered = self.post_process(rendered, "print.html", - book.get_html_config().get_playpen_config()); + let rendered = self.post_process(rendered, + "print.html", + book.get_html_config().get_playpen_config()); - book.write_file( - Path::new("print").with_extension("html"), - &rendered.into_bytes(), - )?; + book.write_file(Path::new("print").with_extension("html"), + &rendered.into_bytes())?; info!("[*] Creating print.html ✓"); // Copy static files (js, css, images, ...) @@ -346,14 +329,11 @@ fn make_data(book: &MDBook) -> Result match style.strip_prefix(book.get_root()) { Ok(p) => css.push(p.to_str().expect("Could not convert to str")), Err(_) => { - css.push( - style - .file_name() - .expect("File has a file name") - .to_str() - .expect("Could not convert to str"), - ) - }, + css.push(style.file_name() + .expect("File has a file name") + .to_str() + .expect("Could not convert to str")) + } } } data.insert("additional_css".to_owned(), json!(css)); @@ -366,14 +346,11 @@ fn make_data(book: &MDBook) -> Result match script.strip_prefix(book.get_root()) { Ok(p) => js.push(p.to_str().expect("Could not convert to str")), Err(_) => { - js.push( - script - .file_name() - .expect("File has a file name") - .to_str() - .expect("Could not convert to str"), - ) - }, + js.push(script.file_name() + .expect("File has a file name") + .to_str() + .expect("Could not convert to str")) + } } } data.insert("additional_js".to_owned(), json!(js)); @@ -385,7 +362,8 @@ fn make_data(book: &MDBook) -> Result data.insert("ace_js".to_owned(), json!("ace.js")); data.insert("mode_rust_js".to_owned(), json!("mode-rust.js")); data.insert("theme_dawn_js".to_owned(), json!("theme-dawn.js")); - data.insert("theme_tomorrow_night_js".to_owned(), json!("theme-tomorrow_night.js")); + data.insert("theme_tomorrow_night_js".to_owned(), + json!("theme-tomorrow_night.js")); } let mut chapters = vec![]; @@ -398,22 +376,25 @@ fn make_data(book: &MDBook) -> Result BookItem::Affix(ref ch) => { chapter.insert("name".to_owned(), json!(ch.name)); let path = ch.path.to_str().ok_or_else(|| { - io::Error::new(io::ErrorKind::Other, "Could not convert path to str") - })?; + io::Error::new(io::ErrorKind::Other, + "Could not convert path \ + to str") + })?; chapter.insert("path".to_owned(), json!(path)); - }, + } BookItem::Chapter(ref s, ref ch) => { chapter.insert("section".to_owned(), json!(s)); chapter.insert("name".to_owned(), json!(ch.name)); let path = ch.path.to_str().ok_or_else(|| { - io::Error::new(io::ErrorKind::Other, "Could not convert path to str") - })?; + io::Error::new(io::ErrorKind::Other, + "Could not convert path \ + to str") + })?; chapter.insert("path".to_owned(), json!(path)); - }, + } BookItem::Spacer => { chapter.insert("spacer".to_owned(), json!("_spacer_")); - }, - + } } chapters.push(chapter); @@ -431,21 +412,22 @@ fn build_header_links(html: &str, filepath: &str) -> String { let regex = Regex::new(r"(.*?)").unwrap(); let mut id_counter = HashMap::new(); - regex - .replace_all(html, |caps: &Captures| { - let level = caps[1].parse().expect( - "Regex should ensure we only ever get numbers here", - ); + regex.replace_all(html, |caps: &Captures| { + let level = caps[1].parse() + .expect("Regex should ensure we only ever get numbers here"); - wrap_header_with_link(level, &caps[2], &mut id_counter, filepath) - }) - .into_owned() + wrap_header_with_link(level, &caps[2], &mut id_counter, filepath) + }) + .into_owned() } /// Wraps a single header tag with a link, making sure each tag gets its own /// unique ID by appending an auto-incremented number (if necessary). -fn wrap_header_with_link(level: usize, content: &str, id_counter: &mut HashMap, filepath: &str) - -> String { +fn wrap_header_with_link(level: usize, + content: &str, + id_counter: &mut HashMap, + filepath: &str) + -> String { let raw_id = id_from_content(content); let id_count = id_counter.entry(raw_id.clone()).or_insert(0); @@ -466,25 +448,23 @@ fn wrap_header_with_link(level: usize, content: &str, id_counter: &mut HashMap String { let mut content = content.to_string(); // Skip any tags or html-encoded stuff - const REPL_SUB: &[&str] = &[ - "", - "", - "", - "", - "", - "", - "<", - ">", - "&", - "'", - """, - ]; + const REPL_SUB: &[&str] = &["", + "", + "", + "", + "", + "", + "<", + ">", + "&", + "'", + """]; for sub in REPL_SUB { content = content.replace(sub, ""); } @@ -500,21 +480,18 @@ fn id_from_content(content: &str) -> String { // that in a very inelegant way fn fix_anchor_links(html: &str, filepath: &str) -> String { let regex = Regex::new(r##"]+)href="#([^"]+)"([^>]*)>"##).unwrap(); - regex - .replace_all(html, |caps: &Captures| { - let before = &caps[1]; - let anchor = &caps[2]; - let after = &caps[3]; + regex.replace_all(html, |caps: &Captures| { + let before = &caps[1]; + let anchor = &caps[2]; + let after = &caps[3]; - format!( - "", + format!("", before = before, filepath = filepath, anchor = anchor, - after = after - ) - }) - .into_owned() + after = after) + }) + .into_owned() } @@ -528,46 +505,53 @@ fn fix_anchor_links(html: &str, filepath: &str) -> String { // This function replaces all commas by spaces in the code block classes fn fix_code_blocks(html: &str) -> String { let regex = Regex::new(r##"]+)class="([^"]+)"([^>]*)>"##).unwrap(); - regex - .replace_all(html, |caps: &Captures| { - let before = &caps[1]; - let classes = &caps[2].replace(",", " "); - let after = &caps[3]; + regex.replace_all(html, |caps: &Captures| { + let before = &caps[1]; + let classes = &caps[2].replace(",", " "); + let after = &caps[3]; - format!(r#""#, before = before, classes = classes, after = after) - }) - .into_owned() + format!(r#""#, + before = before, + classes = classes, + after = after) + }) + .into_owned() } fn add_playpen_pre(html: &str, playpen_config: &PlaypenConfig) -> String { let regex = Regex::new(r##"((?s)]?class="([^"]+)".*?>(.*?))"##).unwrap(); - regex - .replace_all(html, |caps: &Captures| { - let text = &caps[1]; - let classes = &caps[2]; - let code = &caps[3]; + regex.replace_all(html, |caps: &Captures| { + let text = &caps[1]; + let classes = &caps[2]; + let code = &caps[3]; - if (classes.contains("language-rust") && !classes.contains("ignore")) || classes.contains("mdbook-runnable") { - // wrap the contents in an external pre block - if playpen_config.is_editable() && - classes.contains("editable") || text.contains("fn main") || text.contains("quick_main!") { - format!("
{}
", text) - } else { - // we need to inject our own main - let (attrs, code) = partition_source(code); - - format!("
\n# #![allow(unused_variables)]\n\
-                        {}#fn main() {{\n\
-                        {}\
-                        #}}
", - classes, attrs, code) - } + if (classes.contains("language-rust") && !classes.contains("ignore")) || + classes.contains("mdbook-runnable") + { + // wrap the contents in an external pre block + if playpen_config.is_editable() && classes.contains("editable") || + text.contains("fn main") || text.contains("quick_main!") + { + format!("
{}
", text) } else { - // not language-rust, so no-op - text.to_owned() + // we need to inject our own main + let (attrs, code) = partition_source(code); + + format!("
\n# \
+                         #![allow(unused_variables)]\n\
+                         {}#fn main() {{\n\
+                         {}\
+                         #}}
", + classes, + attrs, + code) } - }) - .into_owned() + } else { + // not language-rust, so no-op + text.to_owned() + } + }) + .into_owned() } fn partition_source(s: &str) -> (String, String) { @@ -609,16 +593,14 @@ pub fn normalize_path(path: &str) -> String { pub fn normalize_id(content: &str) -> String { content.chars() - .filter_map(|ch| - if ch.is_alphanumeric() || ch == '_' || ch == '-' { - Some(ch.to_ascii_lowercase()) - } else if ch.is_whitespace() { - Some('-') - } else { - None - } - ) - .collect::() + .filter_map(|ch| if ch.is_alphanumeric() || ch == '_' || ch == '-' { + Some(ch.to_ascii_lowercase()) + } else if ch.is_whitespace() { + Some('-') + } else { + None + }) + .collect::() } @@ -643,15 +625,15 @@ mod tests { ), ( "

", - r##"

"## + r##"

"##, ), ( "

", - r##"

"## + r##"

"##, ), ( "

Foo

Foo

", - r##"

Foo

Foo

"## + r##"

Foo

Foo

"##, ), ]; @@ -668,7 +650,9 @@ mod tests { #[test] fn anchor_generation() { - assert_eq!(id_from_content("## `--passes`: add more rustdoc passes"), "--passes-add-more-rustdoc-passes"); - assert_eq!(id_from_content("## Method-call expressions"), "method-call-expressions"); + assert_eq!(id_from_content("## `--passes`: add more rustdoc passes"), + "--passes-add-more-rustdoc-passes"); + assert_eq!(id_from_content("## Method-call expressions"), + "method-call-expressions"); } } diff --git a/src/renderer/html_handlebars/helpers/navigation.rs b/src/renderer/html_handlebars/helpers/navigation.rs index 7e8fa3ad..235c3949 100644 --- a/src/renderer/html_handlebars/helpers/navigation.rs +++ b/src/renderer/html_handlebars/helpers/navigation.rs @@ -2,7 +2,7 @@ use std::path::Path; use std::collections::BTreeMap; use serde_json; -use handlebars::{Handlebars, RenderError, RenderContext, Helper, Renderable, Context}; +use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError, Renderable}; // Handlebars helper for navigation @@ -11,73 +11,78 @@ pub fn previous(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<( debug!("[fn]: previous (handlebars helper)"); debug!("[*]: Get data from context"); - let chapters = rc.evaluate_absolute("chapters") - .and_then(|c| { - serde_json::value::from_value::>>(c.clone()) - .map_err(|_| RenderError::new("Could not decode the JSON data")) - })?; + let chapters = rc.evaluate_absolute("chapters").and_then(|c| { + serde_json::value::from_value::>>(c.clone()) + .map_err(|_| RenderError::new("Could not decode the JSON data")) + })?; let current = rc.evaluate_absolute("path")? - .as_str().ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? - .replace("\"", ""); + .as_str() + .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? + .replace("\"", ""); let mut previous: Option> = None; debug!("[*]: Search for current Chapter"); // Search for current chapter and return previous entry for item in chapters { - match item.get("path") { Some(path) if !path.is_empty() => { if path == ¤t { - debug!("[*]: Found current chapter"); if let Some(previous) = previous { - debug!("[*]: Creating BTreeMap to inject in context"); // Create new BTreeMap to extend the context: 'title' and 'link' let mut previous_chapter = BTreeMap::new(); // Chapter title - previous - .get("name").ok_or_else(|| RenderError::new("No title found for chapter in JSON data")) - .and_then(|n| { - previous_chapter.insert("title".to_owned(), json!(n)); - Ok(()) - })?; + previous.get("name") + .ok_or_else(|| { + RenderError::new("No title found for chapter in \ + JSON data") + }) + .and_then(|n| { + previous_chapter.insert("title".to_owned(), json!(n)); + Ok(()) + })?; // Chapter link - previous - .get("path").ok_or_else(|| RenderError::new("No path found for chapter in JSON data")) - .and_then(|p| { - Path::new(p) - .with_extension("html") - .to_str().ok_or_else(|| RenderError::new("Link could not be converted to str")) - .and_then(|p| { - previous_chapter - .insert("link".to_owned(), json!(p.replace("\\", "/"))); - Ok(()) - }) - })?; + previous.get("path") + .ok_or_else(|| { + RenderError::new("No path found for chapter in \ + JSON data") + }) + .and_then(|p| { + Path::new(p).with_extension("html") + .to_str() + .ok_or_else(|| { + RenderError::new("Link could not be \ + converted to str") + }) + .and_then(|p| { + previous_chapter + .insert("link".to_owned(), json!(p.replace("\\", "/"))); + Ok(()) + }) + })?; debug!("[*]: Render template"); // Render template _h.template() - .ok_or_else(|| RenderError::new("Error with the handlebars template")) - .and_then(|t| { - let mut local_rc = rc.with_context(Context::wraps(&previous_chapter)?); - t.render(r, &mut local_rc) - })?; + .ok_or_else(|| RenderError::new("Error with the handlebars template")) + .and_then(|t| { + let mut local_rc = rc.with_context(Context::wraps(&previous_chapter)?); + t.render(r, &mut local_rc) + })?; } break; } else { previous = Some(item.clone()); } - }, + } _ => continue, - } } @@ -91,67 +96,71 @@ pub fn next(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), R debug!("[fn]: next (handlebars helper)"); debug!("[*]: Get data from context"); - let chapters = rc.evaluate_absolute("chapters") - .and_then(|c| { - serde_json::value::from_value::>>(c.clone()) - .map_err(|_| RenderError::new("Could not decode the JSON data")) - })?; + let chapters = rc.evaluate_absolute("chapters").and_then(|c| { + serde_json::value::from_value::>>(c.clone()) + .map_err(|_| RenderError::new("Could not decode the JSON data")) + })?; let current = rc.evaluate_absolute("path")? - .as_str().ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? - .replace("\"", ""); + .as_str() + .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? + .replace("\"", ""); let mut previous: Option> = None; debug!("[*]: Search for current Chapter"); // Search for current chapter and return previous entry for item in chapters { - match item.get("path") { - Some(path) if !path.is_empty() => { - if let Some(previous) = previous { - - let previous_path = previous - .get("path").ok_or_else(|| RenderError::new("No path found for chapter in JSON data"))?; + let previous_path = previous.get("path").ok_or_else(|| { + RenderError::new("No path found for chapter in JSON data") + })?; if previous_path == ¤t { - debug!("[*]: Found current chapter"); debug!("[*]: Creating BTreeMap to inject in context"); // Create new BTreeMap to extend the context: 'title' and 'link' let mut next_chapter = BTreeMap::new(); - item.get("name").ok_or_else(|| RenderError::new("No title found for chapter in JSON data")) + item.get("name") + .ok_or_else(|| { + RenderError::new("No title found for chapter in JSON \ + data") + }) .and_then(|n| { next_chapter.insert("title".to_owned(), json!(n)); Ok(()) })?; - Path::new(path) - .with_extension("html") - .to_str().ok_or_else(|| RenderError::new("Link could not converted to str")) - .and_then(|l| { - debug!("[*]: Inserting link: {:?}", l); - // Hack for windows who tends to use `\` as separator instead of `/` - next_chapter.insert("link".to_owned(), json!(l.replace("\\", "/"))); - Ok(()) - })?; + Path::new(path).with_extension("html") + .to_str() + .ok_or_else(|| { + RenderError::new("Link could not converted \ + to str") + }) + .and_then(|l| { + debug!("[*]: Inserting link: {:?}", l); + // Hack for windows who tends to use `\` as separator instead of `/` + next_chapter.insert("link".to_owned(), json!(l.replace("\\", "/"))); + Ok(()) + })?; debug!("[*]: Render template"); // Render template - _h.template().ok_or_else(|| RenderError::new("Error with the handlebars template")) - .and_then(|t| { - let mut local_rc = rc.with_context(Context::wraps(&next_chapter)?); - t.render(r, &mut local_rc) - })?; + _h.template() + .ok_or_else(|| RenderError::new("Error with the handlebars template")) + .and_then(|t| { + let mut local_rc = rc.with_context(Context::wraps(&next_chapter)?); + t.render(r, &mut local_rc) + })?; break; } } previous = Some(item.clone()); - }, + } _ => continue, } diff --git a/src/renderer/html_handlebars/helpers/toc.rs b/src/renderer/html_handlebars/helpers/toc.rs index c5f4b602..0c633bad 100644 --- a/src/renderer/html_handlebars/helpers/toc.rs +++ b/src/renderer/html_handlebars/helpers/toc.rs @@ -2,8 +2,8 @@ use std::path::Path; use std::collections::BTreeMap; use serde_json; -use handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper}; -use pulldown_cmark::{Parser, html, Event, Tag}; +use handlebars::{Handlebars, Helper, HelperDef, RenderContext, RenderError}; +use pulldown_cmark::{html, Event, Parser, Tag}; // Handlebars helper to construct TOC #[derive(Clone, Copy)] @@ -11,29 +11,26 @@ pub struct RenderToc; impl HelperDef for RenderToc { fn call(&self, _h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> { - // get value from context data // rc.get_path() is current json parent path, you should always use it like this // param is the key of value you want to display - let chapters = rc.evaluate_absolute("chapters") - .and_then(|c| { - serde_json::value::from_value::>>(c.clone()) - .map_err(|_| RenderError::new("Could not decode the JSON data")) - })?; + let chapters = rc.evaluate_absolute("chapters").and_then(|c| { + serde_json::value::from_value::>>(c.clone()) + .map_err(|_| RenderError::new("Could not decode the JSON data")) + })?; let current = rc.evaluate_absolute("path")? - .as_str().ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? - .replace("\"", ""); + .as_str() + .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? + .replace("\"", ""); rc.writer.write_all(b"
    ")?; let mut current_level = 1; for item in chapters { - // Spacer if item.get("spacer").is_some() { - rc.writer - .write_all(b"
  • ")?; + rc.writer.write_all(b"
  • ")?; continue; } @@ -126,7 +123,6 @@ impl HelperDef for RenderToc { } rc.writer.write_all(b"")?; - } while current_level > 1 { rc.writer.write_all(b"
")?; diff --git a/src/theme/mod.rs b/src/theme/mod.rs index da6ec25a..6822a1be 100644 --- a/src/theme/mod.rs +++ b/src/theme/mod.rs @@ -18,11 +18,16 @@ pub static JQUERY: &'static [u8] = include_bytes!("jquery.js"); pub static CLIPBOARD_JS: &'static [u8] = include_bytes!("clipboard.min.js"); pub static STORE_JS: &'static [u8] = include_bytes!("store.js"); pub static FONT_AWESOME: &'static [u8] = include_bytes!("_FontAwesome/css/font-awesome.min.css"); -pub static FONT_AWESOME_EOT: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.eot"); -pub static FONT_AWESOME_SVG: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.svg"); -pub static FONT_AWESOME_TTF: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.ttf"); -pub static FONT_AWESOME_WOFF: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff"); -pub static FONT_AWESOME_WOFF2: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff2"); +pub static FONT_AWESOME_EOT: &'static [u8] = + include_bytes!("_FontAwesome/fonts/fontawesome-webfont.eot"); +pub static FONT_AWESOME_SVG: &'static [u8] = + include_bytes!("_FontAwesome/fonts/fontawesome-webfont.svg"); +pub static FONT_AWESOME_TTF: &'static [u8] = + include_bytes!("_FontAwesome/fonts/fontawesome-webfont.ttf"); +pub static FONT_AWESOME_WOFF: &'static [u8] = + include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff"); +pub static FONT_AWESOME_WOFF2: &'static [u8] = + include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff2"); pub static FONT_AWESOME_OTF: &'static [u8] = include_bytes!("_FontAwesome/fonts/FontAwesome.otf"); @@ -59,19 +64,17 @@ impl Theme { // Check for individual files, if they exist copy them across { - let files = vec![ - (theme_dir.join("index.hbs"), &mut theme.index), - (theme_dir.join("book.js"), &mut theme.js), - (theme_dir.join("book.css"), &mut theme.css), - (theme_dir.join("favicon.png"), &mut theme.favicon), - (theme_dir.join("highlight.js"), &mut theme.highlight_js), - (theme_dir.join("clipboard.min.js"), &mut theme.clipboard_js), - (theme_dir.join("store.js"), &mut theme.store_js), - (theme_dir.join("highlight.css"), &mut theme.highlight_css), - (theme_dir.join("tomorrow-night.css"), &mut theme.tomorrow_night_css), - (theme_dir.join("ayu-highlight.css"), &mut theme.ayu_highlight_css), - (theme_dir.join("jquery.js"), &mut theme.jquery), - ]; + let files = vec![(theme_dir.join("index.hbs"), &mut theme.index), + (theme_dir.join("book.js"), &mut theme.js), + (theme_dir.join("book.css"), &mut theme.css), + (theme_dir.join("favicon.png"), &mut theme.favicon), + (theme_dir.join("highlight.js"), &mut theme.highlight_js), + (theme_dir.join("clipboard.min.js"), &mut theme.clipboard_js), + (theme_dir.join("store.js"), &mut theme.store_js), + (theme_dir.join("highlight.css"), &mut theme.highlight_css), + (theme_dir.join("tomorrow-night.css"), &mut theme.tomorrow_night_css), + (theme_dir.join("ayu-highlight.css"), &mut theme.ayu_highlight_css), + (theme_dir.join("jquery.js"), &mut theme.jquery)]; for (filename, dest) in files { if !filename.exists() { diff --git a/src/theme/playpen_editor/mod.rs b/src/theme/playpen_editor/mod.rs index 5602532a..cfef26ed 100644 --- a/src/theme/playpen_editor/mod.rs +++ b/src/theme/playpen_editor/mod.rs @@ -47,13 +47,12 @@ impl PlaypenEditor { // Check for individual files if they exist { - let files = vec![ - (src.join("editor.js"), &mut editor.js), - (src.join("ace.js"), &mut editor.ace_js), - (src.join("mode-rust.js"), &mut editor.mode_rust_js), - (src.join("theme-dawn.js"), &mut editor.theme_dawn_js), - (src.join("theme-tomorrow_night.js"), &mut editor.theme_tomorrow_night_js), - ]; + let files = vec![(src.join("editor.js"), &mut editor.js), + (src.join("ace.js"), &mut editor.ace_js), + (src.join("mode-rust.js"), &mut editor.mode_rust_js), + (src.join("theme-dawn.js"), &mut editor.theme_dawn_js), + (src.join("theme-tomorrow_night.js"), + &mut editor.theme_tomorrow_night_js)]; for (filename, dest) in files { if !filename.exists() { diff --git a/src/utils/fs.rs b/src/utils/fs.rs index 5c27a0f6..af6f5354 100644 --- a/src/utils/fs.rs +++ b/src/utils/fs.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf, Component}; +use std::path::{Component, Path, PathBuf}; use errors::*; use std::io::Read; use std::fs::{self, File}; @@ -11,7 +11,7 @@ pub fn file_to_string>(path: P) -> Result { Err(e) => { debug!("[*]: Failed to open {:?}", path); bail!(e); - }, + } }; let mut content = String::new(); @@ -56,14 +56,14 @@ pub fn path_to_root>(path: P) -> String { .expect("") .components() .fold(String::new(), |mut s, c| { - match c { - Component::Normal(_) => s.push_str("../"), - _ => { - debug!("[*]: Other path component... {:?}", c); - }, + match c { + Component::Normal(_) => s.push_str("../"), + _ => { + debug!("[*]: Other path component... {:?}", c); } - s - }) + } + s + }) } @@ -107,7 +107,10 @@ pub fn remove_dir_content(dir: &Path) -> Result<()> { /// Copies all files of a directory to another one except the files /// with the extensions given in the `ext_blacklist` array -pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str]) +pub fn copy_files_except_ext(from: &Path, + to: &Path, + recursive: bool, + ext_blacklist: &[&str]) -> Result<()> { debug!("[fn] copy_files_except_ext"); // Check that from and to are different @@ -132,9 +135,11 @@ pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blackl fs::create_dir(&to.join(entry.file_name()))?; } - copy_files_except_ext(&from.join(entry.file_name()), &to.join(entry.file_name()), true, ext_blacklist)?; + copy_files_except_ext(&from.join(entry.file_name()), + &to.join(entry.file_name()), + true, + ext_blacklist)?; } else if metadata.is_file() { - // Check if it is in the blacklist if let Some(ext) = entry.path().extension() { if ext_blacklist.contains(&ext.to_str().unwrap()) { @@ -142,22 +147,19 @@ pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blackl } } debug!("[*] creating path for file: {:?}", - &to.join(entry - .path() - .file_name() - .expect("a file should have a file name..."))); + &to.join(entry.path() + .file_name() + .expect("a file should have a file name..."))); info!("[*] Copying file: {:?}\n to {:?}", entry.path(), - &to.join(entry - .path() - .file_name() - .expect("a file should have a file name..."))); + &to.join(entry.path() + .file_name() + .expect("a file should have a file name..."))); fs::copy(entry.path(), - &to.join(entry - .path() - .file_name() - .expect("a file should have a file name...")))?; + &to.join(entry.path() + .file_name() + .expect("a file should have a file name...")))?; } } Ok(()) @@ -216,7 +218,7 @@ mod tests { match copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, &["md"]) { Err(e) => panic!("Error while executing the function:\n{:?}", e), - Ok(_) => {}, + Ok(_) => {} } // Check if the correct files where created @@ -235,6 +237,5 @@ mod tests { if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() { panic!("output/sub_dir/file.png should exist") } - } } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index aa2c3f89..4c265dcc 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,6 +1,7 @@ pub mod fs; -use pulldown_cmark::{Parser, Event, Tag, html, Options, OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES}; +use pulldown_cmark::{html, Event, Options, Parser, Tag, OPTION_ENABLE_FOOTNOTES, + OPTION_ENABLE_TABLES}; use std::borrow::Cow; @@ -17,7 +18,8 @@ pub fn render_markdown(text: &str, curly_quotes: bool) -> String { let p = Parser::new_ext(text, opts); let mut converter = EventQuoteConverter::new(curly_quotes); - let events = p.map(clean_codeblock_headers).map(|event| converter.convert(event)); + let events = p.map(clean_codeblock_headers) + .map(|event| converter.convert(event)); html::push_html(&mut s, events); s @@ -30,7 +32,10 @@ struct EventQuoteConverter { impl EventQuoteConverter { fn new(enabled: bool) -> Self { - EventQuoteConverter { enabled: enabled, convert_text: true } + EventQuoteConverter { + enabled: enabled, + convert_text: true, + } } fn convert<'a>(&mut self, event: Event<'a>) -> Event<'a> { @@ -39,17 +44,17 @@ impl EventQuoteConverter { } match event { - Event::Start(Tag::CodeBlock(_)) | - Event::Start(Tag::Code) => { + Event::Start(Tag::CodeBlock(_)) | Event::Start(Tag::Code) => { self.convert_text = false; event - }, - Event::End(Tag::CodeBlock(_)) | - Event::End(Tag::Code) => { + } + Event::End(Tag::CodeBlock(_)) | Event::End(Tag::Code) => { self.convert_text = true; event - }, - Event::Text(ref text) if self.convert_text => Event::Text(Cow::from(convert_quotes_to_curly(text))), + } + Event::Text(ref text) if self.convert_text => { + Event::Text(Cow::from(convert_quotes_to_curly(text))) + } _ => event, } } @@ -58,13 +63,10 @@ impl EventQuoteConverter { fn clean_codeblock_headers(event: Event) -> Event { match event { Event::Start(Tag::CodeBlock(ref info)) => { - let info: String = info - .chars() - .filter(|ch| !ch.is_whitespace()) - .collect(); + let info: String = info.chars().filter(|ch| !ch.is_whitespace()).collect(); Event::Start(Tag::CodeBlock(Cow::from(info))) - }, + } _ => event, } } @@ -74,20 +76,31 @@ fn convert_quotes_to_curly(original_text: &str) -> String { // We'll consider the start to be "whitespace". let mut preceded_by_whitespace = true; - original_text - .chars() - .map(|original_char| { - let converted_char = match original_char { - '\'' => if preceded_by_whitespace { '‘' } else { '’' }, - '"' => if preceded_by_whitespace { '“' } else { '”' }, - _ => original_char, - }; + original_text.chars() + .map(|original_char| { + let converted_char = match original_char { + '\'' => { + if preceded_by_whitespace { + '‘' + } else { + '’' + } + } + '"' => { + if preceded_by_whitespace { + '“' + } else { + '”' + } + } + _ => original_char, + }; - preceded_by_whitespace = original_char.is_whitespace(); + preceded_by_whitespace = original_char.is_whitespace(); - converted_char - }) - .collect() + converted_char + }) + .collect() } #[cfg(test)] @@ -146,7 +159,8 @@ more text with spaces ``` "#; - let expected = r#"
+ let expected = + r#"
"#; assert_eq!(render_markdown(input, false), expected); assert_eq!(render_markdown(input, true), expected); @@ -159,7 +173,8 @@ more text with spaces ``` "#; - let expected = r#"
+ let expected = + r#"
"#; assert_eq!(render_markdown(input, false), expected); assert_eq!(render_markdown(input, true), expected); @@ -168,7 +183,7 @@ more text with spaces #[test] fn rust_code_block_without_properties_has_proper_html_class() { let input = r#" -```rust +```rust ``` "#; @@ -183,7 +198,6 @@ more text with spaces "#; assert_eq!(render_markdown(input, false), expected); assert_eq!(render_markdown(input, true), expected); - } } @@ -192,12 +206,14 @@ more text with spaces #[test] fn it_converts_single_quotes() { - assert_eq!(convert_quotes_to_curly("'one', 'two'"), "‘one’, ‘two’"); + assert_eq!(convert_quotes_to_curly("'one', 'two'"), + "‘one’, ‘two’"); } #[test] fn it_converts_double_quotes() { - assert_eq!(convert_quotes_to_curly(r#""one", "two""#), "“one”, “two”"); + assert_eq!(convert_quotes_to_curly(r#""one", "two""#), + "“one”, “two”"); } #[test] diff --git a/tests/config.rs b/tests/config.rs index 6601ef39..e7d3cff9 100644 --- a/tests/config.rs +++ b/tests/config.rs @@ -13,10 +13,9 @@ use tempdir::TempDir; fn do_not_overwrite_unspecified_config_values() { let dir = TempDir::new("mdbook").expect("Could not create a temp dir"); - let book = MDBook::new(dir.path()) - .with_source("bar") - .with_destination("baz") - .with_mathjax_support(true); + let book = MDBook::new(dir.path()).with_source("bar") + .with_destination("baz") + .with_mathjax_support(true); assert_eq!(book.get_root(), dir.path()); assert_eq!(book.get_source(), dir.path().join("bar")); @@ -33,7 +32,8 @@ fn do_not_overwrite_unspecified_config_values() { // Try with a partial config file let file_path = dir.path().join("book.toml"); let mut f = File::create(file_path).expect("Could not create config file"); - f.write_all(br#"source = "barbaz""#).expect("Could not write to config file"); + f.write_all(br#"source = "barbaz""#) + .expect("Could not write to config file"); f.sync_all().expect("Could not sync the file"); let book = book.read_config().expect("Error reading the config file"); @@ -43,4 +43,3 @@ fn do_not_overwrite_unspecified_config_values() { assert_eq!(book.get_destination(), dir.path().join("baz")); assert_eq!(book.get_mathjax_support(), true); } - diff --git a/tests/dummy/mod.rs b/tests/dummy/mod.rs index ca561d86..81a8896d 100644 --- a/tests/dummy/mod.rs +++ b/tests/dummy/mod.rs @@ -63,20 +63,17 @@ impl DummyBook { let to_substitute = if self.passing_test { "true" } else { "false" }; let nested_text = NESTED.replace("$TEST_STATUS", to_substitute); - let inputs = vec![ - (src.join("SUMMARY.md"), SUMMARY_MD), - (src.join("intro.md"), INTRO), - (first.join("index.md"), FIRST), - (first.join("nested.md"), &nested_text), - (src.join("second.md"), SECOND), - (src.join("conclusion.md"), CONCLUSION), - ]; + let inputs = vec![(src.join("SUMMARY.md"), SUMMARY_MD), + (src.join("intro.md"), INTRO), + (first.join("index.md"), FIRST), + (first.join("nested.md"), &nested_text), + (src.join("second.md"), SECOND), + (src.join("conclusion.md"), CONCLUSION)]; for (path, content) in inputs { - File::create(path) - .unwrap() - .write_all(content.as_bytes()) - .unwrap(); + File::create(path).unwrap() + .write_all(content.as_bytes()) + .unwrap(); } temp diff --git a/tests/helpers/mod.rs b/tests/helpers/mod.rs index da6af35c..3d1cdcc2 100644 --- a/tests/helpers/mod.rs +++ b/tests/helpers/mod.rs @@ -13,12 +13,15 @@ pub fn assert_contains_strings>(filename: P, strings: &[&str]) { let filename = filename.as_ref(); let mut content = String::new(); - File::open(&filename) - .expect("Couldn't open the provided file") - .read_to_string(&mut content) - .expect("Couldn't read the file's contents"); + File::open(&filename).expect("Couldn't open the provided file") + .read_to_string(&mut content) + .expect("Couldn't read the file's contents"); for s in strings { - assert!(content.contains(s), "Searching for {:?} in {}\n\n{}", s, filename.display(), content); + assert!(content.contains(s), + "Searching for {:?} in {}\n\n{}", + s, + filename.display(), + content); } } diff --git a/tests/init.rs b/tests/init.rs index e7518fde..9597bd04 100644 --- a/tests/init.rs +++ b/tests/init.rs @@ -32,16 +32,19 @@ fn run_mdbook_init_with_custom_book_and_src_locations() { let temp = TempDir::new("mdbook").unwrap(); for file in &created_files { - assert!(!temp.path().join(file).exists(), "{} shouldn't exist yet!", file); + assert!(!temp.path().join(file).exists(), + "{} shouldn't exist yet!", + file); } - let mut md = MDBook::new(temp.path()) - .with_source("in") - .with_destination("out"); + let mut md = MDBook::new(temp.path()).with_source("in") + .with_destination("out"); md.init().unwrap(); for file in &created_files { - assert!(temp.path().join(file).exists(), "{} should have been created by `mdbook init`", file); + assert!(temp.path().join(file).exists(), + "{} should have been created by `mdbook init`", + file); } } diff --git a/tests/rendered_output.rs b/tests/rendered_output.rs index 7de0838f..eb76d056 100644 --- a/tests/rendered_output.rs +++ b/tests/rendered_output.rs @@ -37,13 +37,11 @@ fn make_sure_bottom_level_files_contain_links_to_chapters() { md.build().unwrap(); let dest = temp.path().join("book"); - let links = vec![ - r#"href="intro.html""#, - r#"href="./first/index.html""#, - r#"href="./first/nested.html""#, - r#"href="./second.html""#, - r#"href="./conclusion.html""#, - ]; + let links = vec![r#"href="intro.html""#, + r#"href="./first/index.html""#, + r#"href="./first/nested.html""#, + r#"href="./second.html""#, + r#"href="./conclusion.html""#]; let files_in_bottom_dir = vec!["index.html", "intro.html", "second.html", "conclusion.html"]; @@ -59,14 +57,12 @@ fn check_correct_cross_links_in_nested_dir() { md.build().unwrap(); let first = temp.path().join("book").join("first"); - let links = vec![ - r#""#, - r#"href="intro.html""#, - r#"href="./first/index.html""#, - r#"href="./first/nested.html""#, - r#"href="./second.html""#, - r#"href="./conclusion.html""#, - ]; + let links = vec![r#""#, + r#"href="intro.html""#, + r#"href="./first/index.html""#, + r#"href="./first/nested.html""#, + r#"href="./second.html""#, + r#"href="./conclusion.html""#]; let files_in_nested_dir = vec!["index.html", "nested.html"]; @@ -74,19 +70,11 @@ fn check_correct_cross_links_in_nested_dir() { assert_contains_strings(first.join(filename), &links); } - assert_contains_strings( - first.join("index.html"), - &[ - r##"href="./first/index.html#some-section" id="some-section""## - ], - ); + assert_contains_strings(first.join("index.html"), + &[r##"href="./first/index.html#some-section" id="some-section""##]); - assert_contains_strings( - first.join("nested.html"), - &[ - r##"href="./first/nested.html#some-section" id="some-section""## - ], - ); + assert_contains_strings(first.join("nested.html"), + &[r##"href="./first/nested.html#some-section" id="some-section""##]); } #[test] @@ -106,13 +94,11 @@ fn rendered_code_has_playpen_stuff() { #[test] fn chapter_content_appears_in_rendered_document() { - let content = vec![ - ("index.html", "Here's some interesting text"), - ("second.html", "Second Chapter"), - ("first/nested.html", "testable code"), - ("first/index.html", "more text"), - ("conclusion.html", "Conclusion"), - ]; + let content = vec![("index.html", "Here's some interesting text"), + ("second.html", "Second Chapter"), + ("first/nested.html", "testable code"), + ("first/index.html", "more text"), + ("conclusion.html", "Conclusion")]; let temp = DummyBook::default().build(); let mut md = MDBook::new(temp.path()); diff --git a/tests/testing.rs b/tests/testing.rs index e4cf8da5..57101336 100644 --- a/tests/testing.rs +++ b/tests/testing.rs @@ -9,9 +9,7 @@ use mdbook::MDBook; #[test] fn mdbook_can_correctly_test_a_passing_book() { - let temp = DummyBook::default() - .with_passing_test(true) - .build(); + let temp = DummyBook::default().with_passing_test(true).build(); let mut md = MDBook::new(temp.path()); assert!(md.test(vec![]).is_ok()); @@ -19,9 +17,7 @@ fn mdbook_can_correctly_test_a_passing_book() { #[test] fn mdbook_detects_book_with_failing_tests() { - let temp = DummyBook::default() - .with_passing_test(false) - .build(); + let temp = DummyBook::default().with_passing_test(false).build(); let mut md: MDBook = MDBook::new(temp.path()); assert!(md.test(vec![]).is_err()); diff --git a/tests/tomlconfig.rs b/tests/tomlconfig.rs index eaf83128..b6c02e57 100644 --- a/tests/tomlconfig.rs +++ b/tests/tomlconfig.rs @@ -56,7 +56,8 @@ fn from_toml_authors() { let parsed = TomlConfig::from_toml(toml).expect("This should parse"); let config = BookConfig::from_tomlconfig("root", parsed); - assert_eq!(config.get_authors(), &[String::from("John Doe"), String::from("Jane Doe")]); + assert_eq!(config.get_authors(), + &[String::from("John Doe"), String::from("Jane Doe")]); } // Tests that the default `playpen` config is correct in the TOML config @@ -69,7 +70,8 @@ fn from_toml_playpen_default() { let playpenconfig = config.get_html_config().get_playpen_config(); - assert_eq!(playpenconfig.get_editor(), PathBuf::from("root/theme/editor")); + assert_eq!(playpenconfig.get_editor(), + PathBuf::from("root/theme/editor")); assert_eq!(playpenconfig.is_editable(), false); } @@ -84,7 +86,8 @@ fn from_toml_playpen_editor() { let playpenconfig = config.get_html_config().get_playpen_config(); - assert_eq!(playpenconfig.get_editor(), PathBuf::from("root/theme/editordir")); + assert_eq!(playpenconfig.get_editor(), + PathBuf::from("root/theme/editordir")); } // Tests that the `playpen.editable` key is correctly parsed in the TOML config @@ -168,7 +171,9 @@ fn from_toml_output_html_google_analytics() { let htmlconfig = config.get_html_config(); - assert_eq!(htmlconfig.get_google_analytics_id().expect("the google-analytics key was provided"), String::from("123456")); + assert_eq!(htmlconfig.get_google_analytics_id() + .expect("the google-analytics key was provided"), + String::from("123456")); } // Tests that the `output.html.additional-css` key is correctly parsed in the TOML config @@ -182,7 +187,9 @@ fn from_toml_output_html_additional_stylesheet() { let htmlconfig = config.get_html_config(); - assert_eq!(htmlconfig.get_additional_css(), &[PathBuf::from("root/custom.css"), PathBuf::from("root/two/custom.css")]); + assert_eq!(htmlconfig.get_additional_css(), + &[PathBuf::from("root/custom.css"), + PathBuf::from("root/two/custom.css")]); } // Tests that the `output.html.additional-js` key is correctly parsed in the TOML config @@ -196,5 +203,7 @@ fn from_toml_output_html_additional_scripts() { let htmlconfig = config.get_html_config(); - assert_eq!(htmlconfig.get_additional_js(), &[PathBuf::from("root/custom.js"), PathBuf::from("root/two/custom.js")]); + assert_eq!(htmlconfig.get_additional_js(), + &[PathBuf::from("root/custom.js"), + PathBuf::from("root/two/custom.js")]); }