| Crates.io | clap-nested-commands |
| lib.rs | clap-nested-commands |
| version | 0.0.6 |
| created_at | 2024-03-12 00:33:53.59959+00 |
| updated_at | 2025-01-12 14:42:46.83784+00 |
| description | Rust macros to automate the definitions for nested commands in a clap CLI |
| homepage | https://github.com/mootoday/rust-clap-nested-commands |
| repository | https://github.com/mootoday/rust-clap-nested-commands |
| max_upload_size | |
| id | 1169989 |
| size | 87,185 |
Rust macros to automate the command definitions for nested commands in a clap CLI.
Add clap-nested-commands to your project's Cargo.toml:
[dependencies]
clap = { version = "x.y.z", features = ["derive"] }
clap-nested-commands = "0.*"
If your CLI commands are async, you also need the anyhow dependency:
[dependencies]
anyhow = "x.y.z"
clap = { version = "x.y.z", features = ["derive"] }
clap-nested-commands = "0.*"
For example, imagine a CLI command like my-cli project user add --email name@domain.com.
With clap-nested-commands, you structure this CLI as follows:
examples/sync_commands
├── Cargo.toml
├── cli_context.rs
├── src
│ └── commands
│ ├── mod.rs
│ └── project
│ ├── mod.rs
│ ├── task
│ │ ├── add.rs
│ │ ├── mod.rs
│ │ └── remove.rs
│ └── user
│ ├── add.rs
│ ├── mod.rs
│ └── remove.rs
└── main.rs
Use the following pattern in your src/commands/**/mod.rs files:
// src/commands/project/user
use clap::{Args, Subcommand};
use clap_nested_commands::generate_sync_commands;
use crate::cli_context::CliContext;
// A list of sub-command modules
mod add;
mod remove;
/// User commands
#[derive(Debug, Args)]
pub struct Command {
#[command(subcommand)]
pub command: Commands,
}
generate_sync_commands!(add, remove);
Individual commands look like this:
// src/commands/project/user/add.rs
use clap::Args;
use crate::cli_context::CliContext;
/// Add a user
#[derive(Debug, Args)]
pub struct Command {
/// The email address of the user to add
pub email: String,
}
pub fn execute(_cli_context: &CliContext, _cmd: Command) {
// TODO: Add command logic
}
Note: If you want to return data from your commands, see the sync_commands_with_return_type example.
The only difference compared to sync commands is the use of the generate_async_commands macro.
Use the following pattern in your src/commands/**/mod.rs files:
// src/commands/project/user
use clap::{Args, Subcommand};
use clap_nested_commands::generate_async_commands;
use crate::cli_context::CliContext;
// A list of sub-command modules
mod add;
mod remove;
/// User commands
#[derive(Debug, Args)]
pub struct Command {
#[command(subcommand)]
pub command: Commands,
}
generate_async_commands!(add, remove);
Individual commands look like this:
// src/commands/project/user/add.rs
use anyhow::Error;
use clap::Args;
use crate::cli_context::CliContext;
/// Add a user
#[derive(Debug, Args)]
pub struct Command {
/// The email address of the user to add
pub email: String,
}
pub async fn execute(_cli_context: &CliContext, _cmd: Command) -> Result<(), Error> {
// Add command logic
Ok(())
}
Note: If you want to return data from your commands, see the async_commands_with_return_type example.
See ./examples for both a sync and an async example. To run them, use the following commands:
cargo run --example async_commands <sub-commands>
cargo run --example async_commands project user add --email name@domain.comcargo run --example async_commands_with_return_type <sub-commands>
cargo run --example async_commands_with_return_type project user add --email name@domain.comcargo run --example sync_commands <sub-commands>
cargo run --example sync_commands project user add --email name@domain.comcargo run --example sync_commands_with_return_type <sub-commands>
cargo run --example sync_commands_with_return_type project user add --email name@domain.com