things3_cloud/commands/
upcoming.rs1use crate::app::Cli;
2use crate::commands::{Command, DetailedArgs};
3use crate::common::{colored, fmt_date, fmt_task_line, fmt_task_with_note, BOLD, CYAN, DIM, ICONS};
4use crate::wire::task::TaskStatus;
5use anyhow::Result;
6use clap::Args;
7use std::io::Write;
8
9#[derive(Debug, Default, Args)]
10pub struct UpcomingArgs {
11 #[command(flatten)]
12 pub detailed: DetailedArgs,
13}
14
15impl Command for UpcomingArgs {
16 fn run_with_ctx(
17 &self,
18 cli: &Cli,
19 out: &mut dyn Write,
20 ctx: &mut dyn crate::cmd_ctx::CmdCtx,
21 ) -> Result<()> {
22 let store = cli.load_store()?;
23 let today = ctx.today();
24 let now_ts = today.timestamp();
25
26 let mut tasks = Vec::new();
27 for t in store.tasks(Some(TaskStatus::Incomplete), Some(false), None) {
28 if t.in_someday() {
29 continue;
30 }
31 let Some(start_date) = t.start_date else {
32 continue;
33 };
34 if start_date.timestamp() > now_ts {
35 tasks.push(t);
36 }
37 }
38 tasks.sort_by_key(|t| t.start_date);
39
40 if tasks.is_empty() {
41 writeln!(
42 out,
43 "{}",
44 colored("No upcoming tasks.", &[DIM], cli.no_color)
45 )?;
46 return Ok(());
47 }
48
49 writeln!(
50 out,
51 "{}",
52 colored(
53 &format!("{} Upcoming ({} tasks)", ICONS.upcoming, tasks.len()),
54 &[BOLD, CYAN],
55 cli.no_color,
56 )
57 )?;
58
59 let id_prefix_len =
60 store.unique_prefix_length(&tasks.iter().map(|t| t.uuid.clone()).collect::<Vec<_>>());
61
62 let mut current_date = String::new();
63 for task in tasks {
64 let day = fmt_date(task.start_date);
65 if day != current_date {
66 writeln!(out)?;
67 writeln!(
68 out,
69 "{}",
70 colored(&format!(" {}", day), &[BOLD], cli.no_color)
71 )?;
72 current_date = day;
73 }
74 let line = fmt_task_line(
75 &task,
76 &store,
77 false,
78 true,
79 false,
80 Some(id_prefix_len),
81 &today,
82 cli.no_color,
83 );
84 writeln!(
85 out,
86 "{}",
87 fmt_task_with_note(
88 line,
89 &task,
90 " ",
91 Some(id_prefix_len),
92 self.detailed.detailed,
93 cli.no_color,
94 )
95 )?;
96 }
97 Ok(())
98 }
99}