Use a function substitution in $PS0 for preexec in Bash >= 5.3#166
Use a function substitution in $PS0 for preexec in Bash >= 5.3#166akinomyoga merged 6 commits intorcaloras:masterfrom
$PS0 for preexec in Bash >= 5.3#166Conversation
$PS0 and function substitution in Bash >= 5.3$PS0 for preexec in Bash >= 5.3
47d841d to
a391713
Compare
|
Bash 5.3 has been out for about six months, and sourcing bash-preexec from this PR works for me with atuin. @akinomyoga anything to add other than a rebase? @rcaloras would you be able to take a look? |
No. |
|
On reflection, @rcaloras what do you think about bringing on @akinomyoga as a collaborator with merge permissions (assuming he is amenable to it, of course)? Based on his recent work in bash-preexec, atuin’s Bash integration, ble.sh, bash-completion, and oils (a promising Bash-compatible shell), he seems like an excellent candidate. No affiliation, just an appreciative user! |
|
If @rcaloras is comfortable with it, I can be a collaborator, but I'm not sure if that actually changes the situation. It depends on the goal of this project and what kind of role and discretion in the project would be given to me as a collaborator. Even if I become a collaborator, @rcaloras makes the final decisions on the design and the direction of the project. If the project goal is to show the simplest implementation compromising stability and robustness (as guessed from past replies), any changes that increase the number of lines of code would never be adopted, even if it solves real problems. |
Ah, thanks for the context. Based on the tastes I’ve observed in your comments and commit messages here and elsewhere, if you were to maintain a fork, I’d certainly adopt it. I’m already using the version from this branch, but I don’t think there’s one branch integrating the various other patches you and others have submitted. It would be great if Ryan is open to collaborate, since forks have low visibility and have to build reputation mostly from scratch. But that’s how FOSS works sometimes! |
|
@akinomyoga another option is to create a detached fork (fork and then ask github support to make it a standalone repo). While I am not sure I understand whether this project is dead or going in a different direction, what is clear is that this project's master branch does not work for a bunch of apps (one of which is atuin). I also understand that you probably don't want to take this on as another one of your repos, in which case maybe you could create a matrix or explanation which of your PRs are the minimum requirement to make preexec work again. (master is not working with atuin or bash 5.3, but I am using ble anyway) |
|
Hey all, happy to support a bit here as I'm currently on a sabbatical. Apologies as this project hasn't been actively maintained outside of @akinomyoga's support.
@tessus What's the current issue with Bash 5.3? Seems to be working locally for me. With Atuin, is the issue just support for bash-preexec's primary limitations? i.e. situations preexec is not currently executed |
|
@akinomyoga would be interested to connect on collaborating further and granting you merge access too! You've been an amazing contributor and would love to avoid unnecessary forking so we can retain the repo/community. |
|
@rcaloras I screwed up my test VM and unfortunately the snapsshot is bonked as well. I should have a backup somewhere. I came across this problem a while back (definitely after upgrading to bash 5.3) when I tested on a VM w/o ble and none of the commands were saved into atuin's history. I have used a slightly modified bash-preexec.sh (available for 7 days) that has a few PRs incorporated. I can't recall which though. This version worked with atuin in the past. I'll restore the VM (as soon as find that backup) and run a few tests within the next few days. Maybe somebody else has some input until then. |
That is actually explained in the original explanation of this PR:
In particular, the issues with function definitions and comments are frequently reported to Atuin. @rcaloras I'm curious if there is any chance that this PR is merged. Also, I'd like to know the factors that determine which kind of PRs would be merged or rejected in this repository. Is it purely a matter of the free time you have? Or are there any additional constraints or a specific design goal that might affect the merging of PRs? Maybe there has't been clear design policies for this project, in which case I'd appreciate it if you could share your current feelings (which might later be changed after thorough considerations). |
I'd be happy to join the project as a Collaborator (in the sense of the GitHub terminology for the privileges). In that case, I think I'll later ask several questions about the policy and how we work together for the maintenance. |
There was a problem hiding this comment.
Pull request overview
This PR updates bash-preexec to use a PS0-based function substitution for preexec on Bash ≥ 5.3, avoiding reliance on the DEBUG trap for those versions and aiming to address several long-standing edge cases (e.g., subshells, function definitions, commented commands) specific to the DEBUG-trap approach.
Changes:
- Switch
preexecinstallation to PS0 hook for Bash ≥ 5.3, retaining the DEBUG trap hook for older Bash versions. - Refactor hook invocation to pass through “previous
$?/$_” context and to compute a “last non-zero status” from hook functions. - Add Bats tests for the new
__bp_invoke_precmd_functions/__bp_invoke_preexec_functionssemantics.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
bash-preexec.sh |
Adds PS0-based preexec hook for Bash ≥ 5.3 and refactors hook invocation/return-status handling. |
test/bash-preexec.bats |
Updates DEBUG-trap preservation expectations for older Bash and adds new tests for hook transparency/return behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| # Initial PROMPT_COMMAND string that is removed from PROMPT_COMMAND post __bp_install | ||
| __bp_install_string=$'__bp_trap_string="$(trap -p DEBUG)"\ntrap - DEBUG\n__bp_install' | ||
| __bp_install_string='__bp_install' |
There was a problem hiding this comment.
@akinomyoga Isn't this variable kind of redundant now since the trap string is being set conditionally in the install? Right now it's a string variable containing a substring of its own name, so I think just writing __bp_install is simpler rather than keeping this around.
There was a problem hiding this comment.
I'm neutral on this.
- It is in general a good practice to keep a magic constant (i.e., an integer or a string that is used for identification) in a global constant, though whether "__bp_install" is considered such a string is subtle. Currently,
$__bp_install_stringis used in four places (two places inbash-preexec.shand two places in tests). By the lexical context, if they were replaced by the value, it is not very clear thatPROMPT_COMMAND+='__bp_install'and"${existing_prompt_command//__bp_install/:}"should be updated consistently. In the future, one might modifyPROMPT_COMMANDand forget updating"${existing_prompt_command//__bp_install/:}"(and two additional places in the tests). They might be detected (I'm actually unsure about this because I haven't checked), but it is still non-trivial to rewrite those four places consistently. - Another aspect I'd like to point out is backward compatibility related to #129. Since #129 hasn't been merged and has been pending, external libraries have had to rely on internal variables such as
__bp_install_string. I actually use this variable in ble.sh for bash-preexec integration. If the variable is removed now, those integrations are broken. I can still update my code to work with the new version ofbash-preexec, but that complicates the code for the version detection of bash-preexec, and also the integration with an old version ofble.shin the market continues to be broken, until distributions' packages are replaced with the new version ofble.sh.
If you think it is still better to use the immediate values after considering those points, I'll update the PR. Or we might defer the discussion and the change in a new separate PR. @rcaloras What do you think?
|
edit: I'm sorry. Actually, the lowercase |
|
I rebased the commits on top of the latest |
Sorry, it turned out that Bats identifies the wrong test case for failure. The test cases that actually failed were
but Bats reported
to be failing. That is confusing. I fixed the tests in |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| __bp_invoke_precmd_functions "$__bp_last_ret_value" "$__bp_last_argument_prev_command" | ||
|
|
||
| __bp_set_ret_value "$__bp_last_ret_value" "$__bp_last_argument_prev_command" | ||
| } |
There was a problem hiding this comment.
In the Bash >= 5.3 (PS0-based) path there is no DEBUG trap invocation before __bp_precmd_invoke_cmd, so __bp_last_argument_prev_command is never refreshed to the last argument of the just-executed user command. As a result, the $_ value passed into __bp_invoke_precmd_functions (and later used for preexec) can lag by one command. Capture the current $_ at the very start of __bp_precmd_invoke_cmd (without disturbing the captured $?/PIPESTATUS) and store it into __bp_last_argument_prev_command before using it here.
There was a problem hiding this comment.
I checked the code, but even the current master doesn't seem to process this properly.
- Inside preexec functions,
$_is the exit status of the previous command with a plain Bash plusbash-preexec.sh. This is because the last argument was not properly set inside__bp_preexec_invoke_exec - Inside precmd functions,
$_is alwaysprecmdwith a plain Bash plusbash-preexec.sh. This is because theDEBUGtrap is called for the previousprecmdregistered toprecmd_functions, and theDEBUGtrap overwrites__bp_last_argument_prev_command.
I decided to fix the handling of the last argument altogether: abd0737
Actually, this is a change independent of the primary purpose of this PR, so please tell me if we should separate the PR.
There was a problem hiding this comment.
I have updated the tests abd0737..14ff607.
abd0737 to
14ff607
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
* Do not prefix local varnames with underscores
* Make "__bp_invoke_pre{cmd,exec}_functions" return the last non-zero exit status
* Test "__bp_invoke_pre{cmd,exec}_functions"
The Copilot agent suggested to check readonly variables in a finer way so that PS0 is not checked when PS0 is not used according to the current version of Bash. However, this duplicates the complicated test for the version requirement (( BASH_VERSINFO[0] > 5 || (BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] >= 3) )) for selecting the preexec strategy. However, it is more manageable to store the currently selected preexec strategy in a variable, and switch the behavior based on the saved strategy value. For this purpose, this patch adds a new global variable "$__bp_hook_preexec_proc" that contains the function name to install the hook. Then, we switch the check for readonly variables based on the value of "$__bp_hook_preexec_proc". Now, the conditional checks in Bats tests also use this variable to switch the tests.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@rcaloras I requested your review in the GitHub interface, but there doesn't seem to be an interface to re-request it until there is one, so let me manually mention you for the request of a review. I've processed most of the AI comments that make sense. I try to convince the AI in the review-revision loop, but AI seems to have started to raise different issues unrelated to this PR (some of them are the issues discussed in other PRs), so I stopped the looping.
|
There was a problem hiding this comment.
Tested locally for myself on 5.4 and 3.2. Working on my system.
With this change, I think the script is definitely getting more complicated/complex e.g. now that we're supporting variants across bash versions and also fixing some of the bash variable support which was broken. Would be interested to consider refactors or other clean ups to simplify.
Thank you @akinomyoga!
|
@akinomyoga I've also given you collaborator access as well. Feel free to merge this and would recommend also tagging a version release of 0.7.0 with it. |
|
Thank you! I joined the project.
Thank you for testing the branch too!
The first three commits of this PR have been some refactorings, but I agree that we may consider the global refactoring. In particular, I think we can consider reordering the functions. Currently, after incremental changes in the change history, functions of different purposes are interleaved. I can later review the code again. I'll later check the PR again and merge it. |
|
I'm merging this PR. I keep the respective commits because they contain multiple independent changes (partly because of the AI suggestions), and because I paid attention to keep additional changes properly squashed into the appropriate commits. |
|
Before tagging a new release, I want to see if #143 can be merged, since it seems that these days we are receiving several issues and PRs that would ultimately be solved by #143. Smaller patches have been submitted by PRs #154 and #180, but they will finally be replaced by the global re-implementation by #143, so I hesitate to apply the temporary changes #154 and #180. |
|
🎉 no fork! Thank you both! |
This implements the approach to preexec using a function substitution in PS0 mentioned in #28 (comment). This should solve the issues #164 (subshells), #6 (function definitions), #158 (comments),
#147 (custom HISTIGNORE/HISTCONTROL)in Bash 5.3 (which is now under the beta testing). It should be noted that this doesn't change the situation in Bash <= 5.2.edit: The issue with
HISTIGNOREandHISTCONTROLisn't solved by this PR.