use super::resolve::{classify_surface, default_command_config};
use super::types::{CommandCharacteristics, ParsedCommand, Word};
pub fn find_base_command(words: &[Word]) -> String {
let cmd = words
.iter()
.find(|t| !is_env_assignment(t))
.map(|w| w.as_str())
.unwrap_or("");
match cmd.rsplit_once('/') {
Some((_, name)) if !name.is_empty() => name.to_string(),
_ => cmd.to_string(),
}
}
pub fn command_characteristics(command: &str) -> CommandCharacteristics {
let tokens = shlex_or_whitespace_words(command);
let base = find_base_command(&tokens);
let has_dynamic_command = base.starts_with('$');
let indirect_execution = classify_surface(&base, &tokens, default_command_config());
CommandCharacteristics {
base_command: base,
indirect_execution,
has_dynamic_command,
}
}
pub fn base_command(command: &str) -> String {
command_characteristics(command).base_command
}
pub fn env_vars(command: &str) -> Vec<(String, String)> {
let tokens = shlex_or_whitespace_words(command);
let mut result = Vec::new();
for token in &tokens {
if let Some(eq_pos) = token.find('=') {
let key = &token[..eq_pos];
if is_valid_env_key(key) {
let val = &token[eq_pos + 1..];
result.push((key.to_string(), val.to_string()));
continue;
}
}
break;
}
result
}
pub fn tokenize(command: &str) -> Vec<Word> {
shlex_or_whitespace_words(command)
}
pub(crate) fn is_env_assignment(token: &str) -> bool {
match token.find('=') {
Some(eq_pos) => is_valid_env_key(&token[..eq_pos]),
None => false,
}
}
pub(crate) fn is_valid_env_key(key: &str) -> bool {
!key.is_empty()
&& key.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
&& key
.chars()
.next()
.is_some_and(|c| c.is_ascii_alphabetic() || c == '_')
}
pub fn parse_command(command: &str) -> ParsedCommand {
let tokens = shlex_or_whitespace_words(command);
ParsedCommand::from_words(&tokens)
}
pub(crate) fn shlex_or_whitespace_words(command: &str) -> Vec<Word> {
shlex::split(command)
.unwrap_or_else(|| command.split_whitespace().map(String::from).collect())
.into_iter()
.map(Word::from)
.collect()
}
#[cfg(test)]
#[path = "tokenize_tests.rs"]
mod tokenize_tests;