use colored::Colorize;
use std::process::ExitCode;
use super::commands::{ConfigCommands, HookCommands, HookEvent};
use super::handle_hook_command;
pub fn handle_config_command(action: ConfigCommands) -> ExitCode {
use linthis::config::cli;
match action {
ConfigCommands::Add {
field,
value,
global,
} => cli::handle_config_add(field.as_str(), &value, global),
ConfigCommands::Remove {
field,
value,
global,
} => cli::handle_config_remove(field.as_str(), &value, global),
ConfigCommands::Clear { field, global } => cli::handle_config_clear(field.as_str(), global),
ConfigCommands::Set {
field,
value,
global,
} => cli::handle_config_set(&field, &value, global),
ConfigCommands::Unset { field, global } => cli::handle_config_unset(&field, global),
ConfigCommands::Get { field, global } => cli::handle_config_get(&field, global),
ConfigCommands::List { verbose, global } => cli::handle_config_list(verbose, global),
ConfigCommands::Migrate {
from_tool,
dry_run,
backup,
verbose,
} => handle_config_migrate(from_tool, dry_run, backup, verbose),
}
}
fn parse_tool_filter(
from_tool: &Option<String>,
) -> Result<Option<linthis::config::migrate::Tool>, ExitCode> {
use linthis::config::migrate::Tool;
match from_tool.as_ref() {
Some(t) => match Tool::parse(t) {
Some(tool) => Ok(Some(tool)),
None => {
eprintln!(
"{}: Unknown tool '{}'. Supported: eslint, prettier, black, isort",
"Error".red(),
t
);
Err(ExitCode::from(1))
}
},
None => Ok(None),
}
}
fn print_migration_warnings(warnings: &[linthis::config::migrate::MigrationWarning]) -> bool {
use linthis::config::migrate::WarningSeverity;
let mut has_errors = false;
for warning in warnings {
let prefix = match warning.severity {
WarningSeverity::Info => "Info".cyan(),
WarningSeverity::Warning => "Warning".yellow(),
WarningSeverity::Error => {
has_errors = true;
"Error".red()
}
};
println!(" {} [{}]: {}", prefix, warning.source, warning.message);
}
has_errors
}
fn print_migration_details(result: &linthis::config::migrate::MigrationResult, dry_run: bool) {
if dry_run {
println!();
println!("{}", "Changes that would be made:".bold());
if result.config_changes.is_empty() {
println!(" {}", "(no changes)".dimmed());
} else {
for change in &result.config_changes {
println!(" {} {}", "→".cyan(), change);
}
}
} else {
if !result.backed_up_files.is_empty() {
println!();
println!("{}", "Backed up files:".bold());
for path in &result.backed_up_files {
println!(" {} {}", "✓".green(), path.display());
}
}
if !result.created_files.is_empty() {
println!();
println!("{}", "Created files:".bold());
for path in &result.created_files {
println!(" {} {}", "✓".green(), path.display());
}
}
}
if !result.suggestions.is_empty() {
println!();
println!("{}", "Suggestions:".bold());
for suggestion in &result.suggestions {
println!(" 💡 {}", suggestion);
}
}
}
fn print_migration_summary(
result: &linthis::config::migrate::MigrationResult,
dry_run: bool,
has_errors: bool,
) {
println!();
if dry_run {
let change_count = result.config_changes.len();
if change_count > 0 {
println!(
"{} Dry run complete. {} change(s) would be made.",
"✓".green(),
change_count
);
println!(" Run without {} to apply changes.", "--dry-run".cyan());
} else {
println!("{} No configuration files to migrate.", "ℹ".blue());
}
} else if result.created_files.is_empty() && !has_errors {
println!("{} No configuration files to migrate.", "ℹ".blue());
} else if !has_errors {
println!(
"{} Migration complete! {} file(s) created.",
"✓".green(),
result.created_files.len()
);
}
}
fn handle_config_migrate(
from_tool: Option<String>,
dry_run: bool,
backup: bool,
verbose: bool,
) -> ExitCode {
use linthis::config::migrate::{migrate_configs, MigrationOptions};
let project_root = std::env::current_dir().unwrap_or_default();
let tool_filter = match parse_tool_filter(&from_tool) {
Ok(f) => f,
Err(code) => return code,
};
let options = MigrationOptions {
dry_run,
backup,
tool_filter,
verbose,
};
println!(
"{}",
if dry_run {
"Analyzing configuration files (dry run)...".cyan()
} else {
"Migrating configuration files...".cyan()
}
);
match migrate_configs(&project_root, &options) {
Ok(result) => {
let has_errors = print_migration_warnings(&result.warnings);
print_migration_details(&result, dry_run);
print_migration_summary(&result, dry_run, has_errors);
if has_errors {
ExitCode::from(1)
} else {
ExitCode::SUCCESS
}
}
Err(e) => {
eprintln!("{}: {}", "Error".red(), e);
ExitCode::from(1)
}
}
}
pub fn handle_init_command(global: bool, with_hook: bool, force: bool) -> ExitCode {
use linthis::config::Config;
let config_path = if global {
let home = match linthis::utils::home_dir() {
Some(h) => h,
None => {
eprintln!("{}: Cannot determine home directory", "Error".red());
return ExitCode::from(1);
}
};
home.join(".linthis").join("config.toml")
} else {
Config::project_config_path(&std::env::current_dir().unwrap_or_default())
};
if config_path.exists() && !force {
println!(
"{}: {} already exists, skipping config creation",
"Info".cyan(),
config_path.display()
);
} else {
if let Some(parent) = config_path.parent() {
if let Err(e) = std::fs::create_dir_all(parent) {
eprintln!(
"{}: Failed to create directory {}: {}",
"Error".red(),
parent.display(),
e
);
return ExitCode::from(2);
}
}
let content = Config::generate_default_toml();
match std::fs::write(&config_path, content) {
Ok(_) => {
println!("{} Created {}", "✓".green(), config_path.display());
}
Err(e) => {
eprintln!("{}: Failed to create config: {}", "Error".red(), e);
return ExitCode::from(2);
}
}
}
if with_hook {
if global {
eprintln!(
"{}: Global config does not support --with-hook",
"Warning".yellow()
);
eprintln!(" Global hook template feature has been removed");
eprintln!(
" Use {} in each project instead",
"linthis hook install".cyan()
);
} else {
println!();
let exit_code = handle_hook_command(HookCommands::Install {
hook_types: vec![], hook_events: vec![HookEvent::PreCommit], force, yes: true, global: false, provider: None, args: None, provider_args: None, model: None, fix_commit_mode: None, all_events: false, all_types: false, all: false,
});
if exit_code != ExitCode::SUCCESS {
return exit_code;
}
}
}
ExitCode::SUCCESS
}
pub fn init_linter_configs() -> ExitCode {
use linthis::templates::get_default_configs;
use std::fs;
use std::path::Path;
let configs = get_default_configs();
let mut created = 0;
let mut skipped = 0;
println!(
"{}",
"Generating default linter/formatter configs...".cyan()
);
for (filename, content) in &configs {
let path = Path::new(filename);
if path.exists() {
println!(" {} {} (already exists)", "⊘".yellow(), filename);
skipped += 1;
} else {
match fs::write(path, content) {
Ok(_) => {
println!(" {} {}", "✓".green(), filename);
created += 1;
}
Err(e) => {
eprintln!(" {} {} ({})", "✗".red(), filename, e);
}
}
}
}
linthis::utils::ensure_gitignore_has_linthis(Path::new("."));
println!();
println!(
"Created {} config file{}, skipped {} existing",
created,
if created == 1 { "" } else { "s" },
skipped
);
ExitCode::SUCCESS
}