use clap::{Parser, ValueHint};
use clap_complete::engine::{ArgValueCandidates, CompletionCandidate};
use gnaw_core::secret_scan::SecretPolicy;
use gnaw_core::{
configuration::{DiffMode, DiffShaContent},
sort::FileSortMethod,
template::OutputFormat,
tokenizer::TokenFormat,
tokenizer::TokenizerType,
};
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[clap(
name = "gnaw",
version = env!("CARGO_PKG_VERSION"),
author = env!("CARGO_PKG_AUTHORS")
)]
#[command(arg_required_else_help = true)]
pub struct Cli {
#[arg(value_name = "PATH_TO_ANALYZE", default_value = ".", value_hint = ValueHint::AnyPath)]
pub path: PathBuf,
#[arg(short = 'O', long = "output-file", value_name = "FILE", value_hint = ValueHint::FilePath)]
pub output_file: Option<String>,
#[clap(long)]
pub tui: bool,
#[clap(short = 'i', long = "include")]
pub include: Vec<String>,
#[clap(short = 'e', long = "exclude")]
pub exclude: Vec<String>,
#[clap(short = 'F', long = "output-format", value_enum)]
pub output_format: Option<OutputFormat>,
#[clap(short, long, value_name = "NAME_OR_PATH", value_hint = ValueHint::FilePath,
add = ArgValueCandidates::new(template_candidates))]
pub template: Option<String>,
#[clap(long)]
pub full_directory_tree: bool,
#[clap(long, value_enum)]
pub encoding: Option<TokenizerType>,
#[clap(long, value_enum)]
pub token_format: Option<TokenFormat>,
#[clap(short, long)]
pub diff: bool,
#[clap(long, value_enum, requires = "diff")]
pub diff_mode: Option<DiffMode>,
#[clap(long, value_name = "BRANCHES", num_args = 2, value_delimiter = ',')]
pub git_diff_branch: Option<Vec<String>>,
#[clap(long, value_name = "BRANCHES", num_args = 2, value_delimiter = ',')]
pub git_log_branch: Option<Vec<String>>,
#[clap(long, value_name = "REF1..REF2", num_args = 1..=2)]
pub git_diff_shas: Option<Vec<String>>,
#[clap(
long,
value_enum,
default_value = "after-patch",
requires = "git_diff_shas"
)]
pub git_diff_shas_content: DiffShaContent,
#[clap(
long,
value_name = "BYTES",
default_value_t = 0,
requires = "git_diff_shas"
)]
pub git_diff_shas_max_bytes: usize,
#[clap(short, long)]
pub line_numbers: bool,
#[clap(long)]
pub absolute_paths: bool,
#[clap(short = 'L', long)]
pub follow_symlinks: bool,
#[clap(long)]
pub hidden: bool,
#[clap(long)]
pub no_codeblock: bool,
#[clap(short = 'c', long)]
pub clipboard: bool,
#[clap(long, hide = true)]
pub no_clipboard: bool,
#[clap(long)]
pub no_ignore: bool,
#[clap(long, value_enum)]
pub sort: Option<FileSortMethod>,
#[clap(short = 'q', long)]
pub quiet: bool,
#[clap(long)]
pub token_map: bool,
#[clap(long, value_name = "NUMBER")]
pub token_map_lines: Option<usize>,
#[clap(long, value_name = "PERCENT")]
pub token_map_min_percent: Option<f64>,
#[clap(long)]
pub deselected: bool,
#[arg(long, hide = true)]
pub clipboard_daemon: bool,
#[clap(long, value_name = "TOKENS", conflicts_with = "clipboard")]
pub split_size: Option<usize>,
#[clap(long, value_enum)]
pub compress: Option<gnaw_core::configuration::CompressionLevel>,
#[clap(long, value_name = "TOKENS", value_delimiter = ',',
add = ArgValueCandidates::new(compress_strip_candidates))]
pub compress_strip: Option<Vec<String>>,
#[clap(long, value_enum, default_value = "warn")]
pub secret_scan: Option<SecretPolicy>,
#[clap(long = "secret-scan-allow", value_name = "FRAGMENT")]
pub secret_scan_allow: Vec<String>,
#[clap(long)]
pub timing: bool,
}
fn template_candidates() -> Vec<CompletionCandidate> {
gnaw_core::builtin_templates::BuiltinTemplates::get_all() .iter()
.map(|(key, tpl)| CompletionCandidate::new(*key).help(Some(tpl.description.into())))
.collect()
}
fn compress_strip_candidates() -> Vec<CompletionCandidate> {
["tests", "fn-bodies", "doc-comments", "private-bodies"]
.iter()
.flat_map(|t| {
[
CompletionCandidate::new(*t),
CompletionCandidate::new(format!("no-{t}")),
]
})
.collect()
}