Expand description
§Flag-rs - A Cobra-inspired CLI Framework for Rust
Flag-rs is a powerful command-line interface framework for Rust that brings the best features
of Go’s Cobra library to the Rust ecosystem. The key differentiator is dynamic runtime
completions - unlike other Rust CLI frameworks, Flag-rs can generate completions based on
current system state, making it perfect for tools like kubectl
that need to complete
resource names from a live API.
§Key Features
- Dynamic Completions: Generate completions at runtime based on application state
- Zero Dependencies: Pure Rust implementation with no external crates
- Subcommand Support: Organize complex CLIs with nested subcommands
- Flag Inheritance: Global flags automatically available to all subcommands
- Shell Completion: Generate completion scripts for bash, zsh, and fish
- Colored Output: Beautiful help messages with automatic TTY detection
- Flexible Architecture: Use builder pattern or direct construction
§Quick Start
use flag_rs::{CommandBuilder, Flag, FlagType, FlagValue};
let app = CommandBuilder::new("myapp")
.short("A simple CLI application")
.long("This is my awesome command-line application that does great things")
.flag(
Flag::new("verbose")
.short('v')
.usage("Enable verbose output")
.value_type(FlagType::Bool)
.default(FlagValue::Bool(false))
)
.subcommand(
CommandBuilder::new("serve")
.short("Start the server")
.flag(
Flag::new("port")
.short('p')
.usage("Port to listen on")
.value_type(FlagType::Int)
.default(FlagValue::Int(8080))
)
.run(|ctx| {
let verbose = ctx.flag("verbose")
.and_then(|s| s.parse::<bool>().ok())
.unwrap_or(false);
let port = ctx.flag("port")
.and_then(|s| s.parse::<i64>().ok())
.unwrap_or(8080);
if verbose {
println!("Starting server on port {}", port);
}
Ok(())
})
.build()
)
.build();
// In main():
// let args: Vec<String> = std::env::args().skip(1).collect();
// if let Err(e) = app.execute(args) {
// eprintln!("Error: {}", e);
// std::process::exit(1);
// }
§Dynamic Completions
The killer feature that sets Flag-rs apart from other Rust CLI libraries:
use flag_rs::{CommandBuilder, CompletionResult};
let cmd = CommandBuilder::new("kubectl")
.subcommand(
CommandBuilder::new("get")
.subcommand(
CommandBuilder::new("pods")
.arg_completion(|ctx, prefix| {
// This runs when the user presses TAB!
// In a real app, you'd query the Kubernetes API here
let namespace = ctx.flag("namespace")
.map(|s| s.as_str())
.unwrap_or("default");
let pods = vec!["nginx-abc123", "redis-def456", "postgres-ghi789"];
Ok(CompletionResult::new().extend(
pods.into_iter()
.filter(|p| p.starts_with(prefix))
.map(String::from)
))
})
.build()
)
.build()
)
.build();
§Shell Completion Setup
Add a completion command to enable shell completions:
use flag_rs::{CommandBuilder, Shell};
fn build_completion_command() -> flag_rs::Command {
CommandBuilder::new("completion")
.short("Generate shell completion script")
.run(|ctx| {
let shell_name = ctx.args().first()
.ok_or(flag_rs::Error::ArgumentParsing("shell name required".to_string()))?;
// In a real app, get the root command here
// let script = match shell_name.as_str() {
// "bash" => root_cmd.generate_completion(Shell::Bash),
// "zsh" => root_cmd.generate_completion(Shell::Zsh),
// "fish" => root_cmd.generate_completion(Shell::Fish),
// _ => return Err(flag_rs::Error::ArgumentParsing("unsupported shell".to_string())),
// };
// println!("{}", script);
Ok(())
})
.build()
}
Users can then enable completions:
# Bash
source <(myapp completion bash)
# Zsh
source <(myapp completion zsh)
# Fish
myapp completion fish | source
§Modular Command Structure
For larger applications, Flag-rs supports a modular architecture:
ⓘ
// src/commands/mod.rs
pub fn register_commands(root: &mut flag_rs::Command) {
// Register each command module
serve::register(root);
config::register(root);
migrate::register(root);
}
// src/commands/serve.rs
use flag_rs::{CommandBuilder, Flag, FlagType};
pub fn register(parent: &mut flag_rs::Command) {
let cmd = CommandBuilder::new("serve")
.short("Start the application server")
.flag(
Flag::new("port")
.short('p')
.usage("Port to bind to")
.value_type(FlagType::Int)
)
.run(|ctx| {
// Server implementation
Ok(())
})
.build();
parent.add_command(cmd);
}
§Error Handling
Flag-rs uses idiomatic Rust error handling:
use flag_rs::{CommandBuilder, Error};
let cmd = CommandBuilder::new("deploy")
.run(|ctx| {
let env = ctx.args().first()
.ok_or(Error::ArgumentParsing("environment required".to_string()))?;
if env != "production" && env != "staging" {
return Err(Error::Validation(
format!("unknown environment: {}", env)
));
}
Ok(())
})
.build();
Re-exports§
pub use command::Command;
pub use command::CommandBuilder;
pub use completion::CompletionFunc;
pub use completion::CompletionResult;
pub use context::Context;
pub use error::Error;
pub use error::Result;
pub use flag::Flag;
pub use flag::FlagType;
pub use flag::FlagValue;
pub use shell::Shell;
Modules§
- color
- Color support for terminal output Simple ANSI color support with zero dependencies
- command
- Core command structures and execution Command execution and management
- completion
- Dynamic completion support Dynamic shell completion support
- completion_
format - Completion format handling Completion format handling for different shells
- context
- Runtime context for command execution Context for passing data between commands
- error
- Error types and result handling Error types for the flag framework
- flag
- Flag parsing and value types Flag system for command-line argument parsing
- shell
- Shell completion script generation Shell completion script generation