Subject: Re: bug#67604: Motion problems with inline images

From: Eli Zaretskii <[email-masked]>
Date: Thu, 29 May 2025 10:17:58 +0300

> From: JD Smith <[email-masked]>
> Date: Wed, 28 May 2025 19:42:50 -0400
> Cc: [email-masked]
> 
> #define BUFFER_POS_REACHED_P()					\
>   ((op & MOVE_TO_POS) != 0					\
>    && BUFFERP (it->object)					\
>    && (IT_CHARPOS (*it) == to_charpos				\
>        || ((!it->bidi_p						\
> 	    || BIDI_AT_BASE_LEVEL (it->bidi_it))		\
> 	   && IT_CHARPOS (*it) > to_charpos)			\
>        || (it->what == IT_COMPOSITION				\
> 	   && ((IT_CHARPOS (*it) > to_charpos			\
> 		&& to_charpos >= it->cmp_it.charpos)		\
> 	       || (IT_CHARPOS (*it) < to_charpos		\
> 		   && to_charpos <= it->cmp_it.charpos))))	\
>    && (it->method == GET_FROM_BUFFER				\
>        || (it->method == GET_FROM_DISPLAY_VECTOR		\
> 	   && it->dpvec + it->current.dpvec_index + 1 >= it->dpend)))
> 
> When the iterator arrives on the green box, it has reached its destination (to_charpos=89).  And yet, it does not stop.  Moving past the green box is what causes all the problems.  Why does it move on?  Everything here in this macro test is true, _except_ for it->method==GET_FROM_BUFFER and following.  As we're on an image, we have it->method=GET_FROM_IMAGE.  So, it fails.
> 
> Can you never actually reach a TO_CHARPOS position that is on an image (or stretch)?  Are you doomed to move past it?  That I don't understand.

We never return MOVE_POS_MATCH_OR_ZV unless we are iterating on buffer
text, yes.  That's because display properties and other similar
features can "cover" any number of buffer-text characters, and we
cannot know where it ends until we are done moving over it in its
entirety.  Maybe in your case the image only covered one buffer
position, but that is not always the case.  Or maybe you thought that
we return MOVE_POS_MATCH_OR_ZV when we are _at_ the position, whereas
in fact we return that when we got past the position (look at the
conditions in BUFFER_POS_REACHED_P that compare buffer positions).

So in this case, to return MOVE_POS_MATCH_OR_ZV, you need to move past
the image to the newline.  If that's what you did, and it->method was
still GET_FROM_IMAGE, please see why we don't update it->method,
because that is unexpected, I think.

> And yet, I think based on the various comments I've seen in the code about "moving past" images, BUFFER_POS_REACHED_P is perhaps intentionally False for images/stretches.  Is that your understanding? 

Yes, this is by design.  It's why Emacs can never place the cursor on
any character "covered" by the image, only either before or after the
image.

> I noticed this ChangeLog entry from Richard in 2004:
> 
> 	* xdisp.c (BUFFER_POS_REACHED_P): We haven't reached the specified
> 	position if we're reading from something other than the buffer.
> 
> Why?

Because unless we read from the buffer, we don't know what is the
correct buffer position.  I tried to explain that above.  So this
reason is still accurate.