wasmer_compiler_cli/
error.rs

1//! Implements `PretyError` to print pretty errors in the CLI (when they happen)
2
3use anyhow::{Chain, Error};
4use colored::*;
5use std::fmt::{self, Debug, Write};
6
7/// A `PrettyError` for printing `anyhow::Error` nicely.
8pub struct PrettyError {
9    error: Error,
10}
11
12/// A macro that prints a warning with nice colors
13#[macro_export]
14macro_rules! warning {
15    ($($arg:tt)*) => ({
16        use colored::*;
17        eprintln!("{}: {}", "warning".yellow().bold(), format!($($arg)*));
18    })
19}
20
21impl PrettyError {
22    /// Process a `Result` printing any errors and exiting
23    /// the process after
24    pub fn report<T>(result: Result<T, Error>) -> ! {
25        std::process::exit(match result {
26            Ok(_t) => 0,
27            Err(error) => {
28                eprintln!("{:?}", PrettyError { error });
29                1
30            }
31        });
32    }
33}
34
35impl Debug for PrettyError {
36    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37        let error = &self.error;
38
39        if f.alternate() {
40            return Debug::fmt(&error, f);
41        }
42
43        write!(f, "{}", format!("{}: {}", "error".red(), error).bold())?;
44        // write!(f, "{}", error)?;
45
46        if let Some(cause) = error.source() {
47            // write!(f, "\n{}:", "caused by".bold().blue())?;
48            let chain = Chain::new(cause);
49            let (total_errors, _) = chain.size_hint();
50            for (n, error) in chain.enumerate() {
51                writeln!(f)?;
52                let mut indented = Indented {
53                    inner: f,
54                    number: Some(n + 1),
55                    is_last: n == total_errors - 1,
56                    started: false,
57                };
58                write!(indented, "{error}")?;
59            }
60        }
61        Ok(())
62    }
63}
64
65struct Indented<'a, D> {
66    inner: &'a mut D,
67    number: Option<usize>,
68    started: bool,
69    is_last: bool,
70}
71
72impl<T> Write for Indented<'_, T>
73where
74    T: Write,
75{
76    fn write_str(&mut self, s: &str) -> fmt::Result {
77        for (i, line) in s.split('\n').enumerate() {
78            if !self.started {
79                self.started = true;
80                match self.number {
81                    Some(number) => {
82                        if !self.is_last {
83                            write!(
84                                self.inner,
85                                "{} {: >4} ",
86                                "│".bold().blue(),
87                                format!("{number}:").dimmed()
88                            )?
89                        } else {
90                            write!(
91                                self.inner,
92                                "{}{: >2}: ",
93                                "╰─▶".bold().blue(),
94                                format!("{number}").bold().blue()
95                            )?
96                        }
97                    }
98                    None => self.inner.write_str("    ")?,
99                }
100            } else if i > 0 {
101                self.inner.write_char('\n')?;
102                if self.number.is_some() {
103                    self.inner.write_str("       ")?;
104                } else {
105                    self.inner.write_str("    ")?;
106                }
107            }
108
109            self.inner.write_str(line)?;
110        }
111
112        Ok(())
113    }
114}