// Cargo.toml:
// clap = { version = "4", features = ["derive"] }
use clap::{Parser, Subcommand};
use std::path::PathBuf;
#[derive(Parser, Debug)]
#[command(name = "rustool")]
#[command(about = "A Rust CLI tool", long_about = None)]
#[command(version)]
struct Cli {
/// Optional verbosity flag
#[arg(short, long, action = clap::ArgAction::Count)]
verbose: u8,
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
enum Commands {
/// Count words in a file
Count {
/// File to count
#[arg(value_name = "FILE")]
file: PathBuf,
/// Count characters instead of words
#[arg(short, long)]
chars: bool,
},
/// Search for a pattern in a file
Search {
/// Pattern to search for
pattern: String,
/// Files to search
#[arg(value_name = "FILES")]
files: Vec,
/// Case-insensitive search
#[arg(short, long)]
ignore_case: bool,
},
}
fn main() {
let cli = Cli::parse();
if cli.verbose > 0 { println!("Verbosity: {}", cli.verbose); }
match cli.command {
Commands::Count { file, chars } => {
let content = std::fs::read_to_string(&file)
.unwrap_or_else(|e| { eprintln!("Error: {}", e); std::process::exit(1); });
if chars {
println!("{} characters in {:?}", content.chars().count(), file);
} else {
println!("{} words in {:?}", content.split_whitespace().count(), file);
}
}
Commands::Search { pattern, files, ignore_case } => {
for file in files {
let content = std::fs::read_to_string(&file).unwrap_or_default();
for (i, line) in content.lines().enumerate() {
let matches = if ignore_case {
line.to_lowercase().contains(&pattern.to_lowercase())
} else {
line.contains(&pattern)
};
if matches { println!("{:?}:{}: {}", file, i+1, line); }
}
}
}
}
}