update: add --force option
also collapse multiple consecutive separators into one underscore.
This commit is contained in:
parent
b8c736a783
commit
81cf35c69e
@ -1,12 +1,10 @@
|
||||
[package]
|
||||
name = "snakify"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
edition = "2021"
|
||||
|
||||
authors = ["m-hgn"]
|
||||
authors = ["mxhagen"]
|
||||
description = "Quickly snake-caseify any input text"
|
||||
|
||||
license = "GPL-3.0"
|
||||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
|
||||
92
src/main.rs
92
src/main.rs
@ -1,22 +1,78 @@
|
||||
#![feature(iter_intersperse)]
|
||||
use Flag::*;
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
enum Flag {
|
||||
Force,
|
||||
Help,
|
||||
Version,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = std::env::args();
|
||||
let separators: Vec<char> = vec!['-', '_', ' '];
|
||||
|
||||
let input: String = args.skip(1).intersperse(" ".to_string()).collect();
|
||||
|
||||
let output: String = input
|
||||
.chars()
|
||||
.map(|c| {
|
||||
if separators.contains(&c) {
|
||||
'_'
|
||||
} else {
|
||||
c.to_lowercase().next().unwrap_or_else(|| {
|
||||
panic!("Error: couldn't convert character to lowercase: `{}`", c)
|
||||
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),
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
.unwrap_or_default();
|
||||
|
||||
println!("{}", output);
|
||||
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();
|
||||
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;
|
||||
}
|
||||
|
||||
let last_was_separator = output.bytes().last().map(|x| x == b'_').unwrap_or(true);
|
||||
for c in arg.chars() {
|
||||
match c {
|
||||
' ' | '-' | '_' if last_was_separator => {}
|
||||
' ' | '-' | '_' => output.push('_'),
|
||||
|
||||
'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);
|
||||
}
|
||||
}
|
||||
}
|
||||
output.push('_')
|
||||
}
|
||||
output.pop();
|
||||
|
||||
println!("{output}");
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user