fix: update try_parse_word_only_commands_sequence() to return commands in order (#3881)

Incidentally, we had a test for this in
`accepts_multiple_commands_with_allowed_operators()`, but it was
verifying the bad behavior. Oops!
This commit is contained in:
Michael Bolin
2025-09-18 16:07:38 -07:00
committed by GitHub
parent 8595237505
commit de64f5f007
2 changed files with 8 additions and 7 deletions

View File

@@ -73,6 +73,9 @@ pub fn try_parse_word_only_commands_sequence(tree: &Tree, src: &str) -> Option<V
} }
} }
// Walk uses a stack (LIFO), so re-sort by position to restore source order.
command_nodes.sort_by_key(|node| node.start_byte());
let mut commands = Vec::new(); let mut commands = Vec::new();
for node in command_nodes { for node in command_nodes {
if let Some(words) = parse_plain_command_from_node(node, src) { if let Some(words) = parse_plain_command_from_node(node, src) {
@@ -150,10 +153,10 @@ mod tests {
let src = "ls && pwd; echo 'hi there' | wc -l"; let src = "ls && pwd; echo 'hi there' | wc -l";
let cmds = parse_seq(src).unwrap(); let cmds = parse_seq(src).unwrap();
let expected: Vec<Vec<String>> = vec![ let expected: Vec<Vec<String>> = vec![
vec!["wc".to_string(), "-l".to_string()],
vec!["echo".to_string(), "hi there".to_string()],
vec!["pwd".to_string()],
vec!["ls".to_string()], vec!["ls".to_string()],
vec!["pwd".to_string()],
vec!["echo".to_string(), "hi there".to_string()],
vec!["wc".to_string(), "-l".to_string()],
]; ];
assert_eq!(cmds, expected); assert_eq!(cmds, expected);
} }

View File

@@ -1156,10 +1156,8 @@ fn parse_bash_lc_commands(original: &[String]) -> Option<Vec<ParsedCommand>> {
// bias toward the primary command when pipelines are present. // bias toward the primary command when pipelines are present.
// First, drop obvious small formatting helpers (e.g., wc/awk/etc). // First, drop obvious small formatting helpers (e.g., wc/awk/etc).
let had_multiple_commands = all_commands.len() > 1; let had_multiple_commands = all_commands.len() > 1;
// The bash AST walker yields commands in right-to-left order for // Commands arrive in source order; drop formatting helpers while preserving it.
// connector/pipeline sequences. Reverse to reflect actual execution order. let filtered_commands = drop_small_formatting_commands(all_commands);
let mut filtered_commands = drop_small_formatting_commands(all_commands);
filtered_commands.reverse();
if filtered_commands.is_empty() { if filtered_commands.is_empty() {
return Some(vec![ParsedCommand::Unknown { return Some(vec![ParsedCommand::Unknown {
cmd: script.clone(), cmd: script.clone(),