Skip to content

Commit

Permalink
feat(cli)!: allow exclusive actions
Browse files Browse the repository at this point in the history
This is a backwards incompatible change, because actions are now
exclusive. Up until now, `-a` showed the calendar *and* the agenda. The
calendar is still the default, but if you choose to display the agenda
with `-a` it displays the agenda *instead* of the calendar. If you want
both, you have to use `-ac` or `--calendar --agenda`.

Closes: #97
  • Loading branch information
b1rger committed Jan 10, 2024
1 parent 8b008aa commit 1f2a7c0
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 95 deletions.
131 changes: 51 additions & 80 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use anyhow::{anyhow, Result};
use chrono::prelude::*;
use clap::{crate_authors, crate_name, crate_version, Parser};
use clap::{crate_authors, crate_name, crate_version, Args, Parser};

#[derive(Parser)]
#[clap(version = crate_version!(), author = crate_authors!(","), about = "Display a calendar")]
Expand All @@ -27,32 +27,25 @@ pub struct Cli {
#[clap(short = 'j', long = "julian", help = "output Julian dates")]
pub julian: bool,

#[clap(short = 'a', long = "agenda", help = "show agenda")]
pub agenda: bool,
#[clap(long = "themestyletype", help = "select dark or light theme styles", value_parser=["dark", "light"])]
pub themestyletype: Option<String>,
#[clap(long = "theme", help = "select theme by name", num_args(1))]
pub theme: Option<String>,

#[clap(num_args(0..=3))]
pub date: Vec<String>,

#[command(flatten)]
pub action: Action,
}

impl Default for Cli {
fn default() -> Self {
Cli {
one: true,
three: false,
year: false,
sunday: false,
monday: false,
julian: false,
agenda: false,
date: vec![],
themestyletype: None,
theme: None,
}
}
#[derive(Args, Clone, Default, PartialEq)]
#[group(required = false, multiple = true)]
pub struct Action {
#[clap(short = 'c', long = "calendar", help = "show calendar (default)")]
pub calendar: bool,
#[clap(short = 'a', long = "agenda", help = "show agenda")]
pub agenda: bool,
}

impl Cli {
Expand Down Expand Up @@ -147,16 +140,14 @@ mod tests {
#[test]
fn test_validate_date_defaults_to_now() {
let today: chrono::NaiveDate = Local::now().date_naive();
let o: Cli = Cli::default();
let o: Cli = Cli::parse();
assert_eq!(today, o.validate_date().unwrap());
}
#[test]
fn test_validate_date_default_to_now_with_custom_year() {
let today: chrono::NaiveDate = Local::now().date_naive().with_year(2007).unwrap();
let o: Cli = Cli {
date: vec![String::from("2007")],
..Default::default()
};
let mut o: Cli = Cli::parse();
o.date = vec![String::from("2007")];
assert_eq!(today, o.validate_date().unwrap());
}
#[test]
Expand All @@ -167,10 +158,8 @@ mod tests {
.unwrap()
.with_month(1)
.unwrap();
let o: Cli = Cli {
date: vec![String::from("2007"), String::from("1")],
..Default::default()
};
let mut o: Cli = Cli::parse();
o.date = vec![String::from("2007"), String::from("1")];
assert_eq!(today, o.validate_date().unwrap());
}
#[test]
Expand All @@ -183,93 +172,75 @@ mod tests {
.unwrap()
.with_day(28)
.unwrap();
let o: Cli = Cli {
date: vec![String::from("2007"), String::from("1"), String::from("28")],
..Default::default()
};
let mut o: Cli = Cli::parse();
o.date = vec![String::from("2007"), String::from("1"), String::from("28")];
assert_eq!(today, o.validate_date().unwrap());
}
#[test]
fn test_validate_date_defaults_to_now_with_ambiguous_arguments() {
let today: chrono::NaiveDate = Local::now().date_naive();
let o: Cli = Cli {
date: vec![
String::from("2007"),
String::from("1"),
String::from("28"),
String::from("28"),
],
..Default::default()
};
let mut o: Cli = Cli::parse();
o.date = vec![
String::from("2007"),
String::from("1"),
String::from("28"),
String::from("28"),
];
assert_eq!(today, o.validate_date().unwrap());
}
#[test]
fn test_validate_date_errors_with_wrong_month() {
let o: Cli = Cli {
date: vec![String::from("2007"), String::from("13"), String::from("28")],
..Default::default()
};
let mut o: Cli = Cli::parse();
o.date = vec![String::from("2007"), String::from("13"), String::from("28")];
assert!(o.validate_date().is_err());
}
#[test]
fn test_validate_date_errors_with_wrong_day() {
let o: Cli = Cli {
date: vec![String::from("2007"), String::from("11"), String::from("33")],
..Default::default()
};
let mut o: Cli = Cli::parse();
o.date = vec![String::from("2007"), String::from("11"), String::from("33")];
assert!(o.validate_date().is_err());
}
#[test]
fn test_validate_date_errors_with_wrong_year() {
let o: Cli = Cli {
date: vec![
String::from("999999"),
String::from("11"),
String::from("28"),
],
..Default::default()
};
let mut o: Cli = Cli::parse();
o.date = vec![
String::from("999999"),
String::from("11"),
String::from("28"),
];
assert!(o.validate_date().is_err());
}
#[test]
fn test_validate_date_errors_with_unparsable_year() {
let o: Cli = Cli {
date: vec![String::from("foo"), String::from("13"), String::from("28")],
..Default::default()
};
let mut o: Cli = Cli::parse();
o.date = vec![String::from("foo"), String::from("13"), String::from("28")];
assert!(o.validate_date().is_err());
}
#[test]
fn test_validate_date_errors_with_unparsable_month() {
let o: Cli = Cli {
date: vec![
String::from("2007"),
String::from("foo"),
String::from("23"),
],
..Default::default()
};
let mut o: Cli = Cli::parse();
o.date = vec![
String::from("2007"),
String::from("foo"),
String::from("23"),
];
assert!(o.validate_date().is_err());
}
#[test]
fn test_validate_date_errors_with_unparsable_day() {
let o: Cli = Cli {
date: vec![
String::from("2007"),
String::from("11"),
String::from("foo"),
],
..Default::default()
};
let mut o: Cli = Cli::parse();
o.date = vec![
String::from("2007"),
String::from("11"),
String::from("foo"),
];
assert!(o.validate_date().is_err());
}
#[test]
fn test_validate_date_errors_with_non_existent_date() {
let today: chrono::NaiveDate = Local::now().date_naive();
let o: Cli = Cli {
date: vec![String::from("2007"), String::from("2"), String::from("30")],
..Default::default()
};
let mut o: Cli = Cli::parse();
o.date = vec![String::from("2007"), String::from("2"), String::from("30")];
assert_eq!(today, o.validate_date().unwrap());
}
}
10 changes: 7 additions & 3 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: MIT

use crate::cli::Cli;
use crate::cli::{Action, Cli};
use crate::config::StyleType;
use crate::config::{Config, Theme};
use crate::events::EventInstances;
Expand All @@ -22,7 +22,7 @@ pub struct Context {

impl Context {
pub fn new() -> Result<Context> {
let opts: Cli = Cli::parse();
let mut opts: Cli = Cli::parse();
let config: Config = Config::read();
let theme: Theme = if opts.theme.is_some() {
Theme::read(&opts.theme)
Expand All @@ -41,6 +41,10 @@ impl Context {
Err(x) => return Err(x),
};

if opts.action == Action::default() {
opts.action.calendar = true;
}

Ok(Context {
usersetdate,
opts,
Expand All @@ -56,7 +60,7 @@ impl Default for Context {
fn default() -> Self {
Context {
usersetdate: NaiveDate::default(),
opts: Cli::default(),
opts: Cli::parse(),
config: Config::default(),
theme: Theme::default(),
styletype: StyleType::Light,
Expand Down
20 changes: 12 additions & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,17 @@ fn main() {
}
ctx.eventinstances.sort_by(|a, b| a.date.cmp(&b.date));

let calendar = Calendar {
dates: months,
columns,
ctx: &ctx,
};
print!("{}", calendar);
if ctx.opts.action.calendar {
let calendar = Calendar {
dates: months,
columns,
ctx: &ctx,
};
print!("{}", calendar);
}

let agenda = Agenda { ctx: &ctx };
print!("{}", agenda)
if ctx.opts.action.agenda {
let agenda = Agenda { ctx: &ctx };
print!("{}", agenda)
}
}
6 changes: 2 additions & 4 deletions src/output/agenda.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,8 @@ pub struct Agenda<'a> {
impl fmt::Display for Agenda<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut ret: String = String::new();
if self.ctx.opts.agenda {
for pe in self.ctx.eventinstances.iter() {
ret += format!("{pe}\n").as_str();
}
for pe in self.ctx.eventinstances.iter() {
ret += format!("{pe}\n").as_str();
}
write!(f, "{}", ret)
}
Expand Down

0 comments on commit 1f2a7c0

Please sign in to comment.