use crate::config::{DescriptionCase, InitOption, ParsedCommitDisplayFormat};
use crate::lint::constants::config_descriptions;
use clap::{builder::ArgPredicate, Parser};
use clap_complete::Shell;
#[derive(Parser, Debug)]
#[command(
author = env!("CARGO_PKG_AUTHORS"),
version = env!("CARGO_PKG_VERSION"),
about = env!("CARGO_PKG_DESCRIPTION"),
after_help = "Visit https://sumi.rs to learn more about git-sumi",
)]
pub struct Opt {
#[arg(index = 1, help = config_descriptions::COMMIT_MESSAGE)]
pub commit_message: Option<String>,
#[arg(
long,
value_name = "OPTION",
num_args = 0..=1,
required = false,
default_missing_value = "config",
help = config_descriptions::INIT
)]
pub init: Option<InitOption>,
#[arg(
long = "file",
value_name = "FILE",
help = "Read commit message from file",
conflicts_with = "commit_message"
)]
pub commit_file: Option<String>,
#[arg(long, num_args = 0, hide = true)]
pub prepare_commit_message: bool,
#[arg(long,
value_enum,
required = false,
value_name = "SHELL",
help = config_descriptions::GENERATE_SHELL_COMPLETION
)]
pub generate_shell_completion: Option<Shell>,
#[arg(long, env = "GIT_SUMI_CONFIG", help = config_descriptions::CONFIG)]
pub config: Option<String>,
#[arg(
short = 'q',
num_args = 0,
default_missing_value = "true",
long,
env = "GIT_SUMI_QUIET",
help = config_descriptions::QUIET.short
)]
pub quiet: Option<bool>,
#[arg(
short = 's',
long,
env = "GIT_SUMI_SPLIT_LINES",
num_args = 0,
default_missing_value = "true",
help = config_descriptions::SPLIT_LINES.short
)]
pub split_lines: Option<bool>,
#[arg(
short = 'd',
long,
env = "GIT_SUMI_DISPLAY",
num_args = 0,
default_missing_value = "true",
help = config_descriptions::DISPLAY.short
)]
pub display: Option<bool>,
#[arg(short = 'f',
long,
env = "GIT_SUMI_FORMAT",
help = config_descriptions::FORMAT.short
)]
pub format: Option<ParsedCommitDisplayFormat>,
#[arg(
long,
value_name = "REV",
requires = "to",
conflicts_with_all = ["commit_message", "commit_file", "commit", "force"],
value_parser = non_empty_string,
help = "Start of the revision range (exclusive)"
)]
pub from: Option<String>,
#[arg(
long,
value_name = "REV",
requires = "from",
conflicts_with_all = ["commit_message", "commit_file", "commit", "force"],
value_parser = non_empty_string,
help = "End of the revision range (inclusive)"
)]
pub to: Option<String>,
#[arg(short = 'c', long, help=config_descriptions::COMMIT)]
pub commit: bool,
#[arg(long, help=config_descriptions::FORCE)]
pub force: bool,
#[arg(short = 'C',
long,
env = "GIT_SUMI_CONVENTIONAL",
num_args = 0,
default_missing_value = "true",
default_value_ifs([
("types_allowed", ArgPredicate::IsPresent, Some("true")),
("scopes_allowed", ArgPredicate::IsPresent, Some("true")),
]),
help_heading = "Rules",
help = config_descriptions::CONVENTIONAL.short
)]
pub conventional: Option<bool>,
#[arg(
short = 'I',
long,
env = "GIT_SUMI_IMPERATIVE",
num_args = 0,
default_missing_value = "true",
help_heading = "Rules",
help = config_descriptions::IMPERATIVE.short
)]
pub imperative: Option<bool>,
#[arg(
short = 'G',
long,
env = "GIT_SUMI_GITMOJI",
num_args = 0,
default_missing_value = "true",
help_heading = "Rules",
help = config_descriptions::GITMOJI.short
)]
pub gitmoji: Option<bool>,
#[arg(
short = 'W',
long,
env = "GIT_SUMI_WHITESPACE",
num_args = 0,
default_missing_value = "true",
help_heading = "Rules",
help = config_descriptions::WHITESPACE.short
)]
pub whitespace: Option<bool>,
#[arg(
short = 'E',
long,
env = "GIT_SUMI_DESCRIPTION_CASE",
value_name = "CASE",
help_heading = "Rules",
help = config_descriptions::DESCRIPTION_CASE.short
)]
pub description_case: Option<DescriptionCase>,
#[arg(
short = 'P',
long,
env = "GIT_SUMI_NO_PERIOD",
num_args = 0,
default_missing_value = "true",
help_heading = "Rules",
help = config_descriptions::NO_PERIOD.short
)]
pub no_period: Option<bool>,
#[arg(short = 'H',
long,
env = "GIT_SUMI_MAX_HEADER_LENGTH",
value_parser = clap::value_parser!(usize),
help_heading = "Rules",
help = config_descriptions::MAX_HEADER_LENGTH.short
)]
pub max_header_length: Option<usize>,
#[arg(short = 'B',
long,
env = "GIT_SUMI_MAX_BODY_LENGTH",
value_parser = clap::value_parser!(usize),
help_heading = "Rules",
help = config_descriptions::MAX_BODY_LENGTH.short
)]
pub max_body_length: Option<usize>,
#[arg(
short = 'S',
long,
env = "GIT_SUMI_SCOPES_ALLOWED",
value_name = "SCOPES",
help_heading = "Rules",
help = config_descriptions::SCOPES_ALLOWED.short
)]
pub scopes_allowed: Vec<String>,
#[arg(
short = 'T',
long,
env = "GIT_SUMI_TYPES_ALLOWED",
value_name = "TYPES",
help_heading = "Rules",
help = config_descriptions::TYPES_ALLOWED.short
)]
pub types_allowed: Vec<String>,
#[arg(
short = 'R',
long,
env = "GIT_SUMI_HEADER_PATTERN",
value_name = "PATTERN",
help_heading = "Rules",
help = config_descriptions::HEADER_PATTERN.short
)]
pub header_pattern: Option<String>,
#[arg(
long,
short = 'X',
env = "GIT_SUMI_STRIP_HEADER_PATTERN",
num_args = 0,
default_missing_value = "true",
help_heading = "Rules",
help = config_descriptions::STRIP_HEADER_PATTERN.short
)]
pub strip_header_pattern: Option<bool>,
}
fn non_empty_string(s: &str) -> Result<String, String> {
if s.trim().is_empty() {
Err("value must not be empty".to_string())
} else {
Ok(s.to_string())
}
}