Skip to content

Commit

Permalink
fix(builtins): fix set builtin handling of - and -- (#354)
Browse files Browse the repository at this point in the history
  • Loading branch information
reubeno authored Jan 22, 2025
1 parent 1d29bc8 commit 1a780de
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 8 deletions.
56 changes: 48 additions & 8 deletions brush-core/src/builtins/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ pub(crate) struct SetCommand {
#[clap(flatten)]
set_option: SetOption,

#[arg(trailing_var_arg = true, allow_hyphen_values = true)]
positional_args: Vec<String>,
}

Expand All @@ -137,6 +138,35 @@ impl builtins::Command for SetCommand {
true
}

/// Override the default [`builtins::Command::new`] function to handle clap's limitation related
/// to `--`. See [`builtins::parse_known`] for more information
/// TODO: we can safely remove this after the issue is resolved
fn new<I>(args: I) -> Result<Self, clap::Error>
where
I: IntoIterator<Item = String>,
{
//
// TODO: This is getting pretty messy; we need to see how to avoid this -- handling from
// leaking into too many commands' custom parsing.
//

// Apply the same workaround from the default implementation of Command::new to handle +
// args.
let args = args.into_iter().map(|arg| {
if arg.starts_with('+') {
format!("--{arg}")
} else {
arg
}
});

let (mut this, rest_args) = crate::builtins::try_parse_known::<SetCommand>(args)?;
if let Some(args) = rest_args {
this.positional_args.extend(args);
}
Ok(this)
}

#[allow(clippy::too_many_lines)]
async fn execute(
&self,
Expand Down Expand Up @@ -308,16 +338,26 @@ impl builtins::Command for SetCommand {
}
}

for (i, arg) in self.positional_args.iter().enumerate() {
if arg == "-" && i == 0 {
continue;
let skip = match self.positional_args.first() {
Some(x) if x == "-" => {
if self.positional_args.len() > 1 {
context.shell.positional_parameters.clear();
}
1
}

if i < context.shell.positional_parameters.len() {
arg.clone_into(&mut context.shell.positional_parameters[i]);
} else {
context.shell.positional_parameters.push(arg.to_owned());
Some(x) if x == "--" => {
context.shell.positional_parameters.clear();
1
}
Some(_) => {
context.shell.positional_parameters.clear();
0
}
None => 0,
};

for arg in self.positional_args.iter().skip(skip) {
context.shell.positional_parameters.push(arg.to_owned());
}

saw_option = saw_option || !self.positional_args.is_empty();
Expand Down
35 changes: 35 additions & 0 deletions brush-shell/tests/cases/builtins/set.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,41 @@
name: "Builtins: set"
cases:
- name: "set with no args"
stdin: |
MYVARIABLE=VALUE
set > set-output.txt
grep MYVARIABLE set-output.txt
# Remove set-output.txt to avoid it being byte-for-byte compared.
rm set-output.txt
- name: "Basic set usage"
stdin: |
set a b c d
echo ${*}
- name: "set clearing args"
stdin: |
set a b c
echo ${*}
set a
echo ${*}
- name: "set with -"
stdin: |
set - a b c
echo "args: " ${*}
set -
echo "args: " ${*}
- name: "set with --"
stdin: |
set -- a b c
echo "args: " ${*}
set --
echo "args: " ${*}
- name: "set with option-looking tokens"
stdin: |
set a -v
echo ${*}

0 comments on commit 1a780de

Please sign in to comment.