From 7bd50739ceca80f761fafb4f3166dc72669ce0fe Mon Sep 17 00:00:00 2001 From: Andreas Hartmann Date: Thu, 18 Aug 2022 13:30:16 +0200 Subject: [PATCH] tile: Log plugin errors and display them in the plugin canvas, too. --- zellij-tile/src/lib.rs | 105 ++++++++++++++++++++++++++++------------- 1 file changed, 73 insertions(+), 32 deletions(-) diff --git a/zellij-tile/src/lib.rs b/zellij-tile/src/lib.rs index ef8ce12853..3f9062bb74 100644 --- a/zellij-tile/src/lib.rs +++ b/zellij-tile/src/lib.rs @@ -1,7 +1,7 @@ pub mod prelude; pub mod shim; -use zellij_utils::anyhow::Result; +use zellij_utils::anyhow::{self, Result}; use zellij_utils::data::Event; #[allow(unused_variables)] @@ -17,6 +17,40 @@ pub trait ZellijPlugin { } } +/// Catch non-fatal errors and print their content to the plugins stdout and stderr. This way, the +/// user sees the error and can even report it, but it will not crash the application. Hence, this +/// works only on the empty type `()`. +pub fn catch(ret: anyhow::Result<()>) { + match ret { + Ok(_) => (), + Err(err) => { + println!("ERROR: {}", err); + eprintln!("ERROR: {}", &err); + err.chain().skip(1).for_each(|cause| { + let msg = format!("because: {cause}"); + println!("{}", msg); + eprintln!("{}", &msg); + }); + }, + } +} + +/// Return the inner value if `Ok(_)` and panic the application otherwise. Before panicking, the +/// error is written to the logfile. +pub fn catch_fatal(ret: anyhow::Result) -> T { + match ret { + Ok(val) => val, + Err(err) => { + eprintln!("ERROR: {}", &err); + err.chain().skip(1).for_each(|cause| { + let msg = format!("because: {cause}"); + eprintln!("{}", &msg); + }); + panic!("{:#?}", err); + }, + } +} + #[macro_export] macro_rules! register_plugin { ($t:ty) => { @@ -24,45 +58,52 @@ macro_rules! register_plugin { static STATE: std::cell::RefCell<$t> = std::cell::RefCell::new(Default::default()); } - fn main() -> Result<()> { - STATE - .with(|state| { - state - .try_borrow_mut() - .context("Failed to borrow plugin state for loading")? + fn main() { + catch_fatal( + STATE + .with(|state| { + catch_fatal( + state + .try_borrow_mut() + .context("Failed to borrow plugin state for loading"), + ) .load() - }) - .context("Failed to get plugin for loading")?; - Ok(()) + }) + .context("Failed to get plugin for loading"), + ); } #[no_mangle] - pub fn update() -> Result<()> { - STATE - .with(|state| { - state - .try_borrow_mut() - .context("Failed to borrow plugin state for updating")? - .update( - $crate::shim::object_from_stdin() - .context("Failed to read plugin input for updating")?, + pub fn update() { + catch( + STATE + .with(|state| { + catch_fatal( + state + .try_borrow_mut() + .context("Failed to borrow plugin state for updating"), ) - }) - .context("Failed to get plugin for updating")?; - Ok(()) + .update(catch_fatal( + $crate::shim::object_from_stdin() + .context("Failed to read plugin input for updating"), + )) + }) + .context("Failed to get plugin for updating"), + ); } #[no_mangle] - pub fn render(rows: i32, cols: i32) -> Result<()> { - STATE - .with(|state| { - state - .try_borrow_mut() - .context("Failed to borrow plugin state for rendering")? - .render(rows as usize, cols as usize) - }) - .context("Failed to get plugin for rendering")?; - Ok(()) + pub fn render(rows: i32, cols: i32) { + STATE.with(|state| { + catch( + catch_fatal( + state + .try_borrow_mut() + .context("Failed to borrow plugin state for rendering"), + ) + .render(rows as usize, cols as usize), + ) + }); } }; }