Skip to main content

supercode_frontend_tui/composer/
model.rs

1//! Crossterm input adapter over the donor-neutral composer model.
2
3use std::ops::{Deref, DerefMut};
4
5use crossterm::event::{KeyCode, KeyEvent};
6use supercode::frontend::FrontendRuntimeDescriptor;
7use supercode_frontend_model::{
8    ComposerAction, ComposerInputEvent, ComposerKey, ComposerKeyCode,
9    ComposerModel as NeutralComposerModel,
10};
11
12use crate::terminal::event_stream::TerminalEvent;
13
14#[derive(Clone, Debug)]
15pub struct ComposerModel(NeutralComposerModel);
16
17impl ComposerModel {
18    pub fn new(descriptor: &FrontendRuntimeDescriptor) -> Self {
19        Self(NeutralComposerModel::new(descriptor))
20    }
21
22    pub fn handle_terminal_event(&mut self, event: TerminalEvent) -> Option<ComposerAction> {
23        self.0.handle_input(map_terminal_event(event))
24    }
25
26    pub fn handle_key(&mut self, key: KeyEvent) -> Option<ComposerAction> {
27        self.0.handle_key(map_key(key))
28    }
29}
30
31impl Deref for ComposerModel {
32    type Target = NeutralComposerModel;
33
34    fn deref(&self) -> &Self::Target {
35        &self.0
36    }
37}
38
39impl DerefMut for ComposerModel {
40    fn deref_mut(&mut self) -> &mut Self::Target {
41        &mut self.0
42    }
43}
44
45fn map_terminal_event(event: TerminalEvent) -> ComposerInputEvent {
46    match event {
47        TerminalEvent::Key(key) => ComposerInputEvent::Key(map_key(key)),
48        TerminalEvent::Paste(text) => ComposerInputEvent::Paste(text),
49        TerminalEvent::Resize { width, height } => ComposerInputEvent::Resize { width, height },
50        TerminalEvent::FocusChanged(focused) => ComposerInputEvent::FocusChanged(focused),
51    }
52}
53
54fn map_key(key: KeyEvent) -> ComposerKey {
55    let code = match key.code {
56        KeyCode::Char(character) => ComposerKeyCode::Char(character),
57        KeyCode::Enter => ComposerKeyCode::Enter,
58        KeyCode::Backspace => ComposerKeyCode::Backspace,
59        KeyCode::Delete => ComposerKeyCode::Delete,
60        KeyCode::Left => ComposerKeyCode::Left,
61        KeyCode::Right => ComposerKeyCode::Right,
62        KeyCode::Home => ComposerKeyCode::Home,
63        KeyCode::End => ComposerKeyCode::End,
64        KeyCode::Up => ComposerKeyCode::Up,
65        KeyCode::Down => ComposerKeyCode::Down,
66        KeyCode::Esc => ComposerKeyCode::Escape,
67        _ => ComposerKeyCode::Other,
68    };
69    ComposerKey {
70        code,
71        control: key
72            .modifiers
73            .contains(crossterm::event::KeyModifiers::CONTROL),
74        shift: key
75            .modifiers
76            .contains(crossterm::event::KeyModifiers::SHIFT),
77        alt: key.modifiers.contains(crossterm::event::KeyModifiers::ALT),
78        release: key.kind == crossterm::event::KeyEventKind::Release,
79    }
80}