flatland-play-loop 0.2.28

Engine-agnostic Flatland3 play session frame logic (gfx client)
Documentation
//! In-game chat input buffer (say / whisper).

use flatland_client_ui::{UiKeyCode, UiKeyEvent};

#[derive(Debug, Clone, Default)]
pub struct ChatSession {
    pub active: bool,
    pub whisper: bool,
    pub buffer: String,
}

impl ChatSession {
    pub const MAX_LEN: usize = 200;

    pub fn open(&mut self, whisper: bool) {
        self.active = true;
        self.whisper = whisper;
        self.buffer.clear();
    }

    pub fn close(&mut self) {
        self.active = false;
        self.buffer.clear();
    }

    /// Returns `Some(trimmed text)` when the user submits; `None` otherwise.
    pub fn handle_key(&mut self, key: UiKeyEvent) -> Option<String> {
        match key.code {
            UiKeyCode::Esc => {
                self.close();
                None
            }
            UiKeyCode::Enter => {
                let text = self.buffer.trim().to_string();
                self.close();
                if text.is_empty() {
                    None
                } else {
                    Some(text)
                }
            }
            UiKeyCode::Backspace => {
                self.buffer.pop();
                None
            }
            UiKeyCode::Char(c) => {
                if self.buffer.len() < Self::MAX_LEN {
                    self.buffer.push(c);
                }
                None
            }
            _ => None,
        }
    }

    pub fn prompt_line(&self) -> String {
        if !self.active {
            return String::new();
        }
        let prefix = if self.whisper { "whisper> " } else { "say> " };
        format!("{prefix}{}", self.buffer)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use flatland_client_ui::{UiKeyEventKind, UiKeyModifiers};

    fn char_key(c: char) -> UiKeyEvent {
        UiKeyEvent {
            kind: UiKeyEventKind::Press,
            code: UiKeyCode::Char(c),
            modifiers: UiKeyModifiers::default(),
        }
    }

    #[test]
    fn submit_trims_and_clears() {
        let mut chat = ChatSession::default();
        chat.open(false);
        for c in "  hello  ".chars() {
            assert!(chat.handle_key(char_key(c)).is_none());
        }
        let submitted = chat
            .handle_key(UiKeyEvent {
                kind: UiKeyEventKind::Press,
                code: UiKeyCode::Enter,
                modifiers: UiKeyModifiers::default(),
            })
            .expect("submit");
        assert_eq!(submitted, "hello");
        assert!(!chat.active);
    }
}