Improve event handling and the main loop
This commit is contained in:
parent
fd444a620d
commit
612713ab1b
|
@ -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(());
|
|
||||||
}
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue