Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions scripts/test-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
32 changes: 25 additions & 7 deletions src/cmd/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<String>,

#[arg(long, num_args = 1.., value_delimiter=' ')]
pub tags: Option<Vec<String>>,

#[arg(long)]
pub color: Option<String>,

#[arg(long)]
pub template: Option<String>,

}

// embed all the static markdown template files into binary
Expand Down Expand Up @@ -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<dyn Error>> {
let conf = config::create_conf()?;
pub fn init(opts: InitOptions) -> Result<(), Box<dyn Error>> {

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)?;

Expand Down
5 changes: 3 additions & 2 deletions src/color.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
69 changes: 46 additions & 23 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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;

Expand Down Expand Up @@ -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<OsedaConfig, Box<dyn Error>> {
// let mut title = String::new();
// std::io::std in().read_line(&mut title)?;


pub fn prompt_for_title() -> Result<String, Box<dyn Error>> {
let validator = |input: &str| {
if input.chars().count() < 2 {
Ok(Validation::Invalid(
Expand All @@ -126,22 +122,49 @@ pub fn create_conf() -> Result<OsedaConfig, Box<dyn Error>> {
}
};

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<OsedaConfig, Box<dyn Error>> {

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::<Result<Vec<Tag>, _>>()
.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")?;

Ok(OsedaConfig {
title: title.trim().to_owned(),
author: user_name,
tags,
tags: tags,
last_updated: get_time(),
color: color.into_hex(),
})
Expand All @@ -150,26 +173,24 @@ pub fn create_conf() -> Result<OsedaConfig, Box<dyn Error>> {
/// Prompts user for categories associated with their Oseda project
///
/// # Returns
/// * `Ok(Vec<Tag>)` with selected categories
/// * `Ok(Vec<Category>)` with selected categories
/// * `Err` if the prompting went wrong somewhere
fn get_tags() -> Result<Vec<Tag>, Box<dyn Error>> {
fn prompt_for_tags() -> Result<Vec<Tag>, Box<dyn Error>> {
let options: Vec<Tag> = 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<Color, Box<dyn Error>> {
fn prompt_for_color() -> Result<Color, Box<dyn Error>> {
let options: Vec<Color> = Color::iter().collect();

let selected_color = inquire::Select::new(
Expand Down Expand Up @@ -230,6 +251,8 @@ mod test {
use std::path::Path;
use tempfile::tempdir;

use crate::tags;

use super::*;

#[allow(dead_code)]
Expand All @@ -238,7 +261,7 @@ mod test {
{
"title": "TestableRust",
"author": "JaneDoe",
"tags": ["ComputerScience"],
"category": ["ComputerScience"],
"last_updated": "2024-07-10T12:34:56Z"
}
"#
Expand Down
2 changes: 0 additions & 2 deletions src/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ pub fn get_config_from_user_git(key: &str) -> Option<String> {

let conf_out = String::from_utf8(handle.stdout).ok()?;

println!("{conf_out}");

get_key_from_conf(key, &conf_out)
}

Expand Down
5 changes: 3 additions & 2 deletions src/tags.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
5 changes: 3 additions & 2 deletions src/template.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
Loading