Skip to main content

doing_plugins/
helpers.rs

1use doing_config::Config;
2use doing_taskpaper::Entry;
3use doing_time::{DurationFormat, FormattedDuration};
4use indexmap::IndexMap;
5
6/// Format an entry's interval duration as a string, returning `None` if zero or absent.
7pub fn format_interval(entry: &Entry, config: &Config) -> Option<String> {
8  entry.interval().and_then(|iv| {
9    let fmt = DurationFormat::from_config(&config.interval_format);
10    let formatted = FormattedDuration::new(iv, fmt).to_string();
11    if formatted == "00:00:00" { None } else { Some(formatted) }
12  })
13}
14
15/// Group entries by section name, preserving the order sections are first seen.
16pub fn group_by_section(entries: &[Entry]) -> Vec<(&str, Vec<&Entry>)> {
17  let mut map: IndexMap<&str, Vec<&Entry>> = IndexMap::new();
18  for entry in entries {
19    map.entry(entry.section()).or_default().push(entry);
20  }
21  map.into_iter().collect()
22}
23
24/// Convert an entry's note lines into an HTML unordered list.
25///
26/// Returns an empty string if the note is empty.
27pub fn note_to_html_list(entry: &Entry, css_class: &str, escape: fn(&str) -> String) -> String {
28  if entry.note().is_empty() {
29    return String::new();
30  }
31
32  let items: Vec<String> = entry
33    .note()
34    .lines()
35    .iter()
36    .map(|line| format!("<li>{}</li>", escape(line.trim())))
37    .collect();
38
39  format!(r#"<ul class="{css_class}">{}</ul>"#, items.join(""))
40}