1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#![cfg(feature = "fancy")]
use std::fmt::Write;
use backtrace::Backtrace;
use thiserror::Error;
use crate::{self as miette, Context, Diagnostic, Result};
pub fn set_panic_hook() {
std::panic::set_hook(Box::new(move |info| {
let mut message = "Something went wrong".to_string();
let payload = info.payload();
if let Some(msg) = payload.downcast_ref::<&str>() {
message = msg.to_string();
}
if let Some(msg) = payload.downcast_ref::<String>() {
message = msg.clone();
}
let mut report: Result<()> = Err(Panic(message).into());
if let Some(loc) = info.location() {
report = report
.with_context(|| format!("at {}:{}:{}", loc.file(), loc.line(), loc.column()));
}
if let Err(err) = report.with_context(|| "Main thread panicked.".to_string()) {
eprintln!("Error: {:?}", err);
}
}));
}
#[derive(Debug, Error, Diagnostic)]
#[error("{0}{}", self.maybe_collect_backtrace())]
#[diagnostic(help("set the `RUST_BACKTRACE=1` environment variable to display a backtrace."))]
struct Panic(String);
impl Panic {
fn maybe_collect_backtrace(&self) -> String {
if let Ok(var) = std::env::var("RUST_BACKTRACE") {
if !var.is_empty() && var != "0" {
const HEX_WIDTH: usize = std::mem::size_of::<usize>() + 2;
const NEXT_SYMBOL_PADDING: usize = HEX_WIDTH + 6;
let mut backtrace = String::new();
for (idx, frame) in Backtrace::new().frames().iter().skip(26).enumerate() {
let ip = frame.ip();
let _ = write!(backtrace, "\n{:4}: {:2$?}", idx, ip, HEX_WIDTH);
let symbols = frame.symbols();
if symbols.is_empty() {
let _ = write!(backtrace, " - <unresolved>");
continue;
}
for (idx, symbol) in symbols.iter().enumerate() {
if idx != 0 {
let _ = write!(backtrace, "\n{:1$}", "", NEXT_SYMBOL_PADDING);
}
if let Some(name) = symbol.name() {
let _ = write!(backtrace, " - {}", name);
} else {
let _ = write!(backtrace, " - <unknown>");
}
if let (Some(file), Some(line)) = (symbol.filename(), symbol.lineno()) {
let _ = write!(
backtrace,
"\n{:3$}at {}:{}",
"",
file.display(),
line,
NEXT_SYMBOL_PADDING
);
}
}
}
return backtrace;
}
}
"".into()
}
}