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
}
}
#[must_use]
pub fn styling_enabled() -> bool {
#[cfg(feature = "supports-color")]
{
supports_color::on_cached(supports_color::Stream::Stderr).is_some()
}
#[cfg(not(feature = "supports-color"))]
{
true
}
}
fn common_format(this: &Error, style: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut msg = String::new();
for e in this.iter().rev() {
let is_unit_err = e.downcast_ref::<UnitError>().is_some();
let location = e.get_location();
if is_unit_err && location.is_none() {
continue;
}
writeln!(f)?;
msg.clear();
if !is_unit_err {
write!(msg, "{}", e.get_err())?;
if (!style) || msg.contains('\u{1b}') {
write!(f, " {}", msg)?;
} else {
let color = Style::new().color(CssColors::IndianRed);
write!(f, " {}", msg.style(color))?;
}
}
if let Some(l) = location {
if is_unit_err {
write!(f, " at ")?;
} else if (msg.len() + l.file().len() + 8) > 80 {
write!(f, "\n at ")?;
} else {
write!(f, " at ")?;
}
let dimmed = Style::new().dimmed();
let bold = Style::new().bold();
if style {
write!(
f,
"{} {}",
shorten_location(l.file()).style(dimmed),
format_args!("{}:{}", l.line(), l.column()).style(bold)
)?;
} else {
write!(
f,
"{} {}",
shorten_location(l.file()),
format_args!("{}:{}", l.line(), l.column())
)?;
}
}
}
Ok(())
}
impl Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
common_format(self, styling_enabled(), f)
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
common_format(self, false, f)
}
}