Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

### Fixed

* Fix Ctrl+C handling to use SIGINT signal instead of keypress #491 - @chiranjeevi-max
* Update CONTRIBUTING information #438 - @YJDoc2 @cyqsimon
* Fix new clippy lint #457 - @cyqsimon
* Apply new clippy lints #468 - @cyqsimon
Expand Down
101 changes: 91 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ chrono = "0.4"
clap-verbosity-flag = "3.0.3"
clap = { version = "4.5.41", features = ["derive"] }
crossterm = "0.29.0"
ctrlc = "3.4"
derive_more = { version = "2.0.1", features = ["debug"] }
eyre = "0.6.12"
itertools = "0.14.0"
Expand Down
28 changes: 21 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ fn main() -> eyre::Result<()> {
let _ = crossterm::execute!(&mut stdout, terminal::EnterAlternateScreen);
let terminal_backend = CrosstermBackend::new(stdout);
start(terminal_backend, os_input, opts);

// Ensure terminal is restored after exit (handles SIGINT case).
// These operations are idempotent, so safe to call even if 'q' already cleaned up.
let _ = terminal::disable_raw_mode();
let _ = crossterm::execute!(std::io::stdout(), terminal::LeaveAlternateScreen);
}
Ok(())
}
Expand All @@ -96,6 +101,17 @@ where
let cumulative_time = Arc::new(RwLock::new(Duration::new(0, 0)));
let table_cycle_offset = Arc::new(AtomicUsize::new(0));

// handle SIGINT properly instead of as a keypress
// see https://github.com/imsnif/bandwhich/issues/487
#[cfg(not(test))]
{
let running = running.clone();
ctrlc::set_handler(move || {
running.store(false, Ordering::Release);
})
.expect("failed to set SIGINT handler");
}

Comment thread
chiranjeevi-max marked this conversation as resolved.
let mut active_threads = vec![];

let terminal_events = os_input.terminal_events;
Expand Down Expand Up @@ -175,7 +191,11 @@ where
let display_handler = display_handler.thread().clone();

move || {
for evt in terminal_events {
let mut terminal_events = terminal_events;
while running.load(Ordering::Acquire) {
let Some(evt) = terminal_events.next() else {
continue;
};
let mut ui = ui.lock().unwrap();

match evt {
Expand All @@ -192,12 +212,6 @@ where
);
}
Event::Key(KeyEvent {
modifiers: KeyModifiers::CONTROL,
code: KeyCode::Char('c'),
kind: KeyEventKind::Press,
..
})
| Event::Key(KeyEvent {
modifiers: KeyModifiers::NONE,
code: KeyCode::Char('q'),
kind: KeyEventKind::Press,
Expand Down
16 changes: 13 additions & 3 deletions src/os/shared.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::{
io::{self, ErrorKind, Write},
net::Ipv4Addr,
time,
time::{self, Duration},
};

use crossterm::event::{read, Event};
use crossterm::event::{poll, read, Event};
use eyre::{bail, eyre};
use itertools::Itertools;
use log::{debug, warn};
Expand Down Expand Up @@ -35,12 +35,22 @@ impl ProcessInfo {
}
}

/// Poll timeout for terminal events.
/// This allows the event loop to periodically check the `running` flag
/// for graceful shutdown on SIGINT.
const POLL_TIMEOUT: Duration = Duration::from_millis(100);

pub struct TerminalEvents;

impl Iterator for TerminalEvents {
type Item = Event;
fn next(&mut self) -> Option<Event> {
read().ok()
// Poll with timeout instead of blocking read to allow
// the caller to check for shutdown signals
match poll(POLL_TIMEOUT) {
Ok(true) => read().ok(),
Ok(false) | Err(_) => None,
}
}
Comment thread
cyqsimon marked this conversation as resolved.
}

Expand Down
8 changes: 4 additions & 4 deletions src/tests/cases/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ use crate::{
pub fn sleep_and_quit_events(sleep_num: usize) -> Box<TerminalEvents> {
let events = iter::repeat_n(None, sleep_num)
.chain([Some(Event::Key(KeyEvent::new(
KeyCode::Char('c'),
KeyModifiers::CONTROL,
KeyCode::Char('q'),
KeyModifiers::NONE,
)))])
.collect();
Box::new(TerminalEvents::new(events))
Expand All @@ -37,8 +37,8 @@ pub fn sleep_resize_and_quit_events(sleep_num: usize) -> Box<TerminalEvents> {
.chain([
Some(Event::Resize(100, 100)),
Some(Event::Key(KeyEvent::new(
KeyCode::Char('c'),
KeyModifiers::CONTROL,
KeyCode::Char('q'),
KeyModifiers::NONE,
))),
])
.collect();
Expand Down
Loading