Skip to main content

todo_txt/task/
extended.rs

1#[derive(Clone, Debug, PartialEq, Eq, Default)]
2#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3pub struct Extended {
4    #[cfg_attr(feature = "serde", serde(flatten))]
5    pub inner: super::Simple,
6    #[cfg_attr(feature = "serde", serde(default))]
7    pub note: super::Note,
8    pub recurrence: Option<super::Recurrence>,
9    #[cfg_attr(feature = "serde", serde(default))]
10    pub flagged: bool,
11    #[cfg_attr(feature = "serde", serde(default))]
12    pub hidden: bool,
13}
14
15impl Extended {
16    pub fn has_note(&self) -> bool {
17        self.note != super::Note::None
18    }
19
20    fn note(task: &super::Simple) -> super::Note {
21        if let Some(file) = task.tags.get(&Self::tag_name()) {
22            super::Note::from_file(file)
23        } else {
24            super::Note::None
25        }
26    }
27
28    fn tag_name() -> String {
29        match std::env::var("TODO_NOTE_TAG") {
30            Ok(tag) => tag,
31            Err(_) => "note".to_string(),
32        }
33    }
34}
35
36impl std::convert::From<super::Simple> for Extended {
37    fn from(task: super::Simple) -> Self {
38        use std::str::FromStr;
39
40        let mut inner = task;
41
42        let note = Self::note(&inner);
43        inner.tags.remove(&Self::tag_name());
44
45        let mut recurrence = None;
46
47        if let Some(rec) = inner.tags.get("rec") {
48            recurrence = super::Recurrence::from_str(rec).ok();
49        }
50        inner.tags.remove("rec");
51
52        let flagged = inner.tags.contains_key("f");
53        inner.tags.remove("f");
54
55        let hidden = inner.tags.contains_key("h");
56        inner.tags.remove("h");
57
58        Self {
59            inner,
60            note,
61            recurrence,
62            flagged,
63            hidden,
64        }
65    }
66}
67
68impl std::str::FromStr for Extended {
69    type Err = std::convert::Infallible;
70
71    fn from_str(s: &str) -> Result<Self, Self::Err> {
72        super::Simple::from_str(s).map(|x| x.into())
73    }
74}
75
76impl From<String> for Extended {
77    fn from(value: String) -> Self {
78        value.parse().unwrap()
79    }
80}
81
82impl std::ops::Deref for Extended {
83    type Target = super::Simple;
84
85    fn deref(&self) -> &Self::Target {
86        &self.inner
87    }
88}
89
90impl std::ops::DerefMut for Extended {
91    fn deref_mut(&mut self) -> &mut Self::Target {
92        &mut self.inner
93    }
94}
95
96impl std::fmt::Display for Extended {
97    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98        use std::ops::Deref;
99
100        f.write_str(&format!("{}", self.deref()))?;
101
102        if self.note != super::Note::None {
103            f.write_str(&format!(" {}", self.note))?;
104        }
105
106        if let Some(ref recurrence) = self.recurrence {
107            f.write_str(&format!(" rec:{recurrence}"))?;
108        }
109
110        if self.flagged {
111            f.write_str(" f:1")?;
112        }
113
114        if self.hidden {
115            f.write_str(" h:1")?;
116        }
117
118        Ok(())
119    }
120}
121
122impl std::cmp::PartialOrd for Extended {
123    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
124        Some(self.cmp(other))
125    }
126}
127
128impl std::cmp::Ord for Extended {
129    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
130        self.inner.cmp(&other.inner)
131    }
132}
133
134impl AsRef<super::Simple> for Extended {
135    fn as_ref(&self) -> &super::Simple {
136        &self.inner
137    }
138}