Subject: Re: bug#78180: 31.0.50; Since ab71699e5f2, global value of post-command-hook is useless

From: Ihor Radchenko <[email-masked]>
Date: Thu, 01 May 2025 17:51:37 +0000

Eli Zaretskii <[email-masked]> writes:

> Please explain why "it is no longer possible to setup
> post-command-hook globally", or what do you mean by "impossible".
> Your claim that the global value of post-command-hook is now useless
> sounds grave, but you never explain why you make such a claim.

By "impossible", I did not mean that you cannot set global value, but
rather that pretty much every single buffer will have a buffer-local
value that is shadowing the global value set by add-hook without LOCAL
arg.

Although, I now tested things more rigorously, and post-command-hook
does get evaluated, despite the above. So, I clearly miss something
about how and in which context post-command-hook is evaluated.

> The post-command-hook is modified by calling add-hook and remove-hook,
> which still work.  The global value of post-command-hook was non-nil
> by default before the above change, and it is still not nil after it.

You are right that the global value does get set and it is non-nil.
The problem is with buffer-local value - with eldoc-mode, which is,
after ab71699e5f2, enabled by default in all buffers, every single new
buffer will have non-nil buffer-local value of post-command-hook.

>> It is also not possible to setup transient hooks (self-removed upon
>> first execution) as long as current command ends up in different buffer.
>
> Why not?  Again, please tell the details.

>> (It was technically not exactly possible in the past as well, for
>> buffers holding their buffer-local post-command-hook value, but the
>> problem was less obvious as most buffers had post-command-hook set to
>> its default value)
>
> AFAIU, it is still the case that most buffers have post-command-hook
> set to its default value.  If not, please explain why not.

This is not true - most buffers, after ab71699e5f2, do _not_ have
post-command-hook set to its default value. Let me provide an illustration:

1. emacs -Q
2. M-: (add-hook 'post-command-hook #'always)
2. M-: (dolist (buf (buffer-list))
     (with-current-buffer buf
       (message "%S -> %S" buf post-command-hook)))
3. Observe the following in *Messages*

#<buffer *scratch*> -> (jit-lock--antiblink-post-command eldoc-schedule-timer t)
#<buffer  *Minibuf-1*> -> (eldoc-schedule-timer t)
#<buffer  *Minibuf-0*> -> (eldoc-schedule-timer t)
#<buffer *Messages*> -> (eldoc-schedule-timer t)
#<buffer  *Echo Area 0*> -> (always)
#<buffer  *Echo Area 1*> -> (always)

4. Create a new buffer C-x b new RET
5. M-: post-command-hook RET
   
   (eldoc-schedule-timer t)   

   The new buffers gets buffer-local value, not global (always) value.

I note that Echo Area still gets the global hook value. Maybe it can
explain why global value of post-command-hook still gets executed in my
interactive testing.

I did the following test, I left wondering what is going on:

1. emacs -Q
2. (trace-function #'always)
3. (trace-function #'eldoc-schedule-timer)
4. (add-hook 'post-command-hook #'always)
5. C-n C-p C-n C-p
6. Observe _both_ buffer-local and global values of post-command-hook
   executed. Why is that?

>> The problem may affect:
>> 1. Org mode (that's how I found the problem)
>> 2. vcursor.el, vc.el, type-break.el, transient.el, xterm.el,
>>    scroll-all.el, global-reveal-mode, repeat-mode, gud.el, flymake,
>>    elisp-mode.el, and basically any other part of Emacs setting global
>>    default value of post-command-hook.
>
> Affect how?  Please explain that, not just claim it.

That claim was based on my incomplete understanding. You can ignore this
part.

-- 
Ihor Radchenko // yantar92,
Org mode maintainer,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>