refactor(example): migrate to crossterm

This commit is contained in:
EdJoPaTo
2022-04-28 01:25:47 +02:00
parent 2a4b431e67
commit 677c43c074
4 changed files with 39 additions and 114 deletions
+1 -3
View File
@@ -20,9 +20,7 @@ version = "0.18"
default-features = false default-features = false
[dev-dependencies] [dev-dependencies]
termion = "1" crossterm = "0.23"
[dev-dependencies.tui] [dev-dependencies.tui]
version = "0.18" version = "0.18"
default-features = false
features = ["termion"]
+38 -36
View File
@@ -1,13 +1,14 @@
mod util; mod util;
use crate::util::{ use crate::util::StatefulTree;
event::{Event, Events}, use crossterm::{
StatefulTree, event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
}; };
use std::{error::Error, io}; use std::{error::Error, io};
use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::AlternateScreen};
use tui::{ use tui::{
backend::TermionBackend, backend::{Backend, CrosstermBackend},
style::{Color, Modifier, Style}, style::{Color, Modifier, Style},
widgets::{Block, Borders}, widgets::{Block, Borders},
Terminal, Terminal,
@@ -40,17 +41,33 @@ impl<'a> App<'a> {
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
// Terminal initialization // Terminal initialization
let stdout = io::stdout().into_raw_mode()?; enable_raw_mode()?;
let stdout = MouseTerminal::from(stdout); let mut stdout = io::stdout();
let stdout = AlternateScreen::from(stdout); execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
let backend = TermionBackend::new(stdout); let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?; let mut terminal = Terminal::new(backend)?;
let events = Events::new();
// App // App
let mut app = App::new(); let app = App::new();
let res = run_app(&mut terminal, app);
// restore terminal
disable_raw_mode()?;
execute!(
terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
terminal.show_cursor()?;
if let Err(err) = res {
println!("{:?}", err);
}
Ok(())
}
fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> {
loop { loop {
terminal.draw(|f| { terminal.draw(|f| {
let area = f.size(); let area = f.size();
@@ -71,31 +88,16 @@ fn main() -> Result<(), Box<dyn Error>> {
f.render_stateful_widget(items, area, &mut app.tree.state); f.render_stateful_widget(items, area, &mut app.tree.state);
})?; })?;
match events.next()? { if let Event::Key(key) = event::read()? {
Event::Input(input) => match input { match key.code {
Key::Char('q') => { KeyCode::Char('q') => return Ok(()),
break; KeyCode::Left => app.tree.close(),
} KeyCode::Right => app.tree.open(),
Key::Left => { KeyCode::Char('\n') => app.tree.toggle(),
app.tree.close(); KeyCode::Down => app.tree.next(),
} KeyCode::Up => app.tree.previous(),
Key::Right => {
app.tree.open();
}
Key::Char('\n') => {
app.tree.toggle();
}
Key::Down => {
app.tree.next();
}
Key::Up => {
app.tree.previous();
}
_ => {} _ => {}
}, }
Event::Tick => {}
} }
} }
Ok(())
} }
-73
View File
@@ -1,73 +0,0 @@
use std::io;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
use termion::event::Key;
use termion::input::TermRead;
pub enum Event<I> {
Input(I),
Tick,
}
/// A small event handler that wrap termion input and tick events. Each event
/// type is handled in its own thread and returned to a common `Receiver`
#[allow(dead_code)]
pub struct Events {
rx: mpsc::Receiver<Event<Key>>,
}
#[derive(Debug, Clone, Copy)]
pub struct Config {
pub exit_key: Key,
pub tick_rate: Duration,
}
impl Default for Config {
fn default() -> Self {
Self {
exit_key: Key::Char('q'),
tick_rate: Duration::from_millis(250),
}
}
}
impl Events {
pub fn new() -> Self {
Self::with_config(Config::default())
}
pub fn with_config(config: Config) -> Self {
let (tx, rx) = mpsc::channel();
{
let tx = tx.clone();
thread::spawn(move || {
let stdin = io::stdin();
#[allow(clippy::manual_flatten)]
for evt in stdin.keys() {
if let Ok(key) = evt {
if let Err(err) = tx.send(Event::Input(key)) {
eprintln!("{}", err);
return;
}
if key == config.exit_key {
return;
}
}
}
})
};
thread::spawn(move || loop {
if tx.send(Event::Tick).is_err() {
break;
}
thread::sleep(config.tick_rate);
});
Self { rx }
}
pub fn next(&self) -> Result<Event<Key>, mpsc::RecvError> {
self.rx.recv()
}
}
-2
View File
@@ -1,5 +1,3 @@
pub mod event;
use tui_tree_widget::{flatten, get_identifier_without_leaf, TreeItem, TreeState}; use tui_tree_widget::{flatten, get_identifier_without_leaf, TreeItem, TreeState};
pub struct StatefulTree<'a> { pub struct StatefulTree<'a> {