From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- .../src/display_list/from_snippet.rs | 517 +++++++++++++++++++++ .../src/display_list/mod.rs | 37 ++ .../src/display_list/structs.rs | 191 ++++++++ 3 files changed, 745 insertions(+) create mode 100644 vendor/annotate-snippets-0.8.0/src/display_list/from_snippet.rs create mode 100644 vendor/annotate-snippets-0.8.0/src/display_list/mod.rs create mode 100644 vendor/annotate-snippets-0.8.0/src/display_list/structs.rs (limited to 'vendor/annotate-snippets-0.8.0/src/display_list') diff --git a/vendor/annotate-snippets-0.8.0/src/display_list/from_snippet.rs b/vendor/annotate-snippets-0.8.0/src/display_list/from_snippet.rs new file mode 100644 index 000000000..b3ba5a3dd --- /dev/null +++ b/vendor/annotate-snippets-0.8.0/src/display_list/from_snippet.rs @@ -0,0 +1,517 @@ +//! Trait for converting `Snippet` to `DisplayList`. +use super::*; +use crate::{formatter::get_term_style, snippet}; + +struct CursorLines<'a>(&'a str); + +impl<'a> CursorLines<'a> { + fn new(src: &str) -> CursorLines<'_> { + CursorLines(src) + } +} + +enum EndLine { + EOF = 0, + CRLF = 1, + LF = 2, +} + +impl<'a> Iterator for CursorLines<'a> { + type Item = (&'a str, EndLine); + + fn next(&mut self) -> Option { + if self.0.is_empty() { + None + } else { + self.0 + .find('\n') + .map(|x| { + let ret = if 0 < x { + if self.0.as_bytes()[x - 1] == b'\r' { + (&self.0[..x - 1], EndLine::LF) + } else { + (&self.0[..x], EndLine::CRLF) + } + } else { + ("", EndLine::CRLF) + }; + self.0 = &self.0[x + 1..]; + ret + }) + .or_else(|| { + let ret = Some((&self.0[..], EndLine::EOF)); + self.0 = ""; + ret + }) + } + } +} + +fn format_label( + label: Option<&str>, + style: Option, +) -> Vec> { + let mut result = vec![]; + if let Some(label) = label { + for (idx, element) in label.split("__").enumerate() { + let element_style = match style { + Some(s) => s, + None => { + if idx % 2 == 0 { + DisplayTextStyle::Regular + } else { + DisplayTextStyle::Emphasis + } + } + }; + result.push(DisplayTextFragment { + content: element, + style: element_style, + }); + } + } + result +} + +fn format_title(annotation: snippet::Annotation<'_>) -> DisplayLine<'_> { + let label = annotation.label.unwrap_or_default(); + DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::from(annotation.annotation_type), + id: annotation.id, + label: format_label(Some(&label), Some(DisplayTextStyle::Emphasis)), + }, + source_aligned: false, + continuation: false, + }) +} + +fn format_annotation(annotation: snippet::Annotation<'_>) -> Vec> { + let mut result = vec![]; + let label = annotation.label.unwrap_or_default(); + for (i, line) in label.lines().enumerate() { + result.push(DisplayLine::Raw(DisplayRawLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::from(annotation.annotation_type), + id: None, + label: format_label(Some(line), None), + }, + source_aligned: true, + continuation: i != 0, + })); + } + result +} + +fn format_slice( + mut slice: snippet::Slice<'_>, + is_first: bool, + has_footer: bool, +) -> Vec> { + let main_range = slice.annotations.get(0).map(|x| x.range.0); + let row = slice.line_start; + let origin = slice.origin.take(); + let mut body = format_body(slice, has_footer); + let header = format_header(origin, main_range, row, &body, is_first); + let mut result = vec![]; + + if let Some(header) = header { + result.push(header); + } + result.append(&mut body); + result +} + +fn format_header<'a>( + origin: Option<&'a str>, + main_range: Option, + mut row: usize, + body: &[DisplayLine<'_>], + is_first: bool, +) -> Option> { + let display_header = if is_first { + DisplayHeaderType::Initial + } else { + DisplayHeaderType::Continuation + }; + + if let Some(main_range) = main_range { + let mut col = 1; + + for item in body { + if let DisplayLine::Source { + line: DisplaySourceLine::Content { range, .. }, + .. + } = item + { + if main_range >= range.0 && main_range <= range.1 { + col = main_range - range.0 + 1; + break; + } + row += 1; + } + } + if let Some(path) = origin { + return Some(DisplayLine::Raw(DisplayRawLine::Origin { + path, + pos: Some((row, col)), + header_type: display_header, + })); + } + } + if let Some(path) = origin { + return Some(DisplayLine::Raw(DisplayRawLine::Origin { + path, + pos: None, + header_type: display_header, + })); + } + None +} + +fn fold_body(mut body: Vec>) -> Vec> { + enum Line { + Fold(usize), + Source(usize), + }; + + let mut lines = vec![]; + let mut no_annotation_lines_counter = 0; + + for (idx, line) in body.iter().enumerate() { + match line { + DisplayLine::Source { + line: DisplaySourceLine::Annotation { .. }, + .. + } => { + if no_annotation_lines_counter > 2 { + let fold_start = idx - no_annotation_lines_counter; + let fold_end = idx; + let pre_len = if no_annotation_lines_counter > 8 { + 4 + } else { + 0 + }; + let post_len = if no_annotation_lines_counter > 8 { + 2 + } else { + 1 + }; + for (i, _) in body + .iter() + .enumerate() + .take(fold_start + pre_len) + .skip(fold_start) + { + lines.push(Line::Source(i)); + } + lines.push(Line::Fold(idx)); + for (i, _) in body + .iter() + .enumerate() + .take(fold_end) + .skip(fold_end - post_len) + { + lines.push(Line::Source(i)); + } + } else { + let start = idx - no_annotation_lines_counter; + for (i, _) in body.iter().enumerate().take(idx).skip(start) { + lines.push(Line::Source(i)); + } + } + no_annotation_lines_counter = 0; + } + DisplayLine::Source { .. } => { + no_annotation_lines_counter += 1; + continue; + } + _ => { + no_annotation_lines_counter += 1; + } + } + lines.push(Line::Source(idx)); + } + + let mut new_body = vec![]; + let mut removed = 0; + for line in lines { + match line { + Line::Source(i) => { + new_body.push(body.remove(i - removed)); + removed += 1; + } + Line::Fold(i) => { + if let DisplayLine::Source { + line: DisplaySourceLine::Annotation { .. }, + ref inline_marks, + .. + } = body.get(i - removed).unwrap() + { + new_body.push(DisplayLine::Fold { + inline_marks: inline_marks.clone(), + }) + } else { + unreachable!() + } + } + } + } + + new_body +} + +fn format_body(slice: snippet::Slice<'_>, has_footer: bool) -> Vec> { + let source_len = slice.source.chars().count(); + if let Some(bigger) = slice.annotations.iter().find_map(|x| { + if source_len < x.range.1 { + Some(x.range) + } else { + None + } + }) { + panic!( + "SourceAnnotation range `{:?}` is bigger than source length `{}`", + bigger, source_len + ) + } + + let mut body = vec![]; + let mut current_line = slice.line_start; + let mut current_index = 0; + let mut line_index_ranges = vec![]; + + for (line, end_line) in CursorLines::new(slice.source) { + let line_length = line.chars().count(); + let line_range = (current_index, current_index + line_length); + body.push(DisplayLine::Source { + lineno: Some(current_line), + inline_marks: vec![], + line: DisplaySourceLine::Content { + text: line, + range: line_range, + }, + }); + line_index_ranges.push(line_range); + current_line += 1; + current_index += line_length + end_line as usize; + } + + let mut annotation_line_count = 0; + let mut annotations = slice.annotations; + for (idx, (line_start, line_end)) in line_index_ranges.into_iter().enumerate() { + // It would be nice to use filter_drain here once it's stable. + annotations = annotations + .into_iter() + .filter(|annotation| { + let body_idx = idx + annotation_line_count; + let annotation_type = match annotation.annotation_type { + snippet::AnnotationType::Error => DisplayAnnotationType::None, + snippet::AnnotationType::Warning => DisplayAnnotationType::None, + _ => DisplayAnnotationType::from(annotation.annotation_type), + }; + match annotation.range { + (start, _) if start > line_end => true, + (start, end) + if start >= line_start && end <= line_end + || start == line_end && end - start <= 1 => + { + let range = (start - line_start, end - line_start); + body.insert( + body_idx + 1, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + annotation: Annotation { + annotation_type, + id: None, + label: format_label(Some(&annotation.label), None), + }, + range, + annotation_type: DisplayAnnotationType::from( + annotation.annotation_type, + ), + annotation_part: DisplayAnnotationPart::Standalone, + }, + }, + ); + annotation_line_count += 1; + false + } + (start, end) if start >= line_start && start <= line_end && end > line_end => { + if start - line_start == 0 { + if let DisplayLine::Source { + ref mut inline_marks, + .. + } = body[body_idx] + { + inline_marks.push(DisplayMark { + mark_type: DisplayMarkType::AnnotationStart, + annotation_type: DisplayAnnotationType::from( + annotation.annotation_type, + ), + }); + } + } else { + let range = (start - line_start, start - line_start + 1); + body.insert( + body_idx + 1, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Annotation { + annotation: Annotation { + annotation_type: DisplayAnnotationType::None, + id: None, + label: vec![], + }, + range, + annotation_type: DisplayAnnotationType::from( + annotation.annotation_type, + ), + annotation_part: DisplayAnnotationPart::MultilineStart, + }, + }, + ); + annotation_line_count += 1; + } + true + } + (start, end) if start < line_start && end > line_end => { + if let DisplayLine::Source { + ref mut inline_marks, + .. + } = body[body_idx] + { + inline_marks.push(DisplayMark { + mark_type: DisplayMarkType::AnnotationThrough, + annotation_type: DisplayAnnotationType::from( + annotation.annotation_type, + ), + }); + } + true + } + (start, end) if start < line_start && end >= line_start && end <= line_end => { + if let DisplayLine::Source { + ref mut inline_marks, + .. + } = body[body_idx] + { + inline_marks.push(DisplayMark { + mark_type: DisplayMarkType::AnnotationThrough, + annotation_type: DisplayAnnotationType::from( + annotation.annotation_type, + ), + }); + } + + let range = (end - line_start, end - line_start + 1); + body.insert( + body_idx + 1, + DisplayLine::Source { + lineno: None, + inline_marks: vec![DisplayMark { + mark_type: DisplayMarkType::AnnotationThrough, + annotation_type: DisplayAnnotationType::from( + annotation.annotation_type, + ), + }], + line: DisplaySourceLine::Annotation { + annotation: Annotation { + annotation_type, + id: None, + label: format_label(Some(&annotation.label), None), + }, + range, + annotation_type: DisplayAnnotationType::from( + annotation.annotation_type, + ), + annotation_part: DisplayAnnotationPart::MultilineEnd, + }, + }, + ); + annotation_line_count += 1; + false + } + _ => true, + } + }) + .collect(); + } + + if slice.fold { + body = fold_body(body); + } + + body.insert( + 0, + DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }, + ); + if has_footer { + body.push(DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }); + } else if let Some(DisplayLine::Source { .. }) = body.last() { + body.push(DisplayLine::Source { + lineno: None, + inline_marks: vec![], + line: DisplaySourceLine::Empty, + }); + } + body +} + +impl<'a> From> for DisplayList<'a> { + fn from( + snippet::Snippet { + title, + footer, + slices, + opt, + }: snippet::Snippet<'a>, + ) -> DisplayList<'a> { + let mut body = vec![]; + if let Some(annotation) = title { + body.push(format_title(annotation)); + } + + for (idx, slice) in slices.into_iter().enumerate() { + body.append(&mut format_slice(slice, idx == 0, !footer.is_empty())); + } + + for annotation in footer { + body.append(&mut format_annotation(annotation)); + } + + let FormatOptions { + color, + anonymized_line_numbers, + } = opt; + + Self { + body, + stylesheet: get_term_style(color), + anonymized_line_numbers, + } + } +} + +impl From for DisplayAnnotationType { + fn from(at: snippet::AnnotationType) -> Self { + match at { + snippet::AnnotationType::Error => DisplayAnnotationType::Error, + snippet::AnnotationType::Warning => DisplayAnnotationType::Warning, + snippet::AnnotationType::Info => DisplayAnnotationType::Info, + snippet::AnnotationType::Note => DisplayAnnotationType::Note, + snippet::AnnotationType::Help => DisplayAnnotationType::Help, + } + } +} diff --git a/vendor/annotate-snippets-0.8.0/src/display_list/mod.rs b/vendor/annotate-snippets-0.8.0/src/display_list/mod.rs new file mode 100644 index 000000000..224a9f580 --- /dev/null +++ b/vendor/annotate-snippets-0.8.0/src/display_list/mod.rs @@ -0,0 +1,37 @@ +//! display_list module stores the output model for the snippet. +//! +//! `DisplayList` is a central structure in the crate, which contains +//! the structured list of lines to be displayed. +//! +//! It is made of two types of lines: `Source` and `Raw`. All `Source` lines +//! are structured using four columns: +//! +//! ```text +//! /------------ (1) Line number column. +//! | /--------- (2) Line number column delimiter. +//! | | /------- (3) Inline marks column. +//! | | | /--- (4) Content column with the source and annotations for slices. +//! | | | | +//! ============================================================================= +//! error[E0308]: mismatched types +//! --> src/format.rs:51:5 +//! | +//! 151 | / fn test() -> String { +//! 152 | | return "test"; +//! 153 | | } +//! | |___^ error: expected `String`, for `&str`. +//! | +//! ``` +//! +//! The first two lines of the example above are `Raw` lines, while the rest +//! are `Source` lines. +//! +//! `DisplayList` does not store column alignment information, and those are +//! only calculated by the implementation of `std::fmt::Display` using information such as +//! styling. +//! +//! The above snippet has been built out of the following structure: +mod from_snippet; +mod structs; + +pub use self::structs::*; diff --git a/vendor/annotate-snippets-0.8.0/src/display_list/structs.rs b/vendor/annotate-snippets-0.8.0/src/display_list/structs.rs new file mode 100644 index 000000000..8f6d8fcf1 --- /dev/null +++ b/vendor/annotate-snippets-0.8.0/src/display_list/structs.rs @@ -0,0 +1,191 @@ +use std::fmt; + +use crate::formatter::{get_term_style, style::Stylesheet}; + +/// List of lines to be displayed. +pub struct DisplayList<'a> { + pub body: Vec>, + pub stylesheet: Box, + pub anonymized_line_numbers: bool, +} + +impl<'a> From>> for DisplayList<'a> { + fn from(body: Vec>) -> DisplayList<'a> { + Self { + body, + anonymized_line_numbers: false, + stylesheet: get_term_style(false), + } + } +} + +impl<'a> PartialEq for DisplayList<'a> { + fn eq(&self, other: &Self) -> bool { + self.body == other.body && self.anonymized_line_numbers == other.anonymized_line_numbers + } +} + +impl<'a> fmt::Debug for DisplayList<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DisplayList") + .field("body", &self.body) + .field("anonymized_line_numbers", &self.anonymized_line_numbers) + .finish() + } +} + +#[derive(Debug, Default, Copy, Clone)] +pub struct FormatOptions { + pub color: bool, + pub anonymized_line_numbers: bool, +} + +/// Inline annotation which can be used in either Raw or Source line. +#[derive(Debug, PartialEq)] +pub struct Annotation<'a> { + pub annotation_type: DisplayAnnotationType, + pub id: Option<&'a str>, + pub label: Vec>, +} + +/// A single line used in `DisplayList`. +#[derive(Debug, PartialEq)] +pub enum DisplayLine<'a> { + /// A line with `lineno` portion of the slice. + Source { + lineno: Option, + inline_marks: Vec, + line: DisplaySourceLine<'a>, + }, + + /// A line indicating a folded part of the slice. + Fold { inline_marks: Vec }, + + /// A line which is displayed outside of slices. + Raw(DisplayRawLine<'a>), +} + +/// A source line. +#[derive(Debug, PartialEq)] +pub enum DisplaySourceLine<'a> { + /// A line with the content of the Slice. + Content { + text: &'a str, + range: (usize, usize), // meta information for annotation placement. + }, + + /// An annotation line which is displayed in context of the slice. + Annotation { + annotation: Annotation<'a>, + range: (usize, usize), + annotation_type: DisplayAnnotationType, + annotation_part: DisplayAnnotationPart, + }, + + /// An empty source line. + Empty, +} + +/// Raw line - a line which does not have the `lineno` part and is not considered +/// a part of the snippet. +#[derive(Debug, PartialEq)] +pub enum DisplayRawLine<'a> { + /// A line which provides information about the location of the given + /// slice in the project structure. + Origin { + path: &'a str, + pos: Option<(usize, usize)>, + header_type: DisplayHeaderType, + }, + + /// An annotation line which is not part of any snippet. + Annotation { + annotation: Annotation<'a>, + + /// If set to `true`, the annotation will be aligned to the + /// lineno delimiter of the snippet. + source_aligned: bool, + /// If set to `true`, only the label of the `Annotation` will be + /// displayed. It allows for a multiline annotation to be aligned + /// without displaing the meta information (`type` and `id`) to be + /// displayed on each line. + continuation: bool, + }, +} + +/// An inline text fragment which any label is composed of. +#[derive(Debug, PartialEq)] +pub struct DisplayTextFragment<'a> { + pub content: &'a str, + pub style: DisplayTextStyle, +} + +/// A style for the `DisplayTextFragment` which can be visually formatted. +/// +/// This information may be used to emphasis parts of the label. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum DisplayTextStyle { + Regular, + Emphasis, +} + +/// An indicator of what part of the annotation a given `Annotation` is. +#[derive(Debug, Clone, PartialEq)] +pub enum DisplayAnnotationPart { + /// A standalone, single-line annotation. + Standalone, + /// A continuation of a multi-line label of an annotation. + LabelContinuation, + /// A consequitive annotation in case multiple annotations annotate a single line. + Consequitive, + /// A line starting a multiline annotation. + MultilineStart, + /// A line ending a multiline annotation. + MultilineEnd, +} + +/// A visual mark used in `inline_marks` field of the `DisplaySourceLine`. +#[derive(Debug, Clone, PartialEq)] +pub struct DisplayMark { + pub mark_type: DisplayMarkType, + pub annotation_type: DisplayAnnotationType, +} + +/// A type of the `DisplayMark`. +#[derive(Debug, Clone, PartialEq)] +pub enum DisplayMarkType { + /// A mark indicating a multiline annotation going through the current line. + AnnotationThrough, + /// A mark indicating a multiline annotation starting on the given line. + AnnotationStart, +} + +/// A type of the `Annotation` which may impact the sigils, style or text displayed. +/// +/// There are several ways in which the `DisplayListFormatter` uses this information +/// when formatting the `DisplayList`: +/// +/// * An annotation may display the name of the type like `error` or `info`. +/// * An underline for `Error` may be `^^^` while for `Warning` it coule be `---`. +/// * `ColorStylesheet` may use different colors for different annotations. +#[derive(Debug, Clone, PartialEq)] +pub enum DisplayAnnotationType { + None, + Error, + Warning, + Info, + Note, + Help, +} + +/// Information whether the header is the initial one or a consequitive one +/// for multi-slice cases. +// TODO: private +#[derive(Debug, Clone, PartialEq)] +pub enum DisplayHeaderType { + /// Initial header is the first header in the snippet. + Initial, + + /// Continuation marks all headers of following slices in the snippet. + Continuation, +} -- cgit v1.2.3