diary_cli/
search.rs

1use soulog::*;
2use crate::{archive::Archive, entry::Entry, moc::MOC, sort};
3
4pub trait Searchable {
5    fn get_uid(&self) -> String;
6    #[allow(clippy::ptr_arg)]
7    fn contains_tag(&mut self, tag: &String, logger: impl Logger) -> bool;
8}
9
10pub fn search_strict(tags: &[String], items: Vec<impl Searchable>, logger: impl Logger) -> Vec<String> {
11    let mut result = Vec::new();
12    for mut item in items.into_iter() {
13        let mut all_tags_present = true;
14        for tag in tags.iter() {
15            if !item.contains_tag(tag, logger.hollow()) {
16                all_tags_present = false;
17                break;
18            }
19        } if all_tags_present {
20            result.push(item.get_uid());
21        }
22    }
23
24    result
25}
26
27pub fn search<T: Searchable>(tags: &[String], items: Vec<T>, logger: impl Logger) -> Vec<String> {
28    let mut result = Vec::new();
29    for mut item in items.into_iter() {
30        for tag in tags {
31            if item.contains_tag(tag, logger.hollow()) {
32                result.push(item.get_uid());
33                break;
34            }
35        }
36    }
37    result
38}
39
40pub fn list_command(strict: bool, show_mocs: bool, show_entries: bool, filter: Option<Vec<String>>, mut logger: impl Logger) {
41    let archive = Archive::load(logger.hollow());
42
43    // Get entries and mocs
44    sort::sort(logger.hollow());
45    let mut entries: Vec<_> = sort::read_sorted(&archive, logger.hollow())
46        .into_vec()
47        .into_iter()
48        .map(|x| archive.get_entry(x, logger.hollow()).unwrap())
49        .collect();
50
51    let mut mocs = archive.list_mocs(logger.hollow());
52
53    let filter = match filter {
54        Some(x) => x,
55        None => {
56            log!((logger) List("Listing selected items..."));
57
58            let tags = get_unique_tags(&mut entries, &mut mocs, logger.hollow());
59
60            log!((logger.vital) tags("{tags:#?}") as Result);
61            std::mem::drop(tags);
62
63            let entry_uids: Vec<String> = entries.into_iter().map(|e| e.uid).collect();
64            let moc_uids: Vec<String> = mocs.into_iter().map(|m| m.uid).collect();
65
66            if show_entries { log!((logger.vital) entries("{entry_uids:#?}") as Result) }
67            if show_mocs { log!((logger.vital) mocs("{moc_uids:#?}") as Result) }
68            return;
69        }
70    };
71
72    let entry_uids: Vec<String>;
73    let moc_uids: Vec<String>;
74
75    if strict {
76        log!((logger) List("Searching strictly with tags {filter:?} in mocs and entries..."));
77        entry_uids = search_strict(&filter, entries, logger.hollow());
78        moc_uids = search_strict(&filter, mocs, logger.hollow());
79    } else {
80        log!((logger) List("Searching with tags {filter:?} in mocs and entries..."));
81        entry_uids = search(&filter, entries, logger.hollow());
82        moc_uids = search(&filter, mocs, logger.hollow());
83    }
84
85    log!((logger) List("Listing found entries and mocs..."));
86
87    log!((logger.vital) tags("{filter:?}") as Result);
88    if show_entries { log!((logger.vital) entries("{entry_uids:?}") as Result) }
89    if show_mocs { log!((logger.vital) mocs("{moc_uids:?}") as Result) }
90}
91
92use std::collections::HashSet;
93fn get_unique_tags<'a>(entries: &'a mut [Entry], mocs: &'a mut [MOC], logger: impl Logger) -> HashSet<&'a String> {
94    let mut tags = HashSet::new();
95
96    tags.extend(entries.iter_mut().flat_map(|x| x.tags(logger.hollow()).iter()));
97    tags.extend(mocs.iter_mut().flat_map(|x| x.tags(logger.hollow()).iter()));
98
99    tags
100}