Skip to main content

todo_txt/task/
simple.rs

1use std::collections::BTreeMap;
2
3#[derive(Clone, Debug, PartialEq, Eq, Hash)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5pub struct Simple {
6    pub subject: String,
7    #[cfg_attr(feature = "serde", serde(default))]
8    pub priority: crate::Priority,
9    pub create_date: Option<crate::Date>,
10    pub finish_date: Option<crate::Date>,
11    #[cfg_attr(feature = "serde", serde(default))]
12    pub finished: bool,
13    pub threshold_date: Option<crate::Date>,
14    pub due_date: Option<crate::Date>,
15    #[cfg_attr(feature = "serde", serde(default))]
16    pub contexts: Vec<String>,
17    #[cfg_attr(feature = "serde", serde(default))]
18    pub projects: Vec<String>,
19    #[cfg_attr(feature = "serde", serde(default))]
20    pub hashtags: Vec<String>,
21    #[cfg_attr(feature = "serde", serde(default))]
22    pub tags: BTreeMap<String, String>,
23}
24
25impl Simple {
26    pub fn complete(&mut self) {
27        let today = chrono::Local::now().date_naive();
28
29        self.finished = true;
30        if self.create_date.is_some() {
31            self.finish_date = Some(today);
32        }
33    }
34
35    pub fn uncomplete(&mut self) {
36        self.finished = false;
37        self.finish_date = None;
38    }
39}
40
41impl Default for Simple {
42    fn default() -> Self {
43        Self {
44            subject: String::new(),
45            priority: crate::Priority::lowest(),
46            create_date: None,
47            finish_date: None,
48            finished: false,
49            threshold_date: None,
50            due_date: None,
51            contexts: Vec::new(),
52            projects: Vec::new(),
53            hashtags: Vec::new(),
54            tags: BTreeMap::new(),
55        }
56    }
57}
58
59impl std::str::FromStr for Simple {
60    type Err = std::convert::Infallible;
61
62    fn from_str(s: &str) -> Result<Simple, Self::Err> {
63        Ok(crate::parser::task(s))
64    }
65}
66
67impl From<String> for Simple {
68    fn from(value: String) -> Self {
69        value.parse().unwrap()
70    }
71}
72
73impl std::fmt::Display for Simple {
74    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75        if self.finished {
76            f.write_str("x ")?;
77        }
78
79        if !self.priority.is_lowest() {
80            f.write_str(&format!("({}) ", self.priority))?;
81        }
82
83        if let Some(finish_date) = self.finish_date {
84            f.write_str(&format!("{} ", finish_date.format("%Y-%m-%d")))?;
85        }
86
87        if let Some(create_date) = self.create_date {
88            f.write_str(&format!("{} ", create_date.format("%Y-%m-%d")))?;
89        }
90
91        f.write_str(&self.subject)?;
92
93        if let Some(due_date) = self.due_date {
94            f.write_str(&format!(" due:{}", due_date.format("%Y-%m-%d")))?;
95        }
96
97        if let Some(threshold_date) = self.threshold_date {
98            f.write_str(&format!(" t:{}", threshold_date.format("%Y-%m-%d")))?;
99        }
100
101        for context in &self.contexts {
102            let tag = format!("{}{context}", super::Tag::Context);
103
104            if !self.subject.contains(&tag) {
105                write!(f, " {tag}")?;
106            }
107        }
108
109        for project in &self.projects {
110            let tag = format!("{}{project}", super::Tag::Project);
111
112            if !self.subject.contains(&tag) {
113                write!(f, " {tag}")?;
114            }
115        }
116
117        for hashtags in &self.hashtags {
118            let tag = format!("{}{hashtags}", super::Tag::Hashtag);
119
120            if !self.subject.contains(&tag) {
121                write!(f, " {tag}")?;
122            }
123        }
124
125        for (key, value) in &self.tags {
126            f.write_str(&format!(" {key}:{value}"))?;
127        }
128
129        Ok(())
130    }
131}
132
133impl std::cmp::PartialOrd for Simple {
134    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
135        Some(self.cmp(other))
136    }
137}
138
139impl std::cmp::Ord for Simple {
140    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
141        if self.priority != other.priority {
142            return self.priority.cmp(&other.priority);
143        }
144
145        if self.due_date != other.due_date {
146            return self.due_date.cmp(&other.due_date);
147        }
148
149        if self.subject != other.subject {
150            return self.subject.cmp(&other.subject);
151        }
152
153        std::cmp::Ordering::Equal
154    }
155}
156
157impl AsRef<Simple> for Simple {
158    fn as_ref(&self) -> &Simple {
159        self
160    }
161}