diff --git a/crates/nu-cli/src/commands/cal.rs b/crates/nu-cli/src/commands/cal.rs index db459d63b0..1970ba5f06 100644 --- a/crates/nu-cli/src/commands/cal.rs +++ b/crates/nu-cli/src/commands/cal.rs @@ -24,6 +24,12 @@ impl WholeStreamCommand for Cal { "Display a year-long calendar for the specified year", None, ) + .named( + "week-start", + SyntaxShape::String, + "Display the calendar with the specified day as the first day of the week", + None, + ) .switch( "month-names", "Display the month names instead of integers", @@ -55,6 +61,11 @@ impl WholeStreamCommand for Cal { example: "cal --full-year 2012", result: None, }, + Example { + description: "This month's calendar with the week starting on monday", + example: "cal --week-start monday", + result: None, + }, ] } } @@ -226,11 +237,7 @@ fn add_month_to_table( }, }; - let day_limit = - month_helper.number_of_days_in_month + month_helper.day_number_of_week_month_starts_on; - let mut day_count: u32 = 1; - - let days_of_the_week = [ + let mut days_of_the_week = [ "sunday", "monday", "tuesday", @@ -240,12 +247,43 @@ fn add_month_to_table( "saturday", ]; + let mut week_start_day = days_of_the_week[0].to_string(); + + if let Some(week_start_value) = args.get("week-start") { + if let Ok(day) = week_start_value.as_string() { + if days_of_the_week.contains(&day.as_str()) { + week_start_day = day; + } else { + return Err(ShellError::labeled_error( + "The specified week start day is invalid", + "invalid week start day", + week_start_value.tag(), + )); + } + } + } + + let week_start_day_offset = days_of_the_week.len() + - days_of_the_week + .iter() + .position(|day| *day == week_start_day) + .unwrap_or(0); + + days_of_the_week.rotate_right(week_start_day_offset); + + let mut total_start_offset: u32 = + month_helper.day_number_of_week_month_starts_on + week_start_day_offset as u32; + total_start_offset %= days_of_the_week.len() as u32; + + let mut day_number: u32 = 1; + let day_limit: u32 = total_start_offset + month_helper.number_of_days_in_month; + let should_show_year_column = args.has("year"); let should_show_quarter_column = args.has("quarter"); let should_show_month_column = args.has("month"); let should_show_month_names = args.has("month-names"); - while day_count <= day_limit { + while day_number <= day_limit { let mut indexmap = IndexMap::new(); if should_show_year_column { @@ -273,19 +311,18 @@ fn add_month_to_table( } for day in &days_of_the_week { - let should_add_day_number_to_table = (day_count <= day_limit) - && (day_count > month_helper.day_number_of_week_month_starts_on); + let should_add_day_number_to_table = + (day_number > total_start_offset) && (day_number <= day_limit); let mut value = UntaggedValue::nothing().into_value(tag); if should_add_day_number_to_table { - let day_count_with_offset = - day_count - month_helper.day_number_of_week_month_starts_on; + let adjusted_day_number = day_number - total_start_offset; - value = UntaggedValue::int(day_count_with_offset).into_value(tag); + value = UntaggedValue::int(adjusted_day_number).into_value(tag); if let Some(current_day) = current_day_option { - if current_day == day_count_with_offset { + if current_day == adjusted_day_number { // TODO: Update the value here with a color when color support is added // This colors the current day } @@ -294,7 +331,7 @@ fn add_month_to_table( indexmap.insert((*day).to_string(), value); - day_count += 1; + day_number += 1; } calendar_vec_deque diff --git a/crates/nu-cli/tests/commands/cal.rs b/crates/nu-cli/tests/commands/cal.rs index afb20e26bb..b5fad15686 100644 --- a/crates/nu-cli/tests/commands/cal.rs +++ b/crates/nu-cli/tests/commands/cal.rs @@ -52,6 +52,20 @@ fn cal_rows_in_2020() { assert!(actual.out.contains("62")); } +#[test] +fn cal_week_day_start_monday() { + let actual = nu!( + cwd: ".", pipeline( + r#" + cal --full-year 2020 -m --month-names --week-start monday | where month == january | to json + "# + )); + + let cal_january_json = r#"[{"month":"january","monday":null,"tuesday":null,"wednesday":1,"thursday":2,"friday":3,"saturday":4,"sunday":5},{"month":"january","monday":6,"tuesday":7,"wednesday":8,"thursday":9,"friday":10,"saturday":11,"sunday":12},{"month":"january","monday":13,"tuesday":14,"wednesday":15,"thursday":16,"friday":17,"saturday":18,"sunday":19},{"month":"january","monday":20,"tuesday":21,"wednesday":22,"thursday":23,"friday":24,"saturday":25,"sunday":26},{"month":"january","monday":27,"tuesday":28,"wednesday":29,"thursday":30,"friday":31,"saturday":null,"sunday":null}]"#; + + assert_eq!(actual.out, cal_january_json); +} + #[test] fn cal_sees_pipeline_year() { let actual = nu!( diff --git a/docs/commands/cal.md b/docs/commands/cal.md index 7b02501b90..99fd7cb8cc 100644 --- a/docs/commands/cal.md +++ b/docs/commands/cal.md @@ -8,6 +8,7 @@ Use `cal` to display a calendar. * `-q`, `--quarter`: Display the quarter column * `-m`, `--month`: Display the month column * `--full-year` \: Display a year-long calendar for the specified year +* `--week-start` \: Display the calendar with the specified day as the first day of the week * `--month-names`: Display the month names instead of integers ## Examples @@ -188,3 +189,16 @@ Use `cal` to display a calendar. 1 │ 2020 │ november │ 8 │ 9 │ 10 │ 11 │ 12 │ 13 │ 14 ───┴──────┴──────────┴────────┴────────┴─────────┴───────────┴──────────┴────────┴────────── ``` + +```shell +> cal -ymq --month-names --week-start-day monday +───┬──────┬─────────┬───────┬────────┬─────────┬───────────┬──────────┬────────┬──────────┬──────── + # │ year │ quarter │ month │ monday │ tuesday │ wednesday │ thursday │ friday │ saturday │ sunday +───┼──────┼─────────┼───────┼────────┼─────────┼───────────┼──────────┼────────┼──────────┼──────── + 0 │ 2020 │ 2 │ june │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 + 1 │ 2020 │ 2 │ june │ 8 │ 9 │ 10 │ 11 │ 12 │ 13 │ 14 + 2 │ 2020 │ 2 │ june │ 15 │ 16 │ 17 │ 18 │ 19 │ 20 │ 21 + 3 │ 2020 │ 2 │ june │ 22 │ 23 │ 24 │ 25 │ 26 │ 27 │ 28 + 4 │ 2020 │ 2 │ june │ 29 │ 30 │ │ │ │ │ +───┴──────┴─────────┴───────┴────────┴─────────┴───────────┴──────────┴────────┴──────────┴──────── +```