initiative_core/command/token/
keyword.rs1use 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}