1use eyre::EyreHandler;
2use itertools::Itertools;
3use std::{error::Error, fmt};
4
5#[derive(Default)]
7pub struct Handler {
8 debug_handler: Option<Box<dyn EyreHandler>>,
9}
10
11impl Handler {
12 pub fn new() -> Self {
14 Self::default()
15 }
16
17 pub fn debug_handler(mut self, debug_handler: Option<Box<dyn EyreHandler>>) -> Self {
19 self.debug_handler = debug_handler;
20 self
21 }
22}
23
24impl EyreHandler for Handler {
25 fn display(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 use fmt::Display;
27 foundry_common::errors::dedup_chain(error).into_iter().format("; ").fmt(f)
28 }
29
30 fn debug(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 if let Some(debug_handler) = &self.debug_handler {
32 return debug_handler.debug(error, f);
33 }
34
35 if f.alternate() {
36 return fmt::Debug::fmt(error, f);
37 }
38 let errors = foundry_common::errors::dedup_chain(error);
39
40 let (error, sources) = errors.split_first().unwrap();
41 write!(f, "{error}")?;
42
43 if !sources.is_empty() {
44 write!(f, "\n\nContext:")?;
45
46 let multiple = sources.len() > 1;
47 for (n, error) in sources.iter().enumerate() {
48 writeln!(f)?;
49 if multiple {
50 write!(f, "- Error #{n}: {error}")?;
51 } else {
52 write!(f, "- {error}")?;
53 }
54 }
55 }
56
57 Ok(())
58 }
59
60 fn track_caller(&mut self, location: &'static std::panic::Location<'static>) {
61 if let Some(debug_handler) = &mut self.debug_handler {
62 debug_handler.track_caller(location);
63 }
64 }
65}
66
67pub fn install() {
77 if std::env::var_os("RUST_BACKTRACE").is_none() {
78 unsafe {
79 std::env::set_var("RUST_BACKTRACE", "1");
80 }
81 }
82
83 let panic_section =
84 "This is a bug. Consider reporting it at https://github.com/foundry-rs/foundry";
85 let (panic_hook, debug_hook) =
86 color_eyre::config::HookBuilder::default().panic_section(panic_section).into_hooks();
87 panic_hook.install();
88 let debug_hook = debug_hook.into_eyre_hook();
89 let debug = std::env::var_os("FOUNDRY_DEBUG").is_some();
90 if let Err(e) = eyre::set_hook(Box::new(move |e| {
91 Box::new(Handler::new().debug_handler(debug.then(|| debug_hook(e))))
92 })) {
93 debug!("failed to install eyre error hook: {e}");
94 }
95}