This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch master
in repository terminology.

View the commit online.

commit 544da9e23cef6002c42d2b688c1fb56211954643
Author: Boris Faure <[email protected]>
AuthorDate: Sat Sep 12 16:06:50 2026 +0200

    termptyesc: fix XTMODKEYS argument order
    
    CSI > Pp ; Pv m takes the resource from Pp and the value from Pv; they
    were read the other way round, so nvim's CSI > 4 ; 2 m set xmod[2] = 4.
---
 src/bin/termpty.c    | 40 ++++++++++++++++++++++
 src/bin/termpty.h    |  3 +-
 src/bin/termptyesc.c | 97 +++++++++++++++++++++++++---------------------------
 src/bin/tytest.c     |  1 +
 src/bin/unit_tests.h |  1 +
 5 files changed, 90 insertions(+), 52 deletions(-)

diff --git a/src/bin/termpty.c b/src/bin/termpty.c
index 8c915da8..11eac4a9 100644
--- a/src/bin/termpty.c
+++ b/src/bin/termpty.c
@@ -2232,4 +2232,44 @@ tytest_sync_change_cb_altscreen(void)
    return 0;
 }
 
+/* XTMODKEYS: CSI > Pp ; Pv m, Pp selects the resource, Pv is the value. */
+int
+tytest_xmodkeys_set(void)
+{
+   Termpty ty;
+
+   _ty_test_init(&ty, 80, 24);
+
+   _ty_feed(&ty, "\x1b[>4;2m");
+   assert(ty.termstate.xmod[XMOD_OTHER] == 2);
+   assert(ty.termstate.xmod[XMOD_FUNCTIONS] == 0);
+
+   _ty_feed(&ty, "\x1b[>1;3m");
+   assert(ty.termstate.xmod[XMOD_CURSOR] == 3);
+   assert(ty.termstate.xmod[XMOD_OTHER] == 2);
+
+   /* Pv omitted: back to the initial value. */
+   _ty_feed(&ty, "\x1b[>4m");
+   assert(ty.termstate.xmod[XMOD_OTHER] == 0);
+
+   /* No parameter at all: every resource is reset. */
+   _ty_feed(&ty, "\x1b[>4;2m");
+   _ty_feed(&ty, "\x1b[>m");
+   assert(ty.termstate.xmod[XMOD_CURSOR] == 0);
+   assert(ty.termstate.xmod[XMOD_OTHER] == 0);
+
+   /* CSI > Pp n resets a single resource. */
+   _ty_feed(&ty, "\x1b[>4;2m");
+   _ty_feed(&ty, "\x1b[>4n");
+   assert(ty.termstate.xmod[XMOD_OTHER] == 0);
+
+   /* An out of range resource changes nothing. */
+   _ty_feed(&ty, "\x1b[>4;2m");
+   _ty_feed(&ty, "\x1b[>9;1m");
+   assert(ty.termstate.xmod[XMOD_OTHER] == 2);
+
+   _ty_test_shutdown(&ty);
+   return 0;
+}
+
 #endif /* BINARY_TYFUZZ || BINARY_TYTEST */
diff --git a/src/bin/termpty.h b/src/bin/termpty.h
index 9f26de2e..1890e9fc 100644
--- a/src/bin/termpty.h
+++ b/src/bin/termpty.h
@@ -106,6 +106,7 @@ typedef enum exmod {
      XMOD_KEYPAD = 3,
      XMOD_OTHER = 4,
      XMOD_STRING = 5,
+     XMOD_LAST = 6,
 } XMod;
 
 typedef struct tag_Term_State {
@@ -134,7 +135,7 @@ typedef struct tag_Term_State {
     unsigned int  sace_rectangular : 1;
     unsigned int  esc_keycode : 1;
     unsigned int  alternate_esc : 1;
-    int xmod[6];
+    int xmod[XMOD_LAST];
 } Term_State;
 
 typedef struct tag_Term_Cursor {
diff --git a/src/bin/termptyesc.c b/src/bin/termptyesc.c
index 2348e43e..c45e7ca3 100644
--- a/src/bin/termptyesc.c
+++ b/src/bin/termptyesc.c
@@ -3453,6 +3453,29 @@ _handle_window_manipulation(Termpty *ty, Eina_Unicode **ptr)
 }
 
 
+static Eina_Bool
+_xmod_resource_is_valid(int resource)
+{
+   switch (resource)
+     {
+      case XMOD_KEYBOARD:
+        EINA_FALLTHROUGH;
+      case XMOD_CURSOR:
+        EINA_FALLTHROUGH;
+      case XMOD_FUNCTIONS:
+        EINA_FALLTHROUGH;
+      case XMOD_KEYPAD:
+        EINA_FALLTHROUGH;
+      case XMOD_OTHER:
+        EINA_FALLTHROUGH;
+      case XMOD_STRING:
+        return EINA_TRUE;
+      default:
+        return EINA_FALSE;
+     }
+}
+
+/* XTMODKEYS: CSI > Pp ; Pv m and CSI > Pp n */
 static void
 _handle_xmodkeys(Termpty *ty,
                  Eina_Unicode cmd, Eina_Unicode **ptr)
@@ -3462,7 +3485,7 @@ _handle_xmodkeys(Termpty *ty,
    Eina_Unicode param = *b;
    b++;
    if (param == '?')
-     return; // Not actually supported by xterm
+     return;
    if (param != '>')
      {
         ERR("XMODKEYS: Invalid sequence");
@@ -3471,69 +3494,41 @@ _handle_xmodkeys(Termpty *ty,
      }
    if (set)
      {
-        int arg1 = _csi_arg_get(ty, &b);
-        int arg2 = _csi_arg_get(ty, &b);
-        int v, mod;
-        if (arg1 == -ESC_ARG_ERROR)
+        int resource = _csi_arg_get(ty, &b);
+        int v = _csi_arg_get(ty, &b);
+
+        if (resource == -ESC_ARG_ERROR)
           {
              ERR("XMODKEYS set: Invalid sequence");
              ty->decoding_error = EINA_TRUE;
              return;
           }
-        if (arg2 == -ESC_ARG_NO_VALUE)
-          {
-             mod = arg1;
-             v = 0;
+        if (resource == -ESC_ARG_NO_VALUE)
+          { /* reset all */
+             memset(ty->termstate.xmod, 0, sizeof(ty->termstate.xmod));
+             return;
           }
-        else
+        if (!_xmod_resource_is_valid(resource))
           {
-             mod = arg2;
-             v = arg1;
+             ERR("XMODKEYS set: Invalid sequence");
+             ty->decoding_error = EINA_TRUE;
+             return;
           }
-        switch (mod)
-          {
-           case XMOD_KEYBOARD:
-              EINA_FALLTHROUGH;
-           case XMOD_CURSOR:
-              EINA_FALLTHROUGH;
-           case XMOD_FUNCTIONS:
-              EINA_FALLTHROUGH;
-           case XMOD_KEYPAD:
-              EINA_FALLTHROUGH;
-           case XMOD_OTHER:
-              EINA_FALLTHROUGH;
-           case XMOD_STRING:
-              break;
-           default:
-              ERR("XMODKEYS set: Invalid sequence");
-              ty->decoding_error = EINA_TRUE;
-              return;
-          }
-        ty->termstate.xmod[mod] = v;
+        if (v < 0)
+          v = 0;
+        ty->termstate.xmod[resource] = v;
      }
    else
      { /* reset */
-        int arg = _csi_arg_get(ty, &b);
-        switch (arg)
+        int resource = _csi_arg_get(ty, &b);
+
+        if (!_xmod_resource_is_valid(resource))
           {
-           case XMOD_KEYBOARD:
-              EINA_FALLTHROUGH;
-           case XMOD_CURSOR:
-              EINA_FALLTHROUGH;
-           case XMOD_FUNCTIONS:
-              EINA_FALLTHROUGH;
-           case XMOD_KEYPAD:
-              EINA_FALLTHROUGH;
-           case XMOD_OTHER:
-              EINA_FALLTHROUGH;
-           case XMOD_STRING:
-              break;
-           default:
-              ERR("XMODKEYS reset: Invalid sequence");
-              ty->decoding_error = EINA_TRUE;
-              return;
+             ERR("XMODKEYS reset: Invalid sequence");
+             ty->decoding_error = EINA_TRUE;
+             return;
           }
-        ty->termstate.xmod[arg] = 0;
+        ty->termstate.xmod[resource] = 0;
      }
 }
 static int
diff --git a/src/bin/tytest.c b/src/bin/tytest.c
index 338fe3d0..a5cb7ed9 100644
--- a/src/bin/tytest.c
+++ b/src/bin/tytest.c
@@ -56,6 +56,7 @@ static struct {
        { "sync_change_cb_watchdog", tytest_sync_change_cb_watchdog},
        { "sync_change_cb_altscreen", tytest_sync_change_cb_altscreen},
        { "percent_decode", tytest_percent_decode},
+       { "xmodkeys_set", tytest_xmodkeys_set},
        { NULL, NULL},
 };
 
diff --git a/src/bin/unit_tests.h b/src/bin/unit_tests.h
index b5deeb24..afa2fd42 100644
--- a/src/bin/unit_tests.h
+++ b/src/bin/unit_tests.h
@@ -30,5 +30,6 @@ int tytest_sync_change_cb_coalesced(void);
 int tytest_sync_change_cb_watchdog(void);
 int tytest_sync_change_cb_altscreen(void);
 int tytest_percent_decode(void);
+int tytest_xmodkeys_set(void);
 
 #endif

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to