feat: implement $_ special parameter for last command argument#1030
feat: implement $_ special parameter for last command argument#1030lu-zero wants to merge 1 commit intoreubeno:mainfrom
Conversation
Public API changes for crate: brush-coreAdded itemsPerformance Benchmark Report
Code Coverage Report: Only Changed Files listed
Minimum allowed coverage is Test Summary: bash-completion test suite
|
690b602 to
1581976
Compare
8810085 to
e6f83fa
Compare
|
Now it should be cleaner |
There was a problem hiding this comment.
Pull request overview
Adds bash-compatible handling for $_ by initializing and updating the _ shell variable to track the last argument of the previous command, and updates compatibility tests to cover/enable this behavior (notably #479).
Changes:
- Initialize
_to$0during well-known variable setup and update_from command execution paths. - Set child-process
_env var for external commands to the resolved executable path (bash-like behavior). - Add/adjust compat tests for
$_and remove the known-failure flag for the existingdollar-_case.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| xtask/src/test.rs | Comment wrapping (no functional change). |
| brush-shell/tests/cases/compat/well_known_vars.yaml | Removes known_failure for the dollar-_ compat case. |
| brush-shell/tests/cases/compat/special_parameters.yaml | Adds a basic compat case covering $_ updates across sequential commands. |
| brush-parser/src/tokenizer.rs | Doc comment wrapping (no functional change). |
| brush-core/src/wellknownvars.rs | Initializes _ to the current shell name ($0). |
| brush-core/src/shell/state.rs | Adds ShellState::update_last_arg_variable helper to update _. |
| brush-core/src/shell.rs | Doc comment wrapping (no functional change). |
| brush-core/src/interp.rs | Comment wrapping/formatting (no functional change). |
| brush-core/src/commands.rs | Updates _ after builtin/function/external execution; sets child _ env var for external commands. |
| brush-builtins/src/read.rs | Doc comment wrapping (no functional change). |
| // Strip the function name off args. | ||
| let result = invoke_shell_function(func_registration, cmd_context, &self.args[1..]).await; | ||
|
|
||
| // Update $_ after command execution. | ||
| shell.update_last_arg_variable(last_arg.as_deref()); | ||
|
|
There was a problem hiding this comment.
$_ (via _ variable) is updated only after invoke_shell_function returns, which means the function body will see the previous command’s value for $_ instead of the last argument of the function invocation (bash updates _ for the duration of the command being executed, i.e., after argument expansion but before running the builtin/function body). Consider moving the _ update to just before invoking the function (and likewise for the builtin paths) so $_ is correct inside the executed command, not just for the next command.
| - name: "$_ - last command argument" | ||
| stdin: | |
There was a problem hiding this comment.
PR description mentions adding a SpecialParameter variant / PEG changes for parsing $_, but in the current codebase $_ is still parsed as a normal named variable (_) (no SpecialParameter addition found). If the intent is to implement this via the regular _ variable (as this PR does by setting _ in the environment), the PR description should be updated to reflect that; otherwise the missing parser/AST changes need to be added.
| - name: "$_ - last command argument" | ||
| stdin: | | ||
| : 0 | ||
| echo "$_" | ||
| : 0 1 2 | ||
| echo "$_" | ||
| echo "first command" | ||
| echo "$_" |
There was a problem hiding this comment.
The new $_ case covers basic sequential commands, but it doesn’t exercise the tricky scoping/update boundaries where bash behavior tends to differ (e.g., inside a function body immediately after invocation, inside a subshell/command substitution, and across pipelines/backgrounded commands). Adding a few compat cases covering those would help prevent regressions and confirm the update timing matches bash.
reubeno
left a comment
There was a problem hiding this comment.
Looking pretty good! Just a few comments.
| ); | ||
|
|
||
| // Update $_ after command execution. | ||
| shell.update_last_arg_variable(last_arg.as_deref()); |
There was a problem hiding this comment.
In each of these cases, we have an owned String of the last argument (or at least an Option of one). Couldn't we save a string clone by having the setter in Shell require the owned String?
| : 0 1 2 | ||
| echo "$_" | ||
| echo "first command" | ||
| echo "$_" |
There was a problem hiding this comment.
Could you please add a few test cases that cover other scenarios? e.g.:
- Pipeline with multiple commands
- Commands with
&&/|| - Command substitution / subshell
- Builtin invocation
- Function invocation
- Commands that fail
We typically don't need to go so broad but because there are multiple code paths for handling different kinds of commands here, I think these will be important to ensure compatibility (and prevent us from regressing it in the future).
32ceb25 to
8629cdd
Compare
Add support for $_, which expands to the last argument of the previous command. This is implemented as a regular shell variable, not a special parameter, matching bash semantics. - Initialize $_ to $0 (shell name) at startup in wellknownvars.rs - Update $_ to the last argument after each command execution - Set _ env var to the resolved command path for external commands - Add test cases for $_ behavior fix: properly clear $_ after assignment statements Assignment-only statements should clear $_ (set to empty string) to match bash behavior. Also use the update_last_arg_variable helper consistently throughout the codebase.
8629cdd to
aa48d0b
Compare
Add support for the $_ special parameter, which expands to the last argument of the previous command.