refactor(example): migrate to crossterm
This commit is contained in:
+1
-3
@@ -20,9 +20,7 @@ version = "0.18"
|
||||
default-features = false
|
||||
|
||||
[dev-dependencies]
|
||||
termion = "1"
|
||||
crossterm = "0.23"
|
||||
|
||||
[dev-dependencies.tui]
|
||||
version = "0.18"
|
||||
default-features = false
|
||||
features = ["termion"]
|
||||
|
||||
+38
-36
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
pub mod event;
|
||||
|
||||
use tui_tree_widget::{flatten, get_identifier_without_leaf, TreeItem, TreeState};
|
||||
|
||||
pub struct StatefulTree<'a> {
|
||||
|
||||
Reference in New Issue
Block a user