summaryrefslogtreecommitdiffstats
path: root/vendor/annotate-snippets-0.8.0/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /vendor/annotate-snippets-0.8.0/src
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--vendor/annotate-snippets-0.8.0/src/display_list/from_snippet.rs517
-rw-r--r--vendor/annotate-snippets-0.8.0/src/display_list/mod.rs37
-rw-r--r--vendor/annotate-snippets-0.8.0/src/display_list/structs.rs191
-rw-r--r--vendor/annotate-snippets-0.8.0/src/formatter/mod.rs397
-rw-r--r--vendor/annotate-snippets-0.8.0/src/formatter/style.rs52
-rw-r--r--vendor/annotate-snippets-0.8.0/src/lib.rs54
-rw-r--r--vendor/annotate-snippets-0.8.0/src/snippet.rs88
-rw-r--r--vendor/annotate-snippets-0.8.0/src/stylesheets/color.rs50
-rw-r--r--vendor/annotate-snippets-0.8.0/src/stylesheets/mod.rs11
-rw-r--r--vendor/annotate-snippets-0.8.0/src/stylesheets/no_color.rs31
10 files changed, 1428 insertions, 0 deletions
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<Self::Item> {
+ 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<DisplayTextStyle>,
+) -> Vec<DisplayTextFragment<'_>> {
+ 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<DisplayLine<'_>> {
+ 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<DisplayLine<'_>> {
+ 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<usize>,
+ mut row: usize,
+ body: &[DisplayLine<'_>],
+ is_first: bool,
+) -> Option<DisplayLine<'a>> {
+ 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<DisplayLine<'_>>) -> Vec<DisplayLine<'_>> {
+ 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<DisplayLine<'_>> {
+ 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<snippet::Snippet<'a>> 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<snippet::AnnotationType> 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<DisplayLine<'a>>,
+ pub stylesheet: Box<dyn Stylesheet>,
+ pub anonymized_line_numbers: bool,
+}
+
+impl<'a> From<Vec<DisplayLine<'a>>> for DisplayList<'a> {
+ fn from(body: Vec<DisplayLine<'a>>) -> 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<DisplayTextFragment<'a>>,
+}
+
+/// A single line used in `DisplayList`.
+#[derive(Debug, PartialEq)]
+pub enum DisplayLine<'a> {
+ /// A line with `lineno` portion of the slice.
+ Source {
+ lineno: Option<usize>,
+ inline_marks: Vec<DisplayMark>,
+ line: DisplaySourceLine<'a>,
+ },
+
+ /// A line indicating a folded part of the slice.
+ Fold { inline_marks: Vec<DisplayMark> },
+
+ /// 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,
+}
diff --git a/vendor/annotate-snippets-0.8.0/src/formatter/mod.rs b/vendor/annotate-snippets-0.8.0/src/formatter/mod.rs
new file mode 100644
index 000000000..e93aeb329
--- /dev/null
+++ b/vendor/annotate-snippets-0.8.0/src/formatter/mod.rs
@@ -0,0 +1,397 @@
+use std::{
+ cmp,
+ fmt::{self, Display, Write},
+};
+
+pub mod style;
+
+use self::style::{Style, StyleClass, Stylesheet};
+
+#[cfg(feature = "color")]
+use crate::stylesheets::color::AnsiTermStylesheet;
+use crate::{display_list::*, stylesheets::no_color::NoColorStylesheet};
+
+fn format_repeat_char(c: char, n: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ for _ in 0..n {
+ f.write_char(c)?;
+ }
+ Ok(())
+}
+
+#[inline]
+fn is_annotation_empty(annotation: &Annotation<'_>) -> bool {
+ annotation
+ .label
+ .iter()
+ .all(|fragment| fragment.content.is_empty())
+}
+
+#[cfg(feature = "color")]
+#[inline]
+pub fn get_term_style(color: bool) -> Box<dyn Stylesheet> {
+ if color {
+ Box::new(AnsiTermStylesheet)
+ } else {
+ Box::new(NoColorStylesheet)
+ }
+}
+
+#[cfg(not(feature = "color"))]
+#[inline]
+pub fn get_term_style(_color: bool) -> Box<dyn Stylesheet> {
+ Box::new(NoColorStylesheet)
+}
+
+impl<'a> fmt::Display for DisplayList<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let lineno_width = self.body.iter().fold(0, |max, line| match line {
+ DisplayLine::Source {
+ lineno: Some(lineno),
+ ..
+ } => {
+ // The largest line is the largest width.
+ cmp::max(*lineno, max)
+ }
+ _ => max,
+ });
+ let lineno_width = if lineno_width == 0 {
+ lineno_width
+ } else if self.anonymized_line_numbers {
+ Self::ANONYMIZED_LINE_NUM.len()
+ } else {
+ ((lineno_width as f64).log10().floor() as usize) + 1
+ };
+ let inline_marks_width = self.body.iter().fold(0, |max, line| match line {
+ DisplayLine::Source { inline_marks, .. } => cmp::max(inline_marks.len(), max),
+ _ => max,
+ });
+
+ for (i, line) in self.body.iter().enumerate() {
+ self.format_line(line, lineno_width, inline_marks_width, f)?;
+ if i + 1 < self.body.len() {
+ f.write_char('\n')?;
+ }
+ }
+ Ok(())
+ }
+}
+
+impl<'a> DisplayList<'a> {
+ const ANONYMIZED_LINE_NUM: &'static str = "LL";
+ const ERROR_TXT: &'static str = "error";
+ const HELP_TXT: &'static str = "help";
+ const INFO_TXT: &'static str = "info";
+ const NOTE_TXT: &'static str = "note";
+ const WARNING_TXT: &'static str = "warning";
+
+ #[inline]
+ fn format_annotation_type(
+ annotation_type: &DisplayAnnotationType,
+ f: &mut fmt::Formatter<'_>,
+ ) -> fmt::Result {
+ match annotation_type {
+ DisplayAnnotationType::Error => f.write_str(Self::ERROR_TXT),
+ DisplayAnnotationType::Help => f.write_str(Self::HELP_TXT),
+ DisplayAnnotationType::Info => f.write_str(Self::INFO_TXT),
+ DisplayAnnotationType::Note => f.write_str(Self::NOTE_TXT),
+ DisplayAnnotationType::Warning => f.write_str(Self::WARNING_TXT),
+ DisplayAnnotationType::None => Ok(()),
+ }
+ }
+
+ fn annotation_type_len(annotation_type: &DisplayAnnotationType) -> usize {
+ match annotation_type {
+ DisplayAnnotationType::Error => Self::ERROR_TXT.len(),
+ DisplayAnnotationType::Help => Self::HELP_TXT.len(),
+ DisplayAnnotationType::Info => Self::INFO_TXT.len(),
+ DisplayAnnotationType::Note => Self::NOTE_TXT.len(),
+ DisplayAnnotationType::Warning => Self::WARNING_TXT.len(),
+ DisplayAnnotationType::None => 0,
+ }
+ }
+
+ fn get_annotation_style(&self, annotation_type: &DisplayAnnotationType) -> Box<dyn Style> {
+ self.stylesheet.get_style(match annotation_type {
+ DisplayAnnotationType::Error => StyleClass::Error,
+ DisplayAnnotationType::Warning => StyleClass::Warning,
+ DisplayAnnotationType::Info => StyleClass::Info,
+ DisplayAnnotationType::Note => StyleClass::Note,
+ DisplayAnnotationType::Help => StyleClass::Help,
+ DisplayAnnotationType::None => StyleClass::None,
+ })
+ }
+
+ fn format_label(
+ &self,
+ label: &[DisplayTextFragment<'_>],
+ f: &mut fmt::Formatter<'_>,
+ ) -> fmt::Result {
+ let emphasis_style = self.stylesheet.get_style(StyleClass::Emphasis);
+
+ for fragment in label {
+ match fragment.style {
+ DisplayTextStyle::Regular => fragment.content.fmt(f)?,
+ DisplayTextStyle::Emphasis => emphasis_style.paint(&fragment.content, f)?,
+ }
+ }
+ Ok(())
+ }
+
+ fn format_annotation(
+ &self,
+ annotation: &Annotation<'_>,
+ continuation: bool,
+ in_source: bool,
+ f: &mut fmt::Formatter<'_>,
+ ) -> fmt::Result {
+ let color = self.get_annotation_style(&annotation.annotation_type);
+ let formatted_len = if let Some(id) = &annotation.id {
+ 2 + id.len() + Self::annotation_type_len(&annotation.annotation_type)
+ } else {
+ Self::annotation_type_len(&annotation.annotation_type)
+ };
+
+ if continuation {
+ format_repeat_char(' ', formatted_len + 2, f)?;
+ return self.format_label(&annotation.label, f);
+ }
+ if formatted_len == 0 {
+ self.format_label(&annotation.label, f)
+ } else {
+ color.paint_fn(
+ Box::new(|f| {
+ Self::format_annotation_type(&annotation.annotation_type, f)?;
+ if let Some(id) = &annotation.id {
+ f.write_char('[')?;
+ f.write_str(id)?;
+ f.write_char(']')?;
+ }
+ Ok(())
+ }),
+ f,
+ )?;
+ if !is_annotation_empty(annotation) {
+ if in_source {
+ color.paint_fn(
+ Box::new(|f| {
+ f.write_str(": ")?;
+ self.format_label(&annotation.label, f)
+ }),
+ f,
+ )?;
+ } else {
+ f.write_str(": ")?;
+ self.format_label(&annotation.label, f)?;
+ }
+ }
+ Ok(())
+ }
+ }
+
+ #[inline]
+ fn format_source_line(
+ &self,
+ line: &DisplaySourceLine<'_>,
+ f: &mut fmt::Formatter<'_>,
+ ) -> fmt::Result {
+ match line {
+ DisplaySourceLine::Empty => Ok(()),
+ DisplaySourceLine::Content { text, .. } => {
+ f.write_char(' ')?;
+ text.fmt(f)
+ }
+ DisplaySourceLine::Annotation {
+ range,
+ annotation,
+ annotation_type,
+ annotation_part,
+ } => {
+ let indent_char = match annotation_part {
+ DisplayAnnotationPart::Standalone => ' ',
+ DisplayAnnotationPart::LabelContinuation => ' ',
+ DisplayAnnotationPart::Consequitive => ' ',
+ DisplayAnnotationPart::MultilineStart => '_',
+ DisplayAnnotationPart::MultilineEnd => '_',
+ };
+ let mark = match annotation_type {
+ DisplayAnnotationType::Error => '^',
+ DisplayAnnotationType::Warning => '-',
+ DisplayAnnotationType::Info => '-',
+ DisplayAnnotationType::Note => '-',
+ DisplayAnnotationType::Help => '-',
+ DisplayAnnotationType::None => ' ',
+ };
+ let color = self.get_annotation_style(annotation_type);
+ let indent_length = match annotation_part {
+ DisplayAnnotationPart::LabelContinuation => range.1,
+ DisplayAnnotationPart::Consequitive => range.1,
+ _ => range.0,
+ };
+
+ color.paint_fn(
+ Box::new(|f| {
+ format_repeat_char(indent_char, indent_length + 1, f)?;
+ format_repeat_char(mark, range.1 - indent_length, f)
+ }),
+ f,
+ )?;
+
+ if !is_annotation_empty(&annotation) {
+ f.write_char(' ')?;
+ color.paint_fn(
+ Box::new(|f| {
+ self.format_annotation(
+ annotation,
+ annotation_part == &DisplayAnnotationPart::LabelContinuation,
+ true,
+ f,
+ )
+ }),
+ f,
+ )?;
+ }
+
+ Ok(())
+ }
+ }
+ }
+
+ #[inline]
+ fn format_raw_line(
+ &self,
+ line: &DisplayRawLine<'_>,
+ lineno_width: usize,
+ f: &mut fmt::Formatter<'_>,
+ ) -> fmt::Result {
+ match line {
+ DisplayRawLine::Origin {
+ path,
+ pos,
+ header_type,
+ } => {
+ let header_sigil = match header_type {
+ DisplayHeaderType::Initial => "-->",
+ DisplayHeaderType::Continuation => ":::",
+ };
+ let lineno_color = self.stylesheet.get_style(StyleClass::LineNo);
+
+ if let Some((col, row)) = pos {
+ format_repeat_char(' ', lineno_width, f)?;
+ lineno_color.paint(header_sigil, f)?;
+ f.write_char(' ')?;
+ path.fmt(f)?;
+ f.write_char(':')?;
+ col.fmt(f)?;
+ f.write_char(':')?;
+ row.fmt(f)
+ } else {
+ format_repeat_char(' ', lineno_width, f)?;
+ lineno_color.paint(header_sigil, f)?;
+ f.write_char(' ')?;
+ path.fmt(f)
+ }
+ }
+ DisplayRawLine::Annotation {
+ annotation,
+ source_aligned,
+ continuation,
+ } => {
+ if *source_aligned {
+ if *continuation {
+ format_repeat_char(' ', lineno_width + 3, f)?;
+ self.format_annotation(annotation, *continuation, false, f)
+ } else {
+ let lineno_color = self.stylesheet.get_style(StyleClass::LineNo);
+ format_repeat_char(' ', lineno_width, f)?;
+ f.write_char(' ')?;
+ lineno_color.paint("=", f)?;
+ f.write_char(' ')?;
+ self.format_annotation(annotation, *continuation, false, f)
+ }
+ } else {
+ self.format_annotation(annotation, *continuation, false, f)
+ }
+ }
+ }
+ }
+
+ #[inline]
+ fn format_line(
+ &self,
+ dl: &DisplayLine<'_>,
+ lineno_width: usize,
+ inline_marks_width: usize,
+ f: &mut fmt::Formatter<'_>,
+ ) -> fmt::Result {
+ match dl {
+ DisplayLine::Source {
+ lineno,
+ inline_marks,
+ line,
+ } => {
+ let lineno_color = self.stylesheet.get_style(StyleClass::LineNo);
+ if self.anonymized_line_numbers && lineno.is_some() {
+ lineno_color.paint_fn(
+ Box::new(|f| {
+ f.write_str(Self::ANONYMIZED_LINE_NUM)?;
+ f.write_str(" |")
+ }),
+ f,
+ )?;
+ } else {
+ lineno_color.paint_fn(
+ Box::new(|f| {
+ match lineno {
+ Some(n) => write!(f, "{:>width$}", n, width = lineno_width),
+ None => format_repeat_char(' ', lineno_width, f),
+ }?;
+ f.write_str(" |")
+ }),
+ f,
+ )?;
+ }
+ if *line != DisplaySourceLine::Empty {
+ if !inline_marks.is_empty() || 0 < inline_marks_width {
+ f.write_char(' ')?;
+ self.format_inline_marks(inline_marks, inline_marks_width, f)?;
+ }
+ self.format_source_line(line, f)?;
+ } else if !inline_marks.is_empty() {
+ f.write_char(' ')?;
+ self.format_inline_marks(inline_marks, inline_marks_width, f)?;
+ }
+ Ok(())
+ }
+ DisplayLine::Fold { inline_marks } => {
+ f.write_str("...")?;
+ if !inline_marks.is_empty() || 0 < inline_marks_width {
+ format_repeat_char(' ', lineno_width, f)?;
+ self.format_inline_marks(inline_marks, inline_marks_width, f)?;
+ }
+ Ok(())
+ }
+ DisplayLine::Raw(line) => self.format_raw_line(line, lineno_width, f),
+ }
+ }
+
+ fn format_inline_marks(
+ &self,
+ inline_marks: &[DisplayMark],
+ inline_marks_width: usize,
+ f: &mut fmt::Formatter<'_>,
+ ) -> fmt::Result {
+ format_repeat_char(' ', inline_marks_width - inline_marks.len(), f)?;
+ for mark in inline_marks {
+ self.get_annotation_style(&mark.annotation_type).paint_fn(
+ Box::new(|f| {
+ f.write_char(match mark.mark_type {
+ DisplayMarkType::AnnotationThrough => '|',
+ DisplayMarkType::AnnotationStart => '/',
+ })
+ }),
+ f,
+ )?;
+ }
+ Ok(())
+ }
+}
diff --git a/vendor/annotate-snippets-0.8.0/src/formatter/style.rs b/vendor/annotate-snippets-0.8.0/src/formatter/style.rs
new file mode 100644
index 000000000..f76e6b0ab
--- /dev/null
+++ b/vendor/annotate-snippets-0.8.0/src/formatter/style.rs
@@ -0,0 +1,52 @@
+//! Set of structures required to implement a stylesheet
+//!
+//! In order to provide additional styling information for the
+//! formatter, a structs can implement `Stylesheet` and `Style`
+//! traits.
+//!
+use std::fmt;
+
+/// StyleClass is a collection of named variants of style classes
+pub enum StyleClass {
+ /// Message indicating an error.
+ Error,
+ /// Message indicating a warning.
+ Warning,
+ /// Message indicating an information.
+ Info,
+ /// Message indicating a note.
+ Note,
+ /// Message indicating a help.
+ Help,
+
+ /// Style for line numbers.
+ LineNo,
+
+ /// Parts of the text that are to be emphasised.
+ Emphasis,
+
+ /// Parts of the text that are regular. Usually a no-op.
+ None,
+}
+
+/// This trait implements a return value for the `Stylesheet::get_style`.
+pub trait Style {
+ /// The method used to write text with formatter
+ fn paint(&self, text: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result;
+ /// The method used to write display function with formatter
+ fn paint_fn<'a>(
+ &self,
+ c: Box<dyn FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result + 'a>,
+ f: &mut fmt::Formatter<'_>,
+ ) -> fmt::Result;
+ /// The method used by the DisplayListFormatter to display the message
+ /// in bold font.
+ fn bold(&self) -> Box<dyn Style>;
+}
+
+/// Trait to annotate structs that can provide `Style` implementations for
+/// every `StyleClass` variant.
+pub trait Stylesheet {
+ /// Returns a `Style` implementer based on the requested `StyleClass` variant.
+ fn get_style(&self, class: StyleClass) -> Box<dyn Style>;
+}
diff --git a/vendor/annotate-snippets-0.8.0/src/lib.rs b/vendor/annotate-snippets-0.8.0/src/lib.rs
new file mode 100644
index 000000000..46b25e156
--- /dev/null
+++ b/vendor/annotate-snippets-0.8.0/src/lib.rs
@@ -0,0 +1,54 @@
+#![deny(rust_2018_idioms)]
+
+//! A library for formatting of text or programming code snippets.
+//!
+//! It's primary purpose is to build an ASCII-graphical representation of the snippet
+//! with annotations.
+//!
+//! # Example
+//!
+//! ```text
+//! error[E0308]: mismatched types
+//! --> src/format.rs:52:1
+//! |
+//! 51 | ) -> Option<String> {
+//! | -------------- expected `Option<String>` because of return type
+//! 52 | / for ann in annotations {
+//! 53 | | match (ann.range.0, ann.range.1) {
+//! 54 | | (None, None) => continue,
+//! 55 | | (Some(start), Some(end)) if start > end_index => continue,
+//! ... |
+//! 71 | | }
+//! 72 | | }
+//! | |_____^ expected enum `std::option::Option`, found ()
+//! ```
+//!
+//! The crate uses a three stage process with two conversions between states:
+//!
+//! ```text
+//! Snippet --> DisplayList --> String
+//! ```
+//!
+//! The input type - [Snippet](self::snippet) is a structure designed
+//! to align with likely output from any parser whose code snippet is to be
+//! annotated.
+//!
+//! The middle structure - [DisplayList](self::display_list) is a
+//! structure designed to store the snippet data converted into a vector
+//! of lines containing semantic information about each line.
+//! This structure is the easiest to manipulate and organize.
+//!
+//! Finally, [DisplayListFormatter](self::formatter::DisplayListFormatter) is
+//! used to format the `DisplayList` using a `Stylesheet` into a final `String` output.
+//!
+//! A user of the crate may choose to provide their own equivalent of the input
+//! structure with an `Into<DisplayList>` trait.
+//!
+//! A user of the crate may also choose to provide their own formatter logic,
+//! to convert a `DisplayList` into a `String`, or just a `Stylesheet` to
+//! use the crate's formatting logic, but with a custom stylesheet.
+
+pub mod display_list;
+pub mod formatter;
+pub mod snippet;
+pub mod stylesheets;
diff --git a/vendor/annotate-snippets-0.8.0/src/snippet.rs b/vendor/annotate-snippets-0.8.0/src/snippet.rs
new file mode 100644
index 000000000..bc7ba0099
--- /dev/null
+++ b/vendor/annotate-snippets-0.8.0/src/snippet.rs
@@ -0,0 +1,88 @@
+//! Structures used as an input for the library.
+//!
+//! Example:
+//!
+//! ```
+//! use annotate_snippets::snippet::*;
+//!
+//! Snippet {
+//! title: Some(Annotation {
+//! label: Some("mismatched types"),
+//! id: None,
+//! annotation_type: AnnotationType::Error,
+//! }),
+//! footer: vec![],
+//! slices: vec![
+//! Slice {
+//! source: "Foo",
+//! line_start: 51,
+//! origin: Some("src/format.rs"),
+//! fold: false,
+//! annotations: vec![],
+//! },
+//! Slice {
+//! source: "Faa",
+//! line_start: 129,
+//! origin: Some("src/display.rs"),
+//! fold: false,
+//! annotations: vec![],
+//! },
+//! ],
+//! opt: Default::default(),
+//! };
+//! ```
+use crate::display_list::FormatOptions;
+
+/// Primary structure provided for formatting
+#[derive(Debug, Default)]
+pub struct Snippet<'a> {
+ pub title: Option<Annotation<'a>>,
+ pub footer: Vec<Annotation<'a>>,
+ pub slices: Vec<Slice<'a>>,
+ pub opt: FormatOptions,
+}
+
+/// Structure containing the slice of text to be annotated and
+/// basic information about the location of the slice.
+///
+/// One `Slice` is meant to represent a single, continuous,
+/// slice of source code that you want to annotate.
+#[derive(Debug)]
+pub struct Slice<'a> {
+ pub source: &'a str,
+ pub line_start: usize,
+ pub origin: Option<&'a str>,
+ pub annotations: Vec<SourceAnnotation<'a>>,
+ /// If set explicitly to `true`, the snippet will fold
+ /// parts of the slice that don't contain any annotations.
+ pub fold: bool,
+}
+
+/// Types of annotations.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum AnnotationType {
+ /// Error annotations are displayed using red color and "^" character.
+ Error,
+ /// Warning annotations are displayed using blue color and "-" character.
+ Warning,
+ Info,
+ Note,
+ Help,
+}
+
+/// An annotation for a `Slice`.
+#[derive(Debug)]
+pub struct SourceAnnotation<'a> {
+ pub range: (usize, usize),
+ pub label: &'a str,
+ pub annotation_type: AnnotationType,
+}
+
+/// An annotation for a `Snippet`.
+#[derive(Debug)]
+pub struct Annotation<'a> {
+ /// Identifier of the annotation. Usually error code like "E0308".
+ pub id: Option<&'a str>,
+ pub label: Option<&'a str>,
+ pub annotation_type: AnnotationType,
+}
diff --git a/vendor/annotate-snippets-0.8.0/src/stylesheets/color.rs b/vendor/annotate-snippets-0.8.0/src/stylesheets/color.rs
new file mode 100644
index 000000000..024dd06f6
--- /dev/null
+++ b/vendor/annotate-snippets-0.8.0/src/stylesheets/color.rs
@@ -0,0 +1,50 @@
+use std::fmt::{self, Display};
+
+use yansi_term::{Color::Fixed, Style as AnsiTermStyle};
+
+use crate::formatter::style::{Style, StyleClass, Stylesheet};
+
+struct AnsiTermStyleWrapper {
+ style: AnsiTermStyle,
+}
+
+impl Style for AnsiTermStyleWrapper {
+ fn paint(&self, text: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.style.paint(text).fmt(f)
+ }
+
+ fn paint_fn<'a>(
+ &self,
+ c: Box<dyn FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result + 'a>,
+ f: &mut fmt::Formatter<'_>,
+ ) -> fmt::Result {
+ self.style.paint_fn(c).fmt(f)
+ }
+
+ fn bold(&self) -> Box<dyn Style> {
+ Box::new(AnsiTermStyleWrapper { style: self.style })
+ }
+}
+
+pub struct AnsiTermStylesheet;
+
+impl Stylesheet for AnsiTermStylesheet {
+ fn get_style(&self, class: StyleClass) -> Box<dyn Style> {
+ let ansi_term_style = match class {
+ StyleClass::Error => Fixed(9).bold(),
+ StyleClass::Warning => Fixed(11).bold(),
+ StyleClass::Info => Fixed(12).bold(),
+ StyleClass::Note => AnsiTermStyle::new().bold(),
+ StyleClass::Help => Fixed(14).bold(),
+
+ StyleClass::LineNo => Fixed(12).bold(),
+
+ StyleClass::Emphasis => AnsiTermStyle::new().bold(),
+
+ StyleClass::None => AnsiTermStyle::new(),
+ };
+ Box::new(AnsiTermStyleWrapper {
+ style: ansi_term_style,
+ })
+ }
+}
diff --git a/vendor/annotate-snippets-0.8.0/src/stylesheets/mod.rs b/vendor/annotate-snippets-0.8.0/src/stylesheets/mod.rs
new file mode 100644
index 000000000..49f6ea04b
--- /dev/null
+++ b/vendor/annotate-snippets-0.8.0/src/stylesheets/mod.rs
@@ -0,0 +1,11 @@
+//! List of stylesheets that can be used by the `DisplayListFormatter`.
+//!
+//! The list depends on what optional dependencies the crate has been
+//! compiled with.
+//!
+//! By default the `no_color` is available. If the crate gets compiled
+//! with `ansi_term`, the `color` stylesheet is added.
+
+#[cfg(feature = "color")]
+pub mod color;
+pub mod no_color;
diff --git a/vendor/annotate-snippets-0.8.0/src/stylesheets/no_color.rs b/vendor/annotate-snippets-0.8.0/src/stylesheets/no_color.rs
new file mode 100644
index 000000000..21cb26955
--- /dev/null
+++ b/vendor/annotate-snippets-0.8.0/src/stylesheets/no_color.rs
@@ -0,0 +1,31 @@
+use std::fmt;
+
+use crate::formatter::style::{Style, StyleClass, Stylesheet};
+
+pub struct NoOpStyle {}
+
+impl Style for NoOpStyle {
+ fn paint(&self, text: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str(text)
+ }
+
+ fn paint_fn<'a>(
+ &self,
+ c: Box<dyn FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result + 'a>,
+ f: &mut fmt::Formatter<'_>,
+ ) -> fmt::Result {
+ c(f)
+ }
+
+ fn bold(&self) -> Box<dyn Style> {
+ Box::new(NoOpStyle {})
+ }
+}
+
+pub struct NoColorStylesheet;
+
+impl Stylesheet for NoColorStylesheet {
+ fn get_style(&self, _class: StyleClass) -> Box<dyn Style> {
+ Box::new(NoOpStyle {})
+ }
+}