cosmic_freedesktop_icons/theme/
parse.rs
1use crate::theme::directories::{Directory, DirectoryType};
2use crate::theme::Theme;
3
4fn icon_theme_section(file: &str) -> impl Iterator<Item = (&str, &str)> + '_ {
5 ini_core::Parser::new(file)
6 .skip_while(|item| *item != ini_core::Item::Section("Icon Theme"))
7 .take_while(|item| match item {
8 ini_core::Item::Section(value) => *value == "Icon Theme",
9 _ => true,
10 })
11 .filter_map(|item| {
12 if let ini_core::Item::Property(key, value) = item {
13 Some((key, value?))
14 } else {
15 None
16 }
17 })
18}
19
20#[derive(Debug)]
21enum DirectorySection<'a> {
22 Property(&'a str, &'a str),
23 EndSection,
24 Section(&'a str),
25}
26
27fn sections(file: &str) -> impl Iterator<Item = DirectorySection> {
28 ini_core::Parser::new(file).filter_map(move |item| match item {
29 ini_core::Item::Property(key, Some(value)) => Some(DirectorySection::Property(key, value)),
30 ini_core::Item::Section(section) => Some(DirectorySection::Section(section)),
31 ini_core::Item::SectionEnd => Some(DirectorySection::EndSection),
32 _ => None,
33 })
34}
35
36impl Theme {
37 pub(super) fn get_all_directories<'a>(
38 &'a self,
39 file: &'a str,
40 ) -> impl Iterator<Item = Directory<'a>> + 'a {
41 let mut iterator = sections(file);
42
43 std::iter::from_fn(move || {
44 let mut name = "";
45 let mut size = None;
46 let mut max_size = None;
47 let mut min_size = None;
48 let mut threshold = None;
49 let mut scale = None;
50 let mut dtype = DirectoryType::default();
52
53 #[allow(clippy::while_let_on_iterator)]
54 while let Some(event) = iterator.next() {
55 match event {
56 DirectorySection::Property(key, value) => {
57 if name.is_empty() || name == "Icon Theme" {
58 continue;
59 }
60
61 match key {
62 "Size" => size = str::parse(value).ok(),
63 "Scale" => scale = str::parse(value).ok(),
64 "Type" => dtype = DirectoryType::from(value),
66 "MaxSize" => max_size = str::parse(value).ok(),
67 "MinSize" => min_size = str::parse(value).ok(),
68 "Threshold" => threshold = str::parse(value).ok(),
69 _ => (),
70 }
71 }
72
73 DirectorySection::Section(new_name) => {
74 name = new_name;
75 size = None;
76 max_size = None;
77 min_size = None;
78 threshold = None;
79 scale = None;
80 dtype = DirectoryType::default();
81 }
82
83 DirectorySection::EndSection => {
84 if name.is_empty() || name == "Icon Theme" {
85 continue;
86 }
87
88 let size = size.take()?;
89
90 return Some(Directory {
91 name,
92 size,
93 scale: scale.unwrap_or(1),
94 type_: dtype,
96 maxsize: max_size.unwrap_or(size),
97 minsize: min_size.unwrap_or(size),
98 threshold: threshold.unwrap_or(2),
99 });
100 }
101 }
102 }
103
104 None
105 })
106 }
107
108 pub fn inherits<'a>(&self, file: &'a str) -> Vec<&'a str> {
109 icon_theme_section(file)
110 .find(|&(key, _)| key == "Inherits")
111 .map(|(_, parents)| {
112 parents
113 .split(',')
114 .filter(|parent| parent != &"hicolor")
116 .collect()
117 })
118 .unwrap_or_default()
119 }
120}
121
122#[cfg(test)]
123mod test {
124 use crate::THEMES;
125 use speculoos::prelude::*;
126
127 #[test]
128 fn should_get_theme_parents() {
129 for theme in THEMES.get("Arc").unwrap() {
130 let file = crate::theme::read_ini_theme(&theme.index).ok().unwrap();
131 let file = std::str::from_utf8(file.as_ref()).ok().unwrap();
132 let parents = theme.inherits(file);
133
134 assert_that!(parents).does_not_contain("hicolor");
135
136 assert_that!(parents).is_equal_to(vec![
137 "Moka",
138 "Faba",
139 "elementary",
140 "Adwaita",
141 "gnome",
142 ]);
143 }
144 }
145}