wireman_event_handler/
lib.rs

1mod crossterm;
2pub mod key_event;
3use std::collections::HashMap;
4use std::fmt::Display;
5
6use ::crossterm::event::MouseEvent;
7pub use key_event::KeyCode;
8pub use key_event::KeyEvent;
9pub use key_event::{KeyModifier, KeyModifiers};
10use ratatui::backend::Backend;
11use ratatui::Terminal;
12use std::fmt::Write as _;
13
14/// A trait for handling events with associated contexts.
15pub trait EventHandler {
16    /// The context in which events are handled.
17    type Context;
18
19    /// The type of events to handle.
20    type Event;
21
22    /// Handles a specific app event with the given context.
23    ///
24    /// # Arguments
25    ///
26    /// * `event` - The event to handle.
27    /// * `ctx` - The context in which the event is handled.
28    fn handle_event(event: &Self::Event, ctx: &mut Self::Context);
29
30    /// Passes through key events without any specific handling.
31    ///
32    /// This method is optional and can be used to simply pass through character events without
33    /// registering any specific handling logic.
34    fn pass_through_key_events<B: Backend>(
35        _: &KeyEvent,
36        _: &mut Self::Context,
37        _: &mut Terminal<B>,
38    ) {
39    }
40
41    /// Passes through mouse events without any specific handling.
42    ///
43    /// This method is optional and can be used to simply pass through character events without
44    /// registering any specific handling logic.
45    fn pass_through_mouse_events(_: &MouseEvent, _: &mut Self::Context) {}
46
47    /// Passes through paste events without any specific handling.
48    ///
49    /// This method is optional and can be used to simply pass through character events without
50    /// registering any specific handling logic.
51    fn pass_through_paste_events(_: String, _: &mut Self::Context) {}
52
53    /// Retrieves the key event mappings to their corresponding application events.
54    ///
55    /// Returns a map of key events to application events.
56    fn key_event_mappings(ctx: &Self::Context) -> Vec<(KeyEvent, Self::Event)>;
57
58    /// Handles a key event by dispatching it to the corresponding application event handler.
59    ///
60    /// # Arguments
61    ///
62    /// * `ctx` - The context in which the key event is handled.
63    /// * `event` - The key event to handle.
64    /// * `terminal` - The terminal instance for system editor operations.
65    fn handle_key_event<T: Into<KeyEvent>, B: Backend>(
66        ctx: &mut Self::Context,
67        event: T,
68        terminal: &mut Terminal<B>,
69    ) {
70        let mappings = Self::key_event_mappings(ctx);
71        let event = event.into();
72        if let Some(item) = mappings.iter().find(|item| item.0 == event) {
73            Self::handle_event(&item.1, ctx);
74        } else {
75            Self::pass_through_key_events(&event, ctx, terminal);
76        }
77    }
78
79    /// Handles a mouse event by dispatching it to the corresponding application event handler.
80    ///
81    /// # Arguments
82    ///
83    /// * `ctx` - The context in which the mouse event is handled.
84    /// * `event` - The mouse event to handle.
85    fn handle_mouse_event<T: Into<MouseEvent>>(ctx: &mut Self::Context, event: T) {
86        let event = event.into();
87        Self::pass_through_mouse_events(&event, ctx);
88    }
89
90    /// Handles a paste event by dispatching it to the corresponding application event handler.
91    ///
92    /// # Arguments
93    ///
94    /// * `ctx` - The context in which the paste event is handled.
95    /// * `text` - The text to paste.
96    fn handle_paste_event(ctx: &mut Self::Context, text: String) {
97        Self::pass_through_paste_events(text, ctx);
98    }
99
100    /// Converts the key event mappings into a vector of string representations, i.e.
101    /// (app event as string, key event as string).
102    ///
103    /// This method formats each key event and corresponding app event
104    /// as strings and returns them as a vector of tuples. If multiple key events
105    /// map to the same app event, they are merged into a single entry where
106    /// the keys are concatenated together.
107    fn format_event_mappings_as_strings(ctx: &Self::Context) -> Vec<(String, String)>
108    where
109        Self::Event: Display,
110    {
111        let mappings = Self::key_event_mappings(ctx);
112        let mut formatted_events: Vec<(String, String)> = Vec::new();
113        let mut event_indices: HashMap<String, usize> = HashMap::new();
114
115        for (key_event, event) in mappings {
116            let key_event_str = key_event.to_string();
117            let event_str = event.to_string();
118
119            if let Some(&index) = event_indices.get(&event_str) {
120                let mut s = String::new();
121                let _ = write!(s, ", {key_event_str}");
122                formatted_events[index].0.push_str(&s);
123            } else {
124                formatted_events.push((key_event_str, event_str.clone()));
125                event_indices.insert(event_str, formatted_events.len() - 1);
126            }
127        }
128
129        formatted_events
130    }
131}