1use crate::blocks::{StackTraceBlock, TextBlock};
2use crate::constants::{
3 BOTTOM_RIGHT_CORNER, HORIZONTAL_BAR, RIGHT_ARROW, TOP_RIGHT_CORNER, VERTICAL_BAR,
4 VERTICAL_RIGHT_BAR,
5};
6use crate::printer::{Printable, Printer, PrinterFormat};
7use crate::utils::whitespaces::build_space_string;
8use crate::LogLevel;
9use const_format::concatcp;
10use std::borrow::Cow;
11use std::fmt::Display;
12use std::mem;
13use yansi::Style;
14
15#[derive(Default, Debug, Clone, Eq, PartialEq)]
17pub struct StackBlock<'a> {
18 pub message: TextBlock<'a>,
19 pub traces: Vec<StackTraceBlock<'a>>,
20 pub cause: Option<Box<StackBlock<'a>>>,
21 pub show_stack_numbers: bool,
22
23 pub wrapped_by_format: bool,
25}
26
27impl<'a> StackBlock<'a> {
28 #[inline(always)]
32 pub fn new() -> Self {
33 StackBlock::default()
34 }
35
36 #[inline(always)]
40 pub fn message(mut self, message: impl Into<TextBlock<'a>>) -> Self {
41 self.message = message.into();
42 self
43 }
44
45 #[inline(always)]
47 pub fn add_stack_trace(mut self, stack_trace: StackTraceBlock<'a>) -> Self {
48 self.traces.push(stack_trace);
49 self
50 }
51
52 #[inline(always)]
54 pub fn cause(mut self, cause: StackBlock<'a>) -> Self {
55 self.cause = Some(Box::new(cause));
56 self
57 }
58
59 #[inline(always)]
61 pub fn show_stack_numbers(mut self, show_stack_numbers: bool) -> Self {
62 self.show_stack_numbers = show_stack_numbers;
63 self
64 }
65
66 #[inline(always)]
68 pub fn wrapped_by_format(mut self, wrapped_by_format: bool) -> Self {
69 self.wrapped_by_format = wrapped_by_format;
70 self
71 }
72
73 fn count_traces(&self) -> usize {
77 self.traces.len() + self.cause.as_ref().map_or(0, |v| v.count_traces())
78 }
79
80 fn print_as_caused_by(
83 &self,
84 printer: &mut Printer<'a>,
85 initial_trace_number: usize,
86 max_trace_digits: usize,
87 is_cause: bool,
88 ) {
89 if is_cause {
91 printer.push_styled_text(
92 concatcp!(
93 '\n',
94 VERTICAL_RIGHT_BAR,
95 HORIZONTAL_BAR,
96 HORIZONTAL_BAR,
97 HORIZONTAL_BAR,
98 RIGHT_ARROW,
99 " Caused by: "
100 ),
101 Style::new().bold().fg(printer.level.color()),
102 );
103 } else if self.message.is_empty() {
104 printer.push_styled_text(
105 concatcp!(BOTTOM_RIGHT_CORNER, HORIZONTAL_BAR, ' '),
106 Style::new().bold().fg(printer.level.color()),
107 );
108 } else {
109 printer.push_styled_text(
110 concatcp!(BOTTOM_RIGHT_CORNER, HORIZONTAL_BAR, RIGHT_ARROW, ' '),
111 Style::new().bold().fg(printer.level.color()),
112 );
113 }
114
115 {
116 let mut message_printer = printer.derive();
117 self.message.print(&mut message_printer);
118
119 let prefix = TextBlock::new().add_styled_text(
120 if is_cause {
121 concatcp!(VERTICAL_BAR, " ")
122 } else {
123 concatcp!(VERTICAL_BAR, " ")
124 },
125 Style::new().bold().fg(printer.level.color()),
126 );
127
128 message_printer.indent(&prefix.sections, false);
129 printer.append(message_printer);
130 }
131
132 let trace_prefix = TextBlock::new().add_styled_text(
134 concatcp!(VERTICAL_BAR, " "),
135 Style::new().bold().fg(printer.level.color()),
136 );
137 let full_trace_prefix = trace_prefix.clone().add_styled_text(
138 build_space_string(max_trace_digits + 2),
139 Style::new().bold().fg(printer.level.color()),
140 );
141
142 let mut trace_printer = printer.derive();
143 let mut next_trace_number = 0;
144 for trace in self.traces.iter() {
145 printer.push_plain_text(Cow::Borrowed("\n"));
146 trace_prefix.print(printer);
147
148 let number = self.traces.len() - next_trace_number + initial_trace_number;
149 next_trace_number += 1;
150
151 if self.show_stack_numbers {
152 printer.push_styled_text(
153 format!("[{:>width$}] ", number, width = max_trace_digits),
154 Style::new().bold().fg(printer.level.color()),
155 );
156 } else {
157 printer.push_styled_text(" at ", Style::new().bold().fg(printer.level.color()));
158 }
159
160 trace.print(&mut trace_printer);
161 trace_printer.indent(&full_trace_prefix.sections, false);
162 printer.append(mem::replace(&mut trace_printer, printer.derive()));
163 }
164
165 if let Some(cause) = &self.cause {
167 cause.print_as_caused_by(
168 printer,
169 next_trace_number + initial_trace_number,
170 max_trace_digits,
171 true,
172 );
173 }
174
175 if !is_cause {
177 printer.push_styled_text(
178 concatcp!('\n', TOP_RIGHT_CORNER, HORIZONTAL_BAR),
179 Style::new().bold().fg(printer.level.color()),
180 );
181 }
182 }
183
184 fn print_as_wrapped_by(
187 &self,
188 printer: &mut Printer<'a>,
189 initial_trace_number: usize,
190 max_trace_digits: usize,
191 is_root: bool,
192 ) {
193 let is_cause = match &self.cause {
194 Some(cause) => {
195 cause.print_as_wrapped_by(
196 printer,
197 initial_trace_number + self.traces.len(),
198 max_trace_digits,
199 false,
200 );
201 true
202 }
203 None => false,
204 };
205
206 if is_cause {
208 printer.push_styled_text(
209 concatcp!(
210 '\n',
211 VERTICAL_RIGHT_BAR,
212 HORIZONTAL_BAR,
213 HORIZONTAL_BAR,
214 HORIZONTAL_BAR,
215 RIGHT_ARROW,
216 " Wrapped by: "
217 ),
218 Style::new().bold().fg(printer.level.color()),
219 );
220 } else if self.message.is_empty() {
221 printer.push_styled_text(
222 concatcp!(BOTTOM_RIGHT_CORNER, HORIZONTAL_BAR, ' '),
223 Style::new().bold().fg(printer.level.color()),
224 );
225 } else {
226 printer.push_styled_text(
227 concatcp!(BOTTOM_RIGHT_CORNER, HORIZONTAL_BAR, RIGHT_ARROW, ' '),
228 Style::new().bold().fg(printer.level.color()),
229 );
230 }
231
232 {
233 let mut message_printer = printer.derive();
234 self.message.print(&mut message_printer);
235
236 let prefix = TextBlock::new().add_styled_text(
237 if is_cause {
238 concatcp!(VERTICAL_BAR, " ")
239 } else {
240 concatcp!(VERTICAL_BAR, " ")
241 },
242 Style::new().bold().fg(printer.level.color()),
243 );
244
245 message_printer.indent(&prefix.sections, false);
246 printer.append(message_printer);
247 }
248
249 let trace_prefix = TextBlock::new().add_styled_text(
251 concatcp!(VERTICAL_BAR, " "),
252 Style::new().bold().fg(printer.level.color()),
253 );
254 let full_trace_prefix = trace_prefix.clone().add_styled_text(
255 build_space_string(max_trace_digits + 2),
256 Style::new().bold().fg(printer.level.color()),
257 );
258
259 let mut trace_printer = printer.derive();
260 for (next_trace_number, trace) in self.traces.iter().enumerate() {
261 printer.push_plain_text(Cow::Borrowed("\n"));
262 trace_prefix.print(printer);
263
264 if self.show_stack_numbers {
265 let number = self.traces.len() - next_trace_number + initial_trace_number;
266 printer.push_styled_text(
267 format!("[{:>width$}] ", number, width = max_trace_digits),
268 Style::new().bold().fg(printer.level.color()),
269 );
270 } else {
271 printer.push_styled_text(" at ", Style::new().bold().fg(printer.level.color()));
272 }
273
274 trace.print(&mut trace_printer);
275 trace_printer.indent(&full_trace_prefix.sections, false);
276 printer.append(mem::replace(&mut trace_printer, printer.derive()));
277 }
278
279 if is_root {
281 printer.push_styled_text(
282 concatcp!('\n', TOP_RIGHT_CORNER, HORIZONTAL_BAR),
283 Style::new().bold().fg(printer.level.color()),
284 );
285 }
286 }
287
288 pub fn make_owned(self) -> StackBlock<'static> {
290 StackBlock {
291 message: self.message.make_owned(),
292 traces: self.traces.into_iter().map(|v| v.make_owned()).collect(),
293 cause: self.cause.map(|v| Box::new(v.make_owned())),
294 show_stack_numbers: self.show_stack_numbers,
295 wrapped_by_format: self.wrapped_by_format,
296 }
297 }
298}
299
300impl<'a> Printable<'a> for StackBlock<'a> {
301 fn print<'s>(&'s self, printer: &mut Printer<'a>)
302 where
303 'a: 's,
304 {
305 let max_trace_digits = format!("{}", self.count_traces()).len();
306
307 if self.wrapped_by_format {
308 self.print_as_wrapped_by(printer, 0, max_trace_digits, true)
309 } else {
310 self.print_as_caused_by(printer, 0, max_trace_digits, false)
311 }
312 }
313}
314
315impl<'a> Display for StackBlock<'a> {
316 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317 let mut printer = Printer::new(LogLevel::trace(), PrinterFormat::Plain);
318 self.print(&mut printer);
319 printer.fmt(f, PrinterFormat::Plain)
320 }
321}
322
323#[cfg(test)]
328mod tests {
329 use super::*;
330
331 #[test]
332 fn test_plain() {
333 let log = StackBlock::new();
335 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
336
337 assert_eq!(text, "╭─ \n╰─");
338
339 let log = StackBlock::new().message(TextBlock::new_plain("This is\na message"));
341 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
342
343 assert_eq!(text, "╭─▶ This is\n│ a message\n╰─");
344
345 let log = StackBlock::new()
347 .add_stack_trace(
348 StackTraceBlock::new()
349 .message(TextBlock::new_plain("This is a \n message"))
350 .file_location(TextBlock::new_plain("/a/b/c"))
351 .code_path(TextBlock::new_plain("crate::x")),
352 )
353 .add_stack_trace(
354 StackTraceBlock::new()
355 .message(TextBlock::new_plain("This is a \n message2"))
356 .file_location(TextBlock::new_plain("/a/b/c/2"))
357 .code_path(TextBlock::new_plain("crate::x::2")),
358 );
359 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
360
361 assert_eq!(text, "╭─ \n│ at /a/b/c(crate::x) - This is a \n│ message\n│ at /a/b/c/2(crate::x::2) - This is a \n│ message2\n╰─");
362
363 let log = StackBlock::new()
365 .add_stack_trace(
366 StackTraceBlock::new()
367 .message(TextBlock::new_plain("This is a \n message"))
368 .file_location(TextBlock::new_plain("/a/b/c"))
369 .code_path(TextBlock::new_plain("crate::x")),
370 )
371 .add_stack_trace(
372 StackTraceBlock::new()
373 .message(TextBlock::new_plain("This is a \n message2"))
374 .file_location(TextBlock::new_plain("/a/b/c/2"))
375 .code_path(TextBlock::new_plain("crate::x::2")),
376 )
377 .show_stack_numbers(true);
378 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
379
380 assert_eq!(text, "╭─ \n│ [2] /a/b/c(crate::x) - This is a \n│ message\n│ [1] /a/b/c/2(crate::x::2) - This is a \n│ message2\n╰─");
381
382 let log = StackBlock::new()
384 .message(TextBlock::new_plain("This is\na message"))
385 .add_stack_trace(
386 StackTraceBlock::new()
387 .message(TextBlock::new_plain("This is a \n message"))
388 .file_location(TextBlock::new_plain("/a/b/c"))
389 .code_path(TextBlock::new_plain("crate::x")),
390 )
391 .add_stack_trace(
392 StackTraceBlock::new()
393 .message(TextBlock::new_plain("This is a \n message2"))
394 .file_location(TextBlock::new_plain("/a/b/c/2"))
395 .code_path(TextBlock::new_plain("crate::x::2")),
396 )
397 .show_stack_numbers(true);
398 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
399
400 assert_eq!(text, "╭─▶ This is\n│ a message\n│ [2] /a/b/c(crate::x) - This is a \n│ message\n│ [1] /a/b/c/2(crate::x::2) - This is a \n│ message2\n╰─");
401 }
402
403 #[test]
404 fn test_styled() {
405 let log = StackBlock::new();
407 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
408
409 println!("{}", text);
410 assert_eq!(text, "\u{1b}[1;31m╭─ \n╰─\u{1b}[0m");
411
412 let log = StackBlock::new().message(TextBlock::new_plain("This is\na message"));
414 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
415
416 println!("{}", text);
417 assert_eq!(text, "\u{1b}[1;31m╭─▶ \u{1b}[0mThis is\n\u{1b}[1;31m│ \u{1b}[0ma message\n\u{1b}[1;31m╰─\u{1b}[0m");
418
419 let log = StackBlock::new()
421 .add_stack_trace(
422 StackTraceBlock::new()
423 .message(TextBlock::new_plain("This is a \n message"))
424 .file_location(TextBlock::new_plain("/a/b/c"))
425 .code_path(TextBlock::new_plain("crate::x")),
426 )
427 .add_stack_trace(
428 StackTraceBlock::new()
429 .message(TextBlock::new_plain("This is a \n message2"))
430 .file_location(TextBlock::new_plain("/a/b/c/2"))
431 .code_path(TextBlock::new_plain("crate::x::2")),
432 );
433 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
434
435 println!("{}", text);
436 assert_eq!(text, "\u{1b}[1;31m╭─ \n│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m╰─\u{1b}[0m");
437
438 let log = StackBlock::new()
440 .add_stack_trace(
441 StackTraceBlock::new()
442 .message(TextBlock::new_plain("This is a \n message"))
443 .file_location(TextBlock::new_plain("/a/b/c"))
444 .code_path(TextBlock::new_plain("crate::x")),
445 )
446 .add_stack_trace(
447 StackTraceBlock::new()
448 .message(TextBlock::new_plain("This is a \n message2"))
449 .file_location(TextBlock::new_plain("/a/b/c/2"))
450 .code_path(TextBlock::new_plain("crate::x::2")),
451 )
452 .show_stack_numbers(true);
453 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
454
455 println!("{}", text);
456 assert_eq!(text, "\u{1b}[1;31m╭─ \n│ [2] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [1] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m╰─\u{1b}[0m");
457
458 let log = StackBlock::new()
460 .message(TextBlock::new_plain("This is\na message"))
461 .add_stack_trace(
462 StackTraceBlock::new()
463 .message(TextBlock::new_plain("This is a \n message"))
464 .file_location(TextBlock::new_plain("/a/b/c"))
465 .code_path(TextBlock::new_plain("crate::x")),
466 )
467 .add_stack_trace(
468 StackTraceBlock::new()
469 .message(TextBlock::new_plain("This is a \n message2"))
470 .file_location(TextBlock::new_plain("/a/b/c/2"))
471 .code_path(TextBlock::new_plain("crate::x::2")),
472 )
473 .show_stack_numbers(true);
474 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
475
476 println!("{}", text);
477 assert_eq!(text, "\u{1b}[1;31m╭─▶ \u{1b}[0mThis is\n\u{1b}[1;31m│ \u{1b}[0ma message\n\u{1b}[1;31m│ [2] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [1] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m╰─\u{1b}[0m");
478 }
479
480 #[test]
481 fn test_plain_as_caused_by_format() {
482 let cause = StackBlock::new()
483 .message(TextBlock::new_plain("Cause\nnumber2"))
484 .add_stack_trace(
485 StackTraceBlock::new()
486 .message(TextBlock::new_plain("This is a \n message"))
487 .file_location(TextBlock::new_plain("/a/b/c"))
488 .code_path(TextBlock::new_plain("crate::x")),
489 )
490 .add_stack_trace(
491 StackTraceBlock::new()
492 .message(TextBlock::new_plain("This is a \n message2"))
493 .file_location(TextBlock::new_plain("/a/b/c/2"))
494 .code_path(TextBlock::new_plain("crate::x::2")),
495 )
496 .show_stack_numbers(true);
497 let cause = cause
498 .clone()
499 .message("Cause\nnumber1")
500 .show_stack_numbers(false)
501 .cause(cause.clone());
502
503 let log = StackBlock::new().cause(cause.clone());
505 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
506
507 assert_eq!(text, "╭─ \n├───▶ Caused by: Cause\n│ number1\n│ at /a/b/c(crate::x) - This is a \n│ message\n│ at /a/b/c/2(crate::x::2) - This is a \n│ message2\n├───▶ Caused by: Cause\n│ number2\n│ [4] /a/b/c(crate::x) - This is a \n│ message\n│ [3] /a/b/c/2(crate::x::2) - This is a \n│ message2\n╰─");
508
509 let log = StackBlock::new()
511 .message(TextBlock::new_plain("This is\na message"))
512 .cause(cause.clone());
513 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
514
515 assert_eq!(text, "╭─▶ This is\n│ a message\n├───▶ Caused by: Cause\n│ number1\n│ at /a/b/c(crate::x) - This is a \n│ message\n│ at /a/b/c/2(crate::x::2) - This is a \n│ message2\n├───▶ Caused by: Cause\n│ number2\n│ [4] /a/b/c(crate::x) - This is a \n│ message\n│ [3] /a/b/c/2(crate::x::2) - This is a \n│ message2\n╰─");
516
517 let log = StackBlock::new()
519 .add_stack_trace(
520 StackTraceBlock::new()
521 .message(TextBlock::new_plain("This is a \n message"))
522 .file_location(TextBlock::new_plain("/a/b/c"))
523 .code_path(TextBlock::new_plain("crate::x")),
524 )
525 .add_stack_trace(
526 StackTraceBlock::new()
527 .message(TextBlock::new_plain("This is a \n message2"))
528 .file_location(TextBlock::new_plain("/a/b/c/2"))
529 .code_path(TextBlock::new_plain("crate::x::2")),
530 )
531 .cause(cause.clone());
532 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
533
534 assert_eq!(text, "╭─ \n│ at /a/b/c(crate::x) - This is a \n│ message\n│ at /a/b/c/2(crate::x::2) - This is a \n│ message2\n├───▶ Caused by: Cause\n│ number1\n│ at /a/b/c(crate::x) - This is a \n│ message\n│ at /a/b/c/2(crate::x::2) - This is a \n│ message2\n├───▶ Caused by: Cause\n│ number2\n│ [6] /a/b/c(crate::x) - This is a \n│ message\n│ [5] /a/b/c/2(crate::x::2) - This is a \n│ message2\n╰─");
535
536 let log = StackBlock::new()
538 .add_stack_trace(
539 StackTraceBlock::new()
540 .message(TextBlock::new_plain("This is a \n message"))
541 .file_location(TextBlock::new_plain("/a/b/c"))
542 .code_path(TextBlock::new_plain("crate::x")),
543 )
544 .add_stack_trace(
545 StackTraceBlock::new()
546 .message(TextBlock::new_plain("This is a \n message2"))
547 .file_location(TextBlock::new_plain("/a/b/c/2"))
548 .code_path(TextBlock::new_plain("crate::x::2")),
549 )
550 .show_stack_numbers(true)
551 .cause(cause.clone());
552 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
553
554 assert_eq!(text, "╭─ \n│ [2] /a/b/c(crate::x) - This is a \n│ message\n│ [1] /a/b/c/2(crate::x::2) - This is a \n│ message2\n├───▶ Caused by: Cause\n│ number1\n│ at /a/b/c(crate::x) - This is a \n│ message\n│ at /a/b/c/2(crate::x::2) - This is a \n│ message2\n├───▶ Caused by: Cause\n│ number2\n│ [6] /a/b/c(crate::x) - This is a \n│ message\n│ [5] /a/b/c/2(crate::x::2) - This is a \n│ message2\n╰─");
555
556 let log = StackBlock::new()
558 .message(TextBlock::new_plain("This is\na message"))
559 .add_stack_trace(
560 StackTraceBlock::new()
561 .message(TextBlock::new_plain("This is a \n message"))
562 .file_location(TextBlock::new_plain("/a/b/c"))
563 .code_path(TextBlock::new_plain("crate::x")),
564 )
565 .add_stack_trace(
566 StackTraceBlock::new()
567 .message(TextBlock::new_plain("This is a \n message2"))
568 .file_location(TextBlock::new_plain("/a/b/c/2"))
569 .code_path(TextBlock::new_plain("crate::x::2")),
570 )
571 .show_stack_numbers(true)
572 .cause(cause.clone());
573 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Plain);
574
575 assert_eq!(text, "╭─▶ This is\n│ a message\n│ [2] /a/b/c(crate::x) - This is a \n│ message\n│ [1] /a/b/c/2(crate::x::2) - This is a \n│ message2\n├───▶ Caused by: Cause\n│ number1\n│ at /a/b/c(crate::x) - This is a \n│ message\n│ at /a/b/c/2(crate::x::2) - This is a \n│ message2\n├───▶ Caused by: Cause\n│ number2\n│ [6] /a/b/c(crate::x) - This is a \n│ message\n│ [5] /a/b/c/2(crate::x::2) - This is a \n│ message2\n╰─");
576 }
577
578 #[test]
579 fn test_styled_as_caused_by_format() {
580 let cause = StackBlock::new()
581 .message(TextBlock::new_plain("Cause\nnumber2"))
582 .add_stack_trace(
583 StackTraceBlock::new()
584 .message(TextBlock::new_plain("This is a \n message"))
585 .file_location(TextBlock::new_plain("/a/b/c"))
586 .code_path(TextBlock::new_plain("crate::x")),
587 )
588 .add_stack_trace(
589 StackTraceBlock::new()
590 .message(TextBlock::new_plain("This is a \n message2"))
591 .file_location(TextBlock::new_plain("/a/b/c/2"))
592 .code_path(TextBlock::new_plain("crate::x::2")),
593 )
594 .show_stack_numbers(true);
595 let cause = cause
596 .clone()
597 .message("Cause\nnumber1")
598 .show_stack_numbers(false)
599 .cause(cause.clone());
600
601 let log = StackBlock::new().cause(cause.clone());
603 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
604
605 println!("{}", text);
606 assert_eq!(text, "\u{1b}[1;31m╭─ \n├───▶ Caused by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber1\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Caused by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber2\n\u{1b}[1;31m│ [4] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [3] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m╰─\u{1b}[0m");
607
608 let log = StackBlock::new()
610 .message(TextBlock::new_plain("This is\na message"))
611 .cause(cause.clone());
612 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
613
614 println!("{}", text);
615 assert_eq!(text, "\u{1b}[1;31m╭─▶ \u{1b}[0mThis is\n\u{1b}[1;31m│ \u{1b}[0ma message\n\u{1b}[1;31m├───▶ Caused by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber1\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Caused by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber2\n\u{1b}[1;31m│ [4] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [3] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m╰─\u{1b}[0m");
616
617 let log = StackBlock::new()
619 .add_stack_trace(
620 StackTraceBlock::new()
621 .message(TextBlock::new_plain("This is a \n message"))
622 .file_location(TextBlock::new_plain("/a/b/c"))
623 .code_path(TextBlock::new_plain("crate::x")),
624 )
625 .add_stack_trace(
626 StackTraceBlock::new()
627 .message(TextBlock::new_plain("This is a \n message2"))
628 .file_location(TextBlock::new_plain("/a/b/c/2"))
629 .code_path(TextBlock::new_plain("crate::x::2")),
630 )
631 .cause(cause.clone());
632 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
633
634 println!("{}", text);
635 assert_eq!(text, "\u{1b}[1;31m╭─ \n│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Caused by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber1\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Caused by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber2\n\u{1b}[1;31m│ [6] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [5] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m╰─\u{1b}[0m");
636
637 let log = StackBlock::new()
639 .add_stack_trace(
640 StackTraceBlock::new()
641 .message(TextBlock::new_plain("This is a \n message"))
642 .file_location(TextBlock::new_plain("/a/b/c"))
643 .code_path(TextBlock::new_plain("crate::x")),
644 )
645 .add_stack_trace(
646 StackTraceBlock::new()
647 .message(TextBlock::new_plain("This is a \n message2"))
648 .file_location(TextBlock::new_plain("/a/b/c/2"))
649 .code_path(TextBlock::new_plain("crate::x::2")),
650 )
651 .show_stack_numbers(true)
652 .cause(cause.clone());
653 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
654
655 println!("{}", text);
656 assert_eq!(text, "\u{1b}[1;31m╭─ \n│ [2] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [1] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Caused by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber1\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Caused by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber2\n\u{1b}[1;31m│ [6] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [5] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m╰─\u{1b}[0m");
657
658 let log = StackBlock::new()
660 .message(TextBlock::new_plain("This is\na message"))
661 .add_stack_trace(
662 StackTraceBlock::new()
663 .message(TextBlock::new_plain("This is a \n message"))
664 .file_location(TextBlock::new_plain("/a/b/c"))
665 .code_path(TextBlock::new_plain("crate::x")),
666 )
667 .add_stack_trace(
668 StackTraceBlock::new()
669 .message(TextBlock::new_plain("This is a \n message2"))
670 .file_location(TextBlock::new_plain("/a/b/c/2"))
671 .code_path(TextBlock::new_plain("crate::x::2")),
672 )
673 .show_stack_numbers(true)
674 .cause(cause.clone());
675 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
676
677 println!("{}", text);
678 assert_eq!(text, "\u{1b}[1;31m╭─▶ \u{1b}[0mThis is\n\u{1b}[1;31m│ \u{1b}[0ma message\n\u{1b}[1;31m│ [2] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [1] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Caused by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber1\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Caused by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber2\n\u{1b}[1;31m│ [6] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [5] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m╰─\u{1b}[0m");
679 }
680
681 #[test]
682 fn test_styled_as_wrapped_by_format() {
683 let cause = StackBlock::new()
684 .message(TextBlock::new_plain("Cause\nnumber2"))
685 .add_stack_trace(
686 StackTraceBlock::new()
687 .message(TextBlock::new_plain("This is a \n message"))
688 .file_location(TextBlock::new_plain("/a/b/c"))
689 .code_path(TextBlock::new_plain("crate::x")),
690 )
691 .add_stack_trace(
692 StackTraceBlock::new()
693 .message(TextBlock::new_plain("This is a \n message2"))
694 .file_location(TextBlock::new_plain("/a/b/c/2"))
695 .code_path(TextBlock::new_plain("crate::x::2")),
696 )
697 .show_stack_numbers(true);
698 let cause = cause
699 .clone()
700 .message("Cause\nnumber1")
701 .show_stack_numbers(false)
702 .cause(cause.clone());
703
704 let log = StackBlock::new()
706 .wrapped_by_format(true)
707 .cause(cause.clone());
708 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
709
710 println!("{}", text);
711 assert_eq!(text, "\u{1b}[1;31m╭─▶ \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber2\n\u{1b}[1;31m│ [4] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [3] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Wrapped by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber1\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Wrapped by: \n╰─\u{1b}[0m");
712
713 let log = StackBlock::new()
715 .message(TextBlock::new_plain("This is\na message"))
716 .wrapped_by_format(true)
717 .cause(cause.clone());
718 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
719
720 println!("{}", text);
721 assert_eq!(text, "\u{1b}[1;31m╭─▶ \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber2\n\u{1b}[1;31m│ [4] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [3] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Wrapped by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber1\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Wrapped by: \u{1b}[0mThis is\n\u{1b}[1;31m│ \u{1b}[0ma message\n\u{1b}[1;31m╰─\u{1b}[0m");
722
723 let log = StackBlock::new()
725 .add_stack_trace(
726 StackTraceBlock::new()
727 .message(TextBlock::new_plain("This is a \n message"))
728 .file_location(TextBlock::new_plain("/a/b/c"))
729 .code_path(TextBlock::new_plain("crate::x")),
730 )
731 .add_stack_trace(
732 StackTraceBlock::new()
733 .message(TextBlock::new_plain("This is a \n message2"))
734 .file_location(TextBlock::new_plain("/a/b/c/2"))
735 .code_path(TextBlock::new_plain("crate::x::2")),
736 )
737 .wrapped_by_format(true)
738 .cause(cause.clone());
739 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
740
741 println!("{}", text);
742 assert_eq!(text, "\u{1b}[1;31m╭─▶ \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber2\n\u{1b}[1;31m│ [6] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [5] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Wrapped by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber1\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Wrapped by: \n│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m╰─\u{1b}[0m");
743
744 let log = StackBlock::new()
746 .add_stack_trace(
747 StackTraceBlock::new()
748 .message(TextBlock::new_plain("This is a \n message"))
749 .file_location(TextBlock::new_plain("/a/b/c"))
750 .code_path(TextBlock::new_plain("crate::x")),
751 )
752 .add_stack_trace(
753 StackTraceBlock::new()
754 .message(TextBlock::new_plain("This is a \n message2"))
755 .file_location(TextBlock::new_plain("/a/b/c/2"))
756 .code_path(TextBlock::new_plain("crate::x::2")),
757 )
758 .show_stack_numbers(true)
759 .wrapped_by_format(true)
760 .cause(cause.clone());
761 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
762
763 println!("{}", text);
764 assert_eq!(text, "\u{1b}[1;31m╭─▶ \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber2\n\u{1b}[1;31m│ [6] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [5] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Wrapped by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber1\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Wrapped by: \n│ [2] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [1] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m╰─\u{1b}[0m");
765
766 let log = StackBlock::new()
768 .message(TextBlock::new_plain("This is\na message"))
769 .add_stack_trace(
770 StackTraceBlock::new()
771 .message(TextBlock::new_plain("This is a \n message"))
772 .file_location(TextBlock::new_plain("/a/b/c"))
773 .code_path(TextBlock::new_plain("crate::x")),
774 )
775 .add_stack_trace(
776 StackTraceBlock::new()
777 .message(TextBlock::new_plain("This is a \n message2"))
778 .file_location(TextBlock::new_plain("/a/b/c/2"))
779 .code_path(TextBlock::new_plain("crate::x::2")),
780 )
781 .show_stack_numbers(true)
782 .wrapped_by_format(true)
783 .cause(cause.clone());
784 let text = log.print_to_string(LogLevel::error(), PrinterFormat::Styled);
785
786 println!("{}", text);
787 assert_eq!(text, "\u{1b}[1;31m╭─▶ \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber2\n\u{1b}[1;31m│ [6] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [5] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Wrapped by: \u{1b}[0mCause\n\u{1b}[1;31m│ \u{1b}[0mnumber1\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ at \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m├───▶ Wrapped by: \u{1b}[0mThis is\n\u{1b}[1;31m│ \u{1b}[0ma message\n\u{1b}[1;31m│ [2] \u{1b}[0m/a/b/c\u{1b}[1;31m(\u{1b}[0mcrate::x\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message\n\u{1b}[1;31m│ [1] \u{1b}[0m/a/b/c/2\u{1b}[1;31m(\u{1b}[0mcrate::x::2\u{1b}[1;31m) - \u{1b}[0mThis is a \n\u{1b}[1;31m│ \u{1b}[0m message2\n\u{1b}[1;31m╰─\u{1b}[0m");
788 }
789}