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 | |
147 | impl<T, E> Section for Result<T, E> |
148 | where |
149 | E: Into<Report>, |
150 | { |
151 | type Return = Result<T, Report>; |
152 | |
153 | fn note<D>(self, note: D) -> Self::Return |
154 | where |
155 | D: Display + Send + Sync + 'static, |
156 | { |
157 | self.map_err(|error| error.into()) |
158 | .map_err(|report| report.note(note)) |
159 | } |
160 | |
161 | fn with_note<D, F>(self, note: F) -> Self::Return |
162 | where |
163 | D: Display + Send + Sync + 'static, |
164 | F: FnOnce() -> D, |
165 | { |
166 | self.map_err(|error| error.into()) |
167 | .map_err(|report| report.note(note())) |
168 | } |
169 | |
170 | fn warning<D>(self, warning: D) -> Self::Return |
171 | where |
172 | D: Display + Send + Sync + 'static, |
173 | { |
174 | self.map_err(|error| error.into()) |
175 | .map_err(|report| report.warning(warning)) |
176 | } |
177 | |
178 | fn with_warning<D, F>(self, warning: F) -> Self::Return |
179 | where |
180 | D: Display + Send + Sync + 'static, |
181 | F: FnOnce() -> D, |
182 | { |
183 | self.map_err(|error| error.into()) |
184 | .map_err(|report| report.warning(warning())) |
185 | } |
186 | |
187 | fn suggestion<D>(self, suggestion: D) -> Self::Return |
188 | where |
189 | D: Display + Send + Sync + 'static, |
190 | { |
191 | self.map_err(|error| error.into()) |
192 | .map_err(|report| report.suggestion(suggestion)) |
193 | } |
194 | |
195 | fn with_suggestion<D, F>(self, suggestion: F) -> Self::Return |
196 | where |
197 | D: Display + Send + Sync + 'static, |
198 | F: FnOnce() -> D, |
199 | { |
200 | self.map_err(|error| error.into()) |
201 | .map_err(|report| report.suggestion(suggestion())) |
202 | } |
203 | |
204 | fn with_section<D, F>(self, section: F) -> Self::Return |
205 | where |
206 | D: Display + Send + Sync + 'static, |
207 | F: FnOnce() -> D, |
208 | { |
209 | self.map_err(|error| error.into()) |
210 | .map_err(|report| report.section(section())) |
211 | } |
212 | |
213 | fn section<D>(self, section: D) -> Self::Return |
214 | where |
215 | D: Display + Send + Sync + 'static, |
216 | { |
217 | self.map_err(|error| error.into()) |
218 | .map_err(|report| report.section(section)) |
219 | } |
220 | |
221 | fn error<E2>(self, error: E2) -> Self::Return |
222 | where |
223 | E2: std::error::Error + Send + Sync + 'static, |
224 | { |
225 | self.map_err(|error| error.into()) |
226 | .map_err(|report| report.error(error)) |
227 | } |
228 | |
229 | fn with_error<E2, F>(self, error: F) -> Self::Return |
230 | where |
231 | F: FnOnce() -> E2, |
232 | E2: std::error::Error + Send + Sync + 'static, |
233 | { |
234 | self.map_err(|error| error.into()) |
235 | .map_err(|report| report.error(error())) |
236 | } |
237 | } |
238 | |
239 | pub(crate) enum HelpInfo { |
240 | Error(Box<dyn std::error::Error + Send + Sync + 'static>, Theme), |
241 | Custom(Box<dyn Display + Send + Sync + 'static>), |
242 | Note(Box<dyn Display + Send + Sync + 'static>, Theme), |
243 | Warning(Box<dyn Display + Send + Sync + 'static>, Theme), |
244 | Suggestion(Box<dyn Display + Send + Sync + 'static>, Theme), |
245 | } |
246 | |
247 | impl Display for HelpInfo { |
248 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
249 | match self { |
250 | HelpInfo::Note(note, theme) => { |
251 | write!(f, " {}: {}" , "Note" .style(theme.help_info_note), note) |
252 | } |
253 | HelpInfo::Warning(warning, theme) => write!( |
254 | f, |
255 | " {}: {}" , |
256 | "Warning" .style(theme.help_info_warning), |
257 | warning |
258 | ), |
259 | HelpInfo::Suggestion(suggestion, theme) => write!( |
260 | f, |
261 | " {}: {}" , |
262 | "Suggestion" .style(theme.help_info_suggestion), |
263 | suggestion |
264 | ), |
265 | HelpInfo::Custom(section) => write!(f, " {}" , section), |
266 | HelpInfo::Error(error, theme) => { |
267 | // a lot here |
268 | let errors = std::iter::successors( |
269 | Some(error.as_ref() as &(dyn std::error::Error + 'static)), |
270 | |e| e.source(), |
271 | ); |
272 | |
273 | write!(f, "Error:" )?; |
274 | for (n, error) in errors.enumerate() { |
275 | writeln!(f)?; |
276 | write!(indented(f).ind(n), " {}" , error.style(theme.help_info_error))?; |
277 | } |
278 | |
279 | Ok(()) |
280 | } |
281 | } |
282 | } |
283 | } |
284 | |
285 | impl fmt::Debug for HelpInfo { |
286 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
287 | match self { |
288 | HelpInfo::Note(note: &Box, ..) => f&mut DebugTuple<'_, '_> |
289 | .debug_tuple(name:"Note" ) |
290 | .field(&format_args!(" {}" , note)) |
291 | .finish(), |
292 | HelpInfo::Warning(warning: &Box, ..) => f&mut DebugTuple<'_, '_> |
293 | .debug_tuple(name:"Warning" ) |
294 | .field(&format_args!(" {}" , warning)) |
295 | .finish(), |
296 | HelpInfo::Suggestion(suggestion: &Box, ..) => f&mut DebugTuple<'_, '_> |
297 | .debug_tuple(name:"Suggestion" ) |
298 | .field(&format_args!(" {}" , suggestion)) |
299 | .finish(), |
300 | HelpInfo::Custom(custom: &Box, ..) => f&mut DebugTuple<'_, '_> |
301 | .debug_tuple(name:"CustomSection" ) |
302 | .field(&format_args!(" {}" , custom)) |
303 | .finish(), |
304 | HelpInfo::Error(error: &Box, ..) => f.debug_tuple(name:"Error" ).field(error).finish(), |
305 | } |
306 | } |
307 | } |
308 | |