Open krader1961 opened 1 year ago
Having slept on the idea I've decided there should be a $before-external-cmd
and $after-external-cmd
pair of callback lists.
In the before variant each callback in the list is called with a list composed of the full path to the command, the original command name, and all arguments. If it outputs $true
the next callback, if any, is invoked or the command is run. If it outputs $false
no remaining callbacks are run (including the "after" callbacks) and the external command is not run. The idea is that this allows a $before-external-cmd
callback to substitute different behavior for the external command. Possibly via emulation using only Elvish builtins or via some other external command (which itself is subject to the callbacks). Care needs to be taken to avoid infinite recursion. At a minimum a sane limit on callback recursion needs to be imposed by Elvish itself.
In the after variant each callback in the list is called with the time in fractional seconds the external command ran to completion, its numeric exit status, the full path to the command, the original command name, and all arguments. The after variant is primarily meant for logging which external commands are run but there may be other uses.
The callbacks should include additional info to make it easier to know the context in which the external command is being run; e.g., which module, script, or interactive context invoking the external command. This came to light in response to a change proposed by @xiaq to my PR #1680 to replace some external commands in the epm
module with builtins.
While working on resolving issue #1661 I noticed that
pragma unknown-command = disallow
mostly does what I needed and made it easy to identify most (all?) of the external commands used by theepm
builtin. I say most because it does not warn about explicit external commands; e.g.,e:cat
. Theepm
builtin currently does not use such explicit external commands (AFAICT), but if it did theunknown-command
pragma would not be useful for identifying all of the external commands it uses. A callback that is run before any external command is executed would solve this need and potentially have other uses. The callback should, obviously, be invoked with the external command path and any arguments. It's not clear whether the value stream output of the callback (interpreted as a bool value) should affect whether the command is actually run. If that feature were implemented it would presumably mean treating the external command as if it exited with a non-zero status if the callback indicated the external command should not be run. I don't see a good use-case for that behavior and am therefore not inclined to implement it but I think it's an open question.