use core::result::Result;
use std::path::Path;
use anyhow::Result as anyResult;
use charset::CharsetHandler;
use end_of_line::EndOfLineHandler;
use indentation::IndentationHandler;
use insert_final_newline::InsertFinalNewLineHandler;
use log::info;
use spelling_language::SpellingLanguageHandler;
use trim_trailing_whitespace::TrimTrailingWhitespaceHandler;
use crate::cli::EditorConfigArgs;
mod charset;
mod end_of_line;
mod indentation;
mod insert_final_newline;
mod spelling_language;
mod trim_trailing_whitespace;
pub mod errors;
pub mod status_types;
const PROPERTIES_COUNT: usize = ec4rs::property::STANDARD_KEYS.len();
pub fn check_file(path: &Path, editorconfig_args: &EditorConfigArgs) -> anyResult<()> {
info!("check {}", path.display());
for handler in build_file_handlers(path, editorconfig_args)? {
handler.check(path)?
}
Ok(())
}
pub fn fix_file(path: &Path, editorconfig_args: &EditorConfigArgs) -> anyResult<()> {
info!("fix {}", path.display());
for handler in build_file_handlers(path, editorconfig_args)? {
handler.fix(path)?
}
Ok(())
}
pub fn check_properties(
properties: &ec4rs::Properties,
path: &Path,
section: usize,
handlers: &[BoxedPropConfigHandler],
) -> anyResult<()> {
info!(
"check section #{} in EditorConfig {}",
section + 1,
path.display()
);
for handler in handlers {
handler.check(properties)?;
}
Ok(())
}
fn build_file_handlers(
file_path: &Path,
editorconfig_args: &EditorConfigArgs,
) -> Result<Box<[BoxedPropHandler]>, ec4rs::Error> {
let handler_count = 5; let properties = ec4rs::properties_of(file_path)?;
let mut handlers: Vec<Option<BoxedPropHandler>> = Vec::with_capacity(handler_count);
if editorconfig_args.charset {
handlers.push(CharsetHandler::build(&properties).map(|h| Box::new(h) as BoxedPropHandler));
}
if editorconfig_args.end_of_line {
handlers
.push(EndOfLineHandler::build(&properties).map(|h| Box::new(h) as BoxedPropHandler));
}
if editorconfig_args.trim_trailing_whitespace {
handlers.push(
TrimTrailingWhitespaceHandler::build(&properties)
.map(|h| Box::new(h) as BoxedPropHandler),
);
}
if editorconfig_args.insert_final_newline {
handlers.push(
InsertFinalNewLineHandler::build(&properties).map(|h| Box::new(h) as BoxedPropHandler),
);
}
if editorconfig_args.indentation_handling {
handlers
.push(IndentationHandler::build(&properties).map(|h| Box::new(h) as BoxedPropHandler));
}
debug_assert!(handlers.len() <= handler_count, "handler count is to small");
Ok(handlers.into_iter()
.flatten() .collect::<Vec<BoxedPropHandler>>().into_boxed_slice())
}
type BoxedPropHandler = Box<dyn PropertyHandler>;
trait PropertyHandler {
fn check(&self, file_path: &Path) -> anyResult<()>;
fn fix(&self, file_path: &Path) -> anyResult<()>;
}
pub(crate) fn build_config_handlers(
editorconfig_args: &EditorConfigArgs,
) -> Vec<BoxedPropConfigHandler> {
let handler_count = 1; let mut handlers: Vec<BoxedPropConfigHandler> = Vec::with_capacity(handler_count);
if editorconfig_args.spelling_language {
handlers.push(Box::new(SpellingLanguageHandler {}) as BoxedPropConfigHandler);
}
debug_assert!(handlers.len() <= handler_count, "handler count is to small");
handlers
}
type BoxedPropConfigHandler = Box<dyn PropertyConfigHandler>;
pub(crate) trait PropertyConfigHandler {
fn check(&self, properties: &ec4rs::Properties) -> anyResult<()>;
}