pub fn command_label(command: &str) -> String {
let segments = split_segments(command);
if segments.is_empty() {
return String::new();
}
let mut kept: Vec<&String> = segments.iter().skip_while(|s| is_bare_cd(s)).collect();
if kept.is_empty() {
kept = segments.iter().collect();
}
kept.iter()
.map(|s| collapse_whitespace(s))
.collect::<Vec<_>>()
.join("; ")
}
fn is_bare_cd(segment: &str) -> bool {
segment
.strip_prefix("cd ")
.is_some_and(|rest| !rest.trim().is_empty())
}
fn split_segments(command: &str) -> Vec<String> {
let mut segments = Vec::new();
let mut current = String::new();
let mut in_single = false;
let mut in_double = false;
let mut chars = command.chars().peekable();
while let Some(c) = chars.next() {
match c {
'\'' if !in_double => {
in_single = !in_single;
current.push(c);
}
'"' if !in_single => {
in_double = !in_double;
current.push(c);
}
'\n' | ';' if !in_single && !in_double => {
segments.push(std::mem::take(&mut current));
}
'&' if !in_single && !in_double && chars.peek() == Some(&'&') => {
chars.next();
segments.push(std::mem::take(&mut current));
}
_ => current.push(c),
}
}
segments.push(current);
segments
.into_iter()
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect()
}
fn collapse_whitespace(segment: &str) -> String {
segment.split_whitespace().collect::<Vec<_>>().join(" ")
}