Subject: Re: bug#43519: 28.0.50; Overlay at end of minibuf hides minibuf's real content

From: Stefan Monnier <[email-masked]>
Date: Sat, 19 Sep 2020 18:06:20 -0400

>> I disagree: icomplete merely added text after point via an overlay and
>> didn't do anything which explicitly justifies horizontal scrolling.
>
> Maybe I'm missing something, but what does the code in
> icomplete-completions that calls string-width and window-width try to
> do, then?  I mean this part:
>
> 	     ;;"-prospects" - more than one candidate
> 	     (prospects-len (+ (string-width
> 				(or determ (concat open-bracket close-bracket)))
> 			       (string-width icomplete-separator)
> 			       (+ 2 (string-width ellipsis)) ;; take {…} into account
> 			       (string-width (buffer-string))))
>              (prospects-max
>               ;; Max total length to use, including the minibuffer content.
>               (* (+ icomplete-prospects-height
>                     ;; If the minibuffer content already uses up more than
>                     ;; one line, increase the allowable space accordingly.
>                     (/ prospects-len (window-width)))
>                  (window-width)))

That's not relevant to the issue at hand.  I used `icomplete-mode` only
as a vehicle to show the underlying behavior with a short recipe which
exhibits a real-life problem.

>> > It should produce an overlay string that fits in the window, then the
>> > prompt will be visible.
>> That would merely work around the underlying problem
> What do you think is the underlying problem?

That the redisplay performed horizontal scrolling when it was not needed
since the cursor was already visible without such scrolling.

>> (and as you know it's wickedly difficult to construct a string which
>> will have "just the right size" to fit into the minibuffer window).
> It doesn't have to be "just the right size", it could err on the safe
> side.  It already attempts to do so, by avoiding truncation in the
> middle of a candidate.  It should just do a better job, that's all.

And how do we generalize that to the case where the overlay contains
newlines, TABs, chars in different scripts using different fonts,
different faces, images, etc.... ?

>> Maybe there's a good reason for the redisplay to behave this way
> Behave in what way? what's special about what you see on display in
> this case, given the contents of the mini-window's buffer?

Try the recipe below instead:

    (minibuffer-with-setup-hook
        (lambda ()
          (insert "hello")
          (let ((ol (make-overlay (point) (point)))
                (max-mini-window-height 1)
                (text "askdjfhaklsjdfhlkasjdfhklasdhflkasdhflkajsdhflkashdfkljahsdlfkjahsdlfkjhasldkfhalskdjfhalskdfhlaksdhfklasdhflkasdhflkasdhflkajsdhklajsdgh"))
            (save-excursion (insert text))
            (sit-for 2)
            (delete-region (point) (point-max))
            (put-text-property 0 1 'cursor t text)
            (overlay-put ol 'after-string text)
            (sit-for 2)
            (delete-overlay ol)))
      (read-string "toto: "))

This performs "display of text after point" in 2 different ways:
- first by `insert`.
- then with an overlay.
The visual rendering of the text is the same, with the cursor at the
same place.  When we do it with `insert` there is no horizontal
scrolling, but when we do it with an overlay the text gets scrolled so
the cursor is at `window-start`.

`icomplete` needs the behavior to be the same as with `insert`, but it
prefers to use an overlay to avoid some undesirable side-effects of
modifying the actual text.

So the question is: how to get the same behavior as what we'd get with
`insert` but without actually modifying the buffer's contents?

Is it more clear now?

        Stefan