rcaloras / bash-preexec

⚡ preexec and precmd functions for Bash just like Zsh.
MIT License
877 stars 93 forks source link

Preexec runs before accepting the command line when using readline shell command bindings. #100

Open curusarn opened 5 years ago

curusarn commented 5 years ago

Readline allows us to bind arbitrary shell commands to key sequences using bind -x. Using these shell commands results in preexec() being executed before accepting the command line instead of after. Plus preexec() is executed with the same argument twice effectively skipping the next accepted command-line.

Example

curusarn commented 5 years ago

This issue is very similar to this one: https://github.com/rcaloras/bash-preexec/issues/27

dimo414 commented 4 years ago

Do you have any thoughts for how bash-preexec could better handle this situation? I don't think a consensus was reached in #27.

curusarn commented 4 years ago

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.

curusarn commented 4 years ago

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

curusarn commented 4 years ago

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

dimo414 commented 4 years ago

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.

Rogach commented 8 months ago

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.

akinomyoga commented 8 months ago

I think you are right. The problem reported here should be fixed by #152.