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

git pushed a commit to reference refs/pull/36/head
in repository terminology.

View the commit online.

commit 44b2c8860917dbbd6d1bb98ac9add8e990126cc0
Author: [email protected] <[email protected]>
AuthorDate: Mon Mar 23 22:42:20 2026 -0600

    feat(tymux): encode attach mode in escape sequences
    
    Extend the Terminology escape protocol so --shared and --readonly
    work through native attach paths (including --new-tab):
    
      at;<name>   → hijack, current tab (backward compat)
      ats;<name>  → shared, current tab
      atr;<name>  → readonly, current tab
      atn;<name>  → hijack, new tab
      atns;<name> → shared, new tab
      atnr;<name> → readonly, new tab
    
    termtymux_attach() now accepts a TermSrvAttachMode parameter
    instead of hardcoding HIJACK.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
 src/bin/termio.c          | 66 ++++++++++++++++++++++++++++++---------------
 src/bin/termiointernals.h |  1 +
 src/bin/termtymux.c       |  3 ++-
 src/bin/termtymux.h       |  1 +
 src/bin/tymux.c           | 68 ++++++++++++++++++++++++++---------------------
 5 files changed, 86 insertions(+), 53 deletions(-)

diff --git a/src/bin/termio.c b/src/bin/termio.c
index cda79762..c978be6a 100644
--- a/src/bin/termio.c
+++ b/src/bin/termio.c
@@ -3883,18 +3883,21 @@ _termio_tymux_newtab_job(void *data)
 
    /* Schedule a tymux switch in the new tab on the next iteration. */
    eina_stringshare_replace(&new_sd->tymux_pending, tymux_name);
+   new_sd->tymux_pending_mode = sd->tymux_pending_mode;
    ecore_job_add(_termio_tymux_switch_job, new_termio);
 
    eina_stringshare_del(tymux_name);
 }
 
 static void
-_termio_tymux_newtab(Evas_Object *obj, Termio *sd, const char *tymux_name)
+_termio_tymux_newtab(Evas_Object *obj, Termio *sd, const char *tymux_name,
+                     TermSrvAttachMode mode)
 {
    EINA_SAFETY_ON_NULL_RETURN(tymux_name);
    if (!_tymux_name_valid(tymux_name)) return;
 
    eina_stringshare_replace(&sd->tymux_newtab_pending, tymux_name);
+   sd->tymux_pending_mode = mode;
    ecore_job_add(_termio_tymux_newtab_job, obj);
 }
 
@@ -3934,7 +3937,9 @@ _termio_tymux_switch_job(void *data)
    tymux = termtymux_attach(tymux_name,
                              sd->grid.w,
                              sd->grid.h,
-                             sd->config, &spty);
+                             sd->config,
+                             sd->tymux_pending_mode,
+                             &spty);
    if (!tymux)
      {
         ERR("tymux switch: could not attach to '%s'", tymux_name);
@@ -3972,7 +3977,8 @@ _termio_tymux_switch_job(void *data)
 }
 
 static void
-_termio_tymux_switch(Evas_Object *obj, Termio *sd, const char *tymux_name)
+_termio_tymux_switch(Evas_Object *obj, Termio *sd, const char *tymux_name,
+                     TermSrvAttachMode mode)
 {
    EINA_SAFETY_ON_NULL_RETURN(tymux_name);
    if (!_tymux_name_valid(tymux_name)) return;
@@ -3983,6 +3989,7 @@ _termio_tymux_switch(Evas_Object *obj, Termio *sd, const char *tymux_name)
     * → _handle_esc → _smart_pty_command).  Freeing it now would leave
     * dangling pointers up the call stack. */
    eina_stringshare_replace(&sd->tymux_pending, tymux_name);
+   sd->tymux_pending_mode = mode;
    ecore_job_add(_termio_tymux_switch_job, obj);
 }
 #endif /* HAVE_TYMUX */
@@ -4008,25 +4015,39 @@ _smart_pty_command(void *data)
      }
 
 #ifdef HAVE_TYMUX
-   /* at;<session_name> — escape emitted by 'tymux attach' to request a
-    * native session hand-off.  Handled before the ty_escapes gate so that
-    * it works regardless of whether Terminology escapes are enabled. */
-   if (ty->cur_cmd[0] == 'a' && ty->cur_cmd[1] == 't' && ty->cur_cmd[2] == ';')
+   /* tymux attach escapes — handled before the ty_escapes gate so they
+    * work regardless of whether Terminology escapes are enabled.
+    *
+    * Escape prefixes encode tab behavior and attach mode:
+    *   at;<name>   — hijack, current tab (backward compat)
+    *   ats;<name>  — shared, current tab
+    *   atr;<name>  — readonly, current tab
+    *   atn;<name>  — hijack, new tab
+    *   atns;<name> — shared, new tab
+    *   atnr;<name> — readonly, new tab
+    */
+   if (ty->cur_cmd[0] == 'a' && ty->cur_cmd[1] == 't')
      {
-        const char *sess = &ty->cur_cmd[3];
-        if (sess[0] && _tymux_name_valid(sess))
-          _termio_tymux_switch(obj, sd, sess);
-        return;
-     }
-   /* atn;<session_name> — open a NEW tab attached to the named tymux session.
-    * Emitted by the tymux client when the user requests a new window. */
-   if (ty->cur_cmd[0] == 'a' && ty->cur_cmd[1] == 't' &&
-       ty->cur_cmd[2] == 'n' && ty->cur_cmd[3] == ';')
-     {
-        const char *sess = &ty->cur_cmd[4];
-        if (sess[0] && _tymux_name_valid(sess))
-          _termio_tymux_newtab(obj, sd, sess);
-        return;
+        const char *p = &ty->cur_cmd[2];
+        Eina_Bool newtab = EINA_FALSE;
+        TermSrvAttachMode mode = TSRV_ATTACH_HIJACK;
+
+        if (*p == 'n') { newtab = EINA_TRUE; p++; }
+        if (*p == 's') { mode = TSRV_ATTACH_SHARED; p++; }
+        else if (*p == 'r') { mode = TSRV_ATTACH_READONLY; p++; }
+
+        if (*p == ';')
+          {
+             const char *sess = p + 1;
+             if (sess[0] && _tymux_name_valid(sess))
+               {
+                  if (newtab)
+                    _termio_tymux_newtab(obj, sd, sess, mode);
+                  else
+                    _termio_tymux_switch(obj, sd, sess, mode);
+               }
+             return;
+          }
      }
 #endif
 
@@ -4548,7 +4569,8 @@ termio_add(Evas_Object *win, Config *config,
      {
         sd->tymux_name = eina_stringshare_add(tymux_name);
         Termpty *spty = NULL;
-        sd->tymux = termtymux_attach(tymux_name, w, h, config, &spty);
+        sd->tymux = termtymux_attach(tymux_name, w, h, config,
+                                       TSRV_ATTACH_HIJACK, &spty);
         if (!sd->tymux)
           {
              ERR("Could not attach to tymux '%s'", tymux_name);
diff --git a/src/bin/termiointernals.h b/src/bin/termiointernals.h
index 4c4292d0..be6bb120 100644
--- a/src/bin/termiointernals.h
+++ b/src/bin/termiointernals.h
@@ -83,6 +83,7 @@ struct tag_Termio
    const char  *tymux_name;   /* eina_stringshare */
    const char  *tymux_pending;     /* eina_stringshare; deferred switch target */
    const char  *tymux_newtab_pending; /* eina_stringshare; deferred new-tab session */
+   TermSrvAttachMode tymux_pending_mode; /* mode for pending switch/newtab */
 #endif
    Ecore_Animator *anim;
    Ecore_Timer *delayed_size_timer;
diff --git a/src/bin/termtymux.c b/src/bin/termtymux.c
index e007b186..cca22ea8 100644
--- a/src/bin/termtymux.c
+++ b/src/bin/termtymux.c
@@ -873,6 +873,7 @@ TermTymux *
 termtymux_attach(const char *tymux_name,
                    int cols, int rows,
                    Config *config,
+                   TermSrvAttachMode mode,
                    Termpty **shadow_pty_out)
 {
    char              sock_path[512];
@@ -938,7 +939,7 @@ termtymux_attach(const char *tymux_name,
       size_t   pay_len  = 1 + name_len;
       uint8_t *pay      = alloca(pay_len);
 
-      pay[0] = TSRV_ATTACH_HIJACK;
+      pay[0] = (uint8_t)mode;
       memcpy(pay + 1, tymux_name, name_len);
 
       if (termsrv_msg_send(sock_fd, TSRV_MSG_ATTACH,
diff --git a/src/bin/termtymux.h b/src/bin/termtymux.h
index 2457be88..70b7a18d 100644
--- a/src/bin/termtymux.h
+++ b/src/bin/termtymux.h
@@ -63,6 +63,7 @@ struct _TermTymux {
 TermTymux *termtymux_attach(const char *tymux_name,
                                 int cols, int rows,
                                 Config *config,
+                                TermSrvAttachMode mode,
                                 Termpty **shadow_pty_out);
 
 /* Send DETACH, munmap, close socket, free shadow Termpty. */
diff --git a/src/bin/tymux.c b/src/bin/tymux.c
index e24d5575..5086c86a 100644
--- a/src/bin/tymux.c
+++ b/src/bin/tymux.c
@@ -1106,36 +1106,44 @@ cmd_attach(int argc, char **argv)
     *
     * The liveness check is performed first so we never send the escape
     * for a session that does not exist. */
-   if (new_tab)
-     {
-        if (getenv("TERMINOLOGY"))
-          {
-             char esc[128];
-             int  n = snprintf(esc, sizeof(esc), "\033}atn;%s", name);
-             if (n > 0 && (size_t)n < sizeof(esc))
-               {
-                  ssize_t written = write(STDOUT_FILENO, esc, (size_t)(n + 1));
-                  if (written < 0 || written != (ssize_t)(n + 1))
-                    fprintf(stderr, "tymux: warning: escape delivery failed\n");
-               }
-             return 0;
-          }
-        else
-          fprintf(stderr,
-                  "tymux: --new-tab requires Terminology; "
-                  "falling back to inline attach\n");
-     }
-   else
-     {
-        char esc[128];
-        int  n = snprintf(esc, sizeof(esc), "\033}at;%s", name);
-        if (n > 0 && (size_t)n < sizeof(esc))
-          {
-             ssize_t written = write(STDOUT_FILENO, esc, (size_t)(n + 1)); /* +1 for NUL */
-             if (written < 0 || written != (ssize_t)(n + 1))
-               fprintf(stderr, "tymux: warning: escape delivery failed\n");
-          }
-     }
+   /* Build escape prefix: at[n][s|r];<name>
+    *   at;  = hijack, current tab     ats;  = shared     atr;  = readonly
+    *   atn; = hijack, new tab         atns; = shared     atnr; = readonly */
+   {
+      const char *prefix;
+      if (new_tab)
+        {
+           if      (mode == 1) prefix = "\033}atns;";
+           else if (mode == 2) prefix = "\033}atnr;";
+           else                prefix = "\033}atn;";
+        }
+      else
+        {
+           if      (mode == 1) prefix = "\033}ats;";
+           else if (mode == 2) prefix = "\033}atr;";
+           else                prefix = "\033}at;";
+        }
+
+      if (new_tab && !getenv("TERMINOLOGY"))
+        {
+           fprintf(stderr,
+                   "tymux: --new-tab requires Terminology; "
+                   "falling back to inline attach\n");
+        }
+      else
+        {
+           char esc[128];
+           int  n = snprintf(esc, sizeof(esc), "%s%s", prefix, name);
+           if (n > 0 && (size_t)n < sizeof(esc))
+             {
+                ssize_t written = write(STDOUT_FILENO, esc, (size_t)(n + 1)); /* +1 for NUL */
+                if (written < 0 || written != (ssize_t)(n + 1))
+                  fprintf(stderr, "tymux: warning: escape delivery failed\n");
+             }
+           if (new_tab)
+             return 0; /* exit cleanly — Terminology opens new tab */
+        }
+   }
 
    /* ── Connect ── */
    int sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);

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

Reply via email to