Skip to main content

things3_cloud/commands/
today.rs

1use crate::app::Cli;
2use crate::commands::{Command, DetailedArgs};
3use crate::common::{
4    colored, fmt_project_with_note, fmt_task_line, fmt_task_with_note, BLUE, BOLD, DIM, ICONS,
5    YELLOW,
6};
7use crate::wire::task::TaskStatus;
8use anyhow::Result;
9use clap::Args;
10use std::io::Write;
11
12#[derive(Debug, Default, Args)]
13pub struct TodayArgs {
14    #[command(flatten)]
15    pub detailed: DetailedArgs,
16}
17
18impl Command for TodayArgs {
19    fn run_with_ctx(
20        &self,
21        cli: &Cli,
22        out: &mut dyn Write,
23        ctx: &mut dyn crate::cmd_ctx::CmdCtx,
24    ) -> Result<()> {
25        let store = cli.load_store()?;
26        let today = ctx.today();
27        let tasks = store.today(&today);
28        let mut today_items: Vec<_> = store
29            .tasks(Some(TaskStatus::Incomplete), Some(false), None)
30            .into_iter()
31            .filter(|t| {
32                !t.is_heading()
33                    && !t.title.trim().is_empty()
34                    && t.entity == "Task6"
35                    && (t.is_today(&today) || t.evening)
36            })
37            .collect();
38
39        today_items.sort_by_key(|task| {
40            let tir = task.today_index_reference.unwrap_or(0);
41            (
42                std::cmp::Reverse(tir),
43                task.today_index,
44                std::cmp::Reverse(task.index),
45            )
46        });
47
48        if today_items.is_empty() {
49            writeln!(
50                out,
51                "{}",
52                colored("No tasks for today.", &[DIM], cli.no_color)
53            )?;
54            return Ok(());
55        }
56
57        let regular: Vec<_> = today_items.iter().filter(|t| !t.evening).cloned().collect();
58        let evening: Vec<_> = today_items.iter().filter(|t| t.evening).cloned().collect();
59        let project_count = today_items.iter().filter(|t| t.is_project()).count();
60        let id_prefix_len = store.unique_prefix_length(
61            &today_items
62                .iter()
63                .map(|i| i.uuid.clone())
64                .collect::<Vec<_>>(),
65        );
66
67        if project_count > 0 {
68            let label = if project_count == 1 {
69                "project"
70            } else {
71                "projects"
72            };
73            writeln!(
74                out,
75                "{}",
76                colored(
77                    &format!(
78                        "{} Today  ({} tasks, {} {})",
79                        ICONS.today,
80                        tasks.len(),
81                        project_count,
82                        label
83                    ),
84                    &[BOLD, YELLOW],
85                    cli.no_color,
86                )
87            )?;
88        } else {
89            writeln!(
90                out,
91                "{}",
92                colored(
93                    &format!("{} Today  ({} tasks)", ICONS.today, tasks.len()),
94                    &[BOLD, YELLOW],
95                    cli.no_color,
96                )
97            )?;
98        }
99
100        if !regular.is_empty() {
101            writeln!(out)?;
102            for item in regular {
103                if item.is_project() {
104                    writeln!(
105                        out,
106                        "{}",
107                        fmt_project_with_note(
108                            &item,
109                            &store,
110                            "  ",
111                            Some(id_prefix_len),
112                            false,
113                            true,
114                            self.detailed.detailed,
115                            &today,
116                            cli.no_color,
117                        )
118                    )?;
119                } else {
120                    let line = fmt_task_line(
121                        &item,
122                        &store,
123                        false,
124                        false,
125                        true,
126                        Some(id_prefix_len),
127                        &today,
128                        cli.no_color,
129                    );
130                    writeln!(
131                        out,
132                        "{}",
133                        fmt_task_with_note(
134                            line,
135                            &item,
136                            "  ",
137                            Some(id_prefix_len),
138                            self.detailed.detailed,
139                            cli.no_color,
140                        )
141                    )?;
142                }
143            }
144        }
145
146        if !evening.is_empty() {
147            writeln!(out)?;
148            writeln!(
149                out,
150                "{}",
151                colored(
152                    &format!("{} This Evening", ICONS.evening),
153                    &[BOLD, BLUE],
154                    cli.no_color,
155                )
156            )?;
157            writeln!(out)?;
158
159            for item in evening {
160                if item.is_project() {
161                    writeln!(
162                        out,
163                        "{}",
164                        fmt_project_with_note(
165                            &item,
166                            &store,
167                            "  ",
168                            Some(id_prefix_len),
169                            false,
170                            true,
171                            self.detailed.detailed,
172                            &today,
173                            cli.no_color,
174                        )
175                    )?;
176                } else {
177                    let line = fmt_task_line(
178                        &item,
179                        &store,
180                        false,
181                        false,
182                        true,
183                        Some(id_prefix_len),
184                        &today,
185                        cli.no_color,
186                    );
187                    writeln!(
188                        out,
189                        "{}",
190                        fmt_task_with_note(
191                            line,
192                            &item,
193                            "  ",
194                            Some(id_prefix_len),
195                            self.detailed.detailed,
196                            cli.no_color,
197                        )
198                    )?;
199                }
200            }
201        }
202
203        Ok(())
204    }
205}