diff --git a/Cargo.lock b/Cargo.lock index 6580127..bd8f6e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -787,7 +787,7 @@ checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "streamd" -version = "0.2.1" +version = "0.2.2" dependencies = [ "chrono", "chrono-tz", diff --git a/Cargo.toml b/Cargo.toml index 9199c46..b4d48cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "streamd" -version = "0.2.1" +version = "0.2.2" edition = "2021" description = "Personal knowledge management and time-tracking CLI using @Tag annotations" license = "AGPL-3.0-only" diff --git a/flake.nix b/flake.nix index dbfaed7..38723ae 100644 --- a/flake.nix +++ b/flake.nix @@ -103,12 +103,6 @@ package = toolchain; }; commitizen.enable = true; - cargo-audit = { - enable = true; - entry = "${pkgs.cargo-audit}/bin/cargo-audit audit"; - files = "^Cargo\\.(toml|lock)$"; - pass_filenames = false; - }; }; }; diff --git a/src/cli/args.rs b/src/cli/args.rs index b0da540..11fda90 100644 --- a/src/cli/args.rs +++ b/src/cli/args.rs @@ -51,9 +51,9 @@ pub enum Commands { /// Display extracted timesheets Timesheet { - /// Display time as minutes (HH:MM) instead of decimal hours (H.Hh) + /// Display time as decimal hours (X.XXh) instead of the default HH:MM format #[arg(short, long)] - minutes: bool, + decimal: bool, /// Show all timecards grouped by day instead of the summary report #[arg(short, long)] diff --git a/src/cli/commands/timesheet.rs b/src/cli/commands/timesheet.rs index 2cea3ae..67ab956 100644 --- a/src/cli/commands/timesheet.rs +++ b/src/cli/commands/timesheet.rs @@ -42,28 +42,39 @@ fn load_all_shards(base_folder: &Path) -> Result, StreamdErr Ok(shards) } +enum DisplayMode { + Minutes, + Decimal, +} + /// Format minutes with sign for display. -fn format_diff(minutes: i64, use_minutes: bool) -> String { +fn format_diff(minutes: i64, mode: &DisplayMode) -> String { let sign = if minutes >= 0 { "+" } else { "-" }; - if use_minutes { - let h = minutes.unsigned_abs() / 60; - let m = minutes.unsigned_abs() % 60; - format!("{}{}:{:02}", sign, h, m) - } else { - let hours = minutes.unsigned_abs() as f64 / 60.0; - format!("{}{:.1}h", sign, hours) + match mode { + DisplayMode::Minutes => { + let h = minutes.unsigned_abs() / 60; + let m = minutes.unsigned_abs() % 60; + format!("{}{}:{:02}", sign, h, m) + } + DisplayMode::Decimal => { + let hours = minutes.unsigned_abs() as f64 / 60.0; + format!("{}{:.2}h", sign, hours) + } } } /// Format minutes for display without sign. -fn format_hours(minutes: i64, use_minutes: bool) -> String { - if use_minutes { - let h = minutes.unsigned_abs() / 60; - let m = minutes.unsigned_abs() % 60; - format!("{}:{:02}", h, m) - } else { - let hours = minutes.unsigned_abs() as f64 / 60.0; - format!("{:.1}h", hours) +fn format_hours(minutes: i64, mode: &DisplayMode) -> String { + match mode { + DisplayMode::Minutes => { + let h = minutes.unsigned_abs() / 60; + let m = minutes.unsigned_abs() % 60; + format!("{}:{:02}", h, m) + } + DisplayMode::Decimal => { + let hours = minutes.unsigned_abs() as f64 / 60.0; + format!("{:.2}h", hours) + } } } @@ -90,8 +101,8 @@ fn print_header() { } /// Print a month report. -fn print_month(month: &MonthReport, use_minutes: bool) { - let diff_str = format_diff(month.diff(), use_minutes); +fn print_month(month: &MonthReport, mode: &DisplayMode) { + let diff_str = format_diff(month.diff(), mode); let month_title = format!("{} {}", month.month_name(), month.year); // Month header with diff @@ -112,9 +123,9 @@ fn print_month(month: &MonthReport, use_minutes: bool) { for day in &month.days { let date_str = day.date.format("%Y-%m-%d").to_string(); let weekday = weekday_abbrev(day.date); - let expected = format_hours(day.expected_minutes, use_minutes); - let actual = format_hours(day.actual_minutes, use_minutes); - let diff = format_diff(day.diff(), use_minutes); + let expected = format_hours(day.expected_minutes, mode); + let actual = format_hours(day.actual_minutes, mode); + let diff = format_diff(day.diff(), mode); let type_str = match day.day_type { DayType::Regular => String::new(), @@ -147,26 +158,26 @@ fn print_month(month: &MonthReport, use_minutes: bool) { println!(" {}", light_line); println!( " Monthly: {:>7} {:>7} {:>6}", - format_hours(month.total_expected(), use_minutes), - format_hours(month.total_actual(), use_minutes), - format_diff(month.diff(), use_minutes) + format_hours(month.total_expected(), mode), + format_hours(month.total_actual(), mode), + format_diff(month.diff(), mode) ); println!(); } /// Print the cumulative balance. -fn print_cumulative_balance(balance: i64, use_minutes: bool) { +fn print_cumulative_balance(balance: i64, mode: &DisplayMode) { let light_line = "\u{2500}".repeat(SEPARATOR_WIDTH); println!("{}", light_line); println!( " CUMULATIVE BALANCE: {}", - format_diff(balance, use_minutes) + format_diff(balance, mode) ); println!("{}", light_line); } /// Print warnings section. -fn print_warnings(report: &TimesheetReport, use_minutes: bool) { +fn print_warnings(report: &TimesheetReport, mode: &DisplayMode) { if !report.has_warnings() { return; } @@ -231,7 +242,7 @@ fn print_warnings(report: &TimesheetReport, use_minutes: bool) { println!( " - {}: {} worked (no period configured)", w.date.format("%Y-%m-%d"), - format_hours(*minutes_worked, use_minutes) + format_hours(*minutes_worked, mode) ); } } @@ -297,7 +308,12 @@ fn print_debug(report: &TimesheetReport, timesheets: &[Timesheet]) { } } -pub fn run(use_minutes: bool, debug: bool) -> Result<(), StreamdError> { +pub fn run(decimal: bool, debug: bool) -> Result<(), StreamdError> { + let mode = if decimal { + DisplayMode::Decimal + } else { + DisplayMode::Minutes + }; let settings = Settings::load()?; let base_folder = Path::new(&settings.base_folder); @@ -339,11 +355,11 @@ pub fn run(use_minutes: bool, debug: bool) -> Result<(), StreamdError> { print_header(); for month in &report.months { - print_month(month, use_minutes); + print_month(month, &mode); } - print_cumulative_balance(report.cumulative_balance, use_minutes); - print_warnings(&report, use_minutes); + print_cumulative_balance(report.cumulative_balance, &mode); + print_warnings(&report, &mode); } Ok(()) @@ -355,33 +371,34 @@ mod tests { #[test] fn test_format_hours_decimal() { - assert_eq!(format_hours(480, false), "8.0h"); - assert_eq!(format_hours(510, false), "8.5h"); - assert_eq!(format_hours(0, false), "0.0h"); + assert_eq!(format_hours(480, &DisplayMode::Decimal), "8.00h"); + assert_eq!(format_hours(510, &DisplayMode::Decimal), "8.50h"); + assert_eq!(format_hours(507, &DisplayMode::Decimal), "8.45h"); + assert_eq!(format_hours(0, &DisplayMode::Decimal), "0.00h"); } #[test] fn test_format_hours_minutes() { - assert_eq!(format_hours(480, true), "8:00"); - assert_eq!(format_hours(510, true), "8:30"); - assert_eq!(format_hours(0, true), "0:00"); - assert_eq!(format_hours(75, true), "1:15"); - assert_eq!(format_hours(77, true), "1:17"); - assert_eq!(format_hours(200, true), "3:20"); + assert_eq!(format_hours(480, &DisplayMode::Minutes), "8:00"); + assert_eq!(format_hours(510, &DisplayMode::Minutes), "8:30"); + assert_eq!(format_hours(0, &DisplayMode::Minutes), "0:00"); + assert_eq!(format_hours(75, &DisplayMode::Minutes), "1:15"); + assert_eq!(format_hours(77, &DisplayMode::Minutes), "1:17"); + assert_eq!(format_hours(200, &DisplayMode::Minutes), "3:20"); } #[test] fn test_format_diff_decimal() { - assert_eq!(format_diff(30, false), "+0.5h"); - assert_eq!(format_diff(-90, false), "-1.5h"); - assert_eq!(format_diff(0, false), "+0.0h"); + assert_eq!(format_diff(30, &DisplayMode::Decimal), "+0.50h"); + assert_eq!(format_diff(-90, &DisplayMode::Decimal), "-1.50h"); + assert_eq!(format_diff(0, &DisplayMode::Decimal), "+0.00h"); } #[test] fn test_format_diff_minutes() { - assert_eq!(format_diff(30, true), "+0:30"); - assert_eq!(format_diff(-90, true), "-1:30"); - assert_eq!(format_diff(0, true), "+0:00"); - assert_eq!(format_diff(75, true), "+1:15"); + assert_eq!(format_diff(30, &DisplayMode::Minutes), "+0:30"); + assert_eq!(format_diff(-90, &DisplayMode::Minutes), "-1:30"); + assert_eq!(format_diff(0, &DisplayMode::Minutes), "+0:00"); + assert_eq!(format_diff(75, &DisplayMode::Minutes), "+1:15"); } } diff --git a/src/main.rs b/src/main.rs index 354b8dd..4d311a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,8 +15,8 @@ fn main() -> miette::Result<()> { Some(TodoAction::Done { number }) => streamd::cli::commands::todo::run_done(number)?, }, Some(Commands::Edit { number }) => streamd::cli::commands::edit::run(number)?, - Some(Commands::Timesheet { minutes, debug }) => { - streamd::cli::commands::timesheet::run(minutes, debug)? + Some(Commands::Timesheet { decimal, debug }) => { + streamd::cli::commands::timesheet::run(decimal, debug)? } Some(Commands::Completions { shell }) => { streamd::cli::commands::completions::run(shell);