fix separator reduction to single underscore and trim leading as well as trailing separators from output
88 lines
2.7 KiB
Rust
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}");
|
|
}
|