Subject: Re: bug#34476: fluffy whitespace in the mode-line, despite it running off the screen

From: Eli Zaretskii <[email-masked]>
Date: Sat, 15 Aug 2020 11:47:49 +0300

> Date: Fri, 14 Aug 2020 13:46:19 +0300
> From: Eli Zaretskii <[email-masked]>
> Cc: [email-masked], [email-masked]
> 
> The alternative which I would like to try implementing is to modify
> the code of display_string so that it doesn't produce multiple space
> glyphs, replacing them with a single glyph, when this option is
> non-nil.  Since display_mode_element always calls display_string to
> produce the glyphs, this should allow us to solve the problem cleanly.
> Stay tuned.

Here's the result.  Note that this is slightly sub-optimal, because if
2 Lisp strings are displayed one after another, and the first one ends
with a space, while the second one begins with a space, this will not
be squeezed, because we consider each string separately.  If this is
not acceptable, then we will have to go back to your original proposal
of using Fformat_mode_line (although I'm still unhappy with doing
that, as we had over the years quite a few complaints that the result
is not exactly identical to the displayed mode line).

If the patch below is deemed "good enough", we will probably need to
implement something similar for Fformat_mode_line, because users might
expect the latter to produce a similarly squeezed whitespace.

diff --git a/src/xdisp.c b/src/xdisp.c
index 4fe1c42..d9f6bea 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -26883,6 +26883,25 @@ display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_st
   row->phys_height = it->max_phys_ascent + it->max_phys_descent;
   row->extra_line_spacing = it->max_extra_line_spacing;
 
+  bool space_seen = false;
+  bool squeeze_spaces_p = false;
+  if (!NILP (Vmode_line_compact))
+    {
+      int remapped_modeline_face_id = MODE_LINE_FACE_ID;
+      int remapped_inactive_modeline_face_id = MODE_LINE_INACTIVE_FACE_ID;
+      if (!NILP (Vface_remapping_alist))
+	{
+	  remapped_modeline_face_id
+	    = lookup_basic_face (it->w, it->f, MODE_LINE_FACE_ID);
+	  remapped_inactive_modeline_face_id
+	    = lookup_basic_face (it->w, it->f, MODE_LINE_INACTIVE_FACE_ID);
+	}
+      /* We only squeeze multiple spaces when displaying mode lines.  */
+      squeeze_spaces_p
+	= (it->base_face_id == remapped_modeline_face_id
+	   || it->base_face_id == remapped_inactive_modeline_face_id);
+    }
+
   if (STRINGP (it->string))
     it_charpos = IT_STRING_CHARPOS (*it);
   else
@@ -26898,6 +26917,19 @@ display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_st
       if (!get_next_display_element (it))
 	break;
 
+      if (squeeze_spaces_p)
+	{
+	  if (it->char_to_display == ' ' && it->face_id == it->base_face_id)
+	    {
+	      if (space_seen)
+		goto next_char;
+	      else
+		space_seen = true;
+	    }
+	  else
+	    space_seen = false;
+	}
+
       /* Produce glyphs.  */
       x_before = it->current_x;
       n_glyphs_before = row->used[TEXT_AREA];
@@ -26962,6 +26994,7 @@ display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_st
       if (i < nglyphs)
 	break;
 
+    next_char:
       /* Stop at line ends.  */
       if (ITERATOR_AT_END_OF_LINE_P (it))
 	{