Subject: [PATCH] Implement display-line-numbers-spacing-width

From: Miro Palmu <[email-masked]>
Date: Tue, 25 Feb 2025 18:40:07 +0200

Currently there is hard coded one character wide spacing around line 
numbers.
This patch adds `display-line-numbers-spacing-width' (default: 1),
which allows to configure the width of the spacing.
This is mostly motivated by wanting to set the spacing to zero.

This is result of make -C test:

SUMMARY OF TEST RESULTS
-----------------------
Files examined: 528
Ran 7991 tests, 7784 results as expected, 1 unexpected, 206 skipped
1 files contained unexpected results:
   lisp/progmodes/c-ts-mode-tests.log

1 unexpected results:
    FAILED  c-ts-mode-test-indentation

I assume that failing c-ts-mode-test-indentation is unrelated to this patch.

Miro Palmu

From 1fc084da5211e884fd8439f0ac0a8760b366781b Mon Sep 17 00:00:00 2001
From: Miro Palmu <[email-masked]>
Date: Tue, 25 Feb 2025 17:48:14 +0200
Subject: [PATCH] Implement display-line-numbers-spacing-width

* src/xdisp.c: define `display-line-number-spacing-width'
* src/xdisp.c (maybe_produce_line_number):
take `display-line-number-spacing-width' into account
* lisp/cus-star.el: make `display-line-numbers-spacing-width' customizable
* lisp/frame.el: trigger redisplay when changing
`display-line-number-spacing-width'
---
 lisp/cus-start.el |  4 ++++
 lisp/frame.el     |  1 +
 src/xdisp.c       | 20 ++++++++++++++++----
 3 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index c6e4da6790e..9b2b572729f 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -762,6 +762,10 @@ minibuffer-prompt-properties--setter
                         :value 2
                         :format "%v"))
               "26.1")
+             (display-line-numbers-spacing-width
+              display-line-numbers
+              integer
+              "30.1")
              (display-line-numbers-current-absolute
               display-line-numbers
               (choice
diff --git a/lisp/frame.el b/lisp/frame.el
index e66270130d2..d55f86f3bce 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -3229,6 +3229,7 @@ set-frame-property--interactive
         tab-line-format
         display-line-numbers
         display-line-numbers-width
+        display-line-numbers-spacing-width
         display-line-numbers-current-absolute
         display-line-numbers-widen
         display-line-numbers-major-tick
diff --git a/src/xdisp.c b/src/xdisp.c
index b6d9094e684..0a3e321acd2 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -25032,6 +25032,9 @@ maybe_produce_line_number (struct it *it)
 	it->pt_lnum = display_count_lines_logically (beg_byte, PT_BYTE, PT,
 						     &ignored);
     }
+
+  EMACS_INT lnum_spacing_width = max (0, display_line_numbers_spacing_width);
+
   /* Compute the required width if needed.  */
   if (!it->lnum_width)
     {
@@ -25043,7 +25046,7 @@ maybe_produce_line_number (struct it *it)
 	    = (it->last_visible_x - it->first_visible_x)
 	      / FRAME_COLUMN_WIDTH (it->f)
 	      - 5	/* leave space for a few characters */
-	      - 2;	/* two spaces around the number */
+	      - 2 * lnum_spacing_width;	/* spaces around the number */
 	  it->lnum_width
 	    = clip_to_bounds (1, lnum_width, lnum_width_limit);
 	}
@@ -25068,7 +25071,7 @@ maybe_produce_line_number (struct it *it)
     }
   /* Extra +2 for the two blanks we add before and after the number.  */
   char *lnum_buf = alloca (max (it->lnum_width, INT_STRLEN_BOUND (ptrdiff_t))
-			   + 2 + 1);
+			   + 2 * lnum_spacing_width + 1);
   if (EQ (Vdisplay_line_numbers, Qrelative))
     lnum_offset = it->pt_lnum;
   else if (EQ (Vdisplay_line_numbers, Qvisual))
@@ -25089,8 +25092,10 @@ maybe_produce_line_number (struct it *it)
      called when no display elements were produced from the
      following line, so the paragraph direction might be unknown.
      Therefore we cheat and add 2 blanks, one on either side.  */
-  pint2str (lnum_buf, it->lnum_width + 1, lnum_to_display);
-  strcat (lnum_buf, " ");
+  pint2str (lnum_buf, it->lnum_width + lnum_spacing_width, lnum_to_display);
+  size_t lnum_len_before_spacing = strlen(lnum_buf);
+  memset(lnum_buf + lnum_len_before_spacing, ' ', lnum_spacing_width);
+  lnum_buf[lnum_len_before_spacing + lnum_spacing_width] = '\0';
 
   /* Setup for producing the glyphs.  */
   init_iterator (&tem_it, it->w, -1, -1, &scratch_glyph_row,
@@ -38168,6 +38173,13 @@ syms_of_xdisp (void)
   DEFSYM (Qdisplay_line_numbers_width, "display-line-numbers-width");
   Fmake_variable_buffer_local (Qdisplay_line_numbers_width);
 
+  DEFVAR_INT ("display-line-numbers-spacing-width", display_line_numbers_spacing_width,
+    doc: /* Amount of spaces inserted before and after line numbers.
+Any other value than non-negative integer is treated as 1. */);
+  display_line_numbers_spacing_width = 1;
+  DEFSYM (Qdisplay_line_numbers_spacing_width, "display-line-numbers-spacing-width");
+  Fmake_variable_buffer_local (Qdisplay_line_numbers_spacing_width);
+
   DEFVAR_LISP ("display-line-numbers-current-absolute",
 	       Vdisplay_line_numbers_current_absolute,
     doc: /* Non-nil means display absolute number of current line.
-- 
2.48.1