From 83ec0ae1cf8d91e7e00890744e80b44a272702f9 Mon Sep 17 00:00:00 2001 From: Josh McKinney Date: Sat, 15 Jun 2024 18:12:12 -0700 Subject: [PATCH] feat(color-eyre): Add a default color-eyre feature Apps can now enable color-eyre hooks using the with_color_eyre_hooks method on CrosstermBackend. This is also added to the default features in the Cargo.toml file, and the defaults that are applied to terminals created using CrosstermBackend::into_terminal_with_defaults. --- Cargo.toml | 10 ++++++++-- examples/colors_rgb.rs | 26 ++----------------------- src/backend/crossterm.rs | 41 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 66ec7662..5ea6c429 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ rust-version = "1.74.0" bitflags = "2.3" cassowary = "0.3" compact_str = "0.7.1" +color-eyre = { version = "0.6.2", optional = true } crossterm = { version = "0.27", optional = true } document-features = { version = "0.2.7", optional = true } itertools = "0.13" @@ -49,7 +50,6 @@ unicode-width = "0.1.13" anyhow = "1.0.71" argh = "0.1.12" better-panic = "0.3.0" -color-eyre = "0.6.2" criterion = { version = "0.5.1", features = ["html_reports"] } derive_builder = "0.20.0" fakeit = "1.1" @@ -106,7 +106,7 @@ use_self = "warn" ## By default, we enable the crossterm backend as this is a reasonable choice for most applications ## as it is supported on Linux/Mac/Windows systems. We also enable the `underline-color` feature ## which allows you to set the underline color of text. -default = ["crossterm", "underline-color"] +default = ["crossterm", "underline-color", "color-eyre"] #! Generally an application will only use one backend, so you should only enable one of the following features: ## enables the [`CrosstermBackend`](backend::CrosstermBackend) backend and adds a dependency on [`crossterm`]. crossterm = ["dep:crossterm"] @@ -116,6 +116,12 @@ termion = ["dep:termion"] termwiz = ["dep:termwiz"] #! The following optional features are available for all backends: + +## enables the [`color-eyre`](color_eyre) crate which provides a better error handling experience. +## See [`CrosstermBackend::with_color_eyre_hooks`](crate::backend::CrosstermBackend::with_color_eyre_hooks) +## for more details. +color-eyre = ["dep:color-eyre"] + ## enables serialization and deserialization of style and color types using the [`serde`] crate. ## This is useful if you want to save themes to a file. serde = ["dep:serde", "bitflags/serde", "compact_str/serde"] diff --git a/examples/colors_rgb.rs b/examples/colors_rgb.rs index bd221b7c..60ce8e06 100644 --- a/examples/colors_rgb.rs +++ b/examples/colors_rgb.rs @@ -26,13 +26,9 @@ // is useful when the state is only used by the widget and doesn't need to be shared with // other widgets. -use std::{ - io::stdout, - panic, - time::{Duration, Instant}, -}; +use std::time::{Duration, Instant}; -use color_eyre::{config::HookBuilder, eyre, Result}; +use color_eyre::Result; use palette::{convert::FromColorUnclamped, Okhsv, Srgb}; use ratatui::{ backend::{Backend, CrosstermBackend}, @@ -258,21 +254,3 @@ impl ColorsWidget { } } } - -/// Install `color_eyre` panic and error hooks -/// -/// The hooks restore the terminal to a usable state before printing the error message. -fn install_error_hooks() -> Result<()> { - let (panic, error) = HookBuilder::default().into_hooks(); - let panic = panic.into_panic_hook(); - let error = error.into_eyre_hook(); - eyre::set_hook(Box::new(move |e| { - let _ = CrosstermBackend::reset(stdout()); - error(e) - }))?; - panic::set_hook(Box::new(move |info| { - let _ = CrosstermBackend::reset(stdout()); - panic(info); - })); - Ok(()) -} diff --git a/src/backend/crossterm.rs b/src/backend/crossterm.rs index 43eb373b..347e6e4e 100644 --- a/src/backend/crossterm.rs +++ b/src/backend/crossterm.rs @@ -204,6 +204,9 @@ impl CrosstermBackend { /// /// Raw mode and alternate screen are restored when the `CrosstermBackend` is dropped. /// + /// If the `color-eyre` feature is enabled, the color-eyre panic and error report hooks are + /// installed. + /// /// # Example /// /// ```rust,no_run @@ -213,7 +216,10 @@ impl CrosstermBackend { /// # std::io::Result::Ok(()) /// ``` pub fn stderr_with_defaults() -> io::Result { - Self::stderr().with_raw_mode()?.with_alternate_screen() + let backend = Self::stderr().with_raw_mode()?.with_alternate_screen()?; + #[cfg(feature = "color-eyre")] + let backend = backend.with_color_eyre_hooks()?; + Ok(backend) } } @@ -335,6 +341,39 @@ impl CrosstermBackend { Ok(self) } + /// Installs the color-eyre panic and error report hooks. + /// + /// This is a convenience method that sets up the color-eyre hooks for the terminal backend. + /// + /// # Example + /// + /// ```rust,no_run + /// use ratatui::backend::CrosstermBackend; + /// + /// let backend = CrosstermBackend::stdout().with_color_eyre_hooks()?; + /// ``` + #[cfg(feature = "color-eyre")] + pub fn with_color_eyre_hooks(self) -> color_eyre::Result { + use std::{io::stderr, panic}; + + use color_eyre::{config::HookBuilder, eyre}; + + let (panic, error) = HookBuilder::default().into_hooks(); + let panic = panic.into_panic_hook(); + let error = error.into_eyre_hook(); + eyre::set_hook(Box::new(move |e| { + // ignore errors here because we are already in an error state + let _ = CrosstermBackend::reset(stderr()); + error(e) + }))?; + panic::set_hook(Box::new(move |info| { + // ignore errors here because we are already in an error state + let _ = CrosstermBackend::reset(stderr()); + panic(info); + })); + Ok(self) + } + /// Resets the terminal to its default state. /// /// - Disables raw mode