Subject: Re: bug#40821: Margin strings are displayed in reverse order of overlay priority (low-priority specs hide high-priority ones)

From: Clément Pit-Claudel <[email-masked]>
Date: Sat, 25 Apr 2020 09:01:07 -0400

On 25/04/2020 03.58, Eli Zaretskii wrote:
>> One unfortunate side effect of this is that, when margins are too narrow, low-priority margin specs are displayed before high-priority ones, and hence high-priority ones are not visible.
> 
> Yes, the display margins use this very simple strategy of truncating
> the stuff that has no margin space to be displayed.  Why can't you
> compute the width of the margins taking into consideration the size of
> what you need to display there?

I only want/need to display one margin indicator — the highest priority one :)
Consider a line with the following contents:

eee www ewew

And let's assume that the compiler says this:

0-3: error: …
4-7: warning: …
8-12: error: …
8-12: warning: …

In that case, I don't need 4 indicators in the margin, I want just one (indicating an error). But in the the buffer I'd like 4 overlays to apply error and warning faces (though, since two of them cover the same area, one will not be visible; overlay priorities are used to ensure that the error one will take precedence over the warning one).

>> Additionally, unlike fringe bitmaps, for which the highest-priority bitmap replaces all others on the same line, there doesn't seem to be a way for higher-priority margin specs to replace lower-priority ones.
> 
> First, I don't understand what you say about fringe bitmaps: I don't
> think there's any priority associated with those bitmaps, or what am I
> missing?

Your confusion is understandable: I was wrong :(

(with-current-buffer (get-buffer-create "*fringes*")
  (erase-buffer)
  (delete-all-overlays)
  (let ((beg (point))
        (end (progn (insert "test") (point))))
    (let ((ov-low (make-overlay beg end)))
      (overlay-put ov-low 'before-string (propertize "low" 'display '(left-fringe right-arrow compilation-info)))
      (overlay-put ov-low 'priority 10))
    (let ((ov-mid (make-overlay beg end)))
      (overlay-put ov-mid 'before-string (propertize "mid" 'display '(left-fringe compilation-warning)))
      (overlay-put ov-mid 'priority 50))
    (let ((ov-high (make-overlay beg end)))
      (overlay-put ov-high 'before-string (propertize "high" 'display '(left-fringe compilation-error)))
      (overlay-put ov-high 'priority 100)))
  (pop-to-buffer (current-buffer)))

I thought this would show a fringe icon in compilation-error face, because of the higher priority of the corresponding overlay.  It doesn't.
Should I report this as a separate issue?

> It should be possible to support this idea of "replacing" margin specs
> (which seems strange to me, FWIW), given some special display spec,
> but it would need a separate pass through the overlays, to find those
> which draw in the margins, and mark the replaced ones as "not to be
> processed".  But I question the need for such a complexity, when a
> simpler solution that doesn't require any changes seems to be at hand.

Widening the margin isn't a working solution for this case, but displaying the margin specs in order of increasing priority would work.  However, wouldn't that require a second pass as well?  That is, if margin specs were sorted by priority before being inserted, it would work (it wouldn't matter that there are multiple instead of one, since the most important one would be first).

>> This issue came up when trying to develop a mode to indicate errors and warnings in the margins (instead of drawing symbols in the fringes).  Currently, if a line contains errors and warnings, Flycheck will place multiple overlays on the same line, and the fringe bitmap corresponding to the highest-priority one will be displayed.  But if we put a symbol in the margins instead of the fringes, the symbols won't override each others: instead, they will be concatenated, often in the wrong order (as shown in the attached screenshot).
> 
> A simple way of overcoming this problem is to define the overlay
> priorities in the reverse order of the Flycheck's error/warning
> priorities.  A better solution would be to make the margin wider as
> needed, something that should be easy enough (line-number-mode did
> that, for example).

Unfortunately, neither of these will do.  Reversing the overlay priorities means that the text (ewew) in the example above (eee www ewew) will have the warning face applied to it, not the error face.

Making the margins wider won't help either, because I'd like to display the highest-priority issue in the margin, not all of them (often compilers get confused and issue additional spurious messages, so even if there's multiple errors and warnings on one line displaying a single error indicator in the fringe or margin is enough).

Thanks for your help,
Clément.