Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 1703 timewarrior block #1878

Open
wants to merge 15 commits into
base: master
Choose a base branch
from

Conversation

Mice7R
Copy link

@Mice7R Mice7R commented Apr 25, 2023

Adds a block that displays the time of the current active task in timewarrior.

Closes #1703

@Mice7R Mice7R mentioned this pull request Apr 25, 2023
@Mice7R
Copy link
Author

Mice7R commented Apr 25, 2023

I can fix the things clippy is complaining about and the typo but what can I do with cspell? timew is the name of the program.

@Mice7R Mice7R force-pushed the issue_1703_timewarrior branch from d83df1e to 707a961 Compare April 25, 2023 21:03
@MaxVerevkin
Copy link
Collaborator

timew is the name of the program

Please add it to https://github.com/greshake/i3status-rust/blob/master/cspell.yaml

@MaxVerevkin
Copy link
Collaborator

@notramo would you like to test this?

@Mice7R Mice7R force-pushed the issue_1703_timewarrior branch from 62a7d49 to 5a4e842 Compare February 12, 2024 22:10
@Mice7R
Copy link
Author

Mice7R commented Feb 12, 2024

This thing got stuck in pending. I've implemented your suggestion and updated the code for the new api.

@Mice7R
Copy link
Author

Mice7R commented Feb 12, 2024

Wait, I've noticed there is an error when "continuing" a task

@Mice7R
Copy link
Author

Mice7R commented Feb 12, 2024

There

@bim9262
Copy link
Collaborator

bim9262 commented Feb 14, 2024

Looks like there's 2 small formatting issues (missing ,s)

Diff in /home/runner/work/i3status-rust/i3status-rust/src/blocks/timewarrior.rs at line 141:
             annotation: item.annotation,
             start: chrono::TimeZone::from_utc_datetime(
                 &chrono::Utc,
-                &chrono::NaiveDateTime::parse_from_str(&item.start, "%Y%m%dT%H%M%SZ").unwrap()
+                &chrono::NaiveDateTime::parse_from_str(&item.start, "%Y%m%dT%H%M%SZ").unwrap(),
             ),
             end: item.end.map(|v| {
                 chrono::TimeZone::from_utc_datetime(
Diff in /home/runner/work/i3status-rust/i3status-rust/src/blocks/timewarrior.rs at line 148:
                     &chrono::Utc,
-                    &chrono::NaiveDateTime::parse_from_str(&v, "%Y%m%dT%H%M%SZ").unwrap()
+                    &chrono::NaiveDateTime::parse_from_str(&v, "%Y%m%dT%H%M%SZ").unwrap(),
                 )
             }),
         }

@bim9262

This comment was marked as outdated.

interval: Seconds,
format: FormatConfig,

info: Option<u64>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not make these i64 to avoid casting (elapsed.num_minutes() as u64)?

] {
if let Some(value) = level {
if (elapsed.num_minutes() as u64) >= *value {
state = st;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of keeping a state variable and then later setting the widget state you can just set the widget's state directly.

@bim9262
Copy link
Collaborator

bim9262 commented Feb 14, 2024

Any maybe this is a stupid question, but as someone who's never used taskwarrior can you have multiple tasks at the same time?

@bim9262
Copy link
Collaborator

bim9262 commented Feb 16, 2024

Here's a version without using the RAW intermediate stuct:

diff --git a/src/blocks/timewarrior.rs b/src/blocks/timewarrior.rs
index 26d4a67c..2da0f92b 100644
--- a/src/blocks/timewarrior.rs
+++ b/src/blocks/timewarrior.rs
@@ -35,7 +35,9 @@
 //! - `tasks`
 
 use super::prelude::*;
-use chrono::DateTime;
+
+use chrono::{offset::Utc, DateTime};
+use serde::de::{self, Deserialize, Deserializer};
 use tokio::process::Command;
 
 #[derive(Deserialize, Debug, SmartDefault)]
@@ -68,7 +70,7 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
         if let Some(tw) = data {
             if tw.end.is_none() {
                 // only show active tasks
-                let elapsed = chrono::Utc::now() - tw.start;
+                let elapsed = chrono::Utc::now() - tw.start.0;
 
                 // calculate state
                 for (level, st) in [
@@ -112,51 +114,31 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
     }
 }
 
-/// Raw output from timew
-#[derive(Deserialize, Debug)]
-struct TimewarriorRAW {
-    pub id: u32,
-    pub start: String,
-    pub tags: Vec<String>,
-    pub annotation: Option<String>,
-    pub end: Option<String>,
-}
-
 /// TimeWarrior entry
 #[derive(Debug, PartialEq, Deserialize)]
-#[serde(from = "TimewarriorRAW")]
 struct TimewarriorData {
     pub id: u32,
-    pub start: DateTime<chrono::offset::Utc>,
+    pub start: SerdeDateTime,
     pub tags: Vec<String>,
     pub annotation: Option<String>,
-    pub end: Option<DateTime<chrono::offset::Utc>>,
+    pub end: Option<SerdeDateTime>,
 }
 
-impl From<TimewarriorRAW> for TimewarriorData {
-    fn from(item: TimewarriorRAW) -> Self {
-        Self {
-            id: item.id,
-            tags: item.tags,
-            annotation: item.annotation,
-            start: chrono::TimeZone::from_utc_datetime(
-                &chrono::Utc,
-                &chrono::NaiveDateTime::parse_from_str(&item.start, "%Y%m%dT%H%M%SZ").unwrap()
-            ),
-            end: item.end.map(|v| {
-                chrono::TimeZone::from_utc_datetime(
-                    &chrono::Utc,
-                    &chrono::NaiveDateTime::parse_from_str(&v, "%Y%m%dT%H%M%SZ").unwrap()
-                )
-            }),
-        }
-    }
-}
+#[derive(Debug, PartialEq)]
+struct SerdeDateTime(DateTime<Utc>);
 
-/// Format a DateTime given a format string
-#[allow(dead_code)]
-fn format_datetime(date: &DateTime<chrono::Utc>, format: &str) -> String {
-    date.format(format).to_string()
+impl<'de> Deserialize<'de> for SerdeDateTime {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        use chrono::NaiveDateTime;
+        use de::Error;
+
+        let s = String::deserialize(deserializer)?;
+        let dt = NaiveDateTime::parse_from_str(&s, "%Y%m%dT%H%M%SZ").map_err(D::Error::custom)?;
+        Ok(Self(DateTime::<Utc>::from_naive_utc_and_offset(dt, Utc)))
+    }
 }
 
 /// Execute "timew export now" and return the current task (if any)

@notramo
Copy link

notramo commented Feb 16, 2024

Any maybe this is a stupid question, but as someone who's never used taskwarrior can you have multiple tasks at the same time?

Timewarrior and Taskwarrior are 2 different programs. This PR is about Timewarrior. In Timewarrior, one period can have multiple tags, but they must be started at the same time and ended at the same time (as they are attached to one interval). If someone wants to finish one tag and continue the other, they can stop the current period then start new with only one tag.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TimeWarrior block
4 participants