snakify/src/main.rs
mxhagen f878fbc0a0 fix sep reduction, trim leading/trailing seps
fix separator reduction to single underscore and trim leading
as well as trailing separators from output
2024-11-03 18:14:47 +01:00

88 lines
2.7 KiB
Rust

use Flag::*;
#[derive(PartialEq, Eq, Debug)]
enum Flag {
Force,
Help,
Version,
}
fn main() {
let (appname, version) = (env!("CARGO_BIN_NAME"), env!("CARGO_PKG_VERSION"));
let (flag, arg_start) = std::env::args()
.enumerate()
.skip(1)
.next()
.map(|(i, arg)| match arg.as_str() {
"-f" | "--force" => (Some(Force), i),
"-h" | "--help" => (Some(Help), i),
"-V" | "--version" => (Some(Version), i),
_ => (None, 0),
})
.unwrap_or_default();
if flag == Some(Help) {
println!("Convert space-separated strings to `snake_case` and print to stdout.");
println!("If input contains invalid symbols, exits with code 1.");
println!("");
println!("Usage: {appname} [Option] [<string>...]");
println!("");
println!("Arguments:");
println!(" [<string>...] One or more strings treated as a single input");
println!("");
println!("Options:");
println!(" -f, --force Force successful conversion, ignoring invalid chars");
println!(" -h, --help Print this usage information");
println!(" -V, --version Print version information");
std::process::exit(0);
} else if flag == Some(Version) {
println!("{appname} {version}");
std::process::exit(0);
}
let mut arg_warned = false;
let mut output = String::new();
let mut last = '_';
for arg in std::env::args().skip(1 + arg_start) {
if !arg_warned
&& matches!(
arg.as_str(),
"-f" | "--force" | "-h" | "--help" | "-V" | "--version"
)
{
eprintln!("Warning: You might have passed an option where input was expected.");
eprintln!(" If this was unintentional: pass options *before* input.");
eprintln!("");
arg_warned = true;
}
for c in arg.chars() {
match c {
' ' | '-' | '_' if last == '_' => {},
' ' | '-' | '_' => {
output.push('_');
last = '_';
continue;
},
'a'..='z' | 'A'..='Z' | '0'..='9' => output.push(c.to_ascii_lowercase()),
_ if flag == Some(Force) => output.push(c),
_ => {
eprintln!("Error: Invalid snake_case character: `{c}`");
std::process::exit(1);
}
}
last = c;
}
if last != '_' {
output.push('_');
last = '_';
}
}
output.pop();
println!("{output}");
}