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 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}