Open curusarn opened 5 years ago
This issue is very similar to this one: https://github.com/rcaloras/bash-preexec/issues/27
Do you have any thoughts for how bash-preexec could better handle this situation? I don't think a consensus was reached in #27.
My immediate thought was to use some of the variables that are set when readline widgets are executed (READLINE_LINE
, READLINE_POINT
). The problem is that these are not set when the trap is triggered.
I have read the bash manual to look for other suitable variables but I couldn't find any.
I needed to solve this in my project. (https://github.com/curusarn/resh)
I did work around this by re-enabling bash-preexec in my own custom readline widgets/functions.
Setting __bp_preexec_interactive_mode="on"
re-enables the hook so it runs again. I don't do anything disruptive in my hooked functions so I can safely rerun them like this. I discard the bogus data I get from all the invocations before the last proper one. (https://github.com/curusarn/resh/blob/master/scripts/widgets.sh#L10)
Needless to say, this is nor very safe nor usable in the general case. It breaks if someone uses their own custom readline functions/widgets (luckily this is not common). Not all projects can get away with invoking the hooks repeatedly.
I have just messaged the bug-bash@gnu.org mailing list to ask them if there is a way to determine why the DEBUG trap was triggered. If it was invoked because of "real" interactive command or because of custom readline function/widget.
This is a reply I got from Chet Ramey:
On 3/15/20 7:41 AM, Šimon Let wrote:
Hi All,
I'm using PROMPT_COMMAND and DEBUG trap to emulate "PRE" and "POST" hooks in bash. I have run into the issue where the DEBUG trap gets triggered when any custom readline widget/function is executed. I would like to programmatically determine if the DEBUG trap was triggered for a "real" interactive command or if it was triggered for a custom readline widget.
Since the DEBUG trap happens before the command executes, it's not a real `post-command' hook.
I tried to use READLINE_LINE and READLINE_POINT variables but these are not set during the DEBUG trap.
They're not set when the the DEBUG trap runs before, say, a shell function you've bound to a key sequence using `bind -x' is executed, but they're available to commands called from within that shell function.
Is there another way that can be used to determine why the DEBUG trap was triggered?
No.
PS: I'm wondering what is your opinion on providing PRE and POST functions natively in bash?
I'd have to see a compelling reason to implement them.
Chet
The most important part is that there is no way to tell why was the DEBUG trap triggered.
It seems that there are two options:
1) come up with some ridiculous hack (maybe somehow use both PS0
and DEBUG trap) - unlikely
2) try to persuade maintainers of bash to make it possible to tell or even to support PRE POST hooks natively
It's worth remembering that bash-preexec is attempting to implement support for pre/post on top of a shell that doesn't provide this functionality (as Chet said). There will likely always be gaps in functionality because of this Bash design decision, and if Bash ever provided proper hooks this project would no longer be needed[1].
Certainly if you can identify a reasonable combination of hooks that get what you need without regressing other user experiences it might be possible to improve bash-preexec, but you'd likely be in the best position to drive that.
[1]: But even if a new Bash version implemented hooks people will be running older Bash versions for the foreseeable future, so making changes to Bash itself won't help most users for a fairly long time.
I think this issue might be solved by #152 - the updated version works for me, keybindings set up with bind
do not result in preexec hooks running.
I think you are right. The problem reported here should be fixed by #152.
Readline allows us to bind arbitrary shell commands to key sequences using
bind -x
. Using these shell commands results inpreexec()
being executed before accepting the command line instead of after. Pluspreexec()
is executed with the same argument twice effectively skipping the next accepted command-line.Example
preexec()
andprecmd()
Control+X
Control+X
We can see thatpreexec()
was run before we accepted the command line. We can also notice thatpreexec()
run with the same argument as moments before.Enter
to accept the command typed by readline We can see thatpreexec()
wasn't executed this time effectively skipping the command-line typed by readline.