which: accept several applications/commands (#3024)

* which: accept several applications

* fix fmt: which_.rs
This commit is contained in:
Saeed Rasooli 2021-02-07 22:47:06 +03:30 committed by GitHub
parent ef4e3f907c
commit d883ab250a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

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