diff --git a/scripts/test-init.sh b/scripts/test-init.sh index dd315fb..ab26c40 100755 --- a/scripts/test-init.sh +++ b/scripts/test-init.sh @@ -3,16 +3,13 @@ rm -rf test/* mkdir -p test - - set -e ./scripts/build.sh cp target/release/oseda test - cd test pwd -./oseda init +./oseda init --title ExampleProject --tags economics ComPuterScience --color red --template MaRKDoWN diff --git a/src/cmd/init.rs b/src/cmd/init.rs index 784ce45..235105f 100644 --- a/src/cmd/init.rs +++ b/src/cmd/init.rs @@ -9,7 +9,7 @@ touch vite.config.js -> add the plugin, write this by hand use std::{ error::Error, fs::{self}, - process::Command, + process::Command, str::FromStr, }; use clap::Args; @@ -20,9 +20,18 @@ use crate::{config, template::Template}; /// Options for the `oseda init` command #[derive(Args, Debug)] pub struct InitOptions { - /// Unused for now - #[arg(long, required = false)] - sentation_only: bool, + #[arg(long)] + pub title: Option, + + #[arg(long, num_args = 1.., value_delimiter=' ')] + pub tags: Option>, + + #[arg(long)] + pub color: Option, + + #[arg(long)] + pub template: Option, + } // embed all the static markdown template files into binary @@ -54,10 +63,19 @@ const HTML_FERRIS: &[u8] = include_bytes!("../static/html-templates/ferris.png") /// # Returns /// * `Ok(())` if project initialization is suceeded /// * `Err` if any step (npm, file write, config generation etc) fails -pub fn init(_opts: InitOptions) -> Result<(), Box> { - let conf = config::create_conf()?; +pub fn init(opts: InitOptions) -> Result<(), Box> { + + let template = match opts.template{ + Some(ref arg_template) => { + Template::from_str(&arg_template) + .map_err(|_| format!("Invalid template"))? + } + None => prompt_template()?, + }; + + + let conf = config::create_conf(opts)?; - let template: Template = prompt_template()?; std::fs::create_dir_all(&conf.title)?; diff --git a/src/color.rs b/src/color.rs index 6ad9ae7..b6fef3d 100644 --- a/src/color.rs +++ b/src/color.rs @@ -1,7 +1,8 @@ use serde::{Deserialize, Serialize}; -use strum_macros::{Display, EnumIter}; +use strum_macros::{Display, EnumIter, EnumString}; -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Display, EnumIter)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Display, EnumIter, EnumString)] +#[strum(ascii_case_insensitive)] pub enum Color { Black, White, diff --git a/src/config.rs b/src/config.rs index 1297111..68447d3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,7 @@ use std::error::Error; use std::fs::File; use std::io::BufWriter; +use std::str::FromStr; use std::{ffi::OsString, fs}; use chrono::{DateTime, Utc}; @@ -10,6 +11,7 @@ use strum::IntoEnumIterator; use crate::tags::Tag; use crate::cmd::check::OsedaCheckError; +use crate::cmd::init::InitOptions; use crate::color::Color; use crate::github; @@ -107,15 +109,9 @@ pub struct OsedaConfig { pub color: String, } -/// Prompts the user for everything needed to generate a new OsedaConfig -/// -/// # Returns -/// * `Ok(OsedaConfig)` containing validated project config options -/// * `Err` if a required input conf is invalid -pub fn create_conf() -> Result> { - // let mut title = String::new(); - // std::io::std in().read_line(&mut title)?; + +pub fn prompt_for_title() -> Result> { let validator = |input: &str| { if input.chars().count() < 2 { Ok(Validation::Invalid( @@ -126,14 +122,41 @@ pub fn create_conf() -> Result> { } }; - let mut title = inquire::Text::new("Title: ") + Ok(inquire::Text::new("Title: ") .with_validator(validator) - .prompt()?; + .prompt()?) +} +/// Prompts the user for everything needed to generate a new OsedaConfig +/// +/// # Returns +/// * `Ok(OsedaConfig)` containing validated project config options +/// * `Err` if a required input conf is invalid +pub fn create_conf(options: InitOptions) -> Result> { - title = title.replace(" ", "-"); + let title = match options.title { + Some(arg_title) => arg_title, + None => prompt_for_title()?.replace(" ", "-") + }; - let tags = get_tags()?; - let color = get_color()?; + let tags = match options.tags { + Some(arg_tags) => { + arg_tags + .iter() + .map(|arg_tag| Tag::from_str(arg_tag)) + .collect::, _>>() + .map_err(|_| format!("Invalid tag. Custom Tags may be added to the oseda-config.json after initialization"))? + }, + None => prompt_for_tags()? + }; + + + let color = match options.color { + Some(arg_color) => { + Color::from_str(&arg_color) + .map_err(|_| format!("Invalid color. Please use traditional english color names"))? + }, + None => prompt_for_color()? + }; let user_name = github::get_config_from_user_git("user.name") .ok_or("Could not get github username. Please ensure you are signed into github")?; @@ -141,7 +164,7 @@ pub fn create_conf() -> Result> { Ok(OsedaConfig { title: title.trim().to_owned(), author: user_name, - tags, + tags: tags, last_updated: get_time(), color: color.into_hex(), }) @@ -150,26 +173,24 @@ pub fn create_conf() -> Result> { /// Prompts user for categories associated with their Oseda project /// /// # Returns -/// * `Ok(Vec)` with selected categories +/// * `Ok(Vec)` with selected categories /// * `Err` if the prompting went wrong somewhere -fn get_tags() -> Result, Box> { +fn prompt_for_tags() -> Result, Box> { let options: Vec = Tag::iter().collect(); - println!("Select tags that match your course's meaning and purpose."); - println!("(You can always add custom tags later!)"); let selected_tags = - inquire::MultiSelect::new("Select tags (type to search):", options.clone()) + inquire::MultiSelect::new("Select categories (type to search):", options.clone()) .prompt()?; println!("You selected:"); - for tag in selected_tags.iter() { - println!("- {:?}", tag); + for tags in selected_tags.iter() { + println!("- {:?}", tags); } Ok(selected_tags) } -fn get_color() -> Result> { +fn prompt_for_color() -> Result> { let options: Vec = Color::iter().collect(); let selected_color = inquire::Select::new( @@ -230,6 +251,8 @@ mod test { use std::path::Path; use tempfile::tempdir; + use crate::tags; + use super::*; #[allow(dead_code)] @@ -238,7 +261,7 @@ mod test { { "title": "TestableRust", "author": "JaneDoe", - "tags": ["ComputerScience"], + "category": ["ComputerScience"], "last_updated": "2024-07-10T12:34:56Z" } "# diff --git a/src/github.rs b/src/github.rs index 70610d6..6263fc6 100644 --- a/src/github.rs +++ b/src/github.rs @@ -30,8 +30,6 @@ pub fn get_config_from_user_git(key: &str) -> Option { let conf_out = String::from_utf8(handle.stdout).ok()?; - println!("{conf_out}"); - get_key_from_conf(key, &conf_out) } diff --git a/src/tags.rs b/src/tags.rs index f2ba701..e95f061 100644 --- a/src/tags.rs +++ b/src/tags.rs @@ -1,8 +1,9 @@ use serde::{Deserialize, Serialize}; use strum::IntoEnumIterator; -use strum_macros::{Display, EnumIter}; +use strum_macros::{Display, EnumIter, EnumString}; -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Display, EnumIter)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Display, EnumIter, EnumString)] +#[strum(ascii_case_insensitive)] pub enum Tag { Aerospace, Business, diff --git a/src/template.rs b/src/template.rs index 6575439..e483da9 100644 --- a/src/template.rs +++ b/src/template.rs @@ -1,7 +1,8 @@ use serde::{Deserialize, Serialize}; -use strum_macros::{Display, EnumIter}; +use strum_macros::{Display, EnumIter, EnumString}; -#[derive(Serialize, Deserialize, Debug, Clone, Copy, Display, EnumIter)] +#[derive(Serialize, Deserialize, Debug, Clone, Copy, Display, EnumIter, EnumString)] +#[strum(ascii_case_insensitive)] pub enum Template { Markdown, HTML,