diff --git a/Cargo.lock b/Cargo.lock index 5a7d6bf..19e82d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,17 @@ dependencies = [ "libc", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -68,6 +79,43 @@ dependencies = [ "winapi", ] +[[package]] +name = "clap" +version = "4.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -609,6 +657,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "os_str_bytes" +version = "6.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5bf27447411e9ee3ff51186bf7a08e16c341efdde93f4d823e8844429bed7e" + [[package]] name = "parking_lot" version = "0.12.1" @@ -656,6 +710,30 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.47" @@ -884,6 +962,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "strum" version = "0.24.1" @@ -1055,6 +1139,7 @@ name = "tuemensa" version = "0.1.0" dependencies = [ "chrono", + "clap", "comfy-table", "reqwest", "serde", @@ -1106,6 +1191,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "want" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index d97e744..2f91378 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] chrono = "0.4.23" +clap = { version = "4.0.26", features = ["derive"] } comfy-table = "6.1.2" reqwest = { version = "0.11", features = ["json"] } serde = { version = "1.0.147", features = ["derive"] } diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..8baf49b --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,30 @@ +use clap::Parser; + +/// tuemensa is a simple cli tool to retrieve the current meal plan. +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +pub struct Args { + /// Show Mensa Morgenstelle + #[arg(short, long, default_value_t = false)] + pub morgenstelle: bool, + + /// Show Mensa Shedhalle + #[arg(short, long, default_value_t = false)] + pub shedhalle: bool, + + /// Format as plain text + #[arg(short, long, default_value_t = false)] + pub plaintext: bool, + + /// Use very short format (oneline) + #[arg(short, long, default_value_t = false)] + pub oneline: bool, + + /// Offset of days in the future (valid inputs 0-7) + #[arg(short, long, default_value_t = 0)] + pub days: u8, +} + +pub fn get_args() -> Args { + Args::parse() +} diff --git a/src/main.rs b/src/main.rs index 075d1d6..a9de113 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,27 +4,68 @@ use comfy_table::presets::UTF8_FULL; use comfy_table::modifiers::UTF8_ROUND_CORNERS; mod mensa; +mod cli; //use crate::mensa::*; #[tokio::main] async fn main() -> Result<(), Box> { - let shedhalle = mensa::Mensa::from(mensa::MensaName::Shedhalle); - let morgenstelle = mensa::Mensa::from(mensa::MensaName::Morgenstelle); - if let mensa::Mensa::Shedhalle(resp) = shedhalle.await? { - let data = resp.today().iter().map(|&x| x.get_short_info()).collect::>(); - table_short(data).await; - } + let args = cli::get_args(); + exec_arguments(&args).await?; + //let shedhalle = mensa::Mensa::from(mensa::MensaName::Shedhalle); + //let morgenstelle = mensa::Mensa::from(mensa::MensaName::Morgenstelle); + //if let mensa::Mensa::Shedhalle(resp) = shedhalle.await? { + // let data = resp.today().iter().map(|&x| x.get_short_info()).collect::>(); + // table_short(data); + //} - if let mensa::Mensa::Morgenstelle(resp) = morgenstelle.await? { - let data = resp.today().iter().map(|&x| x.get_short_info()).collect::>(); - table_short(data).await; - } + //if let mensa::Mensa::Morgenstelle(resp) = morgenstelle.await? { + // let data = resp.today().iter().map(|&x| x.get_short_info()).collect::>(); + // table_short(data); + //} Ok(()) } -async fn table_short(data: Vec<(&str, String, &str)>) { +async fn exec_arguments(args: &cli::Args) -> Result<(), Box> { + let shedhalle = mensa::Mensa::from(mensa::MensaName::Shedhalle); + let morgenstelle = mensa::Mensa::from(mensa::MensaName::Morgenstelle); + + if args.morgenstelle { + if let mensa::Mensa::Morgenstelle(resp) = morgenstelle.await? { + exec_arg_helper(args, &resp); + } + } + + if args.shedhalle { + if let mensa::Mensa::Shedhalle(resp) = shedhalle.await? { + exec_arg_helper(args, &resp); + } + } + Ok(()) +} + +fn exec_arg_helper(args: &cli::Args, m: &dyn mensa::Mealplan) { + if let Some(menus) = m.nth(args.days) { + if args.plaintext { + for i in menus.iter() { + i.print_short_info(); + } + return; + } + + if args.oneline { + menus.first().unwrap().print_very_short_info(); + return; + } + + // Default case --> print fancy + println!("{}", m.name()); + table_short(menus.iter().map(|&x| x.get_short_info()).collect::>()); + } +} + +fn table_short(data: Vec<(&str, String, &str)>) { let mut table = Table::new(); //let mut data_cells = data.iter().map(|x| vec![Cell::new(x.0), Cell::new(&x.1), Cell::new(x.2)]).collect::>>(); @@ -46,4 +87,3 @@ async fn table_short(data: Vec<(&str, String, &str)>) { println!("{table}"); } - diff --git a/src/mensa.rs b/src/mensa.rs index 67114ae..0488462 100644 --- a/src/mensa.rs +++ b/src/mensa.rs @@ -1,5 +1,5 @@ extern crate serde_derive; -use chrono::{DateTime, Local}; +use chrono::{Local, Datelike}; use serde::{Serialize, Deserialize}; @@ -11,7 +11,9 @@ pub enum MensaName { pub trait Mealplan { fn id(&self) -> &str; + fn name(&self) -> &str; fn today(&self) -> Vec<&Menu>; + fn nth(&self, days: u8) -> Option>; } pub enum Mensa { @@ -43,6 +45,23 @@ impl Mensa { } + +fn get_nth_date(days: u8) -> Option> { + if days > 7 { + return None; + } + + if let Some(dt) = Local::now().checked_add_days(chrono::Days::new(days as u64)) { + return match dt.weekday() { + chrono::Weekday::Sat => dt.checked_add_days(chrono::Days::new(2)), + chrono::Weekday::Sun => dt.checked_add_days(chrono::Days::new(1)), + _ => Some(dt) + }; + } + None +} + + #[derive(Debug, Serialize, Deserialize)] pub struct MensaShedhalle { #[serde(rename = "611")] @@ -60,10 +79,24 @@ impl Mealplan for MensaShedhalle { &self.canteen.canteen_id } + fn name(&self) -> &str { + &&self.canteen.canteen + } + fn today(&self) -> Vec<&Menu> { let local = format!("{}", Local::now().format("%Y-%m-%d")); self.canteen.menus.iter().filter(|&x| x.menu_date == local).collect() } + + fn nth(&self, days: u8) -> Option> { + match get_nth_date(days) { + Some(dt) => { + let local = format!("{}", dt.format("%Y-%m-%d")); + Some(self.canteen.menus.iter().filter(|&x| x.menu_date == local).collect()) + }, + _ => None + } + } } @@ -80,10 +113,24 @@ impl Mealplan for MensaMorgenstelle { &self.canteen.canteen_id } + fn name(&self) -> &str { + &&self.canteen.canteen + } + fn today(&self) -> Vec<&Menu> { let local = format!("{}", Local::now().format("%Y-%m-%d")); self.canteen.menus.iter().filter(|&x| x.menu_date == local).collect() } + + fn nth(&self, days: u8) -> Option> { + match get_nth_date(days) { + Some(dt) => { + let local = format!("{}", dt.format("%Y-%m-%d")); + Some(self.canteen.menus.iter().filter(|&x| x.menu_date == local).collect()) + }, + _ => None + } + } }