use std::{collections::HashMap, fmt, path::PathBuf};
use ec4rs::{language_tags, property};
use itertools::Itertools;
use snafu::Snafu;
#[derive(Debug, Snafu)]
#[snafu(visibility(pub))]
pub enum CheckErrorType {
#[snafu(display("charset {actual_charset} instead of {expected_charset}"))]
CharsetError {
actual_charset: String,
expected_charset: property::Charset,
},
#[snafu(display(
"{} instead of only using end of line '{expected_end_of_line}'",
wrong_end_of_lines
.iter()
.map(|(end_of_line, count)| format!("end of line '{end_of_line}' occurres {count} time(s)"))
.join(" and ")
))]
EndOfLineError {
expected_end_of_line: property::EndOfLine,
wrong_end_of_lines: HashMap<property::EndOfLine, usize>,
},
#[snafu(display("{lines_with_trailing_whitespace} lines with trailing whitespace"))]
TrimTrailingWhitespaceError {
lines_with_trailing_whitespace: usize,
},
#[snafu(display(
"Wrong indentation in the following lines: {}",
lines_with_wrong_indentation
.iter()
.map(|line| format!("{}", line + 1))
.join(", ")
))]
IndentationError {
lines_with_wrong_indentation: Vec<usize>,
},
#[snafu(display("file has no final newline"))]
InsertFinalNewlineError {},
}
#[derive(Debug, Snafu)]
#[snafu(display("{}: {error_type}", path.display()), visibility(pub))]
pub struct CheckError {
path: PathBuf,
error_type: CheckErrorType,
}
impl CheckError {
pub fn path(&self) -> &PathBuf {
&self.path
}
pub fn error_type(&self) -> &CheckErrorType {
&self.error_type
}
}
#[derive(Debug, Snafu)]
#[snafu(visibility(pub))]
pub enum CheckConfigErrorType {
#[snafu(display("No valid language tag for the spelling_language: {validation_error}"))]
SpellingLanguageError {
validation_error: language_tags::ValidationError,
},
#[snafu(display("'{value}' cannot be parsed as a {property_name}"))]
ParsingError {
value: String,
property_name: &'static str,
},
}
#[derive(Debug, Snafu)]
#[snafu(display("{} section #{}: {error_type}", path.display(), section + 1), visibility(pub))]
pub struct CheckConfigError {
path: PathBuf,
section: usize,
error_type: CheckConfigErrorType,
}
impl CheckConfigError {
pub fn path(&self) -> &PathBuf {
&self.path
}
pub fn section(&self) -> usize {
self.section
}
pub fn error_type(&self) -> &CheckConfigErrorType {
&self.error_type
}
}
#[derive(Debug)]
pub enum EditorConfigError {
FileError(CheckError),
ConfigError(CheckConfigError),
}
impl EditorConfigError {
pub fn path(&self) -> &PathBuf {
match self {
Self::FileError(ce) => &ce.path,
Self::ConfigError(cce) => &cce.path,
}
}
}
impl fmt::Display for EditorConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EditorConfigError::FileError(ce) => write!(f, "{ce}"),
EditorConfigError::ConfigError(cce) => write!(f, "{cce}"),
}
}
}
#[derive(Debug, Snafu)]
#[snafu(display("Check failed with {} errors", errors.len()), visibility(pub))]
pub struct CheckErrorList {
errors: Vec<EditorConfigError>,
}
impl CheckErrorList {
pub fn errors(&self) -> &Vec<EditorConfigError> {
&self.errors
}
}
impl<'a> IntoIterator for &'a CheckErrorList {
type Item = &'a EditorConfigError;
type IntoIter = std::slice::Iter<'a, EditorConfigError>;
fn into_iter(self) -> Self::IntoIter {
self.errors.iter()
}
}
#[derive(Debug, Snafu)]
#[snafu(display("No file named .editorconfig found"), visibility(pub))]
pub struct NoEditorConfigFound {}