lla 0.6.1

Blazing Fast and highly customizable ls Replacement with Superpowers
mod commands;
mod config;
mod error;
mod filter;
mod formatter;
mod installer;
mod lister;
#[cfg(feature = "dynamic-plugins")]
mod plugin;
#[cfg(not(feature = "dynamic-plugins"))]
#[path = "plugin/static.rs"]
mod plugin;
mod sorter;
mod theme;
mod utils;

use commands::args::{Args, Command};
use commands::command_handler::handle_command;
use config::Config;
use error::{LlaError, Result};
use plugin::{PluginManager, DYNAMIC_PLUGINS_AVAILABLE, DYNAMIC_PLUGINS_UNAVAILABLE};
use std::collections::HashSet;
use utils::color::set_theme;

fn main() {
    if let Err(e) = run() {
        print_error(&e);
        std::process::exit(1);
    }
}

fn run() -> Result<()> {
    let (mut config, config_error) = load_config()?;

    set_theme(config.get_theme());

    let args = Args::parse(&config)?;
    theme::set_no_color(args.no_color);

    if let Some(Command::Clean) = args.command {
        if !DYNAMIC_PLUGINS_AVAILABLE {
            return Err(LlaError::Plugin(DYNAMIC_PLUGINS_UNAVAILABLE.to_string()));
        }
        let mut plugin_config = config.clone();
        plugin_config.plugins_dir.clone_from(&args.plugins_dir);
        let mut plugin_manager = PluginManager::new(plugin_config);
        return plugin_manager.clean_plugins(&args.plugins_dir);
    }

    let mut plugin_manager = initialize_plugin_manager(&args, &config)?;
    handle_command(&args, &mut config, &mut plugin_manager, config_error)
}

fn print_error(error: &LlaError) {
    use colored::Colorize;

    let error_type = match error {
        LlaError::Io(_) => "IO Error",
        LlaError::Parse(_) => "Parse Error",
        LlaError::Config(_) => "Config Error",
        LlaError::Plugin(_) => "Plugin Error",
        LlaError::Filter(_) => "Filter Error",
        LlaError::Other(_) => "Error",
    };

    eprintln!();
    eprintln!("{} {}", "".bright_red(), error_type.bright_red().bold());
    eprintln!();

    // Print the error message with proper indentation for multiline messages
    let message = error.to_string();
    for line in message.lines() {
        eprintln!("  {}", line);
    }
    eprintln!();
}

fn load_config() -> Result<(Config, Option<error::LlaError>)> {
    let (layers, config_error) = config::load_config_layers(None)?;
    Ok((layers.effective, config_error))
}

fn initialize_plugin_manager(args: &Args, config: &Config) -> Result<PluginManager> {
    let mut plugin_config = config.clone();
    plugin_config.plugins_dir.clone_from(&args.plugins_dir);
    let mut plugin_manager = PluginManager::new(plugin_config);
    let plugin_paths = config.plugin_search_paths(Some(&args.plugins_dir));
    match &args.command {
        Some(Command::ListPlugins | Command::Use) => {
            plugin_manager.discover_plugin_paths(&plugin_paths)?;
        }
        Some(
            Command::PluginAction(name, _, _)
            | Command::PluginRun(name, _, _, _)
            | Command::PluginInfo(name)
            | Command::PluginPermissions(name),
        ) => {
            let names = HashSet::from([config.resolve_plugin_alias(name)]);
            plugin_manager.discover_plugin_paths_named(&plugin_paths, &names)?;
        }
        None => {
            let mut names: HashSet<_> = config.enabled_plugins.iter().cloned().collect();
            names.extend(args.enable_plugin.iter().cloned());
            names.extend(args.disable_plugin.iter().cloned());
            names.extend(
                args.search_pipelines
                    .iter()
                    .map(|pipeline| pipeline.plugin.clone()),
            );
            plugin_manager.discover_plugin_paths_named(&plugin_paths, &names)?;
        }
        _ => {}
    }
    Ok(plugin_manager)
}