1use std::{
7 fmt::{self, Debug, Formatter},
8 sync::mpsc,
9 thread,
10};
11
12use ratatui::crossterm::event::KeyEvent;
13use serde::{
14 de::{self, Deserializer, Visitor},
15 Deserialize,
16};
17
18pub enum AppEvent {
20 Key(KeyEvent),
21 Resize(usize, usize),
22 Quit,
23}
24
25#[derive(Clone)]
27pub struct Sender {
28 tx: mpsc::Sender<AppEvent>,
29}
30
31impl Sender {
32 pub fn send(&self, event: AppEvent) {
33 let _ = self.tx.send(event);
34 }
35}
36
37impl Debug for Sender {
38 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
39 write!(f, "Sender")
40 }
41}
42
43pub struct Receiver {
45 rx: mpsc::Receiver<AppEvent>,
46}
47
48impl Receiver {
49 pub fn recv(&self) -> AppEvent {
50 self.rx.recv().unwrap_or(AppEvent::Quit)
51 }
52}
53
54pub fn init() -> (Sender, Receiver) {
56 let (tx, rx) = mpsc::channel();
57 let tx = Sender { tx };
58 let rx = Receiver { rx };
59
60 let event_tx = tx.clone();
61 thread::spawn(move || loop {
62 match ratatui::crossterm::event::read() {
63 Ok(e) => match e {
64 ratatui::crossterm::event::Event::Key(key) => {
65 event_tx.send(AppEvent::Key(key));
66 }
67 ratatui::crossterm::event::Event::Resize(w, h) => {
68 event_tx.send(AppEvent::Resize(w as usize, h as usize));
69 }
70 _ => {}
71 },
72 Err(_) => {
73 break;
74 }
75 }
76 });
77
78 (tx, rx)
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
83pub enum UserEvent {
84 ForceQuit,
85 Quit,
86 HelpToggle,
87 Cancel,
88 Close,
89 NavigateUp,
90 NavigateDown,
91 GoToTop,
92 GoToBottom,
93 ScrollUp,
94 ScrollDown,
95 PageUp,
96 PageDown,
97 HalfPageUp,
98 HalfPageDown,
99 Confirm,
100}
101
102impl<'de> Deserialize<'de> for UserEvent {
103 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
104 where
105 D: Deserializer<'de>,
106 {
107 struct UserEventVisitor;
108
109 impl<'de> Visitor<'de> for UserEventVisitor {
110 type Value = UserEvent;
111
112 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
113 formatter.write_str("a string representing a user event")
114 }
115
116 fn visit_str<E>(self, value: &str) -> Result<UserEvent, E>
117 where
118 E: de::Error,
119 {
120 match value {
121 "force_quit" => Ok(UserEvent::ForceQuit),
122 "quit" => Ok(UserEvent::Quit),
123 "help_toggle" => Ok(UserEvent::HelpToggle),
124 "cancel" => Ok(UserEvent::Cancel),
125 "close" => Ok(UserEvent::Close),
126 "navigate_up" => Ok(UserEvent::NavigateUp),
127 "navigate_down" => Ok(UserEvent::NavigateDown),
128 "go_to_top" => Ok(UserEvent::GoToTop),
129 "go_to_bottom" => Ok(UserEvent::GoToBottom),
130 "scroll_up" => Ok(UserEvent::ScrollUp),
131 "scroll_down" => Ok(UserEvent::ScrollDown),
132 "page_up" => Ok(UserEvent::PageUp),
133 "page_down" => Ok(UserEvent::PageDown),
134 "half_page_up" => Ok(UserEvent::HalfPageUp),
135 "half_page_down" => Ok(UserEvent::HalfPageDown),
136 "confirm" => Ok(UserEvent::Confirm),
137 _ => {
138 let msg = format!("Unknown user event: {}", value);
139 Err(de::Error::custom(msg))
140 }
141 }
142 }
143 }
144
145 deserializer.deserialize_str(UserEventVisitor)
146 }
147}