From 4b83723b4728f911ac2368ecfe532400061de3ac Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Thu, 12 Jun 2025 22:59:05 -0700 Subject: [PATCH 01/14] Re-order Cargo.toml --- Cargo.toml | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 254580a..fe16889 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,12 +2,12 @@ name = "bartib" version = "1.1.0" authors = ["Nikolas Schmidt-Voigt "] +edition = "2018" description = "A simple timetracker for the command line" +readme = "README.md" homepage = "https://github.com/nikolassv/bartib" repository = "https://github.com/nikolassv/bartib" -edition = "2018" license = "GPL-3.0-or-later" -readme = "README.md" keywords = ["cli"] categories = ["command-line-utilities"] @@ -17,30 +17,35 @@ path-guid = "BE8CBFAC-1DE6-4B0D-BB4B-C31A85A34AC5" license = false eula = false +# Config for 'cargo dist' +[workspace.metadata.dist] +# The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax) +cargo-dist-version = "0.10.0" +# CI backends to support +ci = ["github"] +# The installers to generate for each app +installers = ["shell", "powershell", "msi"] +# Target platforms to build apps for (Rust target-triple syntax) +targets = [ + "aarch64-apple-darwin", + "x86_64-apple-darwin", + "x86_64-unknown-linux-gnu", + "x86_64-pc-windows-msvc", +] +# Publish jobs to run in CI +pr-run-mode = "upload" + [dependencies] +anyhow = "1.0.0" chrono = "0.4.0" clap = "2.0.0" -thiserror = "1.0.0" -anyhow = "1.0.0" nu-ansi-term = "0.46.0" term_size = "0.3.0" textwrap = "0.16.0" +thiserror = "1.0.0" wildmatch = "2.3.0" # The profile that 'cargo dist' will build with [profile.dist] inherits = "release" lto = "thin" - -# Config for 'cargo dist' -[workspace.metadata.dist] -# The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax) -cargo-dist-version = "0.10.0" -# CI backends to support -ci = ["github"] -# The installers to generate for each app -installers = ["shell", "powershell", "msi"] -# Target platforms to build apps for (Rust target-triple syntax) -targets = ["aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"] -# Publish jobs to run in CI -pr-run-mode = "upload" From 094ed3a372b23828bc038580e5a5f886bcee3a66 Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Thu, 12 Jun 2025 23:00:24 -0700 Subject: [PATCH 02/14] Add 'seconds-precision' feature --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index fe16889..840e0c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,10 @@ textwrap = "0.16.0" thiserror = "1.0.0" wildmatch = "2.3.0" +[features] +# Timestamps are recorded with second precision instead of the default minute precision +second-precision = [] + # The profile that 'cargo dist' will build with [profile.dist] inherits = "release" From e2f5a8b715bfd1fcafe9cf885352525f53deb454 Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Thu, 12 Jun 2025 23:08:31 -0700 Subject: [PATCH 03/14] Feature gate what date-time formatter is being used --- src/conf.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/conf.rs b/src/conf.rs index 710fb09..c83247a 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -1,7 +1,15 @@ use chrono::Duration; +#[cfg(feature = "second-precision")] +pub static FORMAT_DATETIME: &str = "%F %T"; +#[cfg(not(feature = "second-precision"))] pub static FORMAT_DATETIME: &str = "%F %R"; + +#[cfg(feature = "second-precision")] +pub static FORMAT_TIME: &str = "%T"; +#[cfg(not(feature = "second-precision"))] pub static FORMAT_TIME: &str = "%R"; + pub static FORMAT_DATE: &str = "%F"; pub static DEFAULT_WIDTH: usize = usize::MAX; pub static REPORT_INDENTATION: usize = 4; From 8ddb137d28a4d0000593b20aad242bec3bceda15 Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Thu, 12 Jun 2025 23:21:39 -0700 Subject: [PATCH 04/14] Feature gate tests in activity.rs and add unit tests for second-precision feature gate --- src/data/activity.rs | 117 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/src/data/activity.rs b/src/data/activity.rs index 09e7eda..e730170 100644 --- a/src/data/activity.rs +++ b/src/data/activity.rs @@ -195,6 +195,7 @@ mod tests { } #[test] + #[cfg(not(feature = "second-precision"))] fn display() { let mut t = Activity::start( "test project| 1".to_string(), @@ -215,6 +216,30 @@ mod tests { } #[test] + #[cfg(feature = "second-precision")] + fn display() { + let mut t = Activity::start( + "test project| 1".to_string(), + "test\\description".to_string(), + None, + ); + t.start = + NaiveDateTime::parse_from_str("2021-02-16 16:14:53", conf::FORMAT_DATETIME).unwrap(); + assert_eq!( + format!("{t}"), + "2021-02-16 16:14:53 | test project\\| 1 | test\\\\description\n" + ); + t.end = Some( + NaiveDateTime::parse_from_str("2021-02-16 18:23:17", conf::FORMAT_DATETIME).unwrap(), + ); + assert_eq!( + format!("{t}"), + "2021-02-16 16:14:53 - 2021-02-16 18:23:17 | test project\\| 1 | test\\\\description\n" + ); + } + + #[test] + #[cfg(not(feature = "second-precision"))] fn from_str_running_activity() { let t = Activity::from_str("2021-02-16 16:14 | test project | test description").unwrap(); @@ -231,6 +256,26 @@ mod tests { } #[test] + #[cfg(feature = "second-precision")] + fn from_str_running_activity() { + let t = + Activity::from_str("2021-02-16 16:14:53 | test project | test description").unwrap(); + + assert_eq!(t.start.date().year(), 2021); + assert_eq!(t.start.date().month(), 2); + assert_eq!(t.start.date().day(), 16); + + assert_eq!(t.start.time().hour(), 16); + assert_eq!(t.start.time().minute(), 14); + assert_eq!(t.start.time().second(), 53); + + assert_eq!(t.description, "test description".to_string()); + assert_eq!(t.project, "test project".to_string()); + assert_eq!(t.end, None); + } + + #[test] + #[cfg(not(feature = "second-precision"))] fn from_str_running_activity_no_description() { let t = Activity::from_str("2021-02-16 16:14 | test project").unwrap(); @@ -247,6 +292,25 @@ mod tests { } #[test] + #[cfg(feature = "second-precision")] + fn from_str_running_activity_no_description() { + let t = Activity::from_str("2021-02-16 16:14:53 | test project").unwrap(); + + assert_eq!(t.start.date().year(), 2021); + assert_eq!(t.start.date().month(), 2); + assert_eq!(t.start.date().day(), 16); + + assert_eq!(t.start.time().hour(), 16); + assert_eq!(t.start.time().minute(), 14); + assert_eq!(t.start.time().second(), 53); + + assert_eq!(t.description, String::new()); + assert_eq!(t.project, "test project".to_string()); + assert_eq!(t.end, None); + } + + #[test] + #[cfg(not(feature = "second-precision"))] fn from_str_stopped_activity() { let t = Activity::from_str( "2021-02-16 16:14 - 2021-02-16 18:23 | test project | test description", @@ -266,6 +330,28 @@ mod tests { } #[test] + #[cfg(feature = "second-precision")] + fn from_str_stopped_activity() { + let t = Activity::from_str( + "2021-02-16 16:14:53 - 2021-02-16 18:23:17 | test project | test description", + ) + .unwrap(); + + assert_ne!(t.end, None); + + let end = t.end.unwrap(); + + assert_eq!(end.date().year(), 2021); + assert_eq!(end.date().month(), 2); + assert_eq!(end.date().day(), 16); + + assert_eq!(end.time().hour(), 18); + assert_eq!(end.time().minute(), 23); + assert_eq!(end.time().second(), 17); + } + + #[test] + #[cfg(not(feature = "second-precision"))] fn from_str_escaped_chars() { let t = Activity::from_str( "2021-02-16 16:14 - 2021-02-16 18:23 | test project\\| 1 | test\\\\description", @@ -277,6 +363,19 @@ mod tests { } #[test] + #[cfg(feature = "second-precision")] + fn from_str_escaped_chars() { + let t = Activity::from_str( + "2021-02-16 16:14:53 - 2021-02-16 18:23:17 | test project\\| 1 | test\\\\description", + ) + .unwrap(); + + assert_eq!(t.project, "test project| 1"); + assert_eq!(t.description, "test\\description"); + } + + #[test] + #[cfg(not(feature = "second-precision"))] fn string_roundtrip() { let mut t = Activity::start( "ex\\ample\\\\pro|ject".to_string(), @@ -304,6 +403,24 @@ mod tests { assert_eq!(t.description, t2.description); } + #[test] + #[cfg(feature = "second-precision")] + fn string_roundtrip() { + let mut t = Activity::start( + "ex\\ample\\\\pro|ject".to_string(), + "e\\\\xam|||ple tas\t\t\nk".to_string(), + None, + ); + t.stop(None); + let t2 = Activity::from_str(format!("{t}").as_str()).unwrap(); + + assert_eq!(t.start.with_nanosecond(0).unwrap(), t2.start); + assert_eq!(t.end.unwrap().with_nanosecond(0).unwrap(), t2.end.unwrap()); + + assert_eq!(t.project, t2.project); + assert_eq!(t.description, t2.description); + } + #[test] fn from_str_errors() { let t = Activity::from_str("2021 test project"); From cb0a6b53ebcbe7a004b67f3d1b582766d7857166 Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Thu, 12 Jun 2025 23:31:57 -0700 Subject: [PATCH 05/14] Feature gate reporting a task switch that happens for a new activity in under a minute --- src/view/format_util.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/view/format_util.rs b/src/view/format_util.rs index 4f56dde..2dec57b 100644 --- a/src/view/format_util.rs +++ b/src/view/format_util.rs @@ -10,7 +10,10 @@ pub fn format_duration(duration: &Duration) -> String { if duration.num_minutes() > 0 { duration_string.push_str(&format!("{:0>2}m", duration.num_minutes() % 60)); } else { + #[cfg(not(feature = "second-precision"))] duration_string.push_str("<1m"); + #[cfg(feature = "second-precision")] + duration_string.push_str(&format!("{:0>2}s", duration.num_seconds() % 60)); } duration_string From cc5327a90e901670987eed0066fad228cce11da3 Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Thu, 12 Jun 2025 23:35:10 -0700 Subject: [PATCH 06/14] Format report.rs --- src/view/report.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/view/report.rs b/src/view/report.rs index f2757dc..b27e4f9 100644 --- a/src/view/report.rs +++ b/src/view/report.rs @@ -219,11 +219,7 @@ fn get_longest_duration_string(report: &Report) -> Option { fn get_max_option(o1: Option, o2: Option) -> Option { if let Some(s1) = o1 { if let Some(s2) = o2 { - if s1 > s2 { - o1 - } else { - o2 - } + if s1 > s2 { o1 } else { o2 } } else { o1 } From a2a1178595368ded4619427de2a177f0483119f5 Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Fri, 13 Jun 2025 00:03:29 -0700 Subject: [PATCH 07/14] Add more complicated parsing to gracefully handle timestamps from different feature-gated versions of Bartib --- src/conf.rs | 13 ++++++----- src/data/activity.rs | 51 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/conf.rs b/src/conf.rs index c83247a..8454e6e 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -1,15 +1,18 @@ use chrono::Duration; -#[cfg(feature = "second-precision")] -pub static FORMAT_DATETIME: &str = "%F %T"; -#[cfg(not(feature = "second-precision"))] -pub static FORMAT_DATETIME: &str = "%F %R"; +pub static FORMAT_MINUTE_PRECISION_DATETIME: &str = "%F %R"; +pub static FORMAT_SECOND_PRECISION_DATETIME: &str = "%F %T"; +#[cfg(not(feature = "second-precision"))] +pub static FORMAT_DATETIME: &str = FORMAT_MINUTE_PRECISION_DATETIME; #[cfg(feature = "second-precision")] -pub static FORMAT_TIME: &str = "%T"; +pub static FORMAT_DATETIME: &str = FORMAT_SECOND_PRECISION_DATETIME; + #[cfg(not(feature = "second-precision"))] pub static FORMAT_TIME: &str = "%R"; +#[cfg(feature = "second-precision")] +pub static FORMAT_TIME: &str = "%T"; pub static FORMAT_DATE: &str = "%F"; pub static DEFAULT_WIDTH: usize = usize::MAX; pub static REPORT_INDENTATION: usize = 4; diff --git a/src/data/activity.rs b/src/data/activity.rs index e730170..442187d 100644 --- a/src/data/activity.rs +++ b/src/data/activity.rs @@ -1,3 +1,7 @@ +#[cfg(not(feature = "second-precision"))] +use chrono::DurationRound; +#[cfg(feature = "second-precision")] +use chrono::Timelike; use chrono::{Duration, Local, NaiveDateTime}; use std::fmt; use std::str::{Chars, FromStr}; @@ -115,9 +119,52 @@ impl FromStr for Activity { } } +#[cfg(not(feature = "second-precision"))] fn parse_timepart(time_part: &str) -> Result { - NaiveDateTime::parse_from_str(time_part.trim(), conf::FORMAT_DATETIME) - .map_err(|_| ActivityError::DateTimeParseError) + match NaiveDateTime::parse_from_str(time_part.trim(), conf::FORMAT_DATETIME) { + Ok(datetime) => Ok(datetime), + Err(_) => { + // Presume that the timestamp has second-precision and that is the cause of the error + match NaiveDateTime::parse_from_str( + time_part.trim(), + conf::FORMAT_SECOND_PRECISION_DATETIME, + ) { + Ok(datetime) => { + // Successfully parsed timestamp. Round to the nearest minute + let datetime = datetime + .duration_round(Duration::minutes(1)) + .map_err(|_| ActivityError::DateTimeParseError)?; + + Ok(datetime) + } + Err(_) => Err(ActivityError::DateTimeParseError), + } + } + } +} + +#[cfg(feature = "second-precision")] +fn parse_timepart(time_part: &str) -> Result { + match NaiveDateTime::parse_from_str(time_part.trim(), conf::FORMAT_DATETIME) { + Ok(datetime) => Ok(datetime), + Err(_) => { + // Presume that the timestamp has minute-precision and that is the cause of the error + match NaiveDateTime::parse_from_str( + time_part.trim(), + conf::FORMAT_SECOND_PRECISION_DATETIME, + ) { + Ok(datetime) => { + // Successfully parsed timestamp. Set seconds to zero + let datetime = datetime + .with_second(0) + .ok_or(ActivityError::DateTimeParseError)?; + + Ok(datetime) + } + Err(_) => Err(ActivityError::DateTimeParseError), + } + } + } } /** From a1655b1ba5059c37c5a7f1711343086fae59f87f Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Fri, 13 Jun 2025 00:10:11 -0700 Subject: [PATCH 08/14] Add error logs in case there is a mismatch between the expected timestamp precision and the actual timestamp precision --- src/data/activity.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/data/activity.rs b/src/data/activity.rs index 442187d..ca53e53 100644 --- a/src/data/activity.rs +++ b/src/data/activity.rs @@ -130,7 +130,11 @@ fn parse_timepart(time_part: &str) -> Result { conf::FORMAT_SECOND_PRECISION_DATETIME, ) { Ok(datetime) => { - // Successfully parsed timestamp. Round to the nearest minute + // Successfully parsed timestamp. Notify the user about the mismatch + // and round to the nearest minute + eprintln!("WARNING: Bartib log encountered timestamps with minute precision."); + eprintln!("This version of Bartib has been compiled with second precision"); + let datetime = datetime .duration_round(Duration::minutes(1)) .map_err(|_| ActivityError::DateTimeParseError)?; @@ -151,10 +155,14 @@ fn parse_timepart(time_part: &str) -> Result { // Presume that the timestamp has minute-precision and that is the cause of the error match NaiveDateTime::parse_from_str( time_part.trim(), - conf::FORMAT_SECOND_PRECISION_DATETIME, + conf::FORMAT_MINUTE_PRECISION_DATETIME, ) { Ok(datetime) => { - // Successfully parsed timestamp. Set seconds to zero + // Successfully parsed timestamp. Notify the user about the mismatch + // and set seconds to zero + eprintln!("WARNING: Bartib log encountered timestamps with minute precision."); + eprintln!("This version of Bartib has been compiled with second precision"); + let datetime = datetime .with_second(0) .ok_or(ActivityError::DateTimeParseError)?; From 7c38f6d3baa5130aa9386b2a105510bdc945bd9e Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Fri, 13 Jun 2025 00:11:58 -0700 Subject: [PATCH 09/14] Add documentation about the `second-precision` feature --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 73d3528..3c97c44 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Bartib is an easy to use time tracking tool for the command line. It saves a log - [Via homebrew](#via-homebrew) - [Via apk (Alpine Linux)](#via-apk-alpine-linux) - [How to build Bartib](#how-to-build-bartib) + - [Precision](#precision) - [How to define in which file to save the log of your activities](#how-to-define-in-which-file-to-save-the-log-of-your-activities) - [How to edit or delete tracked activities](#how-to-edit-or-delete-tracked-activities) - [How to activate auto completion](#how-to-activate-auto-completion) @@ -186,6 +187,14 @@ Bartib is written in rust. You may build it yourself with the help of cargo. Jus cargo build --release ``` +#### Precision + +By default, Bartib measures timestamps in minutes. If you would like to measure timestamps with second precision, you can enable the `second-precision` feature: + +```bash +cargo build --features=second-precision --release +``` + ### How to define in which file to save the log of your activities You may either specify the absolute path to your log as an extra parameter (`--file` or `-f`) to your bartib command: From 960b38f29cf90467445d1d3eaf9536f34975d254 Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Fri, 13 Jun 2025 00:29:59 -0700 Subject: [PATCH 10/14] Add tests for mismatched precision in the timestamps --- src/data/activity.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/data/activity.rs b/src/data/activity.rs index ca53e53..4fff73c 100644 --- a/src/data/activity.rs +++ b/src/data/activity.rs @@ -484,4 +484,62 @@ mod tests { let t = Activity::from_str("asb - 2021- | project"); assert!(matches!(t, Err(ActivityError::DateTimeParseError))); } + + #[test] + #[cfg(not(feature = "second-precision"))] + fn from_str_second_precision_encountered_when_minute_precision_expected() { + let t = Activity::from_str( + "2021-02-16 16:14:53 - 2021-02-16 18:23:17 | test project | test description", + ) + .unwrap(); + + assert_eq!(t.start.date().year(), 2021); + assert_eq!(t.start.date().month(), 2); + assert_eq!(t.start.date().day(), 16); + + assert_eq!(t.start.time().hour(), 16); + assert_eq!(t.start.time().minute(), 15); + assert_eq!(t.start.time().second(), 0); + + assert_ne!(t.end, None); + + let end = t.end.unwrap(); + + assert_eq!(end.date().year(), 2021); + assert_eq!(end.date().month(), 2); + assert_eq!(end.date().day(), 16); + + assert_eq!(end.time().hour(), 18); + assert_eq!(end.time().minute(), 23); + assert_eq!(end.time().second(), 0); + } + + #[test] + #[cfg(feature = "second-precision")] + fn from_str_minute_precision_encountered_when_second_precision_expected() { + let t = Activity::from_str( + "2021-02-16 16:14 - 2021-02-16 18:23 | test project | test description", + ) + .unwrap(); + + assert_eq!(t.start.date().year(), 2021); + assert_eq!(t.start.date().month(), 2); + assert_eq!(t.start.date().day(), 16); + + assert_eq!(t.start.time().hour(), 16); + assert_eq!(t.start.time().minute(), 14); + assert_eq!(t.start.time().second(), 0); + + assert_ne!(t.end, None); + + let end = t.end.unwrap(); + + assert_eq!(end.date().year(), 2021); + assert_eq!(end.date().month(), 2); + assert_eq!(end.date().day(), 16); + + assert_eq!(end.time().hour(), 18); + assert_eq!(end.time().minute(), 23); + assert_eq!(end.time().second(), 0); + } } From ff53e5eacfb2162305e8e89b9de168ccc28cc225 Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Fri, 13 Jun 2025 00:33:24 -0700 Subject: [PATCH 11/14] Change wording in README blurb about `second-precision` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c97c44..a427f7c 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,7 @@ cargo build --release #### Precision -By default, Bartib measures timestamps in minutes. If you would like to measure timestamps with second precision, you can enable the `second-precision` feature: +By default, Bartib records timestamps in minutes. If you would like to record timestamps with second precision, you can enable the `second-precision` feature: ```bash cargo build --features=second-precision --release From 1abe077e69cd45edf8760858b623c417cacb7cdc Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Fri, 13 Jun 2025 00:34:25 -0700 Subject: [PATCH 12/14] Remove unnecessary newline --- src/conf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conf.rs b/src/conf.rs index 8454e6e..c508abd 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -11,8 +11,8 @@ pub static FORMAT_DATETIME: &str = FORMAT_SECOND_PRECISION_DATETIME; #[cfg(not(feature = "second-precision"))] pub static FORMAT_TIME: &str = "%R"; #[cfg(feature = "second-precision")] - pub static FORMAT_TIME: &str = "%T"; + pub static FORMAT_DATE: &str = "%F"; pub static DEFAULT_WIDTH: usize = usize::MAX; pub static REPORT_INDENTATION: usize = 4; From 7ebf8d1adc2182659ff8bc3702dcfac9dfdd4904 Mon Sep 17 00:00:00 2001 From: "Nicholas R. Smith" Date: Fri, 13 Jun 2025 07:56:59 -0700 Subject: [PATCH 13/14] Revert "Format report.rs" This reverts commit cc5327a90e901670987eed0066fad228cce11da3. --- src/view/report.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/view/report.rs b/src/view/report.rs index b27e4f9..f2757dc 100644 --- a/src/view/report.rs +++ b/src/view/report.rs @@ -219,7 +219,11 @@ fn get_longest_duration_string(report: &Report) -> Option { fn get_max_option(o1: Option, o2: Option) -> Option { if let Some(s1) = o1 { if let Some(s2) = o2 { - if s1 > s2 { o1 } else { o2 } + if s1 > s2 { + o1 + } else { + o2 + } } else { o1 } From f95b4aab0b1131120c8f01ec3eef3b7a03f485c5 Mon Sep 17 00:00:00 2001 From: Nikolas Schmidt-Voigt Date: Mon, 16 Jun 2025 11:38:38 +0200 Subject: [PATCH 14/14] Updated Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e97ce5..d962d73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Feature `second-precision` to build bartib with the ability to track activities to the second (thank to [@johnDeSilencio](https://github.com/johnDeSilencio)) - Subcommand `search` to search the list of last activities for terms (thanks to [@Pyxels](https://github.com/Pyxels)) - Subcommand `status` to display the total duration of activities today, in the current week and in the current month (thanks to [@airenas](https://github.com/airenas)) - Option `--no-quotes` to `project` to suppres quotes in the projects list (thanks to [@defigli](https://github.com/defigli))