I think this is exactly answered by the doc in (elisp) Replacing Specs.
Consecutive text with the same display
property is handled as a block, replacing it by the display
property.
If a list of display specifications includes more than one replacing
display specification, the first overrides the rest. Replacing display
specifications make most other display specifications irrelevant, since
those don’t apply to the replacement.
But what matters is what "the same" means. Here it means eq
, which for a string, such as "|"
, means it has to be the same string object, not just two different string objects that have the same sequence of chars.
For replacing display specifications, “the text that has the
property” means all the consecutive characters that have the same Lisp
object as their ‘display’ property; these characters are replaced as a
single unit. If two characters have different Lisp objects as their
‘display’ properties (i.e., objects which are not ‘eq’), they are
handled separately.
In your first example you propertize the string "."
with a string "|"
, and you insert that. Then you do the same thing with another string "|"
. Two different strings, even though they're applied to consecutive chars, means two separate display
properties.
In your second example, you use function finsert
to insert the same propertized string multiple times.
This is a bit like the problem of using '(some list)
in a let
binding and then modifying that list. The source code "."
puts that single string into the function definition. This is different from having Lisp read and eval separate propertize
calls, reading separate strings that each look like "|"
.
Please read all of the cited node of the manual. It shows a clear example that corresponds exactly to what you do and see. The example puts two different (non-eq
) strings with the same replacement text on consecutive text, with two uses of property display
.
All of the chars that get each of the properties are handled as a block/unit. But the two uses of display
, with two different strings, mean that there are two such blocks of consecutive text, each with a different string used for property display
. The two strings are equal
(string=
), but they are not eq
: they are not the same string object.
If you don't want the same string (eq
) to be used every time you call finsert
, then tell it to create a new string each time, using make-string
:
(defun finsert ()
(insert (propertize "." 'display (make-string 1 ?|))))
Then you'll always see ||2
, because a different string "|"
will be used each time finsert
is called.