Skip to main content

knave_expand/diagnostic/
label.rs

1use crate::source::Span;
2
3#[derive(Clone, Debug, PartialEq, Eq, Hash)]
4pub struct Label {
5    span: Span,
6    message: String,
7    marks_a_macro_call: bool,
8}
9
10impl Label {
11    pub fn new(span: Span, message: impl Into<String>) -> Self {
12        Self {
13            span,
14            message: message.into(),
15            marks_a_macro_call: false,
16        }
17    }
18
19    pub fn at_macro_call(span: Span, message: impl Into<String>) -> Self {
20        Self {
21            marks_a_macro_call: true,
22            ..Self::new(span, message)
23        }
24    }
25
26    pub fn marks_a_macro_call(&self) -> bool {
27        self.marks_a_macro_call
28    }
29
30    pub fn span(&self) -> Span {
31        self.span
32    }
33
34    pub fn message(&self) -> &str {
35        &self.message
36    }
37}
38
39#[derive(Clone, Debug)]
40pub struct Edit {
41    span: Span,
42    replacement: String,
43}
44
45impl Edit {
46    pub fn span(&self) -> Span {
47        self.span
48    }
49
50    pub fn replacement(&self) -> &str {
51        &self.replacement
52    }
53}
54
55#[derive(Clone, Debug)]
56pub struct Suggestion {
57    edits: Vec<Edit>,
58}
59
60impl Suggestion {
61    pub fn new(span: Span, replacement: impl Into<String>) -> Self {
62        Self {
63            edits: vec![Edit {
64                span,
65                replacement: replacement.into(),
66            }],
67        }
68    }
69
70    pub fn wrapping(span: Span, opening: impl Into<String>, closing: impl Into<String>) -> Self {
71        Self {
72            edits: vec![
73                Edit {
74                    span: span.start(),
75                    replacement: opening.into(),
76                },
77                Edit {
78                    span: span.end(),
79                    replacement: closing.into(),
80                },
81            ],
82        }
83    }
84
85    pub fn edits(&self) -> &[Edit] {
86        &self.edits
87    }
88}
89
90#[derive(Clone, Debug)]
91pub struct Help {
92    message: String,
93    suggestion: Option<Suggestion>,
94}
95
96impl Help {
97    pub fn new(message: String) -> Self {
98        Self {
99            message,
100            suggestion: None,
101        }
102    }
103
104    pub fn with_suggestion(self, suggestion: Suggestion) -> Self {
105        Self {
106            suggestion: Some(suggestion),
107            ..self
108        }
109    }
110
111    pub fn message(&self) -> &str {
112        &self.message
113    }
114
115    pub fn suggestion(&self) -> Option<&Suggestion> {
116        self.suggestion.as_ref()
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::Label;
123    use crate::source::{SourceId, Span};
124
125    struct LabelFixture;
126
127    impl LabelFixture {
128        fn span() -> Span {
129            Span::new(SourceId::new(0), 0..1)
130        }
131    }
132
133    #[test]
134    fn a_label_at_a_macro_call_marks_the_call() {
135        assert!(Label::at_macro_call(LabelFixture::span(), "call").marks_a_macro_call());
136    }
137
138    #[test]
139    fn a_plain_label_marks_no_macro_call() {
140        assert!(!Label::new(LabelFixture::span(), "plain").marks_a_macro_call());
141    }
142}