pub fn next_line(candidates: &[Vec<String>]) -> Option<String> {
if candidates.is_empty() {
return None;
}
let commands: Vec<String> = candidates
.iter()
.map(|argv| {
let mut command = String::from("devscout");
for arg in argv {
command.push(' ');
command.push_str("e_arg(arg));
}
command
})
.collect();
Some(format!("next: {}", commands.join(" | ")))
}
fn is_safe_arg_byte(byte: u8) -> bool {
byte.is_ascii_alphanumeric()
|| matches!(
byte,
b'_' | b'@' | b'%' | b'+' | b'=' | b':' | b',' | b'.' | b'/' | b'-'
)
}
fn quote_arg(arg: &str) -> String {
if !arg.is_empty() && arg.bytes().all(is_safe_arg_byte) {
return arg.to_string();
}
let mut out = String::with_capacity(arg.len() + 2);
out.push('\'');
for ch in arg.chars() {
if ch == '\'' {
out.push_str("'\\''");
} else {
out.push(ch);
}
}
out.push('\'');
out
}