summaryrefslogtreecommitdiffstats
path: root/vendor/winnow/src/trace/internals.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/winnow/src/trace/internals.rs')
-rw-r--r--vendor/winnow/src/trace/internals.rs300
1 files changed, 300 insertions, 0 deletions
diff --git a/vendor/winnow/src/trace/internals.rs b/vendor/winnow/src/trace/internals.rs
new file mode 100644
index 000000000..2e91f69a8
--- /dev/null
+++ b/vendor/winnow/src/trace/internals.rs
@@ -0,0 +1,300 @@
+#![cfg(feature = "std")]
+
+use std::io::Write;
+
+use crate::error::ErrMode;
+use crate::stream::Stream;
+
+pub struct Depth {
+ depth: usize,
+ inc: bool,
+}
+
+impl Depth {
+ pub fn new() -> Self {
+ let depth = DEPTH.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
+ let inc = true;
+ Self { depth, inc }
+ }
+
+ pub fn existing() -> Self {
+ let depth = DEPTH.load(std::sync::atomic::Ordering::SeqCst);
+ let inc = false;
+ Self { depth, inc }
+ }
+}
+
+impl Drop for Depth {
+ fn drop(&mut self) {
+ if self.inc {
+ let _ = DEPTH.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
+ }
+ }
+}
+
+impl AsRef<usize> for Depth {
+ #[inline(always)]
+ fn as_ref(&self) -> &usize {
+ &self.depth
+ }
+}
+
+impl crate::lib::std::ops::Deref for Depth {
+ type Target = usize;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ &self.depth
+ }
+}
+
+static DEPTH: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
+
+pub enum Severity {
+ Success,
+ Backtrack,
+ Cut,
+ Incomplete,
+}
+
+impl Severity {
+ pub fn with_result<T, E>(result: &Result<T, ErrMode<E>>) -> Self {
+ match result {
+ Ok(_) => Self::Success,
+ Err(ErrMode::Backtrack(_)) => Self::Backtrack,
+ Err(ErrMode::Cut(_)) => Self::Cut,
+ Err(ErrMode::Incomplete(_)) => Self::Incomplete,
+ }
+ }
+}
+
+pub fn start<I: Stream>(
+ depth: usize,
+ name: &dyn crate::lib::std::fmt::Display,
+ count: usize,
+ input: &I,
+) {
+ let ansi_color = ansi_color();
+ let reset = if ansi_color {
+ anstyle::Reset.render().to_string()
+ } else {
+ "".to_owned()
+ };
+ let gutter_style = if ansi_color {
+ anstyle::Style::new().bold()
+ } else {
+ anstyle::Style::new()
+ }
+ .render();
+ let input_style = if ansi_color {
+ anstyle::Style::new().underline()
+ } else {
+ anstyle::Style::new()
+ }
+ .render();
+ let eof_style = if ansi_color {
+ anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Cyan.into()))
+ } else {
+ anstyle::Style::new()
+ }
+ .render();
+
+ let (call_width, input_width) = column_widths();
+
+ let count = if 0 < count {
+ format!(":{count}")
+ } else {
+ "".to_owned()
+ };
+ let call_column = format!("{:depth$}> {name}{count}", "");
+
+ let eof_offset = input.eof_offset();
+ let offset = input.offset_at(input_width).unwrap_or(eof_offset);
+ let (_, slice) = input.next_slice(offset);
+
+ // The debug version of `slice` might be wider, either due to rendering one byte as two nibbles or
+ // escaping in strings.
+ let mut debug_slice = format!("{:#?}", slice);
+ let (debug_slice, eof) = if let Some(debug_offset) = debug_slice
+ .char_indices()
+ .enumerate()
+ .find_map(|(pos, (offset, _))| (input_width <= pos).then(|| offset))
+ {
+ debug_slice.truncate(debug_offset);
+ let eof = "";
+ (debug_slice, eof)
+ } else {
+ let eof = if debug_slice.chars().count() < input_width {
+ "∅"
+ } else {
+ ""
+ };
+ (debug_slice, eof)
+ };
+
+ let writer = std::io::stderr();
+ let mut writer = writer.lock();
+ let _ = writeln!(writer, "{call_column:call_width$} {gutter_style}|{reset} {input_style}{debug_slice}{eof_style}{eof}{reset}");
+}
+
+pub fn end(
+ depth: usize,
+ name: &dyn crate::lib::std::fmt::Display,
+ count: usize,
+ consumed: Option<usize>,
+ severity: Severity,
+) {
+ let ansi_color = ansi_color();
+ let reset = if ansi_color {
+ anstyle::Reset.render().to_string()
+ } else {
+ "".to_owned()
+ };
+ let gutter_style = if ansi_color {
+ anstyle::Style::new().bold()
+ } else {
+ anstyle::Style::new()
+ }
+ .render();
+
+ let (call_width, _) = column_widths();
+
+ let count = if 0 < count {
+ format!(":{count}")
+ } else {
+ "".to_owned()
+ };
+ let call_column = format!("{:depth$}< {name}{count}", "");
+
+ let (mut status_style, status) = match severity {
+ Severity::Success => {
+ let style = anstyle::Style::new()
+ .fg_color(Some(anstyle::AnsiColor::Green.into()))
+ .render();
+ let status = format!("+{}", consumed.unwrap_or_default());
+ (style, status)
+ }
+ Severity::Backtrack => (
+ anstyle::Style::new()
+ .fg_color(Some(anstyle::AnsiColor::Yellow.into()))
+ .render(),
+ "backtrack".to_owned(),
+ ),
+ Severity::Cut => (
+ anstyle::Style::new()
+ .fg_color(Some(anstyle::AnsiColor::Red.into()))
+ .render(),
+ "cut".to_owned(),
+ ),
+ Severity::Incomplete => (
+ anstyle::Style::new()
+ .fg_color(Some(anstyle::AnsiColor::Red.into()))
+ .render(),
+ "incomplete".to_owned(),
+ ),
+ };
+ if !ansi_color {
+ status_style = anstyle::Style::new().render();
+ }
+
+ let writer = std::io::stderr();
+ let mut writer = writer.lock();
+ let _ = writeln!(
+ writer,
+ "{status_style}{call_column:call_width$}{reset} {gutter_style}|{reset} {status_style}{status}{reset}"
+ );
+}
+
+pub fn result(depth: usize, name: &dyn crate::lib::std::fmt::Display, severity: Severity) {
+ let ansi_color = ansi_color();
+ let reset = if ansi_color {
+ anstyle::Reset.render().to_string()
+ } else {
+ "".to_owned()
+ };
+ let gutter_style = if ansi_color {
+ anstyle::Style::new().bold()
+ } else {
+ anstyle::Style::new()
+ }
+ .render();
+
+ let (call_width, _) = column_widths();
+
+ let call_column = format!("{:depth$}| {name}", "");
+
+ let (mut status_style, status) = match severity {
+ Severity::Success => (
+ anstyle::Style::new()
+ .fg_color(Some(anstyle::AnsiColor::Green.into()))
+ .render(),
+ "",
+ ),
+ Severity::Backtrack => (
+ anstyle::Style::new()
+ .fg_color(Some(anstyle::AnsiColor::Yellow.into()))
+ .render(),
+ "backtrack",
+ ),
+ Severity::Cut => (
+ anstyle::Style::new()
+ .fg_color(Some(anstyle::AnsiColor::Red.into()))
+ .render(),
+ "cut",
+ ),
+ Severity::Incomplete => (
+ anstyle::Style::new()
+ .fg_color(Some(anstyle::AnsiColor::Red.into()))
+ .render(),
+ "incomplete",
+ ),
+ };
+ if !ansi_color {
+ status_style = anstyle::Style::new().render();
+ }
+
+ let writer = std::io::stderr();
+ let mut writer = writer.lock();
+ let _ = writeln!(
+ writer,
+ "{status_style}{call_column:call_width$}{reset} {gutter_style}|{reset} {status_style}{status}{reset}"
+ );
+}
+
+fn ansi_color() -> bool {
+ concolor::get(concolor::Stream::Stderr).ansi_color()
+}
+
+fn column_widths() -> (usize, usize) {
+ let term_width = term_width();
+
+ let min_call_width = 40;
+ let min_input_width = 20;
+ let decor_width = 3;
+ let extra_width = term_width
+ .checked_sub(min_call_width + min_input_width + decor_width)
+ .unwrap_or_default();
+ let call_width = min_call_width + 2 * extra_width / 3;
+ let input_width = min_input_width + extra_width / 3;
+
+ (call_width, input_width)
+}
+
+fn term_width() -> usize {
+ columns_env().or_else(query_width).unwrap_or(80)
+}
+
+fn query_width() -> Option<usize> {
+ use is_terminal::IsTerminal;
+ if std::io::stderr().is_terminal() {
+ terminal_size::terminal_size().map(|(w, _h)| w.0.into())
+ } else {
+ None
+ }
+}
+
+fn columns_env() -> Option<usize> {
+ std::env::var("COLUMNS")
+ .ok()
+ .and_then(|c| c.parse::<usize>().ok())
+}