use alloc::{fmt, fmt::Debug, string::String};
use core::fmt::{Display, Write};
use owo_colors::{CssColors, OwoColorize, Style};
use crate::{error::StackedErrorDowncast, Error, UnitError};
pub struct DisplayStr<'a>(pub &'a str);
impl Debug for DisplayStr<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("{}", self.0))
}
}
pub fn shorten_location(mut s: &str) -> &str {
#[cfg(not(windows))]
{
let find = "/.cargo/registry/src/";
if let Some(i) = s.find(find) {
s = &s[(i + find.len())..];
if let Some(i) = s.find('/') {
s = &s[(i + 1)..];
}
}
s
}
#[cfg(windows)]
{
let find = "\\.cargo\\registry\\src\\";
if let Some(i) = s.find(find) {
s = &s[(i + find.len())..];
if let Some(i) = s.find('\\') {
s = &s[(i + 1)..];
}
}
s
}
}
fn common_format(this: &Error, style: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = String::new();
let mut tmp = String::new();
let mut first = true;
for (i, e) in this.iter().enumerate().rev() {
s.clear();
if first {
writeln!(s)?;
}
let is_unit_err = e.downcast_ref::<UnitError>().is_some();
let is_last = i == 0;
if is_unit_err {
if e.get_location().is_none() {
continue;
}
} else {
tmp.clear();
write!(tmp, "{}", e.get_err())?;
if (!style) || tmp.contains('\u{1b}') {
write!(s, " {}", tmp)?;
} else {
let color = Style::new().color(CssColors::IndianRed);
write!(s, " {}", tmp.style(color))?;
}
}
if let Some(l) = e.get_location() {
if (tmp.len() + l.file().len() + 8) > 80 {
write!(s, "\n at ")?;
} else if !is_unit_err {
write!(s, " at ")?;
} else {
write!(s, " at ")?;
}
let dimmed = Style::new().dimmed();
let bold = Style::new().bold();
tmp.clear();
write!(tmp, "{}:{}", l.line(), l.column())?;
if style {
write!(
s,
"{} {}",
shorten_location(l.file()).style(dimmed),
tmp.style(bold)
)?;
} else {
write!(s, "{} {}", shorten_location(l.file()), tmp)?;
}
}
if !is_last {
writeln!(s)?;
}
f.write_fmt(format_args!("{s}"))?;
first = false;
}
Ok(())
}
impl Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
common_format(self, true, f)
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
common_format(self, false, f)
}
}