[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: replacing process sentinels and filters with hooks
Re: replacing process sentinels and filters with hooks
Mon, 1 Oct 2012 12:53:08 -0400
My mistake, I don't think I posted this response to the list. Sorry
for double message, Stefan.
On Mon, Oct 1, 2012 at 11:34 AM, Stefan Monnier
>> 1) Process filters and sentinels do not fit in with the rest of the
>> Emacs API. In every other API that I can think of that involves a user
>> callback, the hooks API is used.
> Hooks are used normally for un-planned interaction between two
> unrelated packages. OTOH process sentinels and filters are typically
> tightly linked to their process, the package that creates the process
> being usually the same that provides the sentinels and filters.
> 3) It's hard for more than one interested party to interact with a process.
> Indeed, tho it's rarely needed. Concrete examples would be useful for
> this discussion.
This is not my experience working with the shell and comint packages.
For instance, comint has its own hook, comint-input-filter-functions,
for doing exactly what this proposal suggests (sans sentinels). This
hook for example lets shell check for cd/pushd when doing directory
shell is lucky that comint doesn't use a sentinel, because it
sometimes steals the process sentinel to save the shell history on
exit. If comint adds its own sentinel (which isn't too unreasonable,
considering that comint creates the process) then shell's code is
broken; the two will fight with each other. And shell does *assume*
comint doesn't use a sentinel, because it doesn't setup any code to
call "the next sentinel".
Perhaps that's not such a big deal, because both modes are in the
Emacs tree, and we can just fix that. What *is* a big deal is that it
would break anyone else's code to add such a sentinel to comint.
There is no way either to add a "comint-sentinel-functions" because
there is no way comint can guarantee that its sentinel is running (due
to assumptions like the one shell mode made).
In other words, it's really nasty that having or not having a
sentinel/filter is apart of the API of your program.
One could say "it's a best practice to always remember the last
sentinel". And I would respond, "well, if it is a best practice, then
why doesn't the API use hooks?"
For another example, I wrote a package similar to popwin
(https://github.com/m2ym/popwin-el) that uses the shell. On a key
press, I can open a temporary shell in a small popped window, which is
pretty handy. It is also pretty handy that when I exit the shell (by
typing exit in bash) the shell window is destroyed. But I can't know
if I have exited unless I have a sentinel. And I have to share the
sentinel with shell-write-history-on-exit.
> Just <string> would work as well.
I disagree. Ideally I'd like to use pcase to check the three
alternatives; to do this, I either have to ensure that the (input ...)
case is last, or I have to use a more complicated pattern involving
(pred stringp). And with the proposed API, you do have to check--you
cannot simply just assume that your argument is a string. So let's
make it as easy as possible to check.
> So your proposal can be decomposed in 3 parts:
> - provide a standard way to combine sentinels and filters, which is to
> run them in sequence (for sentinels, it might be a fine default, but
> for filters, it might be more useful for each filter to be able to
> affect the <string> passed to the next filter).
I'll add that this can be useful for any hook that takes arguments. I
think it is a bad idea to consider process callback functions special.
If it is useful behavior to modify callback arguments, then let us be
consistent and give that ability to any type of callback, not just
> I agree the third part is a good change (tho not terribly important).
I'm interested in gradually improving the existing Emacs API. To me,
it is very important. And since I have volunteered to do all of the
work (and probably won't volunteer on things that others find
important, as there are many important things to be done) it won't eat
up any of your time, unless you decide to review a patch. In which
case I would be very grateful of your time! :)
> I'm not sure the first is useful since in my experience sentinels and
> filters do different things anyway.
I personally think it is cleaner to have them together, but if others
disagree there is probably a reason for it :) This is not an essential
part of my proposal.
> As for the second, maybe a better path is to try and provide generic
> `add-function' and `remove-function' that can operate on any
> generalized-variable that holds a function. So you could do
> (add-function (process-filter proc) #'toto)
> which would set proc's filter to a new function that runs the old
> function (if any) and runs toto as well. And then `remove-function'
> would reset the sentinel to its original value.
Why have a different way of doing things? One of the reasons I like my
proposal is that it unifies concepts and adds more consistency to the
API. The slogan: "If you want have a callback, use the hook API."
Since there is no way for filters and sentinels to guarantee order
(just like hooks) I think the best route is to just add the ability
for a hook to modify the arguments that are passed to the next hook.
Although I am not too convinced that this is important,
comint-input-filter-functions doesn't do this.
> run-hooks takes symbols as arguments.
It was just an example, I am a busy person and I think I got the gist
of what I was saying across. But I'll add (off-topic) that there seems
to be no reason for run-hooks to take a symbol as an argument. The C
code just immediately dereferences it.