Subject: Re: bug#77452: 31.0.50; Wide characters in left margin on ttys

From: Eli Zaretskii <[email-masked]>
Date: Wed, 02 Apr 2025 17:47:47 +0300

> From: Gerd Möllmann <[email-masked]>
> Cc: [email-masked]
> Date: Wed, 02 Apr 2025 15:04:55 +0200
> 
> Eli Zaretskii <[email-masked]> writes:
> 
> > The problem is not the char-width of 💡 nor with advancement of the
> > cursor, the problem is that the string "1💡" doesn't fit in the
> > 2-column wide margin, and Emacs should have displayed only "1", since
> > we cannot clip glyphs on TTY frames.
> 
> Exactly, that pretty much what I meant :-). The wide character may not
> be output to the terminal, otherwise display and matrices get out of
> sync.
> 
> > Are you going to work on fixing this long-time problem?  Or should I?
> 
> I tried to read and understand display_line etc. this morning, but I'm afraid
> there is too much going on there for me to find the cause of this in
> reasonable time.

Does the below look right to you?

diff --git a/src/xdisp.c b/src/xdisp.c
index 2c676c0..1c54e7c 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -25685,7 +25685,7 @@ #define RECORD_MAX_MIN_POS(IT)					\
 
       /* Now, get the metrics of what we want to display.  This also
 	 generates glyphs in `row' (which is IT->glyph_row).  */
-      n_glyphs_before = row->used[TEXT_AREA];
+      n_glyphs_before = row->used[it->area];
       x = it->current_x;
 
       /* Remember the line height so far in case the next element doesn't
@@ -25732,6 +25732,7 @@ #define RECORD_MAX_MIN_POS(IT)					\
 	 the next one.  */
       if (it->area != TEXT_AREA)
 	{
+	  enum glyph_row_area area = it->area;
 	  row->ascent = max (row->ascent, it->max_ascent);
 	  row->height = max (row->height, it->max_ascent + it->max_descent);
 	  row->phys_ascent = max (row->phys_ascent, it->max_phys_ascent);
@@ -25740,6 +25741,14 @@ #define RECORD_MAX_MIN_POS(IT)					\
 	  row->extra_line_spacing = max (row->extra_line_spacing,
 					 it->max_extra_line_spacing);
 	  set_iterator_to_next (it, true);
+	  /* If we exhausted the glyphs of the marginal area...	 */
+	  if (it->area != area
+	      /* ...and the last character was multi-column...	*/
+	      && it->nglyphs > 1
+	      /* ...and not all of its glyphs fit in the marginal area... */
+	      && row->used[area] < n_glyphs_before + it->nglyphs)
+	      /* ...then reset back to the previous character.	*/
+	    row->used[area] = n_glyphs_before;
 	  /* If we didn't handle the line/wrap prefix above, and the
 	     call to set_iterator_to_next just switched to TEXT_AREA,
 	     process the prefix now.  */