Subject: bug#36312: 27.0.50; (message) in display spec condition causes emacs_abort()

From: Eli Zaretskii <[email-masked]>
Date: Fri, 21 Jun 2019 10:34:26 +0300

> From: Pip Cet <[email-masked]>
> Date: Thu, 20 Jun 2019 19:32:43 +0000
> Cc: [email-masked]
> 
> > You do realize that calling 'message' in a display-spec form causes us
> > to re-enter redisplay in the middle of redisplay?  I didn't even know
> > we allowed that, but there's something new about our display code to
> > learn every day.
> 
> I did learn that today, and it's very puzzling. For starters, why do
> we allow '(when ...), but not '(eval ...)?

Because the idea was that the result of the evaluation should be used
to affect the 'display' property in whose spec it is included, not to
run some arbitrary unrelated code.  With the intended use, 'when' is
more useful than 'eval', because 'when' can do everything 'eval' can
do, but not the other way around.

> And is it really a good idea to call code from redisplay?

That ship has sailed long ago, with Emacs 21.1.  We have
fontification-functions which are called from within redisplay, we
have (height SOMETHING) in display specs, where SOMETHING can be a
function or an arbitrary Lisp form which returns the height to be used
to display text, we have 'eval' in the mode line format, etc. etc.
Just search xdisp.c for safe_call and safe_eval, and you will see how
many of them are there.

It is true that running expensive Lisp from these hooks is a bad idea,
because it will slow down redisplay.  But Emacs gives you enough rope
to hang yourself, and then trusts you not to do that.

> The reason I'm looking at this is that I wanted to define an image
> that changes color based on the face properties at point. It turns out
> you can do that by abusing a (when ...) spec (which I use to call real
> code in a (run-with-timer 0 nil ...), to avoid the issue of recursive
> redisplays etc.).
> 
> It's very ugly, and I'm not sure what the best way to handle things
> would be; luckily, I'm not dependent on running on older or official
> Emacs versions, so I'm free to experiment.

Why not do something like that in a post-command-hook instead?  The
position of point is already up to date then, and retrieving face
properties at point is trivial.  What am I missing?

There's also pre-redisplay-hook.

> So far, what I'm thinking about is a hook that's run _after_ redisplay
> to let an overlay know that redisplay just happened and the face used
> for the text around the overlay changed.

I don't understand why you think you must run after redisplay.  If
redisplay changes the faces (probably via JIT font-lock?), and you
must have the corresponding change in your image without any delays
(though if you use a timer, you seem to not mind a delay), then why
not register a function with jit-lock-register, and do that from
there?  And if you indeed don't mind a short delay, then I think
post-command-hook should be your friend.

> But I'd appreciate any suggestions (the immediate application is to
> define character-like image-based glyphs that "look like text", but
> there might be others).

You seem to be thinking about font-lock like use cases, so plugging
yourself into jit-lock would be my first suggestion.

In any case, (ab)using 'when' in display specs for running code that
doesn't affect the value of that same display spec is to be avoided,
IMO, as that is not what these features is for.

Can we close this bug?  Is the crash fixed in your real-life code as
well?

Thanks.