use crate::output;
use crate::selector;
use crate::user_config::UserConfig;
use clap::Subcommand;
use dialoguer::{Input, theme::ColorfulTheme};
use eyre::Result;
#[derive(Subcommand)]
pub enum ConfigCommands {
#[command(alias = "i", about = "Create template config.toml with all known keys")]
Init,
#[command(alias = "s", about = "Set a config value")]
Set {
#[arg(help = "Key name (e.g. admin_user_name)")]
key: Option<String>,
#[arg(help = "Value to set")]
value: Option<String>,
},
#[command(alias = "g", about = "Get a config value")]
Get {
#[arg(help = "Key name")]
key: Option<String>,
},
#[command(
alias = "l",
about = "List all config keys (sensitive values redacted)"
)]
List,
#[command(alias = "rm", about = "Remove a key from config")]
Remove {
#[arg(help = "Key name")]
key: Option<String>,
},
#[command(alias = "e", about = "Open config in $EDITOR")]
Edit,
#[command(alias = "p", about = "Print config file path")]
Path,
}
fn select_key(config: &UserConfig, prompt: &str) -> Result<String> {
let keys = config.keys();
if keys.is_empty() {
eyre::bail!("No config keys found");
}
selector::select(&keys, prompt).ok_or_else(|| eyre::eyre!("No key selected"))
}
fn resolve_key(key: Option<String>, config: &UserConfig, prompt: &str) -> Result<String> {
match key {
Some(k) => Ok(k),
None if selector::has_skim_support() => select_key(config, prompt),
None => eyre::bail!("Key argument required in non-interactive mode"),
}
}
pub fn run_config_init() -> Result<()> {
let path = UserConfig::init()?;
output::success(&format!("Created config at {}", path.display()));
Ok(())
}
pub fn run_config_set(key: Option<String>, value: Option<String>) -> Result<()> {
let mut config = UserConfig::load()?;
let key = resolve_key(key, &config, "Select key to set")?;
let value = match value {
Some(v) => v,
None if selector::has_skim_support() => {
let current = config.get(&key).unwrap_or_default();
Input::<String>::with_theme(&ColorfulTheme::default())
.with_prompt(format!("Value for '{}'", key))
.default(current)
.allow_empty(true)
.interact_text()?
}
None => eyre::bail!("Value argument required in non-interactive mode"),
};
config.set(&key, &value)?;
output::success(&format!("{} = {}", key, value));
Ok(())
}
pub fn run_config_get(key: Option<String>) -> Result<()> {
let config = UserConfig::load()?;
let key = resolve_key(key, &config, "Select key to get")?;
match config.get(&key) {
Some(value) => println!("{}", value),
None => eyre::bail!("Key '{}' not found", key),
}
Ok(())
}
pub fn run_config_list() -> Result<()> {
let config = UserConfig::load()?;
for (key, value) in config.keys_redacted() {
println!("{} = {}", key, value);
}
Ok(())
}
pub fn run_config_remove(key: Option<String>) -> Result<()> {
let mut config = UserConfig::load()?;
let key = resolve_key(key, &config, "Select key to remove")?;
if config.remove(&key)? {
output::success(&format!("Removed '{}'", key));
} else {
eyre::bail!("Key '{}' not found", key);
}
Ok(())
}
pub fn run_config_edit() -> Result<()> {
let path = UserConfig::path()?;
if !path.exists() {
eyre::bail!(
"Config not found at {}. Run `auberge config init` first.",
path.display()
);
}
let editor = std::env::var("EDITOR").unwrap_or_else(|_| "vi".to_string());
std::process::Command::new(&editor)
.arg(&path)
.status()
.map_err(|e| eyre::eyre!("Failed to open editor '{}': {}", editor, e))?;
Ok(())
}
pub fn run_config_path() -> Result<()> {
println!("{}", UserConfig::path()?.display());
Ok(())
}