diff --git a/crates/nu-command/src/commands/which_.rs b/crates/nu-command/src/commands/which_.rs index 76d5a471ee..0472901650 100644 --- a/crates/nu-command/src/commands/which_.rs +++ b/crates/nu-command/src/commands/which_.rs @@ -17,6 +17,7 @@ impl WholeStreamCommand for Which { fn signature(&self) -> Signature { Signature::build("which") .required("application", SyntaxShape::String, "application") + .rest(SyntaxShape::String, "additional applications") .switch("all", "list all executables", Some('a')) } @@ -166,56 +167,76 @@ async fn get_all_entries_in_path(_: &str, _: Tag) -> Vec<Value> { #[derive(Deserialize, Debug)] struct WhichArgs { application: Tagged<String>, + rest: Vec<Tagged<String>>, all: bool, } -async fn which(args: CommandArgs) -> Result<OutputStream, ShellError> { - let scope = args.scope.clone(); - - let (WhichArgs { application, all }, _) = args.process().await?; - +async fn which_single(application: Tagged<String>, all: bool, scope: &Scope) -> Vec<Value> { let (external, prog_name) = if application.starts_with('^') { (true, application.item[1..].to_string()) } else { (false, application.item.clone()) }; - let mut output = vec![]; - //If prog_name is an external command, don't search for nu-specific programs //If all is false, we can save some time by only searching for the first matching //program //This match handles all different cases match (all, external) { (true, true) => { - output.extend(get_all_entries_in_path(&prog_name, application.tag.clone()).await); + return get_all_entries_in_path(&prog_name, application.tag.clone()).await; } (true, false) => { + let mut output: Vec<Value> = vec![]; output.extend(get_entries_in_nu( - &scope, + scope, &prog_name, application.tag.clone(), false, )); output.extend(get_all_entries_in_path(&prog_name, application.tag.clone()).await); + return output; } (false, true) => { if let Some(entry) = get_first_entry_in_path(&prog_name, application.tag.clone()).await { - output.push(entry); + return vec![entry]; } + return vec![]; } (false, false) => { - let nu_entries = get_entries_in_nu(&scope, &prog_name, application.tag.clone(), true); + let nu_entries = get_entries_in_nu(scope, &prog_name, application.tag.clone(), true); if !nu_entries.is_empty() { - output.push(nu_entries[0].clone()); + return vec![nu_entries[0].clone()]; } else if let Some(entry) = get_first_entry_in_path(&prog_name, application.tag.clone()).await { - output.push(entry); + return vec![entry]; } + return vec![]; } } +} + +async fn which(args: CommandArgs) -> Result<OutputStream, ShellError> { + let scope = args.scope.clone(); + + let ( + WhichArgs { + application, + rest, + all, + }, + _, + ) = args.process().await?; + + let mut output = vec![]; + + for app in vec![application].into_iter().chain(rest.into_iter()) { + let values = which_single(app, all, &scope).await; + output.extend(values); + } + Ok(futures::stream::iter(output.into_iter().map(ReturnSuccess::value)).to_output_stream()) }