1 | #![cfg_attr (feature = "debug" , allow(clippy::std_instead_of_core))] |
2 | |
3 | #[cfg (feature = "debug" )] |
4 | mod internals; |
5 | |
6 | use crate::error::ParserError; |
7 | use crate::stream::Stream; |
8 | use crate::Parser; |
9 | |
10 | /// Trace the execution of the parser |
11 | /// |
12 | /// Note that [`Parser::context`] also provides high level trace information. |
13 | /// |
14 | /// See [tutorial][crate::_tutorial::chapter_8] for more details. |
15 | /// |
16 | /// # Example |
17 | /// |
18 | /// ```rust |
19 | /// # use winnow::{error::ErrMode, error::Needed}; |
20 | /// # use winnow::token::take_while; |
21 | /// # use winnow::stream::AsChar; |
22 | /// # use winnow::prelude::*; |
23 | /// use winnow::combinator::trace; |
24 | /// |
25 | /// fn short_alpha<'s>(s: &mut &'s [u8]) -> ModalResult<&'s [u8]> { |
26 | /// trace("short_alpha" , |
27 | /// take_while(3..=6, AsChar::is_alpha) |
28 | /// ).parse_next(s) |
29 | /// } |
30 | /// |
31 | /// assert_eq!(short_alpha.parse_peek(b"latin123" ), Ok((&b"123" [..], &b"latin" [..]))); |
32 | /// assert_eq!(short_alpha.parse_peek(b"lengthy" ), Ok((&b"y" [..], &b"length" [..]))); |
33 | /// assert_eq!(short_alpha.parse_peek(b"latin" ), Ok((&b"" [..], &b"latin" [..]))); |
34 | /// assert!(short_alpha.parse_peek(b"ed" ).is_err()); |
35 | /// assert!(short_alpha.parse_peek(b"12345" ).is_err()); |
36 | /// ``` |
37 | #[cfg_attr (not(feature = "debug" ), allow(unused_variables))] |
38 | #[cfg_attr (not(feature = "debug" ), allow(unused_mut))] |
39 | #[cfg_attr (not(feature = "debug" ), inline(always))] |
40 | pub fn trace<I: Stream, O, E: ParserError<I>>( |
41 | name: impl crate::lib::std::fmt::Display, |
42 | parser: impl Parser<I, O, E>, |
43 | ) -> impl Parser<I, O, E> { |
44 | #[cfg (feature = "debug" )] |
45 | { |
46 | internals::Trace::new(parser, name) |
47 | } |
48 | #[cfg (not(feature = "debug" ))] |
49 | { |
50 | parser |
51 | } |
52 | } |
53 | |
54 | #[cfg_attr (not(feature = "debug" ), allow(unused_variables))] |
55 | pub(crate) fn trace_result<T, I: Stream, E: ParserError<I>>( |
56 | name: impl crate::lib::std::fmt::Display, |
57 | res: &Result<T, E>, |
58 | ) { |
59 | #[cfg (feature = "debug" )] |
60 | { |
61 | let depth = internals::Depth::existing(); |
62 | let severity = internals::Severity::with_result(res); |
63 | internals::result(*depth, &name, severity); |
64 | } |
65 | } |
66 | |
67 | pub(crate) struct DisplayDebug<D>(pub(crate) D); |
68 | |
69 | impl<D: crate::lib::std::fmt::Debug> crate::lib::std::fmt::Display for DisplayDebug<D> { |
70 | fn fmt(&self, f: &mut crate::lib::std::fmt::Formatter<'_>) -> crate::lib::std::fmt::Result { |
71 | write!(f, " {:?}" , self.0) |
72 | } |
73 | } |
74 | |
75 | #[test ] |
76 | #[cfg (feature = "std" )] |
77 | #[cfg_attr (miri, ignore)] |
78 | #[cfg (unix)] |
79 | #[cfg (feature = "debug" )] |
80 | fn example() { |
81 | use term_transcript::{test::TestConfig, ShellOptions}; |
82 | |
83 | let path = snapbox::cmd::compile_example("string" , ["--features=debug" ]).unwrap(); |
84 | |
85 | let current_dir = path.parent().unwrap(); |
86 | let cmd = path.file_name().unwrap(); |
87 | // HACK: term_transcript doesn't allow non-UTF8 paths |
88 | let cmd = format!("./{}" , cmd.to_string_lossy()); |
89 | |
90 | TestConfig::new( |
91 | ShellOptions::default() |
92 | .with_current_dir(current_dir) |
93 | .with_env("CLICOLOR_FORCE" , "1" ), |
94 | ) |
95 | .test("assets/trace.svg" , [format!(r#"{cmd} '"abc"'"# ).as_str()]); |
96 | } |
97 | |