Skip to main content

commit_wizard/cli/cmd/add/
mod.rs

1use std::path::PathBuf;
2
3use crate::core::usage;
4use crate::{cli::CliResult, core::context::Context};
5use clap::{ArgAction, Args as ClapArgs};
6use std::collections::HashSet;
7
8#[derive(Debug, Clone, ClapArgs)]
9#[command(about = "Stage changes in the current Git repository for commit preparation")]
10pub struct Args {
11    /// One or more paths (files or directories) to stage/unstage
12    /// e.g. `cw add src/ README.md templates/`
13    #[arg(value_name = "PATH", num_args = 0.., trailing_var_arg = true)]
14    pub paths: Vec<PathBuf>,
15
16    /// Additional explicit paths; may be repeated: `--path a --path b`
17    #[arg(long = "path", value_name = "PATH", num_args = 1.., action = ArgAction::Append)]
18    pub more_paths: Option<Vec<PathBuf>>,
19
20    /// Add all files (equivalent to `git add -A`)
21    #[arg(long, short = 'A')]
22    pub all: bool,
23
24    /// Exclude already staged files from the selection list (interactive)
25    #[arg(long)]
26    pub exclude_staged: bool,
27
28    /// Unstage instead of staging (affects paths and --all fast-paths; narrows interactive to staged)
29    #[arg(long)]
30    pub unstage: bool,
31}
32
33pub async fn run(ctx: &Context, args: Args) -> CliResult<()> {
34    let mut paths = args.paths;
35
36    if let Some(mut more) = args.more_paths {
37        paths.append(&mut more);
38    }
39
40    let mut seen = HashSet::new();
41    paths.retain(|p| seen.insert(p.clone()));
42
43    usage::stage::run(ctx, paths, args.all, args.exclude_staged, args.unstage)
44}