refactor(example): migrate to crossterm
This commit is contained in:
+1
-3
@@ -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
@@ -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(())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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};
|
use tui_tree_widget::{flatten, get_identifier_without_leaf, TreeItem, TreeState};
|
||||||
|
|
||||||
pub struct StatefulTree<'a> {
|
pub struct StatefulTree<'a> {
|
||||||
|
|||||||
Reference in New Issue
Block a user