1use anyhow::{Chain, Error};
4use colored::*;
5use std::fmt::{self, Debug, Write};
6#[cfg(not(any(feature = "jsc", feature = "wamr", feature = "wasmi", feature = "v8")))]
7use wasmer::RuntimeError;
8
9pub struct PrettyError {
11 error: Error,
12}
13
14impl PrettyError {
15 pub fn new(error: Error) -> Self {
17 PrettyError { error }
18 }
19}
20
21#[macro_export]
23macro_rules! warning {
24 ($($arg:tt)*) => ({
25 use colored::*;
26 eprintln!("{}: {}", "warning".yellow().bold(), format!($($arg)*));
27 })
28}
29
30#[cfg(not(any(feature = "jsc", feature = "wamr", feature = "wasmi", feature = "v8")))]
31impl PrettyError {
32 pub fn report<T>(result: Result<T, Error>) -> ! {
35 std::process::exit(match result {
36 Ok(_t) => 0,
37 Err(error) => {
38 let runtime: Option<&RuntimeError> = error.downcast_ref();
39 let trapcode = runtime.map(|e| e.clone().to_trap());
40 eprintln!("{:?}", PrettyError { error });
41 match trapcode {
45 #[cfg(target_os = "windows")]
46 Some(_) => 3,
47 #[cfg(not(target_os = "windows"))]
48 Some(_) => 128 + libc::SIGABRT,
49 _ => 1,
50 }
51 }
52 });
53 }
54}
55
56#[cfg(any(feature = "jsc", feature = "wamr", feature = "wasmi", feature = "v8"))]
57impl PrettyError {
58 pub fn report<T>(result: Result<T, Error>) -> ! {
61 std::process::exit(match result {
62 Ok(_t) => 0,
63 Err(error) => {
64 eprintln!("{:?}", PrettyError { error });
65 1
69 }
70 });
71 }
72}
73
74impl Debug for PrettyError {
75 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76 let error = &self.error;
77
78 if f.alternate() {
79 return Debug::fmt(&error, f);
80 }
81
82 write!(f, "{}", format!("{}: {}", "error".red(), error).bold())?;
83 if let Some(cause) = error.source() {
86 let chain = Chain::new(cause);
88 let (total_errors, _) = chain.size_hint();
89 for (n, error) in chain.enumerate() {
90 writeln!(f)?;
91 let mut indented = Indented {
92 inner: f,
93 number: Some(n + 1),
94 is_last: n == total_errors - 1,
95 started: false,
96 };
97 write!(indented, "{error}")?;
98 }
99 }
100 Ok(())
101 }
102}
103
104struct Indented<'a, D> {
105 inner: &'a mut D,
106 number: Option<usize>,
107 started: bool,
108 is_last: bool,
109}
110
111impl<T> Write for Indented<'_, T>
112where
113 T: Write,
114{
115 fn write_str(&mut self, s: &str) -> fmt::Result {
116 for (i, line) in s.split('\n').enumerate() {
117 if !self.started {
118 self.started = true;
119 match self.number {
120 Some(number) => {
121 if !self.is_last {
122 write!(
123 self.inner,
124 "{} {: >4} ",
125 "│".bold().blue(),
126 format!("{number}:").dimmed()
127 )?
128 } else {
129 write!(
130 self.inner,
131 "{}{: >2}: ",
132 "╰─▶".bold().blue(),
133 format!("{number}").bold().blue()
134 )?
135 }
136 }
137 None => self.inner.write_str(" ")?,
138 }
139 } else if i > 0 {
140 self.inner.write_char('\n')?;
141 if self.number.is_some() {
142 self.inner.write_str(" ")?;
143 } else {
144 self.inner.write_str(" ")?;
145 }
146 }
147
148 self.inner.write_str(line)?;
149 }
150
151 Ok(())
152 }
153}