16 KiB
name, description
| name | description |
|---|---|
| cli-enhance | Add features to existing CLI applications like colors, progress bars, shell completions, and better error messages |
CLI Enhance Command
Add modern CLI features to an existing Rust CLI application, including colors, progress bars, interactive prompts, shell completions, and beautiful error messages.
Arguments
$1- Feature to add: "colors", "progress", "prompts", "completions", "errors", "config", "logging", or "all" (required)$2- Path to project directory (optional, defaults to current directory)
Usage
# Add all enhancements
/cli-enhance all
# Add specific feature
/cli-enhance colors
/cli-enhance progress
/cli-enhance completions
# Enhance specific project
/cli-enhance colors /path/to/my-cli
Available Enhancements
1. Colors and Styling
Add semantic colors to CLI output using owo-colors.
What Gets Added:
- Dependency:
owo-colors - Dependency:
supports-color(for detection) - Color module with semantic helpers
- NO_COLOR environment variable support
- Terminal capability detection
Example Implementation:
// src/colors.rs
use owo_colors::{OwoColorize, Stream};
pub fn success(message: &str) {
println!(
"{} {}",
"✓".if_supports_color(Stream::Stdout, |text| text.green().bold()),
message
);
}
pub fn error(message: &str) {
eprintln!(
"{} {}",
"✗".if_supports_color(Stream::Stderr, |text| text.red().bold()),
message
);
}
pub fn warning(message: &str) {
println!(
"{} {}",
"⚠".if_supports_color(Stream::Stdout, |text| text.yellow().bold()),
message
);
}
pub fn info(message: &str) {
println!(
"{} {}",
"ℹ".if_supports_color(Stream::Stdout, |text| text.blue().bold()),
message
);
}
pub fn supports_color() -> bool {
use supports_color::Stream as ColorStream;
supports_color::on(ColorStream::Stdout).is_some()
}
Usage in Code:
use crate::colors;
colors::success("Build completed!");
colors::error("Failed to read file");
colors::warning("Configuration incomplete");
colors::info("Processing 10 files");
2. Progress Bars and Spinners
Add visual feedback for long-running operations using indicatif.
What Gets Added:
- Dependency:
indicatif - Progress module with common patterns
- Spinner for indeterminate operations
- Progress bars with custom styling
- Multi-progress for parallel tasks
Example Implementation:
// src/progress.rs
use indicatif::{ProgressBar, ProgressStyle, MultiProgress, HumanDuration};
use std::time::Duration;
pub fn create_progress_bar(total: u64) -> ProgressBar {
let pb = ProgressBar::new(total);
pb.set_style(
ProgressStyle::default_bar()
.template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})")
.unwrap()
.progress_chars("#>-")
);
pb
}
pub fn create_spinner(message: &str) -> ProgressBar {
let spinner = ProgressBar::new_spinner();
spinner.set_style(
ProgressStyle::default_spinner()
.template("{spinner:.green} {msg}")
.unwrap()
.tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"])
);
spinner.set_message(message.to_string());
spinner
}
pub fn create_multi_progress() -> MultiProgress {
MultiProgress::new()
}
Usage in Code:
use crate::progress;
// Progress bar for known total
let pb = progress::create_progress_bar(100);
for i in 0..100 {
// Do work
pb.inc(1);
}
pb.finish_with_message("Complete!");
// Spinner for unknown duration
let spinner = progress::create_spinner("Processing...");
// Do work
spinner.finish_with_message("Done!");
3. Interactive Prompts
Add user-friendly interactive prompts using dialoguer.
What Gets Added:
- Dependency:
dialoguer - Prompts module with common patterns
- Confirmation prompts
- Text input with validation
- Selection menus
- Multi-select options
Example Implementation:
// src/prompts.rs
use dialoguer::{
Confirm, Input, Select, MultiSelect, Password,
theme::ColorfulTheme
};
use anyhow::Result;
pub fn confirm(prompt: &str, default: bool) -> Result<bool> {
Ok(Confirm::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.default(default)
.interact()?)
}
pub fn input(prompt: &str, default: Option<String>) -> Result<String> {
let mut input = Input::with_theme(&ColorfulTheme::default())
.with_prompt(prompt);
if let Some(d) = default {
input = input.default(d);
}
Ok(input.interact_text()?)
}
pub fn select<T: ToString>(prompt: &str, items: &[T]) -> Result<usize> {
Ok(Select::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.items(items)
.interact()?)
}
pub fn multi_select<T: ToString>(prompt: &str, items: &[T]) -> Result<Vec<usize>> {
Ok(MultiSelect::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.items(items)
.interact()?)
}
pub fn password(prompt: &str, confirm: bool) -> Result<String> {
if confirm {
Ok(Password::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.with_confirmation("Confirm password", "Passwords don't match")
.interact()?)
} else {
Ok(Password::with_theme(&ColorfulTheme::default())
.with_prompt(prompt)
.interact()?)
}
}
Usage in Code:
use crate::prompts;
// Confirmation
if prompts::confirm("Continue with deployment?", false)? {
deploy()?;
}
// Text input
let name = prompts::input("Project name", Some("my-project".to_string()))?;
// Selection
let envs = vec!["dev", "staging", "production"];
let idx = prompts::select("Select environment", &envs)?;
4. Shell Completions
Add shell completion generation support.
What Gets Added:
- Dependency:
clap_complete - Completion generation command
- Support for bash, zsh, fish, powershell
- Installation instructions
Example Implementation:
// src/completions.rs
use clap::CommandFactory;
use clap_complete::{generate, Generator, Shell};
use std::io;
pub fn generate_completions<G: Generator>(gen: G) {
let mut cmd = crate::cli::Cli::command();
generate(gen, &mut cmd, cmd.get_name().to_string(), &mut io::stdout());
}
pub fn print_install_instructions(shell: Shell) {
match shell {
Shell::Bash => {
eprintln!("To install completions, add to ~/.bashrc:");
eprintln!(" eval \"$(myapp --generate bash)\"");
}
Shell::Zsh => {
eprintln!("To install completions, add to ~/.zshrc:");
eprintln!(" eval \"$(myapp --generate zsh)\"");
}
Shell::Fish => {
eprintln!("To install completions:");
eprintln!(" myapp --generate fish | source");
eprintln!(" Or save to: ~/.config/fish/completions/myapp.fish");
}
Shell::PowerShell => {
eprintln!("To install completions, add to $PROFILE:");
eprintln!(" Invoke-Expression (& myapp --generate powershell)");
}
_ => {}
}
}
Add to CLI:
// src/cli.rs
use clap::{Parser, ValueEnum};
#[derive(Parser)]
pub struct Cli {
/// Generate shell completions
#[arg(long = "generate", value_enum)]
pub generate: Option<Shell>,
// ... other fields
}
#[derive(ValueEnum, Clone)]
pub enum Shell {
Bash,
Zsh,
Fish,
PowerShell,
}
5. Beautiful Error Messages
Upgrade error handling with miette for rich diagnostics.
What Gets Added:
- Dependency:
miettewithfancyfeature - Structured error types
- Source code snippets in errors
- Help text and suggestions
- Error URLs
Example Implementation:
// src/error.rs
use miette::{Diagnostic, SourceSpan};
use thiserror::Error;
#[derive(Error, Debug, Diagnostic)]
#[error("Configuration error")]
#[diagnostic(
code(config::invalid),
url("https://example.com/docs/config"),
help("Check your configuration file syntax")
)]
pub struct ConfigError {
#[source_code]
pub src: String,
#[label("this field is invalid")]
pub span: SourceSpan,
#[help]
pub advice: Option<String>,
}
#[derive(Error, Debug, Diagnostic)]
pub enum AppError {
#[error("File not found: {path}")]
#[diagnostic(
code(app::file_not_found),
help("Check that the file exists and you have permission to read it")
)]
FileNotFound {
path: String,
},
#[error("Build failed")]
#[diagnostic(
code(app::build_failed),
help("Run with -vv for detailed logs")
)]
BuildFailed {
#[source]
source: anyhow::Error,
},
}
Update main.rs:
fn main() -> miette::Result<()> {
miette::set_panic_hook();
// Rest of application
}
6. Configuration Management
Add comprehensive configuration system.
What Gets Added:
- Dependency:
config - Dependency:
serde - Dependency:
toml - Dependency:
directories - Config module with precedence handling
- XDG directory support
- Environment variable support
Example Implementation:
// src/config.rs
use config::{Config as ConfigBuilder, Environment, File};
use directories::ProjectDirs;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use anyhow::Result;
#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
pub general: General,
pub features: Features,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct General {
pub log_level: String,
pub timeout: u64,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Features {
pub colors: bool,
pub progress: bool,
}
impl Config {
pub fn load(cli_config: Option<PathBuf>) -> Result<Self> {
let mut builder = ConfigBuilder::builder()
.set_default("general.log_level", "info")?
.set_default("general.timeout", 30)?
.set_default("features.colors", true)?
.set_default("features.progress", true)?;
// Load from standard locations
if let Some(proj_dirs) = ProjectDirs::from("com", "example", "myapp") {
let config_dir = proj_dirs.config_dir();
builder = builder
.add_source(File::from(config_dir.join("config.toml")).required(false));
}
// Override with CLI-specified config
if let Some(path) = cli_config {
builder = builder.add_source(File::from(path));
}
// Environment variables override everything
builder = builder.add_source(
Environment::with_prefix("MYAPP")
.separator("_")
.try_parsing(true)
);
Ok(builder.build()?.try_deserialize()?)
}
pub fn write_default(path: &PathBuf) -> Result<()> {
let default = Config {
general: General {
log_level: "info".to_string(),
timeout: 30,
},
features: Features {
colors: true,
progress: true,
},
};
let toml = toml::to_string_pretty(&default)?;
std::fs::write(path, toml)?;
Ok(())
}
}
7. Structured Logging
Add tracing-based structured logging.
What Gets Added:
- Dependency:
tracing - Dependency:
tracing-subscriber - Logging module with verbosity support
- Structured logging macros
Example Implementation:
// src/logging.rs
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
use anyhow::Result;
pub fn setup(verbosity: u8) -> Result<()> {
let level = match verbosity {
0 => "error",
1 => "warn",
2 => "info",
3 => "debug",
_ => "trace",
};
let env_filter = EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new(level))?;
tracing_subscriber::registry()
.with(fmt::layer().with_target(false).with_level(true))
.with(env_filter)
.init();
Ok(())
}
Usage:
use tracing::{info, warn, error, debug};
info!("Starting build process");
debug!("Configuration: {:?}", config);
warn!("Using default value for missing field");
error!("Build failed: {}", error);
Workflow
When you invoke this command:
-
Analyze Current Project
- Detect existing dependencies
- Identify CLI framework (Clap version)
- Check for existing features
- Find integration points
-
Add Dependencies
- Update Cargo.toml with new dependencies
- Add appropriate feature flags
- Ensure version compatibility
-
Generate Code
- Create new modules for features
- Add helper functions and patterns
- Integrate with existing code
-
Update Existing Code
- Replace println! with colored output
- Add progress bars to long operations
- Upgrade error types
- Add completion generation to CLI
-
Add Documentation
- Document new features in README
- Add inline code documentation
- Provide usage examples
-
Verify Integration
- Run cargo check
- Run tests
- Test new features
-
Generate Report
- List added features
- Show usage examples
- Provide next steps
Example Output
✓ Analyzed project structure
✓ Added dependencies to Cargo.toml
✓ Created colors module (src/colors.rs)
✓ Created progress module (src/progress.rs)
✓ Created prompts module (src/prompts.rs)
✓ Updated CLI for completions
✓ Upgraded error types with miette
✓ Updated 15 call sites with new features
✓ Added documentation
Enhancements Applied Successfully!
Added Features:
• Colors and styling (owo-colors)
• Progress bars and spinners (indicatif)
• Interactive prompts (dialoguer)
• Shell completions (bash, zsh, fish, powershell)
• Beautiful error messages (miette)
New Dependencies:
owo-colors = "4"
indicatif = "0.17"
dialoguer = "0.11"
clap_complete = "4"
miette = { version = "7", features = ["fancy"] }
Files Modified:
• Cargo.toml (dependencies added)
• src/lib.rs (modules exported)
• src/cli.rs (completion flag added)
• src/main.rs (error handler updated)
Files Created:
• src/colors.rs
• src/progress.rs
• src/prompts.rs
• src/completions.rs
Updated Code Locations:
• src/commands/build.rs (added progress bar)
• src/commands/init.rs (added prompts)
• src/error.rs (upgraded to miette)
Usage Examples:
Colors:
use crate::colors;
colors::success("Build completed!");
colors::error("Failed to read file");
Progress:
use crate::progress;
let pb = progress::create_progress_bar(100);
pb.inc(1);
pb.finish_with_message("Done!");
Prompts:
use crate::prompts;
if prompts::confirm("Continue?", true)? {
// do something
}
Completions:
myapp --generate bash > /etc/bash_completion.d/myapp
myapp --generate zsh > ~/.zfunc/_myapp
Next Steps:
1. Review generated code
2. Test new features: cargo run
3. Update documentation if needed
4. Commit changes: git add . && git commit
Implementation
Use the appropriate rust-cli-developer agents:
Use Task tool with subagent_type="rust-cli-developer:cli-ux-specialist"
for colors, progress, and prompts
Use Task tool with subagent_type="rust-cli-developer:cli-architect"
for configuration and logging
Use Task tool with subagent_type="rust-cli-developer:clap-expert"
for shell completions integration
Notes
- Enhancements are additive and non-destructive
- Existing code is updated carefully to maintain functionality
- Dependencies are added with compatible versions
- All changes are tested before completion
- Documentation is updated to reflect new features
- Backward compatibility is maintained where possible