paris/formatter/keys/
key_list.rs

1use super::Key;
2
3pub struct KeyList<'a> {
4    input: &'a str,
5}
6
7impl<'a> KeyList<'a> {
8    pub fn new(input: &'a str) -> Self {
9        Self { input }
10    }
11
12    fn fetch_next_key(&mut self) -> Option<(Key<'a>, bool)> {
13        let mut key = None;
14
15        if let Some(i) = self.input.find('<') {
16            self.input = &self.input[i..];
17
18            let mut omit = false;
19
20            let rest = self
21                .input
22                .char_indices()
23                .take_while(|(idx, c)| {
24                    if *idx == 0 && *c == '<' {
25                        return true;
26                    }
27
28                    if *c == '<' {
29                        omit = true;
30                        return false;
31                    }
32
33                    *c != '>'
34                })
35                .last()
36                .map(|(idx, c)| idx + c.len_utf8())
37                .unwrap_or_default();
38
39            // +1 to get the last '>' that's excluded only if the key
40            // isn't a 'fake' key with a false opening
41            let adder = if omit || self.input[..rest].len() == self.input.len() {
42                // Don't add anything else if we're at the end of the string
43                0
44            } else {
45                1
46            };
47
48            key = Some((Key::new(&self.input[..(rest + adder)]), omit));
49            self.input = &self.input[(rest + adder)..];
50        }
51
52        key
53    }
54}
55
56impl<'a> Iterator for KeyList<'a> {
57    type Item = Key<'a>;
58
59    fn next(&mut self) -> Option<Self::Item> {
60        loop {
61            let key = self.fetch_next_key();
62
63            if key.is_none() {
64                break;
65            }
66
67            let (key, omit) = key.unwrap();
68
69            // If provided key was a 'fake' with a false opening
70            // like this "<---------------" we don't want it in the key list.
71            if omit {
72                continue;
73            }
74
75            return Some(key);
76        }
77
78        None
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn find_keys() {
88        let input = "<black> <red> one two <three>";
89        let key_count = KeyList::new(&input).count();
90
91        assert_eq!(key_count, 3);
92    }
93
94    #[test]
95    fn ignore_fake_keys() {
96        let input = "<black><-------------------- some text <some random opening here, <and another here </>";
97        let key_count = KeyList::new(&input).count();
98
99        assert_eq!(key_count, 2);
100    }
101
102    #[test]
103    fn mess_around() {
104        let input = "<< powering on 'TV' (0)";
105        let _keys = KeyList::new(&input).count();
106
107        let input = "<< something that doesn't end after weird patterns < alksdfa < ngi2oueng <<ikdoqlksmads <black></>";
108        let keys = KeyList::new(&input).count();
109
110        assert_eq!(keys, 2);
111    }
112}