//! Provides an extension trait for attaching `Section` to error reports. use crate::{ eyre::{Report, Result}, Section, }; use indenter::indented; use owo_colors::OwoColorize; use std::fmt::Write; use std::fmt::{self, Display}; impl Section for Report { type Return = Report; fn note(mut self, note: D) -> Self::Return where D: Display + Send + Sync + 'static, { if let Some(handler) = self.handler_mut().downcast_mut::() { handler.sections.push(HelpInfo::Note(Box::new(note))); } self } fn with_note(mut self, note: F) -> Self::Return where D: Display + Send + Sync + 'static, F: FnOnce() -> D, { if let Some(handler) = self.handler_mut().downcast_mut::() { handler.sections.push(HelpInfo::Note(Box::new(note()))); } self } fn warning(mut self, warning: D) -> Self::Return where D: Display + Send + Sync + 'static, { if let Some(handler) = self.handler_mut().downcast_mut::() { handler.sections.push(HelpInfo::Warning(Box::new(warning))); } self } fn with_warning(mut self, warning: F) -> Self::Return where D: Display + Send + Sync + 'static, F: FnOnce() -> D, { if let Some(handler) = self.handler_mut().downcast_mut::() { handler .sections .push(HelpInfo::Warning(Box::new(warning()))); } self } fn suggestion(mut self, suggestion: D) -> Self::Return where D: Display + Send + Sync + 'static, { if let Some(handler) = self.handler_mut().downcast_mut::() { handler .sections .push(HelpInfo::Suggestion(Box::new(suggestion))); } self } fn with_suggestion(mut self, suggestion: F) -> Self::Return where D: Display + Send + Sync + 'static, F: FnOnce() -> D, { if let Some(handler) = self.handler_mut().downcast_mut::() { handler .sections .push(HelpInfo::Suggestion(Box::new(suggestion()))); } self } fn with_section(mut self, section: F) -> Self::Return where D: Display + Send + Sync + 'static, F: FnOnce() -> D, { if let Some(handler) = self.handler_mut().downcast_mut::() { let section = Box::new(section()); handler.sections.push(HelpInfo::Custom(section)); } self } fn section(mut self, section: D) -> Self::Return where D: Display + Send + Sync + 'static, { if let Some(handler) = self.handler_mut().downcast_mut::() { let section = Box::new(section); handler.sections.push(HelpInfo::Custom(section)); } self } fn error(mut self, error: E2) -> Self::Return where E2: std::error::Error + Send + Sync + 'static, { if let Some(handler) = self.handler_mut().downcast_mut::() { let error = error.into(); handler.sections.push(HelpInfo::Error(error)); } self } fn with_error(mut self, error: F) -> Self::Return where F: FnOnce() -> E2, E2: std::error::Error + Send + Sync + 'static, { if let Some(handler) = self.handler_mut().downcast_mut::() { let error = error().into(); handler.sections.push(HelpInfo::Error(error)); } self } } impl Section for Result where E: Into, { type Return = Result; fn note(self, note: D) -> Self::Return where D: Display + Send + Sync + 'static, { self.map_err(|error| error.into()) .map_err(|report| report.note(note)) } fn with_note(self, note: F) -> Self::Return where D: Display + Send + Sync + 'static, F: FnOnce() -> D, { self.map_err(|error| error.into()) .map_err(|report| report.note(note())) } fn warning(self, warning: D) -> Self::Return where D: Display + Send + Sync + 'static, { self.map_err(|error| error.into()) .map_err(|report| report.warning(warning)) } fn with_warning(self, warning: F) -> Self::Return where D: Display + Send + Sync + 'static, F: FnOnce() -> D, { self.map_err(|error| error.into()) .map_err(|report| report.warning(warning())) } fn suggestion(self, suggestion: D) -> Self::Return where D: Display + Send + Sync + 'static, { self.map_err(|error| error.into()) .map_err(|report| report.suggestion(suggestion)) } fn with_suggestion(self, suggestion: F) -> Self::Return where D: Display + Send + Sync + 'static, F: FnOnce() -> D, { self.map_err(|error| error.into()) .map_err(|report| report.suggestion(suggestion())) } fn with_section(self, section: F) -> Self::Return where D: Display + Send + Sync + 'static, F: FnOnce() -> D, { self.map_err(|error| error.into()) .map_err(|report| report.section(section())) } fn section(self, section: D) -> Self::Return where D: Display + Send + Sync + 'static, { self.map_err(|error| error.into()) .map_err(|report| report.section(section)) } fn error(self, error: E2) -> Self::Return where E2: std::error::Error + Send + Sync + 'static, { self.map_err(|error| error.into()) .map_err(|report| report.error(error)) } fn with_error(self, error: F) -> Self::Return where F: FnOnce() -> E2, E2: std::error::Error + Send + Sync + 'static, { self.map_err(|error| error.into()) .map_err(|report| report.error(error())) } } pub(crate) enum HelpInfo { Error(Box), Custom(Box), Note(Box), Warning(Box), Suggestion(Box), } impl Display for HelpInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { HelpInfo::Note(note) => write!(f, "{}: {}", "Note".bright_cyan(), note), HelpInfo::Warning(warning) => write!(f, "{}: {}", "Warning".bright_yellow(), warning), HelpInfo::Suggestion(suggestion) => { write!(f, "{}: {}", "Suggestion".bright_cyan(), suggestion) } HelpInfo::Custom(section) => write!(f, "{}", section), HelpInfo::Error(error) => { // a lot here let errors = std::iter::successors( Some(error.as_ref() as &(dyn std::error::Error + 'static)), |e| e.source(), ); write!(f, "Error:")?; for (n, error) in errors.enumerate() { writeln!(f)?; write!(indented(f).ind(n), "{}", error.bright_red())?; } Ok(()) } } } } impl fmt::Debug for HelpInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { HelpInfo::Note(note) => f .debug_tuple("Note") .field(&format_args!("{}", note)) .finish(), HelpInfo::Warning(warning) => f .debug_tuple("Warning") .field(&format_args!("{}", warning)) .finish(), HelpInfo::Suggestion(suggestion) => f .debug_tuple("Suggestion") .field(&format_args!("{}", suggestion)) .finish(), HelpInfo::Custom(custom) => f .debug_tuple("CustomSection") .field(&format_args!("{}", custom)) .finish(), HelpInfo::Error(error) => f.debug_tuple("Error").field(error).finish(), } } }