From 49ece42651b72fb1fc1d7f2b56ee9a15facb119b Mon Sep 17 00:00:00 2001 From: ClementTsang <34804052+ClementTsang@users.noreply.github.com> Date: Fri, 17 Jan 2025 21:08:18 -0500 Subject: [PATCH 1/3] bug: handle terminal cleanup if main.rs panics from an Err --- src/bin/main.rs | 6 ++++-- src/lib.rs | 40 ++++++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 5b2f20acc..b77298d22 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,5 +1,7 @@ -use bottom::start_bottom; +use bottom::{reset_stdout, start_bottom}; fn main() -> anyhow::Result<()> { - start_bottom() + start_bottom().inspect_err(|_| { + reset_stdout(); + }) } diff --git a/src/lib.rs b/src/lib.rs index 1a4a275d8..3b0c3897d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ pub mod widgets; use std::{ boxed::Box, - io::{stderr, stdout, Write}, + io::{stderr, stdout, Stdout, Write}, panic::{self, PanicHookInfo}, sync::{ mpsc::{self, Receiver, Sender}, @@ -38,12 +38,12 @@ use std::{ use app::{layout_manager::UsedWidgets, App, AppConfigFields, DataFilters}; use crossterm::{ + cursor::{Hide, Show}, event::{ poll, read, DisableBracketedPaste, DisableMouseCapture, EnableBracketedPaste, EnableMouseCapture, Event, KeyEventKind, MouseEventKind, }, execute, - style::Print, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; use data_conversion::*; @@ -80,7 +80,8 @@ fn cleanup_terminal( terminal.backend_mut(), DisableBracketedPaste, DisableMouseCapture, - LeaveAlternateScreen + LeaveAlternateScreen, + Show, )?; terminal.show_cursor()?; @@ -101,11 +102,24 @@ fn check_if_terminal() { } } +/// This manually resets stdout back to normal state. +pub fn reset_stdout() -> Stdout { + let mut stdout = stdout(); + let _ = disable_raw_mode(); + let _ = execute!( + stdout, + DisableBracketedPaste, + DisableMouseCapture, + LeaveAlternateScreen, + Show, + ); + + stdout +} + /// A panic hook to properly restore the terminal in the case of a panic. /// Originally based on [spotify-tui's implementation](https://github.com/Rigellute/spotify-tui/blob/master/src/main.rs). fn panic_hook(panic_info: &PanicHookInfo<'_>) { - let mut stdout = stdout(); - let msg = match panic_info.payload().downcast_ref::<&'static str>() { Some(s) => *s, None => match panic_info.payload().downcast_ref::() { @@ -116,22 +130,11 @@ fn panic_hook(panic_info: &PanicHookInfo<'_>) { let backtrace = format!("{:?}", backtrace::Backtrace::new()); - let _ = disable_raw_mode(); - let _ = execute!( - stdout, - DisableBracketedPaste, - DisableMouseCapture, - LeaveAlternateScreen - ); + reset_stdout(); // Print stack trace. Must be done after! if let Some(panic_info) = panic_info.location() { - let _ = execute!( - stdout, - Print(format!( - "thread '' panicked at '{msg}', {panic_info}\n\r{backtrace}", - )), - ); + println!("thread '' panicked at '{msg}', {panic_info}\n\r{backtrace}") } // TODO: Might be cleaner in the future to use a cancellation token, but that causes some fun issues with @@ -339,6 +342,7 @@ pub fn start_bottom() -> anyhow::Result<()> { let mut stdout_val = stdout(); execute!( stdout_val, + Hide, EnterAlternateScreen, EnableMouseCapture, EnableBracketedPaste From 27de7635b14971a0093cec91091669e39fadce72 Mon Sep 17 00:00:00 2001 From: ClementTsang <34804052+ClementTsang@users.noreply.github.com> Date: Fri, 17 Jan 2025 21:14:55 -0500 Subject: [PATCH 2/3] add comment --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 3b0c3897d..769fd7db1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -369,6 +369,7 @@ pub fn start_bottom() -> anyhow::Result<()> { panic::set_hook(Box::new(panic_hook)); // Set termination hook + // TODO: On UNIX, use signal-hook to handle cleanup as well. ctrlc::set_handler(move || { let _ = sender.send(BottomEvent::Terminate); })?; From 72f5134890392621ec1bbd82d7bda891ad09de23 Mon Sep 17 00:00:00 2001 From: ClementTsang <34804052+ClementTsang@users.noreply.github.com> Date: Fri, 17 Jan 2025 21:19:28 -0500 Subject: [PATCH 3/3] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2de9b3c..c69e2ff14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ That said, these are more guidelines rather than hardset rules, though the proje - [#1593](https://github.com/ClementTsang/bottom/pull/1593): Fix using `"none"` for chart legend position in configs. - [#1594](https://github.com/ClementTsang/bottom/pull/1594): Fix incorrect default config definitions for chart legends. - [#1596](https://github.com/ClementTsang/bottom/pull/1596): Fix support for nilfs2 file system. +- [#1660](https://github.com/ClementTsang/bottom/pull/1660): Handle terminal cleanup if the program is terminated due to an `Err` bubbling to the top. ### Changes