| 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 | |