#![deny(missing_docs)]
use std::path::PathBuf;
use clap::builder::PossibleValue;
use clap::{ArgGroup, Parser};
use clap_complete as complete;
use url::Url;
use crate::cli::color_choice::ColorChoice;
use crate::config::{GistRepository, GitHubRepository, GitProtocol, Shell};
use crate::util::build;
const HELP_TEMPLATE: &str = "\
{before-help}{bin} {version}
{author}
{about}
{usage-heading}
{tab}{usage}
{all-args}{after-help}";
#[derive(Debug, PartialEq, Eq, Parser)]
#[clap(
author,
version = build::CRATE_RELEASE,
long_version = build::CRATE_LONG_VERSION,
about,
long_about = None,
help_template = HELP_TEMPLATE,
disable_help_subcommand(true),
subcommand_required(true),
)]
pub struct RawOpt {
#[clap(long, short)]
pub quiet: bool,
#[clap(long)]
pub non_interactive: bool,
#[clap(long, short)]
pub verbose: bool,
#[clap(long, value_name = "WHEN", default_value_t)]
pub color: ColorChoice,
#[clap(long, value_name = "PATH", env = "SHELDON_CONFIG_DIR")]
pub config_dir: Option<PathBuf>,
#[clap(long, value_name = "PATH", env = "SHELDON_DATA_DIR")]
pub data_dir: Option<PathBuf>,
#[clap(long, value_name = "PATH", env = "SHELDON_CONFIG_FILE")]
pub config_file: Option<PathBuf>,
#[clap(long, value_name = "PROFILE", env = "SHELDON_PROFILE")]
pub profile: Option<String>,
#[clap(subcommand)]
pub command: RawCommand,
}
#[derive(Debug, PartialEq, Eq, Parser)]
pub enum RawCommand {
Init {
#[clap(long, value_name = "SHELL")]
shell: Option<Shell>,
},
Add(Box<Add>),
Edit,
Remove {
#[clap(value_name = "NAME")]
name: String,
},
Lock {
#[clap(long)]
update: bool,
#[clap(long, conflicts_with = "update")]
reinstall: bool,
},
Source {
#[clap(long)]
relock: bool,
#[clap(long)]
update: bool,
#[clap(long, conflicts_with = "update")]
reinstall: bool,
},
Completions {
#[clap(long, value_name = "SHELL")]
shell: complete::Shell,
},
Version,
}
#[derive(Debug, PartialEq, Eq, Parser)]
#[clap(
group = ArgGroup::new("plugin").required(true),
group = ArgGroup::new("git-reference").conflicts_with_all(&["remote", "local"]),
)]
pub struct Add {
#[clap(value_name = "NAME")]
pub name: String,
#[clap(long, value_name = "URL", group = "plugin")]
pub git: Option<Url>,
#[clap(long, value_name = "ID", group = "plugin")]
pub gist: Option<GistRepository>,
#[clap(long, value_name = "REPO", group = "plugin")]
pub github: Option<GitHubRepository>,
#[clap(long, value_name = "URL", group = "plugin")]
pub remote: Option<Url>,
#[clap(long, value_name = "DIR", group = "plugin")]
pub local: Option<PathBuf>,
#[clap(long, value_name = "PROTO", conflicts_with_all = &["git", "remote", "local"])]
pub proto: Option<GitProtocol>,
#[clap(long, value_name = "BRANCH", group = "git-reference")]
pub branch: Option<String>,
#[clap(long, value_name = "SHA", group = "git-reference")]
pub rev: Option<String>,
#[clap(long, value_name = "TAG", group = "git-reference")]
pub tag: Option<String>,
#[clap(long, value_name = "PATH")]
pub dir: Option<String>,
#[clap(long = "use", value_name = "MATCH", num_args(1..))]
pub uses: Option<Vec<String>>,
#[clap(long, value_name = "TEMPLATE", num_args(1..))]
pub apply: Option<Vec<String>>,
#[clap(long, value_name = "PROFILES", num_args(1..))]
pub profiles: Option<Vec<String>>,
#[clap(long, value_name = "SCRIPT", value_parser = key_value_parser, num_args(1..))]
pub hooks: Option<Vec<(String, String)>>,
}
impl clap::ValueEnum for ColorChoice {
fn value_variants<'a>() -> &'a [Self] {
&[ColorChoice::Auto, ColorChoice::Always, ColorChoice::Never]
}
fn to_possible_value(&self) -> Option<PossibleValue> {
Some(match self {
ColorChoice::Auto => PossibleValue::new("auto"),
ColorChoice::Always => PossibleValue::new("always"),
ColorChoice::Never => PossibleValue::new("never"),
})
}
}
impl clap::ValueEnum for Shell {
fn value_variants<'a>() -> &'a [Self] {
&[Shell::Bash, Shell::Zsh]
}
fn to_possible_value(&self) -> Option<PossibleValue> {
Some(match self {
Shell::Bash => PossibleValue::new("bash"),
Shell::Zsh => PossibleValue::new("zsh"),
})
}
}
fn key_value_parser(s: &str) -> Result<(String, String), String> {
match s.split_once('=') {
Some((k, v)) => Ok((k.to_string(), v.to_string())),
_ => Err(format!("{s} isn't a valid key-value pair separated with =")),
}
}