mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-07-25 22:55:06 +02:00
deps: Update crossterm + tui-rs, along with event handling code
This commit is contained in:
parent
f73ea0da36
commit
5749c32bd5
50
Cargo.lock
generated
50
Cargo.lock
generated
@ -144,7 +144,7 @@ dependencies = [
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"once_cell",
|
||||
"signal-hook",
|
||||
"signal-hook 0.1.17",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
@ -454,25 +454,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.18.2"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e86d73f2a0b407b5768d10a8c720cf5d2df49a9efc10ca09176d201ead4b7fb"
|
||||
checksum = "c0ebde6a9dd5e331cd6c6f48253254d117642c31653baa475e394657c59c1f7d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm_winapi",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"signal-hook",
|
||||
"signal-hook 0.3.9",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.6.2"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2265c3f8e080075d9b6417aa72293fc71662f34b4af2612d8d1b074d29510db"
|
||||
checksum = "3a6966607622438301997d3dac0d2f6e9a90c68bb6bc1785ea98456ab93c0507"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
@ -1333,20 +1333,40 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.1.16"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "604508c1418b99dfe1925ca9224829bb2a8a9a04dda655cc01fcad46f4ab05ed"
|
||||
checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.2.2"
|
||||
name = "signal-hook"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce32ea0c6c56d5eacaeb814fbed9960547021d3edd010ded1425f180536b20ab"
|
||||
checksum = "470c5a6397076fae0094aaf06a08e6ba6f37acb77d3b1b91ea92b4d6c8650c39"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@ -1483,9 +1503,9 @@ checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
|
||||
|
||||
[[package]]
|
||||
name = "tui"
|
||||
version = "0.14.0"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ced152a8e9295a5b168adc254074525c17ac4a83c90b2716274cc38118bddc9"
|
||||
checksum = "39c8ce4e27049eed97cfa363a5048b09d995e209994634a0efc26a14ab6c0c23"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cassowary",
|
||||
|
@ -38,7 +38,7 @@ anyhow = "1.0.40"
|
||||
backtrace = "0.3.59"
|
||||
battery = "0.7.8"
|
||||
chrono = "0.4.19"
|
||||
crossterm = "0.18.2"
|
||||
crossterm = "0.20.0"
|
||||
ctrlc = { version = "3.1.9", features = ["termination"] }
|
||||
clap = "2.33"
|
||||
cfg-if = "1.0"
|
||||
@ -55,7 +55,7 @@ serde = { version = "1.0.125", features = ["derive"] }
|
||||
sysinfo = "0.18.2"
|
||||
thiserror = "1.0.24"
|
||||
toml = "0.5.8"
|
||||
tui = { version = "0.14.0", features = ["crossterm"], default-features = false }
|
||||
tui = { version = "0.16.0", features = ["crossterm"], default-features = false }
|
||||
typed-builder = "0.9.0"
|
||||
unicode-segmentation = "1.7.1"
|
||||
unicode-width = "0.1"
|
||||
|
@ -8,7 +8,7 @@ use bottom::{canvas, constants::*, data_conversion::*, options::*, *};
|
||||
|
||||
use std::{
|
||||
boxed::Box,
|
||||
io::{stdout, Write},
|
||||
io::stdout,
|
||||
panic,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
@ -96,7 +96,7 @@ fn main() -> Result<()> {
|
||||
};
|
||||
|
||||
// Event loop
|
||||
let (collection_thread_ctrl_sender, collection_thread_ctrl_receiver) = mpsc::channel();
|
||||
let (collection_sender, collection_thread_ctrl_receiver) = mpsc::channel();
|
||||
let _collection_thread = create_collection_thread(
|
||||
sender,
|
||||
collection_thread_ctrl_receiver,
|
||||
@ -131,15 +131,29 @@ fn main() -> Result<()> {
|
||||
if let Ok(recv) = receiver.recv_timeout(Duration::from_millis(TICK_RATE_IN_MILLISECONDS)) {
|
||||
match recv {
|
||||
BottomEvent::KeyInput(event) => {
|
||||
if handle_key_event_or_break(event, &mut app, &collection_thread_ctrl_sender) {
|
||||
match handle_key_event(event, &mut app, &collection_sender) {
|
||||
EventResult::Quit => {
|
||||
break;
|
||||
}
|
||||
EventResult::Redraw => {
|
||||
// TODO: Be even more granular! Maybe the event triggered no change, then we shouldn't redraw.
|
||||
force_redraw(&mut app);
|
||||
try_drawing(&mut terminal, &mut app, &mut painter)?;
|
||||
}
|
||||
EventResult::Continue => {}
|
||||
}
|
||||
}
|
||||
BottomEvent::MouseInput(event) => match handle_mouse_event(event, &mut app) {
|
||||
EventResult::Quit => {
|
||||
break;
|
||||
}
|
||||
handle_force_redraws(&mut app);
|
||||
}
|
||||
BottomEvent::MouseInput(event) => {
|
||||
handle_mouse_event(event, &mut app);
|
||||
handle_force_redraws(&mut app);
|
||||
}
|
||||
EventResult::Redraw => {
|
||||
// TODO: Be even more granular! Maybe the event triggered no change, then we shouldn't redraw.
|
||||
force_redraw(&mut app);
|
||||
try_drawing(&mut terminal, &mut app, &mut painter)?;
|
||||
}
|
||||
EventResult::Continue => {}
|
||||
},
|
||||
BottomEvent::Update(data) => {
|
||||
app.data_collection.eat_data(data);
|
||||
|
||||
@ -220,6 +234,8 @@ fn main() -> Result<()> {
|
||||
app.canvas_data.battery_data =
|
||||
convert_battery_harvest(&app.data_collection);
|
||||
}
|
||||
|
||||
try_drawing(&mut terminal, &mut app, &mut painter)?;
|
||||
}
|
||||
}
|
||||
BottomEvent::Clean => {
|
||||
@ -228,17 +244,11 @@ fn main() -> Result<()> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: [OPT] Should not draw if no change (ie: scroll max)
|
||||
try_drawing(&mut terminal, &mut app, &mut painter)?;
|
||||
}
|
||||
|
||||
// I think doing it in this order is safe...
|
||||
|
||||
*thread_termination_lock.lock().unwrap() = true;
|
||||
|
||||
thread_termination_cvar.notify_all();
|
||||
|
||||
cleanup_terminal(&mut terminal)?;
|
||||
|
||||
Ok(())
|
||||
|
101
src/lib.rs
101
src/lib.rs
@ -20,7 +20,10 @@ use std::{
|
||||
};
|
||||
|
||||
use crossterm::{
|
||||
event::{poll, read, DisableMouseCapture, Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent},
|
||||
event::{
|
||||
read, DisableMouseCapture, Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent,
|
||||
MouseEventKind,
|
||||
},
|
||||
execute,
|
||||
style::Print,
|
||||
terminal::{disable_raw_mode, LeaveAlternateScreen},
|
||||
@ -71,29 +74,36 @@ pub enum ThreadControlEvent {
|
||||
UpdateUpdateTime(u64),
|
||||
}
|
||||
|
||||
pub fn handle_mouse_event(event: MouseEvent, app: &mut AppState) {
|
||||
match event {
|
||||
MouseEvent::ScrollUp(_x, _y, _modifiers) => app.handle_scroll_up(),
|
||||
MouseEvent::ScrollDown(_x, _y, _modifiers) => app.handle_scroll_down(),
|
||||
MouseEvent::Down(button, x, y, _modifiers) => {
|
||||
if !app.app_config_fields.disable_click {
|
||||
match button {
|
||||
crossterm::event::MouseButton::Left => {
|
||||
// Trigger left click widget activity
|
||||
app.on_left_mouse_up(x, y);
|
||||
}
|
||||
crossterm::event::MouseButton::Right => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
pub enum EventResult {
|
||||
Quit,
|
||||
Redraw,
|
||||
Continue,
|
||||
}
|
||||
|
||||
pub fn handle_key_event_or_break(
|
||||
pub fn handle_mouse_event(event: MouseEvent, app: &mut AppState) -> EventResult {
|
||||
match event.kind {
|
||||
MouseEventKind::Down(button) => match button {
|
||||
MouseButton::Left => {
|
||||
app.on_left_mouse_up(event.column, event.row);
|
||||
EventResult::Redraw
|
||||
}
|
||||
_ => EventResult::Continue,
|
||||
},
|
||||
MouseEventKind::ScrollUp => {
|
||||
app.handle_scroll_up();
|
||||
EventResult::Redraw
|
||||
}
|
||||
MouseEventKind::ScrollDown => {
|
||||
app.handle_scroll_down();
|
||||
EventResult::Redraw
|
||||
}
|
||||
_ => EventResult::Continue,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_key_event(
|
||||
event: KeyEvent, app: &mut AppState, reset_sender: &std::sync::mpsc::Sender<ThreadControlEvent>,
|
||||
) -> bool {
|
||||
) -> EventResult {
|
||||
// debug!("KeyEvent: {:?}", event);
|
||||
|
||||
// TODO: [PASTE] Note that this does NOT support some emojis like flags. This is due to us
|
||||
@ -104,7 +114,7 @@ pub fn handle_key_event_or_break(
|
||||
if event.modifiers.is_empty() {
|
||||
// Required catch for searching - otherwise you couldn't search with q.
|
||||
if event.code == KeyCode::Char('q') && !app.is_in_search_widget() {
|
||||
return true;
|
||||
return EventResult::Quit;
|
||||
}
|
||||
match event.code {
|
||||
KeyCode::End => app.skip_to_last(),
|
||||
@ -125,7 +135,9 @@ pub fn handle_key_event_or_break(
|
||||
KeyCode::F(5) => app.toggle_tree_mode(),
|
||||
KeyCode::F(6) => app.toggle_sort(),
|
||||
KeyCode::F(9) => app.start_killing_process(),
|
||||
_ => {}
|
||||
_ => {
|
||||
return EventResult::Continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Otherwise, track the modifier as well...
|
||||
@ -140,7 +152,7 @@ pub fn handle_key_event_or_break(
|
||||
}
|
||||
} else if let KeyModifiers::CONTROL = event.modifiers {
|
||||
if event.code == KeyCode::Char('c') {
|
||||
return true;
|
||||
return EventResult::Quit;
|
||||
}
|
||||
|
||||
match event.code {
|
||||
@ -166,7 +178,9 @@ pub fn handle_key_event_or_break(
|
||||
// Can't do now, CTRL+BACKSPACE doesn't work and graphemes
|
||||
// are hard to iter while truncating last (eloquently).
|
||||
// KeyCode::Backspace => app.skip_word_backspace(),
|
||||
_ => {}
|
||||
_ => {
|
||||
return EventResult::Continue;
|
||||
}
|
||||
}
|
||||
} else if let KeyModifiers::SHIFT = event.modifiers {
|
||||
match event.code {
|
||||
@ -175,12 +189,14 @@ pub fn handle_key_event_or_break(
|
||||
KeyCode::Up => app.move_widget_selection(&WidgetDirection::Up),
|
||||
KeyCode::Down => app.move_widget_selection(&WidgetDirection::Down),
|
||||
KeyCode::Char(caught_char) => app.on_char_key(caught_char),
|
||||
_ => {}
|
||||
_ => {
|
||||
return EventResult::Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
EventResult::Redraw
|
||||
}
|
||||
|
||||
pub fn read_config(config_location: Option<&str>) -> error::Result<Option<PathBuf>> {
|
||||
@ -300,7 +316,7 @@ pub fn panic_hook(panic_info: &PanicInfo<'_>) {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn handle_force_redraws(app: &mut AppState) {
|
||||
pub fn force_redraw(app: &mut AppState) {
|
||||
// Currently we use an Option... because we might want to future-proof this
|
||||
// if we eventually get widget-specific redrawing!
|
||||
if app.proc_state.force_update_all {
|
||||
@ -607,25 +623,30 @@ pub fn create_input_thread(
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Ok(poll) = poll(Duration::from_millis(20)) {
|
||||
if poll {
|
||||
if let Ok(event) = read() {
|
||||
if let Event::Key(key) = event {
|
||||
if Instant::now().duration_since(keyboard_timer).as_millis() >= 20 {
|
||||
if sender.send(BottomEvent::KeyInput(key)).is_err() {
|
||||
break;
|
||||
}
|
||||
keyboard_timer = Instant::now();
|
||||
|
||||
if let Ok(event) = read() {
|
||||
match event {
|
||||
Event::Key(event) => {
|
||||
if Instant::now().duration_since(keyboard_timer).as_millis() >= 20 {
|
||||
if sender.send(BottomEvent::KeyInput(event)).is_err() {
|
||||
break;
|
||||
}
|
||||
} else if let Event::Mouse(mouse) = event {
|
||||
keyboard_timer = Instant::now();
|
||||
}
|
||||
}
|
||||
Event::Mouse(event) => match &event.kind {
|
||||
MouseEventKind::Drag(_) => {}
|
||||
MouseEventKind::Moved => {}
|
||||
_ => {
|
||||
if Instant::now().duration_since(mouse_timer).as_millis() >= 20 {
|
||||
if sender.send(BottomEvent::MouseInput(mouse)).is_err() {
|
||||
if sender.send(BottomEvent::MouseInput(event)).is_err() {
|
||||
break;
|
||||
}
|
||||
mouse_timer = Instant::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Event::Resize(_, _) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,6 @@ pub enum BottomError {
|
||||
/// An error when the heim library encounters a problem.
|
||||
#[error("Error caused by Heim, {0}")]
|
||||
InvalidHeim(String),
|
||||
/// An error when the Crossterm library encounters a problem.
|
||||
#[error("Error caused by Crossterm, {0}")]
|
||||
CrosstermError(String),
|
||||
/// An error to represent generic errors.
|
||||
#[error("Generic error, {0}")]
|
||||
GenericError(String),
|
||||
@ -55,11 +52,6 @@ impl From<heim::Error> for BottomError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crossterm::ErrorKind> for BottomError {
|
||||
fn from(err: crossterm::ErrorKind) -> Self {
|
||||
BottomError::CrosstermError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::num::ParseIntError> for BottomError {
|
||||
fn from(err: std::num::ParseIntError) -> Self {
|
||||
|
Loading…
x
Reference in New Issue
Block a user