Skip to main content

flatland_play_loop/
chat.rs

1//! In-game chat input buffer (say / whisper).
2
3use flatland_client_ui::{UiKeyCode, UiKeyEvent};
4
5#[derive(Debug, Clone, Default)]
6pub struct ChatSession {
7    pub active: bool,
8    pub whisper: bool,
9    pub buffer: String,
10}
11
12impl ChatSession {
13    pub const MAX_LEN: usize = 200;
14
15    pub fn open(&mut self, whisper: bool) {
16        self.active = true;
17        self.whisper = whisper;
18        self.buffer.clear();
19    }
20
21    pub fn close(&mut self) {
22        self.active = false;
23        self.buffer.clear();
24    }
25
26    /// Returns `Some(trimmed text)` when the user submits; `None` otherwise.
27    pub fn handle_key(&mut self, key: UiKeyEvent) -> Option<String> {
28        match key.code {
29            UiKeyCode::Esc => {
30                self.close();
31                None
32            }
33            UiKeyCode::Enter => {
34                let text = self.buffer.trim().to_string();
35                self.close();
36                if text.is_empty() {
37                    None
38                } else {
39                    Some(text)
40                }
41            }
42            UiKeyCode::Backspace => {
43                self.buffer.pop();
44                None
45            }
46            UiKeyCode::Char(c) => {
47                if self.buffer.len() < Self::MAX_LEN {
48                    self.buffer.push(c);
49                }
50                None
51            }
52            _ => None,
53        }
54    }
55
56    pub fn prompt_line(&self) -> String {
57        if !self.active {
58            return String::new();
59        }
60        let prefix = if self.whisper { "whisper> " } else { "say> " };
61        format!("{prefix}{}", self.buffer)
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68    use flatland_client_ui::{UiKeyEventKind, UiKeyModifiers};
69
70    fn char_key(c: char) -> UiKeyEvent {
71        UiKeyEvent {
72            kind: UiKeyEventKind::Press,
73            code: UiKeyCode::Char(c),
74            modifiers: UiKeyModifiers::default(),
75        }
76    }
77
78    #[test]
79    fn submit_trims_and_clears() {
80        let mut chat = ChatSession::default();
81        chat.open(false);
82        for c in "  hello  ".chars() {
83            assert!(chat.handle_key(char_key(c)).is_none());
84        }
85        let submitted = chat
86            .handle_key(UiKeyEvent {
87                kind: UiKeyEventKind::Press,
88                code: UiKeyCode::Enter,
89                modifiers: UiKeyModifiers::default(),
90            })
91            .expect("submit");
92        assert_eq!(submitted, "hello");
93        assert!(!chat.active);
94    }
95}