|  | 
|  | 1 | +use anstyle::Style; | 
|  | 2 | + | 
|  | 3 | +use crate::{renderer::stylesheet::Stylesheet, snippet}; | 
|  | 4 | + | 
|  | 5 | +use super::{constants::*, display_text::DisplayTextFragment}; | 
|  | 6 | + | 
|  | 7 | +/// A type of the `Annotation` which may impact the sigils, style or text displayed. | 
|  | 8 | +/// | 
|  | 9 | +/// There are several ways to uses this information when formatting the `DisplayList`: | 
|  | 10 | +/// | 
|  | 11 | +/// * An annotation may display the name of the type like `error` or `info`. | 
|  | 12 | +/// * An underline for `Error` may be `^^^` while for `Warning` it could be `---`. | 
|  | 13 | +/// * `ColorStylesheet` may use different colors for different annotations. | 
|  | 14 | +#[derive(Debug, Clone, PartialEq)] | 
|  | 15 | +pub(crate) enum DisplayAnnotationType { | 
|  | 16 | +    None, | 
|  | 17 | +    Error, | 
|  | 18 | +    Warning, | 
|  | 19 | +    Info, | 
|  | 20 | +    Note, | 
|  | 21 | +    Help, | 
|  | 22 | +} | 
|  | 23 | + | 
|  | 24 | +/// An inline text | 
|  | 25 | +/// An indicator of what part of the annotation a given `Annotation` is. | 
|  | 26 | +#[derive(Debug, Clone, PartialEq)] | 
|  | 27 | +pub(crate) enum DisplayAnnotationPart { | 
|  | 28 | +    /// A standalone, single-line annotation. | 
|  | 29 | +    Standalone, | 
|  | 30 | +    /// A continuation of a multi-line label of an annotation. | 
|  | 31 | +    LabelContinuation, | 
|  | 32 | +    /// A line starting a multiline annotation. | 
|  | 33 | +    MultilineStart(usize), | 
|  | 34 | +    /// A line ending a multiline annotation. | 
|  | 35 | +    MultilineEnd(usize), | 
|  | 36 | +} | 
|  | 37 | + | 
|  | 38 | +/// Inline annotation which can be used in either Raw or Source line. | 
|  | 39 | +#[derive(Clone, Debug, PartialEq)] | 
|  | 40 | +pub(crate) struct Annotation<'a> { | 
|  | 41 | +    pub(crate) annotation_type: DisplayAnnotationType, | 
|  | 42 | +    pub(crate) id: Option<&'a str>, | 
|  | 43 | +    pub(crate) label: Vec<DisplayTextFragment<'a>>, | 
|  | 44 | +} | 
|  | 45 | + | 
|  | 46 | +#[derive(Clone, Debug, PartialEq)] | 
|  | 47 | +pub(crate) struct DisplaySourceAnnotation<'a> { | 
|  | 48 | +    pub(crate) annotation: Annotation<'a>, | 
|  | 49 | +    pub(crate) range: (usize, usize), | 
|  | 50 | +    pub(crate) annotation_type: DisplayAnnotationType, | 
|  | 51 | +    pub(crate) annotation_part: DisplayAnnotationPart, | 
|  | 52 | +} | 
|  | 53 | + | 
|  | 54 | +impl DisplaySourceAnnotation<'_> { | 
|  | 55 | +    pub(crate) fn has_label(&self) -> bool { | 
|  | 56 | +        !self | 
|  | 57 | +            .annotation | 
|  | 58 | +            .label | 
|  | 59 | +            .iter() | 
|  | 60 | +            .all(|label| label.content.is_empty()) | 
|  | 61 | +    } | 
|  | 62 | + | 
|  | 63 | +    // Length of this annotation as displayed in the stderr output | 
|  | 64 | +    pub(crate) fn len(&self) -> usize { | 
|  | 65 | +        // Account for usize underflows | 
|  | 66 | +        if self.range.1 > self.range.0 { | 
|  | 67 | +            self.range.1 - self.range.0 | 
|  | 68 | +        } else { | 
|  | 69 | +            self.range.0 - self.range.1 | 
|  | 70 | +        } | 
|  | 71 | +    } | 
|  | 72 | + | 
|  | 73 | +    pub(crate) fn takes_space(&self) -> bool { | 
|  | 74 | +        // Multiline annotations always have to keep vertical space. | 
|  | 75 | +        matches!( | 
|  | 76 | +            self.annotation_part, | 
|  | 77 | +            DisplayAnnotationPart::MultilineStart(_) | DisplayAnnotationPart::MultilineEnd(_) | 
|  | 78 | +        ) | 
|  | 79 | +    } | 
|  | 80 | +} | 
|  | 81 | + | 
|  | 82 | +impl From<snippet::Level> for DisplayAnnotationType { | 
|  | 83 | +    fn from(at: snippet::Level) -> Self { | 
|  | 84 | +        match at { | 
|  | 85 | +            snippet::Level::Error => DisplayAnnotationType::Error, | 
|  | 86 | +            snippet::Level::Warning => DisplayAnnotationType::Warning, | 
|  | 87 | +            snippet::Level::Info => DisplayAnnotationType::Info, | 
|  | 88 | +            snippet::Level::Note => DisplayAnnotationType::Note, | 
|  | 89 | +            snippet::Level::Help => DisplayAnnotationType::Help, | 
|  | 90 | +        } | 
|  | 91 | +    } | 
|  | 92 | +} | 
|  | 93 | + | 
|  | 94 | +#[inline] | 
|  | 95 | +pub(crate) fn annotation_type_str(annotation_type: &DisplayAnnotationType) -> &'static str { | 
|  | 96 | +    match annotation_type { | 
|  | 97 | +        DisplayAnnotationType::Error => ERROR_TXT, | 
|  | 98 | +        DisplayAnnotationType::Help => HELP_TXT, | 
|  | 99 | +        DisplayAnnotationType::Info => INFO_TXT, | 
|  | 100 | +        DisplayAnnotationType::Note => NOTE_TXT, | 
|  | 101 | +        DisplayAnnotationType::Warning => WARNING_TXT, | 
|  | 102 | +        DisplayAnnotationType::None => "", | 
|  | 103 | +    } | 
|  | 104 | +} | 
|  | 105 | + | 
|  | 106 | +pub(crate) fn annotation_type_len(annotation_type: &DisplayAnnotationType) -> usize { | 
|  | 107 | +    match annotation_type { | 
|  | 108 | +        DisplayAnnotationType::Error => ERROR_TXT.len(), | 
|  | 109 | +        DisplayAnnotationType::Help => HELP_TXT.len(), | 
|  | 110 | +        DisplayAnnotationType::Info => INFO_TXT.len(), | 
|  | 111 | +        DisplayAnnotationType::Note => NOTE_TXT.len(), | 
|  | 112 | +        DisplayAnnotationType::Warning => WARNING_TXT.len(), | 
|  | 113 | +        DisplayAnnotationType::None => 0, | 
|  | 114 | +    } | 
|  | 115 | +} | 
|  | 116 | + | 
|  | 117 | +pub(crate) fn get_annotation_style<'a>( | 
|  | 118 | +    annotation_type: &DisplayAnnotationType, | 
|  | 119 | +    stylesheet: &'a Stylesheet, | 
|  | 120 | +) -> &'a Style { | 
|  | 121 | +    match annotation_type { | 
|  | 122 | +        DisplayAnnotationType::Error => stylesheet.error(), | 
|  | 123 | +        DisplayAnnotationType::Warning => stylesheet.warning(), | 
|  | 124 | +        DisplayAnnotationType::Info => stylesheet.info(), | 
|  | 125 | +        DisplayAnnotationType::Note => stylesheet.note(), | 
|  | 126 | +        DisplayAnnotationType::Help => stylesheet.help(), | 
|  | 127 | +        DisplayAnnotationType::None => stylesheet.none(), | 
|  | 128 | +    } | 
|  | 129 | +} | 
|  | 130 | + | 
|  | 131 | +#[inline] | 
|  | 132 | +pub(crate) fn is_annotation_empty(annotation: &Annotation<'_>) -> bool { | 
|  | 133 | +    annotation | 
|  | 134 | +        .label | 
|  | 135 | +        .iter() | 
|  | 136 | +        .all(|fragment| fragment.content.is_empty()) | 
|  | 137 | +} | 
0 commit comments