Skip to main content

tui_pages/command/
resolver.rs

1use crate::command::{CommandRegistry, CommandResponse};
2use std::time::{Duration, Instant};
3use tracing::debug;
4
5#[derive(Debug, Clone)]
6pub struct CommandResolver<A> {
7    pub registry: CommandRegistry<A>,
8    last_input_time: Option<Instant>,
9    timeout: Duration,
10}
11
12impl<A> CommandResolver<A> {
13    pub fn new(registry: CommandRegistry<A>, timeout_ms: u64) -> Self {
14        Self {
15            registry,
16            last_input_time: None,
17            timeout: Duration::from_millis(timeout_ms),
18        }
19    }
20
21    pub fn touch(&mut self) {
22        self.last_input_time = Some(Instant::now());
23    }
24
25    pub fn reset(&mut self) {
26        self.last_input_time = None;
27    }
28
29    pub fn is_idle(&self) -> bool {
30        self.last_input_time
31            .map(|time| time.elapsed() > self.timeout)
32            .unwrap_or(true)
33    }
34}
35
36impl<A: Clone> CommandResolver<A> {
37    pub fn process(&self, input: &str) -> CommandResponse<A> {
38        let input = input.trim();
39        if input.is_empty() {
40            return CommandResponse::Empty;
41        }
42
43        debug!(input, "processing command input");
44
45        if let Some(action) = self.registry.match_action(input) {
46            CommandResponse::Execute(action)
47        } else if self.registry.is_prefix(input) {
48            CommandResponse::Incomplete(self.registry.get_hints(input))
49        } else {
50            CommandResponse::Unknown
51        }
52    }
53
54    pub fn get_feedback(&self, input: &str) -> Option<String> {
55        if input.trim().is_empty() || !self.is_idle() {
56            return None;
57        }
58
59        match self.process(input) {
60            CommandResponse::Execute(_) | CommandResponse::Empty => None,
61            CommandResponse::Unknown => Some("[Unknown command]".to_string()),
62            CommandResponse::Incomplete(hints) => {
63                let hint_str: Vec<String> = hints
64                    .iter()
65                    .take(5)
66                    .map(|hint| format!("{} ({})", hint.alias, hint.action_name))
67                    .collect();
68                Some(format!("[Incomplete: {}]", hint_str.join(", ")))
69            }
70        }
71    }
72}