1use crate::app::AppResult;
2use crate::git::repo::{Log, RepoStatus};
3use crossterm::event::{self, Event as CrosstermEvent, KeyEvent, MouseEvent};
4use std::sync::mpsc;
5use std::thread;
6use std::time::{Duration, Instant};
7
8#[derive(Clone, Debug)]
10pub enum Event {
11 Tick(mpsc::Sender<Event>),
13 Key(KeyEvent),
15 Mouse(MouseEvent),
17 Resize(u16, u16),
19 RepoStatusChange(String, RepoStatus),
21 RepoStatusComplete(String, Vec<Log>),
23}
24
25#[derive(Debug)]
27pub struct EventHandler {
28 pub sender: mpsc::Sender<Event>,
30 receiver: mpsc::Receiver<Event>,
32 pub handler: thread::JoinHandle<()>,
34}
35
36impl EventHandler {
37 pub fn new(tick_rate: u64) -> Self {
39 let tick_rate = Duration::from_millis(tick_rate);
40 let (sender, receiver) = mpsc::channel();
41 let handler = {
42 let sender = sender.clone();
43 thread::spawn(move || {
44 let mut last_tick = Instant::now();
45 loop {
46 let timeout = tick_rate
47 .checked_sub(last_tick.elapsed())
48 .unwrap_or(tick_rate);
49
50 if event::poll(timeout).expect("no events available") {
51 match event::read().expect("unable to read event") {
52 CrosstermEvent::Key(e) => sender.send(Event::Key(e)),
53 CrosstermEvent::Mouse(e) => sender.send(Event::Mouse(e)),
54 CrosstermEvent::Resize(w, h) => sender.send(Event::Resize(w, h)),
55 _ => Ok(()),
56 }
57 .expect("failed to send terminal event")
58 }
59
60 if last_tick.elapsed() >= tick_rate {
61 sender
62 .send(Event::Tick(sender.clone()))
63 .expect("failed to send tick event");
64 last_tick = Instant::now();
65 }
66 }
67 })
68 };
69 Self {
70 sender,
71 receiver,
72 handler,
73 }
74 }
75
76 pub fn next(&self) -> AppResult<Event> {
81 Ok(self.receiver.recv()?)
82 }
83}