1 | //! Provides an extension trait for attaching `Section` to error reports. |
2 | use crate::{ |
3 | config::Theme, |
4 | eyre::{Report, Result}, |
5 | Section, |
6 | }; |
7 | use indenter::indented; |
8 | use owo_colors::OwoColorize; |
9 | use std::fmt::Write; |
10 | use std::fmt::{self, Display}; |
11 | |
12 | impl Section for Report { |
13 | type Return = Report; |
14 | |
15 | fn note<D>(mut self, note: D) -> Self::Return |
16 | where |
17 | D: Display + Send + Sync + 'static, |
18 | { |
19 | if let Some(handler) = self.handler_mut().downcast_mut::<crate::Handler>() { |
20 | handler |
21 | .sections |
22 | .push(HelpInfo::Note(Box::new(note), handler.theme)); |
23 | } |
24 | |
25 | self |
26 | } |
27 | |
28 | fn with_note<D, F>(mut self, note: F) -> Self::Return |
29 | where |
30 | D: Display + Send + Sync + 'static, |
31 | F: FnOnce() -> D, |
32 | { |
33 | if let Some(handler) = self.handler_mut().downcast_mut::<crate::Handler>() { |
34 | handler |
35 | .sections |
36 | .push(HelpInfo::Note(Box::new(note()), handler.theme)); |
37 | } |
38 | |
39 | self |
40 | } |
41 | |
42 | fn warning<D>(mut self, warning: D) -> Self::Return |
43 | where |
44 | D: Display + Send + Sync + 'static, |
45 | { |
46 | if let Some(handler) = self.handler_mut().downcast_mut::<crate::Handler>() { |
47 | handler |
48 | .sections |
49 | .push(HelpInfo::Warning(Box::new(warning), handler.theme)); |
50 | } |
51 | |
52 | self |
53 | } |
54 | |
55 | fn with_warning<D, F>(mut self, warning: F) -> Self::Return |
56 | where |
57 | D: Display + Send + Sync + 'static, |
58 | F: FnOnce() -> D, |
59 | { |
60 | if let Some(handler) = self.handler_mut().downcast_mut::<crate::Handler>() { |
61 | handler |
62 | .sections |
63 | .push(HelpInfo::Warning(Box::new(warning()), handler.theme)); |
64 | } |
65 | |
66 | self |
67 | } |
68 | |
69 | fn suggestion<D>(mut self, suggestion: D) -> Self::Return |
70 | where |
71 | D: Display + Send + Sync + 'static, |
72 | { |
73 | if let Some(handler) = self.handler_mut().downcast_mut::<crate::Handler>() { |
74 | handler |
75 | .sections |
76 | .push(HelpInfo::Suggestion(Box::new(suggestion), handler.theme)); |
77 | } |
78 | |
79 | self |
80 | } |
81 | |
82 | fn with_suggestion<D, F>(mut self, suggestion: F) -> Self::Return |
83 | where |
84 | D: Display + Send + Sync + 'static, |
85 | F: FnOnce() -> D, |
86 | { |
87 | if let Some(handler) = self.handler_mut().downcast_mut::<crate::Handler>() { |
88 | handler |
89 | .sections |
90 | .push(HelpInfo::Suggestion(Box::new(suggestion()), handler.theme)); |
91 | } |
92 | |
93 | self |
94 | } |
95 | |
96 | fn with_section<D, F>(mut self, section: F) -> Self::Return |
97 | where |
98 | D: Display + Send + Sync + 'static, |
99 | F: FnOnce() -> D, |
100 | { |
101 | if let Some(handler) = self.handler_mut().downcast_mut::<crate::Handler>() { |
102 | let section = Box::new(section()); |
103 | handler.sections.push(HelpInfo::Custom(section)); |
104 | } |
105 | |
106 | self |
107 | } |
108 | |
109 | fn section<D>(mut self, section: D) -> Self::Return |
110 | where |
111 | D: Display + Send + Sync + 'static, |
112 | { |
113 | if let Some(handler) = self.handler_mut().downcast_mut::<crate::Handler>() { |
114 | let section = Box::new(section); |
115 | handler.sections.push(HelpInfo::Custom(section)); |
116 | } |
117 | |
118 | self |
119 | } |
120 | |
121 | fn error<E2>(mut self, error: E2) -> Self::Return |
122 | where |
123 | E2: std::error::Error + Send + Sync + 'static, |
124 | { |
125 | if let Some(handler) = self.handler_mut().downcast_mut::<crate::Handler>() { |
126 | let error = error.into(); |
127 | handler.sections.push(HelpInfo::Error(error, handler.theme)); |
128 | } |
129 | |
130 | self |
131 | } |
132 | |
133 | fn with_error<E2, F>(mut self, error: F) -> Self::Return |
134 | where |
135 | F: FnOnce() -> E2, |
136 | E2: std::error::Error + Send + Sync + 'static, |
137 | { |
138 | if let Some(handler) = self.handler_mut().downcast_mut::<crate::Handler>() { |
139 | let error = error().into(); |
140 | handler.sections.push(HelpInfo::Error(error, handler.theme)); |
141 | } |
142 | |
143 | self |
144 | } |
145 | |
146 | fn suppress_backtrace(mut self, suppress: bool) -> Self::Return { |
147 | if let Some(handler) = self.handler_mut().downcast_mut::<crate::Handler>() { |
148 | handler.suppress_backtrace = suppress; |
149 | } |
150 | |
151 | self |
152 | } |
153 | } |
154 | |
155 | impl<T, E> Section for Result<T, E> |
156 | where |
157 | E: Into<Report>, |
158 | { |
159 | type Return = Result<T, Report>; |
160 | |
161 | fn note<D>(self, note: D) -> Self::Return |
162 | where |
163 | D: Display + Send + Sync + 'static, |
164 | { |
165 | self.map_err(|error| error.into()) |
166 | .map_err(|report| report.note(note)) |
167 | } |
168 | |
169 | fn with_note<D, F>(self, note: F) -> Self::Return |
170 | where |
171 | D: Display + Send + Sync + 'static, |
172 | F: FnOnce() -> D, |
173 | { |
174 | self.map_err(|error| error.into()) |
175 | .map_err(|report| report.note(note())) |
176 | } |
177 | |
178 | fn warning<D>(self, warning: D) -> Self::Return |
179 | where |
180 | D: Display + Send + Sync + 'static, |
181 | { |
182 | self.map_err(|error| error.into()) |
183 | .map_err(|report| report.warning(warning)) |
184 | } |
185 | |
186 | fn with_warning<D, F>(self, warning: F) -> Self::Return |
187 | where |
188 | D: Display + Send + Sync + 'static, |
189 | F: FnOnce() -> D, |
190 | { |
191 | self.map_err(|error| error.into()) |
192 | .map_err(|report| report.warning(warning())) |
193 | } |
194 | |
195 | fn suggestion<D>(self, suggestion: D) -> Self::Return |
196 | where |
197 | D: Display + Send + Sync + 'static, |
198 | { |
199 | self.map_err(|error| error.into()) |
200 | .map_err(|report| report.suggestion(suggestion)) |
201 | } |
202 | |
203 | fn with_suggestion<D, F>(self, suggestion: F) -> Self::Return |
204 | where |
205 | D: Display + Send + Sync + 'static, |
206 | F: FnOnce() -> D, |
207 | { |
208 | self.map_err(|error| error.into()) |
209 | .map_err(|report| report.suggestion(suggestion())) |
210 | } |
211 | |
212 | fn with_section<D, F>(self, section: F) -> Self::Return |
213 | where |
214 | D: Display + Send + Sync + 'static, |
215 | F: FnOnce() -> D, |
216 | { |
217 | self.map_err(|error| error.into()) |
218 | .map_err(|report| report.section(section())) |
219 | } |
220 | |
221 | fn section<D>(self, section: D) -> Self::Return |
222 | where |
223 | D: Display + Send + Sync + 'static, |
224 | { |
225 | self.map_err(|error| error.into()) |
226 | .map_err(|report| report.section(section)) |
227 | } |
228 | |
229 | fn error<E2>(self, error: E2) -> Self::Return |
230 | where |
231 | E2: std::error::Error + Send + Sync + 'static, |
232 | { |
233 | self.map_err(|error| error.into()) |
234 | .map_err(|report| report.error(error)) |
235 | } |
236 | |
237 | fn with_error<E2, F>(self, error: F) -> Self::Return |
238 | where |
239 | F: FnOnce() -> E2, |
240 | E2: std::error::Error + Send + Sync + 'static, |
241 | { |
242 | self.map_err(|error| error.into()) |
243 | .map_err(|report| report.error(error())) |
244 | } |
245 | |
246 | fn suppress_backtrace(self, suppress: bool) -> Self::Return { |
247 | self.map_err(|error| error.into()) |
248 | .map_err(|report| report.suppress_backtrace(suppress)) |
249 | } |
250 | } |
251 | |
252 | pub(crate) enum HelpInfo { |
253 | Error(Box<dyn std::error::Error + Send + Sync + 'static>, Theme), |
254 | Custom(Box<dyn Display + Send + Sync + 'static>), |
255 | Note(Box<dyn Display + Send + Sync + 'static>, Theme), |
256 | Warning(Box<dyn Display + Send + Sync + 'static>, Theme), |
257 | Suggestion(Box<dyn Display + Send + Sync + 'static>, Theme), |
258 | } |
259 | |
260 | impl Display for HelpInfo { |
261 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
262 | match self { |
263 | HelpInfo::Note(note, theme) => { |
264 | write!(f, " {}: {}" , "Note" .style(theme.help_info_note), note) |
265 | } |
266 | HelpInfo::Warning(warning, theme) => write!( |
267 | f, |
268 | " {}: {}" , |
269 | "Warning" .style(theme.help_info_warning), |
270 | warning |
271 | ), |
272 | HelpInfo::Suggestion(suggestion, theme) => write!( |
273 | f, |
274 | " {}: {}" , |
275 | "Suggestion" .style(theme.help_info_suggestion), |
276 | suggestion |
277 | ), |
278 | HelpInfo::Custom(section) => write!(f, " {}" , section), |
279 | HelpInfo::Error(error, theme) => { |
280 | // a lot here |
281 | let errors = std::iter::successors( |
282 | Some(error.as_ref() as &(dyn std::error::Error + 'static)), |
283 | |e| e.source(), |
284 | ); |
285 | |
286 | write!(f, "Error:" )?; |
287 | for (n, error) in errors.enumerate() { |
288 | writeln!(f)?; |
289 | write!(indented(f).ind(n), " {}" , error.style(theme.help_info_error))?; |
290 | } |
291 | |
292 | Ok(()) |
293 | } |
294 | } |
295 | } |
296 | } |
297 | |
298 | impl fmt::Debug for HelpInfo { |
299 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
300 | match self { |
301 | HelpInfo::Note(note: &Box, ..) => f&mut DebugTuple<'_, '_> |
302 | .debug_tuple(name:"Note" ) |
303 | .field(&format_args!(" {}" , note)) |
304 | .finish(), |
305 | HelpInfo::Warning(warning: &Box, ..) => f&mut DebugTuple<'_, '_> |
306 | .debug_tuple(name:"Warning" ) |
307 | .field(&format_args!(" {}" , warning)) |
308 | .finish(), |
309 | HelpInfo::Suggestion(suggestion: &Box, ..) => f&mut DebugTuple<'_, '_> |
310 | .debug_tuple(name:"Suggestion" ) |
311 | .field(&format_args!(" {}" , suggestion)) |
312 | .finish(), |
313 | HelpInfo::Custom(custom: &Box, ..) => f&mut DebugTuple<'_, '_> |
314 | .debug_tuple(name:"CustomSection" ) |
315 | .field(&format_args!(" {}" , custom)) |
316 | .finish(), |
317 | HelpInfo::Error(error: &Box, ..) => f.debug_tuple(name:"Error" ).field(error).finish(), |
318 | } |
319 | } |
320 | } |
321 | |