use clap::{ArgAction, Args, Command, CommandFactory, Parser, Subcommand};
use std::path::PathBuf;
use crate::command_name;
#[derive(Parser)]
#[command(author, version, about, color = clap::ColorChoice::Never)]
pub struct Cli {
#[arg(long, global = true)]
pub plain: bool,
#[arg(long, global = true)]
pub json: bool,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
Save {
#[arg(value_name = "label")]
#[arg(long)]
label: Option<String>,
},
Load {
#[arg(value_name = "label")]
#[arg(long, conflicts_with = "id")]
label: Option<String>,
#[arg(value_name = "profile-id")]
#[arg(long, conflicts_with = "label")]
id: Option<String>,
#[arg(long)]
force: bool,
},
List {
#[arg(long)]
show_id: bool,
},
Export {
#[arg(value_name = "label")]
#[arg(long, conflicts_with = "id")]
label: Option<String>,
#[arg(value_name = "profile-id")]
#[arg(long, conflicts_with = "label", action = ArgAction::Append)]
id: Vec<String>,
#[arg(long, value_name = "file")]
output: PathBuf,
},
Import {
#[arg(long, value_name = "file")]
input: PathBuf,
},
Doctor {
#[arg(long)]
fix: bool,
},
Label {
#[command(subcommand)]
command: LabelCommands,
},
Status {
#[arg(long, conflicts_with = "label", conflicts_with = "id")]
all: bool,
#[arg(
long,
value_name = "label",
conflicts_with = "id",
conflicts_with = "all"
)]
label: Option<String>,
#[arg(
long,
value_name = "profile-id",
conflicts_with = "label",
conflicts_with = "all"
)]
id: Option<String>,
},
Delete {
#[arg(long)]
yes: bool,
#[arg(value_name = "label")]
#[arg(long, conflicts_with = "id")]
label: Option<String>,
#[arg(value_name = "profile-id")]
#[arg(long, conflicts_with = "label", action = ArgAction::Append)]
id: Vec<String>,
},
}
#[derive(Args)]
#[group(multiple = false)]
pub struct SavedProfileSelector {
#[arg(value_name = "label")]
#[arg(long)]
pub label: Option<String>,
#[arg(value_name = "profile-id")]
#[arg(long)]
pub id: Option<String>,
}
#[derive(Subcommand)]
pub enum LabelCommands {
Set {
#[command(flatten)]
selector: SavedProfileSelector,
#[arg(long, value_name = "label")]
to: String,
},
Clear {
#[command(flatten)]
selector: SavedProfileSelector,
},
Rename {
#[arg(value_name = "label")]
#[arg(long)]
label: String,
#[arg(long, value_name = "label")]
to: String,
},
}
pub fn command_with_examples() -> Command {
let name = command_name();
let mut cmd = Cli::command();
cmd.set_bin_name(name);
cmd = cmd.mut_subcommand("label", |label| {
label
.mut_subcommand("set", |set| set.override_usage(label_set_usage(name)))
.mut_subcommand("clear", |clear| {
clear.override_usage(label_clear_usage(name))
})
});
cmd = cmd.after_help(examples_root(name));
cmd
}
pub fn label_set_usage(name: &str) -> String {
format!("{name} label set [OPTIONS] --to <label> (--label <label> | --id <profile-id>)")
}
pub fn label_clear_usage(name: &str) -> String {
format!("{name} label clear [OPTIONS] (--label <label> | --id <profile-id>)")
}
fn examples_root(name: &str) -> String {
format!(
"Examples:\n {name} save --label work\n {name} load --label work\n {name} list --json\n {name} status --all --json\n {name} export --output profiles-export.json\n {name} import --input profiles-export.json\n {name} delete --label work --yes\n\nUse `--json` for machine-readable success output. Run `{name} help <command>` for command-specific options."
)
}
#[cfg(test)]
mod tests {
use super::examples_root;
#[test]
fn examples_root_uses_clear_professional_headings() {
let text = examples_root("codex-profiles");
assert!(text.contains("Examples:"));
assert!(text.contains("Use `--json` for machine-readable success output."));
assert!(!text.contains("Common options:"));
assert!(!text.contains("Machine-readable output:"));
}
}