Improve event handling and the main loop

This commit is contained in:
Savanni D'Gerinel 2024-05-05 23:27:19 -04:00
parent fd444a620d
commit 612713ab1b
1 changed files with 63 additions and 30 deletions

View File

@ -1,11 +1,23 @@
use crossterm::{event::{self, KeyCode, KeyEvent}, terminal::{disable_raw_mode, enable_raw_mode}}; use crossterm::{
use std::{io::{self, Read}, sync::mpsc, thread, time::{Duration, Instant}}; event::{self, KeyCode, KeyEvent, KeyModifiers},
terminal::{disable_raw_mode, enable_raw_mode},
};
use std::{
io::{self, Read},
sync::mpsc,
thread,
time::{Duration, Instant},
};
use tui::{ use tui::{
backend::CrosstermBackend, layout::{Alignment, Constraint, Direction, Layout}, style::{Color, Style}, widgets::{Block, BorderType, Borders, Paragraph}, Terminal backend::CrosstermBackend,
layout::{Alignment, Constraint, Direction, Layout},
style::{Color, Style},
widgets::{Block, BorderType, Borders, Paragraph},
Terminal,
}; };
const TITLE: &str = "Editor Challenge"; const TITLE: &str = "Text Editor Challenge";
const COPYRIGHT: &str = "Editor Challenge, (c) Savanni D'Gerinel - all rights reserved"; const COPYRIGHT: &str = "(c) Savanni D'Gerinel - all rights reserved";
const TICK_RATE_MS: u64 = 200; const TICK_RATE_MS: u64 = 200;
fn render<T>(terminal: &mut Terminal<T>) -> Result<(), anyhow::Error> fn render<T>(terminal: &mut Terminal<T>) -> Result<(), anyhow::Error>
@ -54,29 +66,55 @@ where
Ok(()) Ok(())
} }
#[derive(Debug)]
enum Event<I> { enum Event<I> {
Input(I), Input(I),
Tick, Tick,
} }
fn handle_input(tx: mpsc::Sender<Event<KeyEvent>>, tick_rate: Duration) { fn handle_input(tx: mpsc::Sender<Event<KeyEvent>>, tick_rate: Duration) {
let mut last_tick = Instant::now(); let mut last_tick = Instant::now();
loop { loop {
let timeout = tick_rate.checked_sub(last_tick.elapsed()) let timeout = tick_rate
.unwrap_or_else(|| Duration::from_secs(0)); .checked_sub(last_tick.elapsed())
.unwrap_or_else(|| Duration::from_secs(0));
if event::poll(timeout).expect("poll works") { if event::poll(timeout).expect("poll works") {
if let event::Event::Key(key) = event::read().expect("can read events") { if let event::Event::Key(key) = event::read().expect("can read events") {
tx.send(Event::Input(key)).expect("can send events"); tx.send(Event::Input(key)).expect("can send events");
}
}
if last_tick.elapsed() >= tick_rate {
if let Ok(_) = tx.send(Event::Tick) {
last_tick = Instant::now();
}
} }
} }
if last_tick.elapsed() >= tick_rate {
if let Ok(_) = tx.send(Event::Tick) {
last_tick = Instant::now();
}
}
}
}
fn app_loop<T>(
terminal: &mut Terminal<T>,
rx: mpsc::Receiver<Event<KeyEvent>>,
) -> Result<(), anyhow::Error>
where
T: tui::backend::Backend,
{
loop {
render(terminal)?;
let event = rx.recv()?;
match event {
Event::Input(KeyEvent { code, modifiers })
if code == KeyCode::Char('x') && modifiers == KeyModifiers::CONTROL =>
{
break;
}
_ => {}
}
}
Ok(())
} }
fn main() -> Result<(), anyhow::Error> { fn main() -> Result<(), anyhow::Error> {
@ -94,17 +132,12 @@ fn main() -> Result<(), anyhow::Error> {
let mut terminal = Terminal::new(backend)?; let mut terminal = Terminal::new(backend)?;
let _ = terminal.clear()?; let _ = terminal.clear()?;
loop { let result = app_loop(&mut terminal, rx);
render(&mut terminal)?;
let event = rx.recv()?; disable_raw_mode()?;
terminal.show_cursor()?;
match event { result?;
Event::Input(KeyEvent{ code, .. }) if code == KeyCode::Char('q') => {
disable_raw_mode()?; Ok(())
return Ok(());
}
_ => {},
}
}
} }