use anyhow::{Context, Result};
use colored::*;
use std::fs;
use xore_config::{Config, XorePaths};
pub struct ConfigArgs {
pub subcommand: ConfigSubcommand,
}
#[derive(Debug, Clone)]
pub enum ConfigSubcommand {
Show,
Get { key: String },
Set { key: String, value: String },
Reset,
Edit,
}
pub fn execute(args: ConfigArgs) -> Result<()> {
match args.subcommand {
ConfigSubcommand::Show => show_config()?,
ConfigSubcommand::Get { key } => get_config_value(&key)?,
ConfigSubcommand::Set { key, value } => set_config_value(&key, &value)?,
ConfigSubcommand::Reset => reset_config()?,
ConfigSubcommand::Edit => edit_config()?,
}
Ok(())
}
fn show_config() -> Result<()> {
let xore_paths = XorePaths::new().context("无法获取 XORE 路径")?;
let config_file = xore_paths.config_file();
if !config_file.exists() {
println!("{}", "配置文件不存在,正在创建默认配置...".yellow());
let config = Config::default();
config.save(&config_file).context("无法保存默认配置")?;
println!("默认配置已创建于: {}", config_file.display());
}
let config = Config::load(&config_file).context("无法加载配置文件")?;
let toml_string = toml::to_string_pretty(&config).context("无法序列化配置")?;
println!("{}", "=== XORE 全局配置 ===".cyan());
println!();
println!("配置文件路径: {}", config_file.display());
println!();
println!("{}", toml_string);
Ok(())
}
fn get_config_value(key: &str) -> Result<()> {
let xore_paths = XorePaths::new().context("无法获取 XORE 路径")?;
let config_file = xore_paths.config_file();
if !config_file.exists() {
anyhow::bail!("配置文件不存在,请先运行 'xore config show' 创建配置");
}
let config = Config::load(&config_file).context("无法加载配置文件")?;
let parts: Vec<&str> = key.split('.').collect();
if parts.is_empty() {
anyhow::bail!("无效的配置键");
}
let json_value = serde_json::to_value(&config).context("无法序列化配置")?;
let mut current = &json_value;
for part in parts {
current = current.get(part).context(format!("配置键 '{}' 不存在", key))?;
}
println!("{} = {}", key, current);
Ok(())
}
fn set_config_value(key: &str, value: &str) -> Result<()> {
let xore_paths = XorePaths::new().context("无法获取 XORE 路径")?;
let config_file = xore_paths.config_file();
if let Some(parent) = config_file.parent() {
fs::create_dir_all(parent).context("无法创建配置目录")?;
}
let config = if config_file.exists() {
Config::load(&config_file).context("无法加载配置文件")?
} else {
Config::default()
};
let parts: Vec<&str> = key.split('.').collect();
if parts.is_empty() {
anyhow::bail!("无效的配置键");
}
let mut json_value = serde_json::to_value(&config).context("无法序列化配置")?;
let mut current: &mut serde_json::Value = &mut json_value;
for (i, part) in parts.iter().enumerate() {
if i == parts.len() - 1 {
let parsed_value = if let Ok(num) = value.parse::<i64>() {
serde_json::Value::Number(num.into())
} else if let Ok(float) = value.parse::<f64>() {
serde_json::Number::from_f64(float)
.map(serde_json::Value::Number)
.unwrap_or_else(|| serde_json::Value::String(value.to_string()))
} else if value == "true" {
serde_json::Value::Bool(true)
} else if value == "false" {
serde_json::Value::Bool(false)
} else {
serde_json::Value::String(value.to_string())
};
if let Some(map) = current.as_object_mut() {
map.insert(part.to_string(), parsed_value);
} else {
anyhow::bail!("无法设置配置值:路径无效");
}
} else {
current = current.get_mut(part).context(format!("配置键路径 '{}' 不存在", key))?;
}
}
println!("{}", format!("设置 {} = {}", key, value).green());
println!("配置文件路径: {}", config_file.display());
let updated_config: Config =
serde_json::from_value(json_value).context("无法将修改后的值反序列化为配置结构")?;
updated_config.save(&config_file).context("无法保存配置文件")?;
println!("{}", "配置已更新".green());
Ok(())
}
fn reset_config() -> Result<()> {
let xore_paths = XorePaths::new().context("无法获取 XORE 路径")?;
let config_file = xore_paths.config_file();
if config_file.exists() {
let backup_file = config_file.with_extension("toml.bak");
fs::copy(&config_file, &backup_file).context("无法备份配置")?;
println!("{}", format!("已备份现有配置到: {}", backup_file.display()).yellow());
}
let config = Config::default();
config.save(&config_file).context("无法保存默认配置")?;
println!("{}", "配置已重置为默认值".green());
Ok(())
}
fn edit_config() -> Result<()> {
let xore_paths = XorePaths::new().context("无法获取 XORE 路径")?;
let config_file = xore_paths.config_file();
if !config_file.exists() {
let config = Config::default();
config.save(&config_file).context("无法创建默认配置")?;
println!("{}", "已创建默认配置文件".yellow());
}
let editor = std::env::var("EDITOR")
.or_else(|_| std::env::var("VISUAL"))
.unwrap_or_else(|_| "vi".to_string());
println!("{}", format!("使用 {} 编辑配置文件...", editor).cyan());
println!("配置文件路径: {}", config_file.display());
std::process::Command::new(&editor).arg(&config_file).status().context("无法打开编辑器")?;
println!("{}", "配置文件已更新".green());
Ok(())
}