initiative_core/command/token/
keyword_list.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::KeywordList(keywords) = &token.token_type else {
14 unreachable!();
15 };
16
17 Box::pin(stream! {
18 let mut iter = quoted_words(input).peekable();
19 if let Some(first_word) = iter.next() {
20 for keyword in keywords.iter() {
21 if keyword.eq_ci(first_word.as_str()) {
22 if iter.peek().is_none() {
23 yield FuzzyMatch::Exact(TokenMatch::new(token, first_word.as_str()));
24 } else {
25 yield FuzzyMatch::Overflow(
26 TokenMatch::new(token, first_word.as_str()),
27 first_word.after(),
28 );
29 }
30 } else if first_word.can_complete() {
31 if let Some(completion) = keyword.strip_prefix_ci(&first_word) {
32 yield FuzzyMatch::Partial(
33 TokenMatch::new(token, first_word.as_str()),
34 Some(completion.to_string()),
35 );
36 }
37 }
38 }
39 }
40 })
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 use crate::test_utils as test;
48
49 #[derive(Hash)]
50 enum Marker {
51 Token,
52 }
53
54 #[tokio::test]
55 async fn match_input_test_no_complete() {
56 let token = keyword_list(["badger", "mushroom", "snake", "badgering"]);
57
58 test::assert_eq_unordered!(
59 [FuzzyMatch::Exact(TokenMatch::new(&token, "badger"))],
60 token
61 .match_input("badger ", &test::app_meta())
62 .collect::<Vec<_>>()
63 .await,
64 );
65 }
66
67 #[tokio::test]
68 async fn match_input_test_partial() {
69 let token = keyword_list_m(Marker::Token, ["polyp", "POLYPHEMUS"]);
70
71 test::assert_eq_unordered!(
72 [
73 FuzzyMatch::Exact(TokenMatch::new(&token, "polyp")),
74 FuzzyMatch::Partial(TokenMatch::new(&token, "polyp"), Some("HEMUS".to_string())),
75 ],
76 token
77 .match_input("polyp", &test::app_meta())
78 .collect::<Vec<_>>()
79 .await,
80 );
81 }
82
83 #[tokio::test]
84 async fn match_input_test_overflow() {
85 let token = keyword_list(["badger", "mushroom"]);
86
87 test::assert_eq_unordered!(
88 [FuzzyMatch::Overflow(
89 TokenMatch::new(&token, "badger"),
90 " mushroom".into(),
91 )],
92 token
93 .match_input("badger mushroom", &test::app_meta())
94 .collect::<Vec<_>>()
95 .await,
96 );
97 }
98}