knave_expand/diagnostic/
label.rs1use 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}