From 07719a8e0ea3fcc31c680672b59f68aa9029e565 Mon Sep 17 00:00:00 2001 From: Dylan Maccora Date: Thu, 15 Mar 2018 02:27:56 +1100 Subject: [PATCH] Adding for content to book.toml on init (#627) * Obtaining author name from gitconfig * Writing theme to config on init * Addressing a FIXME came across * Add request for book title. --- src/bin/init.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++- src/book/mod.rs | 11 +++++------ src/config.rs | 21 ++++++++++++++++----- 3 files changed, 70 insertions(+), 12 deletions(-) diff --git a/src/bin/init.rs b/src/bin/init.rs index b0299059..b51ee73a 100644 --- a/src/bin/init.rs +++ b/src/bin/init.rs @@ -1,8 +1,11 @@ use std::io; use std::io::Write; +use std::env; use clap::{App, ArgMatches, SubCommand}; use mdbook::MDBook; use mdbook::errors::Result; +use mdbook::utils; +use mdbook::config; use get_book_dir; // Create clap subcommand arguments @@ -20,9 +23,11 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> { pub fn execute(args: &ArgMatches) -> Result<()> { let book_dir = get_book_dir(args); let mut builder = MDBook::init(&book_dir); + let mut config = config::Config::default(); // If flag `--theme` is present, copy theme to src if args.is_present("theme") { + config.set("output.html.theme", "src/theme")?; // Skip this if `--force` is present if !args.is_present("force") { // Print warning @@ -38,6 +43,8 @@ pub fn execute(args: &ArgMatches) -> Result<()> { if confirm() { builder.copy_theme(true); } + } else { + builder.copy_theme(true); } } @@ -47,13 +54,54 @@ pub fn execute(args: &ArgMatches) -> Result<()> { builder.create_gitignore(true); } + config.book.title = request_book_title(); + + if let Some(author) = get_author_name() { + debug!("Obtained user name from gitconfig: {:?}", author); + config.book.authors.push(author); + builder.with_config(config); + } + builder.build()?; println!("\nAll done, no errors..."); Ok(()) } -// Simple function that user comfirmation +/// Obtains author name from git config file if it can be located. +fn get_author_name() -> Option { + if let Some(home) = env::home_dir() { + let git_config_path = home.join(".gitconfig"); + let content = utils::fs::file_to_string(git_config_path).unwrap(); + let user_name = content + .lines() + .filter(|x| !x.starts_with("#")) + .map(|x| x.trim_left()) + .filter(|x| x.starts_with("name")) + .next(); + user_name + .and_then(|x| x.rsplit("=").next()) + .map(|x| x.trim().to_owned()) + } else { + None + } +} + +/// Request book title from user and return if provided. +fn request_book_title() -> Option { + println!("What title would you like to give the book? "); + io::stdout().flush().unwrap(); + let mut resp = String::new(); + io::stdin().read_line(&mut resp).unwrap(); + let resp = resp.trim(); + if resp.is_empty() { + None + } else { + Some(resp.into()) + } +} + +// Simple function for user confirmation fn confirm() -> bool { io::stdout().flush().unwrap(); let mut s = String::new(); diff --git a/src/book/mod.rs b/src/book/mod.rs index 141b6cf7..9c5aeac2 100644 --- a/src/book/mod.rs +++ b/src/book/mod.rs @@ -288,13 +288,12 @@ impl MDBook { self.root.join(&self.config.book.src) } - // FIXME: This really belongs as part of the `HtmlConfig`. - #[doc(hidden)] + /// Get the directory containing the theme resources for the book. pub fn theme_dir(&self) -> PathBuf { - match self.config.html_config().and_then(|h| h.theme) { - Some(d) => self.root.join(d), - None => self.root.join("theme"), - } + self.config + .html_config() + .unwrap_or_default() + .theme_dir(&self.root) } } diff --git a/src/config.rs b/src/config.rs index 253c2fd1..898ec6b7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -383,7 +383,6 @@ pub struct BuildConfig { pub create_missing: bool, /// Which preprocessors should be applied pub preprocess: Option>, - } impl Default for BuildConfig { @@ -429,6 +428,17 @@ pub struct HtmlConfig { pub search: Option, } +impl HtmlConfig { + /// Returns the directory of theme from the provided root directory. If the + /// directory is not present it will append the default directory of "theme" + pub fn theme_dir(&self, root: &PathBuf) -> PathBuf { + match self.theme { + Some(ref d) => root.join(d), + None => root.join("theme"), + } + } +} + /// Configuration for tweaking how the the HTML renderer handles the playpen. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(default, rename_all = "kebab-case")] @@ -471,7 +481,7 @@ pub struct Search { /// Default: `1`. pub boost_paragraph: u8, /// True if the searchword `micro` should match `microwave`. Default: `true`. - pub expand : bool, + pub expand: bool, /// Documents are split into smaller parts, seperated by headings. This defines, until which /// level of heading documents should be split. Default: `3`. (`### This is a level 3 heading`) pub heading_split_level: u8, @@ -497,7 +507,6 @@ impl Default for Search { } } - /// Allows you to "update" any arbitrary field in a struct by round-tripping via /// a `toml::Value`. /// @@ -570,8 +579,10 @@ mod tests { let build_should_be = BuildConfig { build_dir: PathBuf::from("outputs"), create_missing: false, - preprocess: Some(vec!["first_preprocessor".to_string(), - "second_preprocessor".to_string()]), + preprocess: Some(vec![ + "first_preprocessor".to_string(), + "second_preprocessor".to_string(), + ]), }; let playpen_should_be = Playpen { editable: true,