Subject: bug#31067: 27.0.50; After-string hidden by subsequent invisible text

From: Eli Zaretskii <[email-masked]>
Date: Thu, 05 Apr 2018 12:49:20 +0300

> From: Stefan Monnier <[email-masked]>
> Date: Wed, 04 Apr 2018 22:28:59 -0400
> 
>     (defun foo ()
>       (interactive)
>       (with-current-buffer "*scratch*"
>         (add-to-invisibility-spec '(foo . t))
>         (let ((beg (point)))
>           (insert "text")
>           (let ((ol1 (make-overlay beg (point))))
>             (overlay-put ol1 'after-string "!after!")
>             (overlay-put ol1 'evaporate t)))
>         (let ((beg (point)))
>           (insert "\nhidden")
>           (let ((ol1 (make-overlay beg (point))))
>             (overlay-put ol1 'invisible 'foo)
>             (overlay-put ol1 'evaporate t)))))
> 
> and then try it with `M-x foo`.
> The result for me is to display "text...", whereas I would have expected
> "text!after!...".
> 
> I.e. the after-string which I placed over "text" gets hidden by
> `invisible` property of the overlay placed on the immediately following
> "\nhidden".
> 
> I know these kinds of interactions are pretty delicate and often
> somewhat arbitrary (several behaviors are valid and we just have to pick
> one), but I think in this case it is clearly an error.

Would you expect the after-string to be shown in the variant below?

(defun foo ()
  (interactive)
  (with-current-buffer "*scratch*"
    (add-to-invisibility-spec '(foo . t))
    (let ((beg (point))
	  end)
      (insert "hidden")
      (setq end (point))
      (insert "text")
      (let ((ol1 (make-overlay beg end)))
        (overlay-put ol1 'after-string "!after!")
        (overlay-put ol1 'evaporate t))
      (let ((ol2 (make-overlay (1+ beg) (point))))
        (overlay-put ol2 'invisible 'foo)
        (overlay-put ol2 'evaporate t)))))

IOW, the question is what should happen when the end-point of the
overlay with after-string is in invisible text?