initiative_core/command/token/
keyword.rs

1use crate::command::prelude::*;
2use crate::utils::{quoted_words, CaseInsensitiveStr};
3
4use std::pin::Pin;
5
6use async_stream::stream;
7use futures::prelude::*;
8
9pub fn match_input<'a>(
10    token: &'a Token,
11    input: &'a str,
12) -> Pin<Box<dyn Stream<Item = FuzzyMatch<'a>> + 'a>> {
13    let TokenType::Keyword(keyword) = token.token_type else {
14        unreachable!();
15    };
16
17    Box::pin(stream! {
18        let mut iter = quoted_words(input);
19        if let Some(first_word) = iter.next() {
20            if keyword.eq_ci(first_word.as_str()) {
21                if first_word.is_at_end() {
22                    yield FuzzyMatch::Exact(token.into());
23                } else {
24                    yield FuzzyMatch::Overflow(token.into(), first_word.after());
25                }
26            } else if first_word.can_complete() {
27                if let Some(completion) = keyword.strip_prefix_ci(first_word) {
28                    yield FuzzyMatch::Partial(token.into(), Some(completion.to_string()));
29                }
30            }
31        }
32    })
33}
34
35#[cfg(test)]
36mod test {
37    use super::*;
38
39    use crate::test_utils as test;
40
41    #[derive(Hash)]
42    enum Marker {
43        Keyword,
44    }
45
46    #[tokio::test]
47    async fn match_input_test_exact() {
48        let token = keyword_m(Marker::Keyword, "badger");
49
50        test::assert_eq_unordered!(
51            [FuzzyMatch::Exact(TokenMatch::from(&token))],
52            token
53                .match_input("BADGER", &test::app_meta())
54                .collect::<Vec<_>>()
55                .await,
56        );
57    }
58
59    #[tokio::test]
60    async fn match_input_test_overflow() {
61        let token = keyword("badger");
62
63        test::assert_eq_unordered!(
64            [FuzzyMatch::Overflow(
65                TokenMatch::from(&token),
66                " badger".into(),
67            )],
68            token
69                .match_input("badger badger", &test::app_meta())
70                .collect::<Vec<_>>()
71                .await,
72        );
73    }
74
75    #[tokio::test]
76    async fn match_input_test_partial() {
77        let token = keyword("badger");
78
79        test::assert_eq_unordered!(
80            [FuzzyMatch::Partial(
81                TokenMatch::from(&token),
82                Some("er".to_string()),
83            )],
84            token
85                .match_input(" badg", &test::app_meta())
86                .collect::<Vec<_>>()
87                .await,
88        );
89
90        test::assert_empty!(
91            token
92                .match_input(" badg ", &test::app_meta())
93                .collect::<Vec<_>>()
94                .await,
95        );
96
97        test::assert_empty!(
98            token
99                .match_input(r#""badg""#, &test::app_meta())
100                .collect::<Vec<_>>()
101                .await,
102        );
103    }
104}