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

From: Lars Ingebrigtsen <[email-masked]>
Date: Fri, 07 Aug 2020 10:31:22 +0200

Lars Ingebrigtsen <[email-masked]> writes:

> Hm...  well, since this is an optional thing users can switch on,
> perhaps making it slightly slower wouldn't be that much of a problem.
> Let's see...

OK, here's a proof of concept.  With the patch, the mode line looks like:

If this way of implementing it sounds OK to everybody, then I'll finish
the patch (and add support for "only compact if the line is too long")
and add documentation and NEWS.

diff --git a/src/xdisp.c b/src/xdisp.c
index 4fe1c4288a..938b3b408a 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -25216,14 +25216,42 @@ display_mode_line (struct window *w, enum face_id face_id, Lisp_Object format)
 			 format_mode_line_unwind_data (NULL, NULL,
 						       Qnil, false));
 
-  mode_line_target = MODE_LINE_DISPLAY;
-
   /* Temporarily make frame's keyboard the current kboard so that
      kboard-local variables in the mode_line_format will get the right
      values.  */
   push_kboard (FRAME_KBOARD (it.f));
   record_unwind_save_match_data ();
-  display_mode_element (&it, 0, 0, 0, format, Qnil, false);
+
+  if (NILP (Vmode_line_compact))
+    {
+      mode_line_target = MODE_LINE_DISPLAY;
+      display_mode_element (&it, 0, 0, 0, format, Qnil, false);
+    }
+  else
+    {
+      Lisp_Object mode_string = Fformat_mode_line (format, Qnil, Qnil, Qnil);
+      char *string = xmalloc (SBYTES (mode_string) + 1),
+	*ostring = SSDATA (mode_string);
+      char *s = string, prev = 0;
+
+      /* Copy over the data from the mode line string, but ignore
+	 repeating spaces.  This should be safe even for multibyte
+	 strings, since this is UTF-8. */
+      for (int i = 0; i < SBYTES (mode_string); i++)
+	{
+	  char c = ostring[i];
+	  if (!(c == ' ' && prev == ' '))
+	    {
+	      *s++ = c;
+	      prev = c;
+	    }
+	}
+      *s = 0;
+      
+      display_string (string, Qnil, Qnil, 0, 0, &it, 0, 0, 0,
+		      STRING_MULTIBYTE (mode_string));
+      xfree (string);
+    }
   pop_kboard ();
 
   unbind_to (count, Qnil);
@@ -34551,6 +34579,11 @@ syms_of_xdisp (void)
 The face used for trailing whitespace is `trailing-whitespace'.  */);
   Vshow_trailing_whitespace = Qnil;
 
+  DEFVAR_LISP ("mode-line-compact", Vmode_line_compact,
+    doc: /* Non-nil means that mode lines should be compact.
+This means that repeating spaces will be replaced with a single space.  */);
+  Vmode_line_compact = Qnil;
+
   DEFVAR_LISP ("nobreak-char-display", Vnobreak_char_display,
     doc: /* Control highlighting of non-ASCII space and hyphen chars.
 If the value is t, Emacs highlights non-ASCII chars which have the

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no