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