hlctl/src/split.rs

115 lines
2.8 KiB
Rust

use std::ops::Deref;
#[allow(unused)]
pub enum SplitArg<'a> {
Normal(&'a str),
Once(&'a str),
}
impl<'a> SplitArg<'a> {
fn once(&self) -> bool {
if let Self::Once(_) = self {
true
} else {
false
}
}
}
impl<'a> Deref for SplitArg<'a> {
type Target = str;
fn deref(&self) -> &Self::Target {
match self {
SplitArg::Normal(s) | SplitArg::Once(s) => s,
}
}
}
impl<'a> From<&'a str> for SplitArg<'a> {
fn from(value: &'a str) -> Self {
SplitArg::Normal(value)
}
}
impl<'a> From<&'a String> for SplitArg<'a> {
fn from(value: &'a String) -> Self {
SplitArg::Normal(value)
}
}
pub fn tab_or_space<'a, S>(s: S) -> Vec<String>
where
S: Into<SplitArg<'a>>,
{
let value = s.into();
let mut chars = value.chars();
let mut working: Vec<char> = Vec::with_capacity(value.len());
let mut out: Vec<String> = Vec::new();
let mut match_quote = false;
while let Some(c) = chars.next() {
match c {
'\\' => {
working.push(c);
if let Some(c) = chars.next() {
working.push(c);
}
}
'"' => {
match_quote = !match_quote;
working.push(c);
}
'\t' | ' ' => {
if match_quote {
working.push(c);
} else if working.is_empty() {
continue;
} else {
out.push((&working).into_iter().collect());
working.clear();
if value.once() {
out.push(chars.collect());
break;
}
}
}
_ => working.push(c),
}
}
if !working.is_empty() {
out.push(working.into_iter().collect());
}
out
}
pub fn on_first_match(s: &str, match_set: &[char]) -> Option<((String, String), char)> {
let mut first: Vec<char> = Vec::with_capacity(s.len());
let mut chars = s.chars();
while let Some(char) = chars.next() {
if (&match_set).into_iter().any(|m| m.eq(&char)) {
return Some(((first.into_iter().collect(), chars.collect()), char));
}
first.push(char);
}
None
}
#[cfg(test)]
mod test {
#[test]
fn test_tab_or_space_split() {
for (base, expected) in [
("hello world", vec!["hello", "world"]),
("hello\tworld", vec!["hello", "world"]),
(
r#"hello "world! I never made it!" up til now"#,
vec!["hello", "\"world! I never made it!\"", "up", "til", "now"],
),
("hello world", vec!["hello", "world"]),
] {
assert_eq!(expected, super::tab_or_space(base))
}
}
}