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}