ecformat 0.1.1

command line tool to keep files correct in respect of your EditorConfig
Documentation
// SPDX-FileCopyrightText: Contributors to ecformat project <https://codeberg.org/BaumiCoder/ecformat>
//
// SPDX-License-Identifier: BlueOak-1.0.0

//! Module related to the properties of EditorConfig.

use core::result::Result;
use std::path::Path;

use anyhow::Result as anyResult;
use charset::CharsetHandler;
use end_of_line::EndOfLineHandler;
use log::info;

use crate::cli::EditorConfigArgs;

mod charset;

mod end_of_line;

pub mod errors;

pub fn check_file(path: &Path, editorconfig_args: &EditorConfigArgs) -> anyResult<()> {
    info!("check {}", path.display());
    for handler in build_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_handlers(path, editorconfig_args)? {
        handler.fix(path)?
    }
    Ok(())
}

/// Builds the array of all applicable handlers for the given file path.
fn build_handlers(
    file_path: &Path,
    editorconfig_args: &EditorConfigArgs,
) -> Result<Box<[BoxedPropHandler]>, ec4rs::Error> {
    let handler_count = 2; // maximal number of handlers
    let properties = ec4rs::properties_of(file_path)?;
    let mut handlers: Vec<Option<Box<dyn PropertyHandler>>> = 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));
    }
    debug_assert!(handlers.len() <= handler_count, "handler count is to small");
    Ok(handlers.into_iter()
        .flatten() // filter out "None" entries
        .collect::<Vec<BoxedPropHandler>>().into_boxed_slice())
}

type BoxedPropHandler = Box<dyn PropertyHandler>;

/// Trait for handlers for a EditorConfig property on a single file.
trait PropertyHandler {
    /// Performs the handler's check on the given file.
    /// If a EditorConfig Property is violated,
    /// it returns a [`errors::CheckError`] inside a [`anyhow::Error`].
    fn check(&self, file_path: &Path) -> anyResult<()>;

    /// Performs the handler's fix on the given file.
    fn fix(&self, file_path: &Path) -> anyResult<()>;
}