1
- use std:: sync:: Arc ;
1
+ use std:: { error :: Error , fmt :: Display , iter , sync:: Arc } ;
2
2
3
- use miette:: { Diagnostic , SourceSpan } ;
4
- use thiserror:: Error ;
3
+ use miette:: { Diagnostic , LabeledSpan , Severity , SourceSpan } ;
5
4
6
5
#[ cfg( doc) ]
7
6
use {
@@ -34,30 +33,43 @@ use {
34
33
/// ╰────
35
34
/// help: Floating point numbers must be base 10, and have numbers after the decimal point.
36
35
/// ```
37
- #[ derive( Debug , Diagnostic , Clone , Eq , PartialEq , Error ) ]
38
- #[ error( "Failed to parse KDL document" ) ]
36
+ #[ derive( Debug , Clone , Eq , PartialEq ) ]
39
37
pub struct KdlError {
40
38
/// Original input that this failure came from.
41
- #[ source_code]
42
39
pub input : Arc < String > ,
43
40
44
41
/// Sub-diagnostics for this failure.
45
- #[ related]
46
42
pub diagnostics : Vec < KdlDiagnostic > ,
47
43
}
48
44
45
+ impl Display for KdlError {
46
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
47
+ write ! ( f, "Failed to parse KDL document" )
48
+ }
49
+ }
50
+ impl Error for KdlError { }
51
+
52
+ impl Diagnostic for KdlError {
53
+ fn source_code ( & self ) -> Option < & dyn miette:: SourceCode > {
54
+ Some ( & self . input )
55
+ }
56
+
57
+ fn related < ' a > ( & ' a self ) -> Option < Box < dyn Iterator < Item = & ' a dyn Diagnostic > + ' a > > {
58
+ Some ( Box :: new (
59
+ self . diagnostics . iter ( ) . map ( |d| d as & dyn Diagnostic ) ,
60
+ ) )
61
+ }
62
+ }
63
+
49
64
/// An individual diagnostic message for a KDL parsing issue.
50
65
///
51
66
/// While generally signifying errors, they can also be treated as warnings.
52
- #[ derive( Debug , Diagnostic , Clone , Eq , PartialEq , Error ) ]
53
- #[ error( "{}" , message. clone( ) . unwrap_or_else( || "Unexpected error" . into( ) ) ) ]
67
+ #[ derive( Debug , Clone , Eq , PartialEq ) ]
54
68
pub struct KdlDiagnostic {
55
69
/// Shared source for the diagnostic.
56
- #[ source_code]
57
70
pub input : Arc < String > ,
58
71
59
72
/// Offset in chars of the error.
60
- #[ label( "{}" , label. clone( ) . unwrap_or_else( || "here" . into( ) ) ) ]
61
73
pub span : SourceSpan ,
62
74
63
75
/// Message for the error itself.
@@ -67,12 +79,42 @@ pub struct KdlDiagnostic {
67
79
pub label : Option < String > ,
68
80
69
81
/// Suggestion for fixing the parser error.
70
- #[ help]
71
82
pub help : Option < String > ,
72
83
73
84
/// Severity level for the Diagnostic.
74
- #[ diagnostic( severity) ]
75
- pub severity : miette:: Severity ,
85
+ pub severity : Severity ,
86
+ }
87
+
88
+ impl Display for KdlDiagnostic {
89
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
90
+ let message = self
91
+ . message
92
+ . clone ( )
93
+ . unwrap_or_else ( || "Unexpected error" . into ( ) ) ;
94
+ write ! ( f, "{message}" )
95
+ }
96
+ }
97
+ impl Error for KdlDiagnostic { }
98
+
99
+ impl Diagnostic for KdlDiagnostic {
100
+ fn source_code ( & self ) -> Option < & dyn miette:: SourceCode > {
101
+ Some ( & self . input )
102
+ }
103
+
104
+ fn severity ( & self ) -> Option < Severity > {
105
+ Some ( self . severity )
106
+ }
107
+
108
+ fn help < ' a > ( & ' a self ) -> Option < Box < dyn Display + ' a > > {
109
+ self . help . as_ref ( ) . map ( |s| Box :: new ( s) as Box < dyn Display > )
110
+ }
111
+
112
+ fn labels ( & self ) -> Option < Box < dyn Iterator < Item = miette:: LabeledSpan > + ' _ > > {
113
+ let label = self . label . clone ( ) . unwrap_or_else ( || "here" . to_owned ( ) ) ;
114
+ let labeled_span = LabeledSpan :: new_with_span ( Some ( label) , self . span ) ;
115
+
116
+ Some ( Box :: new ( iter:: once ( labeled_span) ) )
117
+ }
76
118
}
77
119
78
120
#[ cfg( feature = "v1" ) ]
@@ -87,8 +129,84 @@ impl From<kdlv1::KdlError> for KdlError {
87
129
message: Some ( format!( "{}" , value. kind) ) ,
88
130
label: value. label. map( |x| x. into( ) ) ,
89
131
help: value. help. map( |x| x. into( ) ) ,
90
- severity: miette :: Severity :: Error ,
132
+ severity: Severity :: Error ,
91
133
} ] ,
92
134
}
93
135
}
94
136
}
137
+
138
+ #[ cfg( test) ]
139
+ mod tests {
140
+ use super :: * ;
141
+
142
+ #[ test]
143
+ fn kdl_error ( ) {
144
+ let kdl_diagnostic = KdlDiagnostic {
145
+ input : Default :: default ( ) ,
146
+ span : SourceSpan :: new ( 0 . into ( ) , 0 ) ,
147
+ message : Default :: default ( ) ,
148
+ label : Default :: default ( ) ,
149
+ help : Default :: default ( ) ,
150
+ severity : Default :: default ( ) ,
151
+ } ;
152
+
153
+ let kdl_error = KdlError {
154
+ input : Arc :: new ( "bark? i guess?" . to_owned ( ) ) ,
155
+ diagnostics : vec ! [ kdl_diagnostic. clone( ) , kdl_diagnostic] ,
156
+ } ;
157
+
158
+ // Test `Error` impl
159
+ assert_eq ! ( kdl_error. to_string( ) , "Failed to parse KDL document" ) ;
160
+ assert ! ( kdl_error. source( ) . is_none( ) ) ;
161
+
162
+ // Test `Diagnostic` impl
163
+ let related: Vec < _ > = kdl_error. related ( ) . unwrap ( ) . collect ( ) ;
164
+ assert_eq ! ( related. len( ) , 2 ) ;
165
+ assert_eq ! (
166
+ kdl_error
167
+ . source_code( )
168
+ . unwrap( )
169
+ . read_span( & SourceSpan :: new( 0 . into( ) , 5 ) , 0 , 0 )
170
+ . unwrap( )
171
+ . data( ) ,
172
+ b"bark?"
173
+ ) ;
174
+ }
175
+
176
+ #[ test]
177
+ fn kdl_diagnostic ( ) {
178
+ let mut kdl_diagnostic = KdlDiagnostic {
179
+ input : Arc :: new ( "Catastrophic failure!!!" . to_owned ( ) ) ,
180
+ span : SourceSpan :: new ( 0 . into ( ) , 3 ) ,
181
+ message : None ,
182
+ label : Some ( "cute" . to_owned ( ) ) ,
183
+ help : Some ( "try harder?" . to_owned ( ) ) ,
184
+ severity : Severity :: Error ,
185
+ } ;
186
+
187
+ // Test `Error` impl
188
+ assert_eq ! ( kdl_diagnostic. to_string( ) , "Unexpected error" ) ;
189
+ assert ! ( kdl_diagnostic. source( ) . is_none( ) ) ;
190
+
191
+ kdl_diagnostic. message = Some ( "mega bad news, kiddo" . to_owned ( ) ) ;
192
+
193
+ assert_eq ! ( kdl_diagnostic. to_string( ) , "mega bad news, kiddo" ) ;
194
+ assert ! ( kdl_diagnostic. source( ) . is_none( ) ) ;
195
+
196
+ // Test `Diagnostic` impl
197
+ let labels: Vec < _ > = kdl_diagnostic. labels ( ) . unwrap ( ) . collect ( ) ;
198
+ assert_eq ! ( labels. len( ) , 1 ) ;
199
+ assert_eq ! ( labels[ 0 ] . label( ) . unwrap( ) , "cute" ) ;
200
+ assert_eq ! (
201
+ kdl_diagnostic
202
+ . source_code( )
203
+ . unwrap( )
204
+ . read_span( labels[ 0 ] . inner( ) , 0 , 0 )
205
+ . unwrap( )
206
+ . data( ) ,
207
+ b"Cat"
208
+ ) ;
209
+ assert_eq ! ( kdl_diagnostic. help( ) . unwrap( ) . to_string( ) , "try harder?" ) ;
210
+ assert_eq ! ( kdl_diagnostic. severity( ) . unwrap( ) , Severity :: Error ) ;
211
+ }
212
+ }
0 commit comments