diff --git a/collection.toml b/collection.toml index d3bd1ba..7f0cb3b 100644 --- a/collection.toml +++ b/collection.toml @@ -1,4 +1,5 @@ title = "Title" +output_file = "local/collection-output.md" [[collections]] label = "Items" diff --git a/docs/release-notes.md b/docs/release-notes.md new file mode 100644 index 0000000..c7e14ed --- /dev/null +++ b/docs/release-notes.md @@ -0,0 +1,13 @@ +# Release Notes + +## v0.2.2 + +Added write output file. + +## v0.2.1 + +Added wait for user. + +## v0.1.1 + +Initial release. diff --git a/src/config/mod.rs b/src/config/mod.rs index 50d1629..9d25877 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -6,10 +6,20 @@ use std::fs; use collection::Collection; +// Struct containing the processed configuration. +#[derive(Debug)] +pub struct Config { + pub title: String, + // Defaults to "collection.txt". + pub output_file: String, + pub collections: Vec, +} + // Top level struct to hold entire input configuration. #[derive(Debug, Deserialize)] -pub struct Config { +pub struct ConfigInput { pub title: String, + pub output_file: Option, pub collections: Vec, } @@ -19,8 +29,13 @@ impl Config { let contents = fs::read_to_string(filename).map_err(|err| format!("Unable to read file '{}'. Error: {}", filename, err))?; - let input: Config = toml::from_str(&contents).map_err(|err| format!("Unable to load data from '{}'. Error: {}", filename, err))?; + let input: ConfigInput = + toml::from_str(&contents).map_err(|err| format!("Unable to load data from '{}'. Error: {}", filename, err))?; - Ok(input) + Ok(Config { + title: input.title, + output_file: input.output_file.unwrap_or("collection.txt".to_string()), + collections: input.collections, + }) } } diff --git a/src/lib.rs b/src/lib.rs index b733ca8..a8c6d67 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,9 @@ use crate::{config::Config, library::format::Row}; use rand::prelude::*; use std::error::Error; +use std::fs; use std::io::{stdin, stdout, Write}; +use std::path::Path; mod config; mod library; @@ -10,13 +12,13 @@ pub fn main() -> Result<(), Box> { // Read configuration. let mut config = Config::read()?; - // Print title. - println!("\n{}\n", config.title); - shuffle_items(&mut config); - print_labels(&config); - print_items(&config); + // Format output. + let output = format!("{}\n\n{}\n{}", config.title, format_labels(&config), format_items(&config)); + + println!("\n{}", output); + write_to_file(config.output_file, output); wait_for_user(); @@ -31,14 +33,15 @@ fn shuffle_items(config: &mut Config) { } } -fn print_labels(config: &Config) { +fn format_labels(config: &Config) -> String { let labels = config.collections.iter().map(|c| Row { output: &c.label, width: c.width.into() }); let widths = config.collections.iter().map(|c| c.width.into()); - println!("{}", library::format::row(labels)); - println!("{}", library::format::divider(widths, None)); + + format!("{}\n{}", library::format::row(labels), library::format::divider(widths, None)) } -fn print_items(config: &Config) { +fn format_items(config: &Config) -> String { + let mut builder = String::new(); let string_empty = String::new(); let length = config.collections.iter().map(|c| c.items.len()).max().unwrap_or(0); for index in 0..length { @@ -46,12 +49,25 @@ fn print_items(config: &Config) { output: c.items.get(index).unwrap_or(&string_empty), width: c.width.into(), }); - println!("{}", library::format::row(items)); + builder.push_str(&library::format::row(items)); + builder.push('\n'); } + builder } fn wait_for_user() { - print!("\nPress to exit: "); + print!("Press to exit: "); stdout().flush().expect("Error writing output."); stdin().read_line(&mut String::new()).expect("Error reading input."); } + +fn write_to_file(path: P, contents: C) +where + P: AsRef, + C: AsRef<[u8]>, +{ + if let Some(parent) = path.as_ref().parent() { + fs::create_dir_all(parent).expect("Error creating parent directories."); + } + fs::write(path, contents).expect("Error writing output to file."); +}