diff --git a/Cargo.lock b/Cargo.lock index 3380552..2c47462 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,7 +24,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi", + "winapi 0.3.8", ] [[package]] @@ -70,7 +70,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -112,7 +112,7 @@ dependencies = [ "nix 0.15.0", "num-traits", "uom 0.26.0", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -198,6 +198,15 @@ dependencies = [ "vec_map", ] +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -307,6 +316,31 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crossterm" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9851d20b9809e561297ec3ca85d7cba3a57507fe8d01d07ba7b52469e1c89a11" +dependencies = [ + "bitflags", + "crossterm_winapi", + "lazy_static", + "libc", + "mio", + "parking_lot", + "signal-hook", + "winapi 0.3.8", +] + +[[package]] +name = "crossterm_winapi" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057b7146d02fb50175fd7dbe5158f6097f33d02831f43b4ee8ae4ddf67b68f5c" +dependencies = [ + "winapi 0.3.8", +] + [[package]] name = "darwin-libproc" version = "0.1.2" @@ -346,7 +380,7 @@ dependencies = [ "cfg-if", "libc", "redox_users", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -380,6 +414,22 @@ dependencies = [ "version_check", ] +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + [[package]] name = "futures" version = "0.3.5" @@ -538,7 +588,7 @@ dependencies = [ "nix 0.17.0", "pin-utils", "uom 0.28.0", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -557,7 +607,7 @@ dependencies = [ "mach 0.3.2", "ntapi", "smol", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -574,7 +624,7 @@ dependencies = [ "libc", "mach 0.3.2", "widestring", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -592,7 +642,7 @@ dependencies = [ "mach 0.3.2", "ntapi", "platforms", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -607,7 +657,7 @@ dependencies = [ "lazy_static", "libc", "mach 0.3.2", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -647,7 +697,7 @@ dependencies = [ "ntapi", "ordered-float", "smol", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -706,6 +756,15 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + [[package]] name = "itertools" version = "0.9.0" @@ -715,6 +774,16 @@ dependencies = [ "either", ] +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -733,6 +802,15 @@ version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +[[package]] +name = "lock_api" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.8" @@ -793,6 +871,48 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mio" +version = "0.6.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" +dependencies = [ + "cfg-if", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "miow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "net2" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" +dependencies = [ + "cfg-if", + "libc", + "winapi 0.3.8", +] + [[package]] name = "nix" version = "0.15.0" @@ -825,7 +945,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a31937dea023539c72ddae0e3571deadc1414b300483fa7aaec176168cfa9d2" dependencies = [ - "winapi", + "winapi 0.3.8", ] [[package]] @@ -924,6 +1044,30 @@ dependencies = [ "num-traits", ] +[[package]] +name = "parking_lot" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "smallvec", + "winapi 0.3.8", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -1187,6 +1331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ff2db2112d6c761e12522c65f7768548bd6e8cd23d2a9dae162520626629bd6" dependencies = [ "libc", + "mio", "signal-hook-registry", ] @@ -1240,7 +1385,7 @@ dependencies = [ "cfg-if", "libc", "redox_syscall", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -1291,7 +1436,7 @@ dependencies = [ "ntapi", "once_cell", "rayon", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -1331,7 +1476,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ "libc", - "winapi", + "winapi 0.3.8", ] [[package]] @@ -1351,6 +1496,7 @@ checksum = "9533d39bef0ae8f510e8a99d78702e68d1bbf0b98a78ec9740509d287010ae1e" dependencies = [ "bitflags", "cassowary", + "crossterm", "either", "itertools", "termion", @@ -1521,6 +1667,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6" +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.8" @@ -1531,6 +1683,12 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -1553,6 +1711,16 @@ dependencies = [ "syn 0.11.11", ] +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "zenith" version = "0.9.2" @@ -1562,6 +1730,7 @@ dependencies = [ "byte-unit", "chrono", "clap", + "crossterm", "dirs", "env_logger", "futures", @@ -1575,7 +1744,6 @@ dependencies = [ "serde_derive", "signal-hook", "sysinfo", - "termion", "tui", "users", ] diff --git a/Cargo.toml b/Cargo.toml index 9569e47..0c91412 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,8 @@ default = [] nvidia = ["nvml-wrapper"] [dependencies] -tui = "0.9.*" -termion = "1.5" +tui = {version = "0.9.*", features = ["crossterm"]} +crossterm = "0.17.5" byte-unit = "3.0.3" users = "0.9.1" num-derive = "0.3.0" diff --git a/src/main.rs b/src/main.rs index fe416e4..3e707d9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,13 @@ mod zprocess; use crate::render::TerminalRenderer; use clap::{App, Arg}; +use crossterm::{ + cursor, execute, + terminal::{ + disable_raw_mode, enable_raw_mode, Clear, ClearType, EnterAlternateScreen, + LeaveAlternateScreen, + }, +}; use futures::executor::block_on; use std::error::Error; use std::fs; @@ -32,11 +39,6 @@ use std::panic; use std::panic::PanicInfo; use std::path::Path; use std::process::exit; -use termion::input::MouseTerminal; -use termion::raw::IntoRawMode; -use termion::screen::AlternateScreen; -use tui::backend::TermionBackend; -use tui::Terminal; fn panic_hook(info: &PanicInfo<'_>) { let location = info.location().unwrap(); // The current implementation always returns Some @@ -48,46 +50,28 @@ fn panic_hook(info: &PanicInfo<'_>) { }, }; error!("thread '' panicked at '{}', {}\r", msg, location); - println!( - "{}thread '' panicked at '{}', {}\r", - termion::screen::ToMainScreen, - msg, - location - ); + restore_terminal(); + println!("thread '' panicked at '{}', {}\r", msg, location); } fn init_terminal() { debug!("Initializing Terminal"); - let raw_term = stdout() - .into_raw_mode() - .expect("Could not bind to STDOUT in raw mode."); - debug!("Create Mouse Term"); - let mouse_term = MouseTerminal::from(raw_term); - debug!("Create Alternate Screen"); - let mut screen = AlternateScreen::from(mouse_term); - debug!("Clear Screen"); - // Need to clear screen for TTYs - write!(screen, "{}", termion::clear::All) - .expect("Attempt to write to alternate screen failed."); + let mut sout = stdout(); + execute!(sout, EnterAlternateScreen).expect("Unable to enter alternate screen"); + execute!(sout, cursor::Hide).expect("Unable to hide cursor"); + execute!(sout, Clear(ClearType::All)).expect("Unable to clear screen."); + enable_raw_mode().expect("Unable to enter raw mode."); } fn restore_terminal() { debug!("Restoring Terminal"); - let raw_term = stdout() - .into_raw_mode() - .expect("Could not bind to STDOUT in raw mode."); - let mut screen = AlternateScreen::from(raw_term); + let mut sout = stdout(); // Restore cursor position and clear screen for TTYs - write!( - screen, - "{}{}", - termion::cursor::Goto(1, 1), - termion::clear::All - ) - .expect("Attempt to write to alternate screen failed."); - let backend = TermionBackend::new(screen); - let mut terminal = Terminal::new(backend).expect("Could not create new terminal."); - terminal.show_cursor().expect("Restore cursor failed."); + execute!(sout, cursor::MoveTo(0, 0)).expect("Attempt to write to alternate screen failed."); + execute!(sout, Clear(ClearType::All)).expect("Unable to clear screen."); + execute!(sout, LeaveAlternateScreen).expect("Unable to leave alternate screen."); + execute!(sout, cursor::Show).expect("Unable to restore cursor."); + disable_raw_mode().expect("Unable to disable raw mode"); } fn start_zenith( diff --git a/src/render.rs b/src/render.rs index 3de0031..7cf034e 100644 --- a/src/render.rs +++ b/src/render.rs @@ -12,17 +12,19 @@ use byte_unit::{Byte, ByteUnit}; use chrono::prelude::DateTime; use chrono::Duration as CDuration; use chrono::{Datelike, Local, Timelike}; +use crossterm::{ + event::{KeyCode as Key, KeyEvent, KeyModifiers}, + execute, + terminal::EnterAlternateScreen, +}; use num_traits::FromPrimitive; use std::borrow::Cow; use std::io; use std::io::Stdout; +use std::io::Write; use std::path::PathBuf; use std::time::{Duration, Instant, UNIX_EPOCH}; -use termion::event::Key; -use termion::input::MouseTerminal; -use termion::raw::{IntoRawMode, RawTerminal}; -use termion::screen::AlternateScreen; -use tui::backend::TermionBackend; +use tui::{backend::CrosstermBackend, Terminal}; use std::ops::Mul; use tui::backend::Backend; @@ -30,11 +32,10 @@ use tui::layout::{Alignment, Constraint, Direction, Layout, Rect}; use tui::style::{Color, Modifier, Style}; use tui::widgets::{BarChart, Block, Borders, List, Paragraph, Row, Sparkline, Table, Text}; use tui::Frame; -use tui::Terminal; const PROCESS_SELECTION_GRACE: Duration = Duration::from_millis(2000); -type ZBackend = TermionBackend>>>; +type ZBackend = CrosstermBackend; /// Compatibility trait, that preserves an older method from tui 0.6.5 /// Exists mostly to keep the caller code idiomatic for the use cases in this file @@ -1306,7 +1307,7 @@ fn render_help(area: Rect, f: &mut Frame<'_, ZBackend>) { } pub struct TerminalRenderer { - terminal: Terminal>>>>, + terminal: Terminal>, app: CPUTimeApp, events: Events, process_table_row_start: usize, @@ -1343,12 +1344,9 @@ impl<'a> TerminalRenderer { db_path: Option, ) -> TerminalRenderer { debug!("Hide Cursor"); - let stdout = io::stdout() - .into_raw_mode() - .expect("Could not bind to STDOUT in raw mode."); - let stdout = MouseTerminal::from(stdout); - let stdout = AlternateScreen::from(stdout); - let backend = TermionBackend::new(stdout); + let mut stdout = io::stdout(); + execute!(stdout, EnterAlternateScreen).expect("Unable to enter alternate screen"); + let backend = CrosstermBackend::new(stdout); let mut terminal = Terminal::new(backend).expect("Couldn't create new terminal with backend"); terminal.hide_cursor().ok(); @@ -1574,7 +1572,7 @@ impl<'a> TerminalRenderer { }; debug!("Event Key: {:?}", input); - match input { + match input.code { Key::Up => self.view_up(process_table, 1), Key::PageUp => self.view_up(process_table, process_table_height.into()), Key::Down => self.view_down(process_table, process_table_height.into(), 1), @@ -1585,20 +1583,22 @@ impl<'a> TerminalRenderer { ), Key::Left => self.histogram_left(), Key::Right => self.histogram_right(), - Key::Char('\n') => { + Key::Enter => { self.app.select_process(highlighted_process); self.process_message = None; self.show_find = false; self.process_table_row_start = 0; } - Key::Ctrl('c') => { - return Action::Quit; + Key::Char('c') => { + if input.modifiers.contains(KeyModifiers::CONTROL) { + return Action::Quit; + } } - other => { + _other => { if self.show_find { - self.process_find_input(other); + self.process_find_input(input); } else { - return self.process_toplevel_input(other).await; + return self.process_toplevel_input(input).await; } } }; @@ -1669,8 +1669,8 @@ impl<'a> TerminalRenderer { } } - fn process_find_input(&mut self, input: Key) { - match input { + fn process_find_input(&mut self, input: KeyEvent) { + match input.code { Key::Esc => { self.show_find = false; self.filter = String::from(""); @@ -1691,8 +1691,8 @@ impl<'a> TerminalRenderer { } } - async fn process_toplevel_input(&mut self, input: Key) -> Action { - match input { + async fn process_toplevel_input(&mut self, input: KeyEvent) -> Action { + match input.code { Key::Char('q') => { return Action::Quit; } @@ -1777,7 +1777,7 @@ impl<'a> TerminalRenderer { None => None, }; } - Key::Char('\t') => { + Key::Tab => { let mut i = self.selected_section as u32 + 1; if i > 4 { i = 0; diff --git a/src/util.rs b/src/util.rs index 03f4e02..6ae3480 100644 --- a/src/util.rs +++ b/src/util.rs @@ -3,15 +3,14 @@ * Copyright 2019-2020, Benjamin Vaisvil and the zenith contributors */ use crate::constants::DEFAULT_TICK; +use crossterm::{event, event::Event as CEvent, event::KeyCode as Key, event::KeyEvent}; use signal_hook::{iterator::Signals, SIGABRT, SIGINT, SIGTERM}; use std::fs::{remove_file, File}; -use std::io::{self, Write}; +use std::io::Write; use std::path::{Path, PathBuf}; use std::sync::mpsc; use std::thread; use std::time::Duration; -use termion::event::Key; -use termion::input::TermRead; pub enum Event { Input(I), @@ -22,7 +21,7 @@ pub enum Event { #[allow(dead_code)] pub struct Events { - rx: mpsc::Receiver>, + rx: mpsc::Receiver>, input_handle: thread::JoinHandle<()>, tick_handle: thread::JoinHandle<()>, sig_handle: thread::JoinHandle<()>, @@ -55,14 +54,9 @@ impl Events { let (tx, rx) = mpsc::channel(); let input_handle = { let tx = tx.clone(); - thread::spawn(move || { - let stdin = io::stdin(); - for evt in stdin.keys() { - if let Ok(key) = evt { - if tx.send(Event::Input(key)).is_err() { - return; - } - } + thread::spawn(move || loop { + if let CEvent::Key(key) = event::read().expect("Couldn't read event") { + tx.send(Event::Input(key)).expect("Couldn't send event."); } }) }; @@ -101,7 +95,7 @@ impl Events { } } - pub fn next(&self) -> Result, mpsc::RecvError> { + pub fn next(&self) -> Result, mpsc::RecvError> { self.rx.recv() } }