Skip to main content

gcop_rs/
cli.rs

1use clap::{Args, Parser, Subcommand, builder::styling};
2
3const STYLES: styling::Styles = styling::Styles::styled()
4    .header(styling::AnsiColor::Green.on_default().bold())
5    .usage(styling::AnsiColor::Green.on_default().bold())
6    .literal(styling::AnsiColor::Cyan.on_default().bold())
7    .placeholder(styling::AnsiColor::Cyan.on_default());
8
9#[derive(Parser)]
10#[command(name = "gcop-rs")]
11#[command(author, version, long_about = None)]
12#[command(styles = STYLES)]
13/// Top-level CLI options shared by all subcommands.
14pub struct Cli {
15    /// Selected subcommand and its arguments.
16    #[command(subcommand)]
17    pub command: Commands,
18
19    /// Enable verbose output.
20    #[arg(short, long, global = true)]
21    pub verbose: bool,
22
23    /// Override the default LLM provider (used by `commit` and `review`).
24    #[arg(short, long, global = true)]
25    pub provider: Option<String>,
26}
27
28/// Arguments for the `commit` subcommand.
29#[derive(Args, Debug)]
30pub struct CommitArgs {
31    /// Skip the interactive editor.
32    #[arg(short, long)]
33    pub no_edit: bool,
34
35    /// Skip confirmation before committing.
36    #[arg(short = 'y', long)]
37    pub yes: bool,
38
39    /// Generate and print a commit message without creating a commit.
40    #[arg(short, long)]
41    pub dry_run: bool,
42
43    /// Output format: `text` or `json` (`json` implies `--dry-run`).
44    #[arg(short, long, default_value = "text")]
45    pub format: String,
46
47    /// Shortcut for `--format json`.
48    #[arg(long)]
49    pub json: bool,
50
51    /// Split staged changes into multiple atomic commits.
52    #[arg(short = 's', long)]
53    pub split: bool,
54
55    /// Amend the last commit with a new AI-generated message.
56    #[arg(long)]
57    pub amend: bool,
58
59    /// Feedback or constraints passed to commit message generation.
60    #[arg(trailing_var_arg = true)]
61    pub feedback: Vec<String>,
62}
63
64#[derive(Subcommand)]
65/// Supported gcop-rs subcommands.
66pub enum Commands {
67    /// Generate a commit message for staged changes.
68    Commit(CommitArgs),
69
70    /// Review code changes.
71    Review {
72        /// Review target.
73        #[command(subcommand)]
74        target: ReviewTarget,
75
76        /// Output format: `text`, `json`, or `markdown`.
77        #[arg(short, long, default_value = "text")]
78        format: String,
79
80        /// Shortcut for `--format json`.
81        #[arg(long)]
82        json: bool,
83    },
84
85    /// Initialize a configuration file.
86    Init {
87        /// Force overwriting existing config.
88        #[arg(short, long)]
89        force: bool,
90
91        /// Initialize `.gcop/config.toml` at the current repository root.
92        #[arg(long)]
93        project: bool,
94    },
95
96    /// Manage configuration.
97    Config {
98        /// Optional configuration action. If omitted, defaults to interactive edit flow.
99        #[command(subcommand)]
100        action: Option<ConfigAction>,
101    },
102
103    /// Manage Git aliases.
104    Alias {
105        /// Force overwriting existing aliases.
106        #[arg(short, long)]
107        force: bool,
108
109        /// List all available aliases and their status.
110        #[arg(short, long)]
111        list: bool,
112
113        /// Remove all gcop-related aliases.
114        #[arg(short, long)]
115        remove: bool,
116    },
117
118    /// Show repository statistics.
119    Stats {
120        /// Output format: `text`, `json`, or `markdown`.
121        #[arg(short, long, default_value = "text")]
122        format: String,
123
124        /// Shortcut for `--format json`.
125        #[arg(long)]
126        json: bool,
127
128        /// Filter by author name or email.
129        #[arg(long)]
130        author: Option<String>,
131
132        /// Show per-author line-level contribution statistics.
133        #[arg(long)]
134        contrib: bool,
135    },
136
137    /// Manage git hooks (prepare-commit-msg)
138    Hook {
139        /// Hook action to run.
140        #[command(subcommand)]
141        action: HookAction,
142    },
143}
144
145#[derive(Subcommand, Debug)]
146/// Target scope for the `review` command.
147pub enum ReviewTarget {
148    /// Review unstaged working tree changes (`index -> workdir`).
149    Changes,
150
151    /// Review a specific commit.
152    Commit {
153        /// Commit hash.
154        hash: String,
155    },
156
157    /// Review a range of commits.
158    Range {
159        /// Commit range (for example `main..feature`).
160        range: String,
161    },
162
163    /// Review a specific file.
164    File {
165        /// Path to file.
166        path: String,
167    },
168}
169
170#[derive(Subcommand)]
171/// Actions for the `config` command.
172pub enum ConfigAction {
173    /// Edit the user config file with syntax/schema checks.
174    Edit,
175
176    /// Validate merged config and test provider-chain connectivity.
177    Validate,
178}
179
180#[derive(Subcommand)]
181/// Actions for the `hook` command.
182pub enum HookAction {
183    /// Install the `prepare-commit-msg` hook in the current repository.
184    Install {
185        /// Force overwriting an existing hook.
186        #[arg(short, long)]
187        force: bool,
188    },
189
190    /// Uninstall the `prepare-commit-msg` hook from the current repository.
191    Uninstall,
192
193    /// Run hook logic (called by Git, not intended for direct use).
194    #[command(hide = true)]
195    Run {
196        /// Path to the commit message file (provided by Git).
197        commit_msg_file: String,
198
199        /// Source of the commit message.
200        #[arg(default_value = "")]
201        source: String,
202
203        /// Commit SHA (for amend).
204        #[arg(default_value = "")]
205        sha: String,
206    },
207}