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
+38 -36
View File
@@ -1,13 +1,14 @@
mod util;
use crate::util::{
event::{Event, Events},
StatefulTree,
use crate::util::StatefulTree;
use crossterm::{
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use std::{error::Error, io};
use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::AlternateScreen};
use tui::{
backend::TermionBackend,
backend::{Backend, CrosstermBackend},
style::{Color, Modifier, Style},
widgets::{Block, Borders},
Terminal,
@@ -40,17 +41,33 @@ impl<'a> App<'a> {
fn main() -> Result<(), Box<dyn Error>> {
// Terminal initialization
let stdout = io::stdout().into_raw_mode()?;
let stdout = MouseTerminal::from(stdout);
let stdout = AlternateScreen::from(stdout);
let backend = TermionBackend::new(stdout);
enable_raw_mode()?;
let mut stdout = io::stdout();
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
let backend = CrosstermBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
let events = Events::new();
// 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 {
terminal.draw(|f| {
let area = f.size();
@@ -71,31 +88,16 @@ fn main() -> Result<(), Box<dyn Error>> {
f.render_stateful_widget(items, area, &mut app.tree.state);
})?;
match events.next()? {
Event::Input(input) => match input {
Key::Char('q') => {
break;
}
Key::Left => {
app.tree.close();
}
Key::Right => {
app.tree.open();
}
Key::Char('\n') => {
app.tree.toggle();
}
Key::Down => {
app.tree.next();
}
Key::Up => {
app.tree.previous();
}
if let Event::Key(key) = event::read()? {
match key.code {
KeyCode::Char('q') => return Ok(()),
KeyCode::Left => app.tree.close(),
KeyCode::Right => app.tree.open(),
KeyCode::Char('\n') => app.tree.toggle(),
KeyCode::Down => app.tree.next(),
KeyCode::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};
pub struct StatefulTree<'a> {