nu_protocol/errors/
chained_error.rs1use super::shell_error::ShellError;
2use crate::Span;
3use miette::{LabeledSpan, Severity, SourceCode};
4use thiserror::Error;
5
6#[derive(Debug, Clone, PartialEq, Error)]
15pub struct ChainedError {
16 first: bool,
17 pub(crate) sources: Vec<ShellError>,
18 span: Span,
19}
20
21impl std::fmt::Display for ChainedError {
22 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23 if self.first {
24 write!(f, "{}", self.sources[0])
25 } else {
26 write!(f, "oops")
27 }
28 }
29}
30
31impl ChainedError {
32 pub fn new(source: ShellError, span: Span) -> Self {
33 Self {
34 first: true,
35 sources: vec![source],
36 span,
37 }
38 }
39
40 pub fn new_chained(sources: Self, span: Span) -> Self {
41 Self {
42 first: false,
43 sources: vec![ShellError::ChainedError(sources)],
44 span,
45 }
46 }
47
48 pub fn sources_iter(self) -> impl Iterator<Item = ShellError> {
51 self.sources.into_iter()
52 }
53}
54
55impl miette::Diagnostic for ChainedError {
56 fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn miette::Diagnostic> + 'a>> {
57 if self.first {
58 self.sources[0].related()
59 } else {
60 Some(Box::new(self.sources.iter().map(|s| s as _)))
61 }
62 }
63
64 fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
65 if self.first {
66 self.sources[0].code()
67 } else {
68 Some(Box::new("chained_error"))
69 }
70 }
71
72 fn severity(&self) -> Option<Severity> {
73 if self.first {
74 self.sources[0].severity()
75 } else {
76 None
77 }
78 }
79
80 fn help<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
81 if self.first {
82 self.sources[0].help()
83 } else {
84 None
85 }
86 }
87
88 fn url<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
89 if self.first {
90 self.sources[0].url()
91 } else {
92 None
93 }
94 }
95
96 fn labels<'a>(&'a self) -> Option<Box<dyn Iterator<Item = LabeledSpan> + 'a>> {
97 if self.first {
98 self.sources[0].labels()
99 } else {
100 Some(Box::new(
101 vec![LabeledSpan::new_with_span(
102 Some("error happened when running this".to_string()),
103 self.span,
104 )]
105 .into_iter(),
106 ))
107 }
108 }
109
110 fn source_code(&self) -> Option<&dyn SourceCode> {
112 if self.first {
113 self.sources[0].source_code()
114 } else {
115 None
116 }
117 }
118
119 fn diagnostic_source(&self) -> Option<&dyn miette::Diagnostic> {
120 if self.first {
121 self.sources[0].diagnostic_source()
122 } else {
123 None
124 }
125 }
126}