77 } ,
88 console:: style,
99 ignore:: Walk ,
10+ miette:: { Diagnostic , Report } ,
1011 ropey:: Rope ,
1112 std:: {
1213 path:: { Path , PathBuf } ,
1314 time:: Duration ,
1415 } ,
16+ thiserror:: Error ,
1517} ;
1618
19+ //
20+ // ERRORS
21+ //
22+
23+ #[ derive( Error , Debug , Diagnostic ) ]
24+ pub enum CliError {
25+ #[ error( "Check failed" ) ]
26+ #[ diagnostic( code( roughly:: check:: failed) ) ]
27+ Check ,
28+
29+ #[ error( "Format failed" ) ]
30+ #[ diagnostic( code( roughly:: format:: failed) ) ]
31+ Format ,
32+
33+ #[ error( "Debug command failed" ) ]
34+ #[ diagnostic( code( roughly:: debug:: failed) ) ]
35+ Debug ,
36+
37+ #[ error( "Configuration error" ) ]
38+ #[ diagnostic( code( roughly:: config:: error) ) ]
39+ Config {
40+ #[ source]
41+ source : config:: ConfigError ,
42+ } ,
43+
44+ #[ error( "I/O error" ) ]
45+ #[ diagnostic( code( roughly:: io:: error) ) ]
46+ Io {
47+ #[ source]
48+ source : std:: io:: Error ,
49+ path : PathBuf ,
50+ } ,
51+
52+ #[ error( "Format error" ) ]
53+ #[ diagnostic( code( roughly:: format:: error) ) ]
54+ FormatError {
55+ #[ source]
56+ source : format:: FormatError ,
57+ path : PathBuf ,
58+ #[ source_code]
59+ source_code : String ,
60+ } ,
61+ }
62+
63+ // Keep the old error types for backwards compatibility
64+ #[ derive( Debug ) ]
65+ pub struct CheckError ;
66+
67+ #[ derive( Debug ) ]
68+ pub struct FmtError ;
69+
70+ #[ derive( Debug ) ]
71+ pub struct DebugError ;
72+
73+ /// Report an error using miette
74+ pub fn report_error < T : Into < Report > > ( error : T ) {
75+ eprintln ! ( "{:?}" , error. into( ) ) ;
76+ }
77+
78+ /// Report a diagnostic error using miette
79+ pub fn report_diagnostic_error < T : Diagnostic + Send + Sync + ' static > ( error : T ) {
80+ let report = Report :: new ( error) ;
81+ eprintln ! ( "{:?}" , report) ;
82+ }
83+
1784//
1885// LOG
1986//
@@ -53,9 +120,6 @@ pub fn error(message: &str) {
53120// CHECK
54121//
55122
56- #[ derive( Debug ) ]
57- pub struct CheckError ;
58-
59123pub fn check (
60124 maybe_files : Option < & [ PathBuf ] > ,
61125 experimental_features : ExperimentalFeatures ,
@@ -71,7 +135,7 @@ pub fn check(
71135 let config = match config:: Config :: from_path ( file, experimental_features) {
72136 Ok ( config) => config,
73137 Err ( err) => {
74- error ( & err. to_string ( ) ) ;
138+ report_diagnostic_error ( err) ;
75139 return Err ( CheckError ) ;
76140 }
77141 } ;
@@ -209,9 +273,6 @@ pub fn check(
209273// FMT
210274//
211275
212- #[ derive( Debug ) ]
213- pub struct FmtError ;
214-
215276pub fn fmt (
216277 maybe_files : Option < & [ PathBuf ] > ,
217278 check : bool ,
@@ -228,7 +289,7 @@ pub fn fmt(
228289 . iter ( )
229290 . map ( |file| {
230291 let config = config:: Config :: from_path ( file, experimental_features) . map_err ( |err| {
231- error ( & err. to_string ( ) ) ;
292+ report_diagnostic_error ( err) ;
232293 FmtError
233294 } ) ?;
234295
@@ -279,8 +340,8 @@ pub fn fmt(
279340 Ok ( new) => new,
280341 Err ( err) => {
281342 n_errors += 1 ;
282- error ( & format ! ( "failed to format: {}" , path. display( ) ) ) ;
283- eprintln ! ( "{ err}" ) ;
343+ eprintln ! ( "Failed to format: {}" , path. display( ) ) ;
344+ report_diagnostic_error ( err) ;
284345 continue ;
285346 }
286347 } ;
@@ -354,9 +415,6 @@ pub fn server(experimental_features: ExperimentalFeatures) {
354415// DEBUG
355416//
356417
357- #[ derive( Debug ) ]
358- pub struct DebugError ;
359-
360418pub fn index ( paths : Option < & [ PathBuf ] > , nested : bool , print_items : bool ) -> Result < ( ) , DebugError > {
361419 let mut parser = tree:: new_parser ( ) ;
362420
@@ -497,3 +555,54 @@ pub fn parse_experimental_flags(flags: &[impl AsRef<str>]) -> ExperimentalFeatur
497555
498556 features
499557}
558+
559+ #[ cfg( test) ]
560+ mod tests {
561+ use super :: * ;
562+ use miette:: Report ;
563+ use crate :: config:: ConfigError ;
564+ use crate :: format:: FormatError ;
565+
566+ #[ test]
567+ fn test_config_error_is_miette_diagnostic ( ) {
568+ let io_error = std:: io:: Error :: new ( std:: io:: ErrorKind :: NotFound , "config file not found" ) ;
569+ let config_error = ConfigError :: IoError ( io_error) ;
570+
571+ // Test that we can create a miette Report from the error
572+ let report = Report :: new ( config_error) ;
573+ let error_string = format ! ( "{:?}" , report) ;
574+
575+ // Should contain the error code and help text
576+ assert ! ( error_string. contains( "roughly::config::io" ) ) ;
577+ assert ! ( error_string. contains( "Failed to read config file" ) ) ;
578+ }
579+
580+ #[ test]
581+ fn test_format_error_is_miette_diagnostic ( ) {
582+ let format_error = FormatError :: SyntaxError {
583+ kind : "identifier" ,
584+ line : 1 ,
585+ col : 10 ,
586+ } ;
587+
588+ // Test that we can create a miette Report from the error
589+ let report = Report :: new ( format_error) ;
590+ let error_string = format ! ( "{:?}" , report) ;
591+
592+ // Should contain the error code and help text
593+ assert ! ( error_string. contains( "roughly::format::syntax" ) ) ;
594+ assert ! ( error_string. contains( "Syntax error" ) ) ;
595+ }
596+
597+ #[ test]
598+ fn test_report_diagnostic_error ( ) {
599+ let format_error = FormatError :: Missing {
600+ kind : "identifier" ,
601+ line : 2 ,
602+ col : 17 ,
603+ } ;
604+
605+ // This should not panic and should format properly
606+ report_diagnostic_error ( format_error) ;
607+ }
608+ }
0 commit comments