Skip to content

Commit e39624c

Browse files
Implement miette library for enhanced error reporting
Co-authored-by: felix-andreas-copilot <[email protected]>
1 parent 49e5a1a commit e39624c

File tree

7 files changed

+268
-19
lines changed

7 files changed

+268
-19
lines changed

Cargo.lock

Lines changed: 107 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ console = "0.16.0"
1212
ignore = "0.4.23"
1313
indoc = "2.0.6"
1414
itertools = "0.14.0"
15+
miette = { version = "7.4.0", features = ["fancy"] }
1516
ropey = "1.6.1"
1617
serde = "1.0.219"
1718
serde_json = "1.0.140"

crates/roughly/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ console.workspace = true
99
ignore.workspace = true
1010
indoc.workspace = true
1111
itertools.workspace = true
12+
miette.workspace = true
1213
ropey.workspace = true
1314
serde.workspace = true
1415
similar.workspace = true

crates/roughly/src/cli.rs

Lines changed: 122 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,80 @@ use {
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-
59123
pub 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-
215276
pub 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-
360418
pub 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

Comments
 (0)