Subject: Re: bug#78474: 31.0.50; Wrong char insertion in rxvt

From: Manuel Giraud <[email-masked]>
Date: Sun, 03 Aug 2025 14:03:51 +0200

Eli Zaretskii <[email-masked]> writes:

>> From: Manuel Giraud <[email-masked]>
>> Cc: [email-masked],  [email-masked],  [email-masked],
>>   [email-masked],  [email-masked]
>> Date: Sun, 03 Aug 2025 11:17:18 +0200
>> 
>> > I see no reason to make this a user option.  It should be a simple
>> > variable.
>> 
>> I have used the DEFVAR_BOOL macro but no defcustom: does that make it a
>> "simple variable"?
>
> Yes.  To make such a variable a defcustom, you need to add it to
> cus-start.el.
>
>> Sorry for my lack of understanding of Emacs internals here.
>
> No need to feel sorry, no one is borne with this knowledge.

Thanks.  Here is the new version of the patch that, I think, addresses
all the left issues.
>From baba5cd65c60e8aeb6557ade4625535bcfdaae96 Mon Sep 17 00:00:00 2001
From: Manuel Giraud <[email-masked]>
Date: Tue, 22 Jul 2025 15:15:39 +0200
Subject: [PATCH] Variable to control overshoot and backup for tty motions

* src/term.c (syms_of_term): New variable.
* src/cm.c (calccost): Control overshooting with new variable.
* etc/NEWS: Document new variable.
* lisp/term/rxvt.el (terminal-init-rxvt): Force no TAB+BS for
rxvt.
---
 etc/NEWS          |  8 ++++++++
 lisp/term/rxvt.el |  3 +++
 src/cm.c          | 45 ++++++++++++++++++++++++++-------------------
 src/term.c        |  9 +++++++++
 4 files changed, 46 insertions(+), 19 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index b469b22aacf..35277e49eb7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2512,6 +2512,14 @@ separator, are also supported.
 ---
 ** The obsolete variable 'load-convert-to-unibyte' has been removed.
 
+---
+** New variable 'tty-cursor-movement-use-TAB-BS'.
+The display optimization where the combination TAB characters +
+BACKSPACE is used to move to a position on a TTY frame is now disabled
+by default and controlled by this variable.  This can be set to non-nil
+to keep the old behavior.  This change is to accomodate to screen
+readers.
+
 
 * Lisp Changes in Emacs 31.1
 
diff --git a/lisp/term/rxvt.el b/lisp/term/rxvt.el
index 1e431102d58..9de58b25e6b 100644
--- a/lisp/term/rxvt.el
+++ b/lisp/term/rxvt.el
@@ -190,6 +190,9 @@ terminal-init-rxvt
   (when rxvt-set-window-title
     (xterm--init-frame-title))
 
+  ;; Do not use TAB+BS optimization.
+  (setq tty-cursor-movement-use-TAB-BS nil)
+
   (run-hooks 'terminal-init-rxvt-hook))
 
 ;; rxvt puts the default colors into an environment variable
diff --git a/src/cm.c b/src/cm.c
index 150d1c9a580..d52ac22f27a 100644
--- a/src/cm.c
+++ b/src/cm.c
@@ -187,9 +187,9 @@ calccost (struct tty_display_info *tty,
                     c,
                     totalcost;
     int     ntabs,
-            n2tabs,
-            tabx,
-            tab2x,
+	    n2tabs,
+	    tabx,
+	    tab2x,
             tabcost;
     register const char *p;
 
@@ -229,36 +229,43 @@ calccost (struct tty_display_info *tty,
 	goto olddelta;		/* forget it! */
 
     /*
-     * ntabs is # tabs towards but not past dstx; n2tabs is one more
-     * (ie past dstx), but this is only valid if that is not past the
-     * right edge of the screen.  We can check that at the same time
-     * as we figure out where we would be if we use the tabs (which
-     * we will put into tabx (for ntabs) and tab2x (for n2tabs)).
+     * ntabs is # tabs towards but not past dstx.  tabx is where we
+     * would be if we put those ntabs tabulations.
      */
 
     ntabs = (deltax + srcx % tty->Wcm->cm_tabwidth) / tty->Wcm->cm_tabwidth;
-    n2tabs = ntabs + 1;
     tabx = (srcx / tty->Wcm->cm_tabwidth + ntabs) * tty->Wcm->cm_tabwidth;
-    tab2x = tabx + tty->Wcm->cm_tabwidth;
 
-    if (tab2x >= tty->Wcm->cm_cols)	/* too far (past edge) */
+    if (tty_cursor_movement_use_TAB_BS) {
+      /*
+       * n2tabs is one more tab than ntabs (i.e. past dstx), but this is
+       * only valid if that is not past the right edge of the screen.
+       * tab2x is where we would be if we put those n2tabs tabulations.
+       */
+      n2tabs = ntabs + 1;
+      tab2x = tabx + tty->Wcm->cm_tabwidth;
+      if (tab2x >= tty->Wcm->cm_cols)	/* too far (past edge) */
 	n2tabs = 0;
 
+      /*
+       * Set c to the cost for using n2tabs
+       */
+                /* cost for n2tabs          +    cost for left motion */
+      c = n2tabs ? n2tabs * tty->Wcm->cc_tab + (tab2x - dstx) * tty->Wcm->cc_left
+	: BIG;
+    }
+
     /*
-     * Now set tabcost to the cost for using ntabs, and c to the cost
-     * for using n2tabs, then pick the minimum.
+     * Set tabcost to the cost for using ntabs.
      */
 
 		   /* cost for ntabs           +    cost for right motion */
     tabcost = ntabs ? ntabs * tty->Wcm->cc_tab + (dstx - tabx) * tty->Wcm->cc_right
 		    : BIG;
 
-		   /* cost for n2tabs          +    cost for left motion */
-    c = n2tabs  ?    n2tabs * tty->Wcm->cc_tab + (tab2x - dstx) * tty->Wcm->cc_left
-		: BIG;
-
-    if (c < tabcost)		/* then cheaper to overshoot & back up */
-	ntabs = n2tabs, tabcost = c, tabx = tab2x;
+    /* Is it allowed and cheaper to overshoot & back up? */
+    if (tty_cursor_movement_use_TAB_BS && (c < tabcost))
+      ntabs = n2tabs, tabcost = c, tabx = tab2x;
 
     if (tabcost >= BIG)		/* caint use tabs */
 	goto newdelta;
diff --git a/src/term.c b/src/term.c
index 8aa47322d19..a1e3f6312c6 100644
--- a/src/term.c
+++ b/src/term.c
@@ -5167,6 +5167,15 @@ syms_of_term (void)
 trigger redisplay.  */);
   tty_menu_calls_mouse_position_function = 0;
 
+  DEFVAR_BOOL ("tty-cursor-movement-use-TAB-BS", tty_cursor_movement_use_TAB_BS,
+    doc: /* Whether TTY frames may use the combination TAB + BACKSPACE for moving around.
+On TTY frames, as a display optimization, Emacs may move to a position
+by "overshooting" with TAB characters and one BACKSPACE character, when
+this is more efficient.  This combination can interfere with the
+functioning of some software, such as screen readers.  Set this to
+non-nil to enable this optimization.  */);
+  tty_cursor_movement_use_TAB_BS = 0;
+
   defsubr (&Stty_display_color_p);
   defsubr (&Stty_display_color_cells);
   defsubr (&Stty_no_underline);
-- 
2.50.1

-- 
Manuel Giraud