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

git pushed a commit to branch tymux
in repository terminology.

View the commit online.

commit 877d81e6e9e44417886d65e450ca061ec35f239a
Author: [email protected] <[email protected]>
AuthorDate: Mon May 4 19:04:14 2026 -0600

    feat(tymux): replace detach trigger with tmux-style Ctrl+b d chord
    
    The proxy client detach mechanism now uses a two-key chord (Ctrl+b
    followed by 'd') instead of the single-byte Ctrl+] trigger. This
    aligns the detach action with tmux muscle memory, which users
    already have when attaching to background terminals.
    
    The chord state (`prefix_pending`) lives in `cmd_attach` and is
    shared by both the main stdin→INPUT scan and the pause-mode drain,
    ensuring a chord that straddles a pause/resume boundary completes.
    
    Main scan algorithm: each input byte is filtered into a separate
    output buffer. If Ctrl+b is pending and the next byte is 'd', send
    DETACH and exit. If pending and the byte is anything else, emit the
    swallowed 0x02 followed by the byte (no detach). If no prefix is
    pending and the byte is 0x02, swallow it and set prefix_pending.
    Otherwise forward unchanged. The output buffer is sized nr+1 to
    handle the carry-over case where a prior read ended with a pending
    prefix and the next read starts with a non-'d' byte.
    
    Pause-mode drain follows the same state machine but discards
    non-detach bytes (since nothing is forwarded while paused).
    
    Note: Ctrl+b is now slightly latent — the byte is held until the
    next byte arrives to decide whether the chord completes. This is
    the same tradeoff as tmux. Programs relying on raw Ctrl+b delivery
    (readline backward-char, emacs, vim) will see the byte arrive one
    keystroke later than pressed. Two consecutive Ctrl+b presses emit
    0x02 0x02 (not a single literal 0x02); acceptable for now.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---
 src/bin/tymux.c | 62 ++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 46 insertions(+), 16 deletions(-)

diff --git a/src/bin/tymux.c b/src/bin/tymux.c
index e2b6fba4..15783dc2 100644
--- a/src/bin/tymux.c
+++ b/src/bin/tymux.c
@@ -1031,7 +1031,7 @@ cmd_new(int argc, char **argv)
  * Connects to tymuxd, sends ATTACH, receives ATTACHED + memfd, then takes
  * over the current terminal: puts it in raw mode, polls stdin and the
  * daemon socket in a tight loop, renders shm cells on NOTIFY, and forwards
- * stdin bytes as TSRV_MSG_INPUT.  Detach key: Ctrl+] (0x1D).
+ * stdin bytes as TSRV_MSG_INPUT.  Detach key: Ctrl+b d (tmux-style prefix chord).
  */
 static int
 cmd_attach(int argc, char **argv)
@@ -1253,8 +1253,9 @@ cmd_attach(int argc, char **argv)
    setenv("TYMUX_SESSION", name, 1);
 
    /* ── Main I/O loop ── */
-   int running   = 1;
-   int exit_code = 0;
+   int running        = 1;
+   int exit_code      = 0;
+   int prefix_pending = 0; /* 1 after Ctrl+b (0x02), waiting for 'd' */
 
    while (running)
      {
@@ -1311,19 +1312,37 @@ cmd_attach(int argc, char **argv)
                }
              if (nr == 0) { running = 0; break; }
 
-             /* Scan for detach key: Ctrl+] (0x1D) */
+             /* Scan for detach chord: Ctrl+b d */
+             char    obuf[4097]; /* nr+1 to handle carry-over prefix */
+             ssize_t on = 0;
              for (ssize_t i = 0; i < nr; i++)
                {
-                  if ((unsigned char)ibuf[i] == 0x1D)
+                  unsigned char b = (unsigned char)ibuf[i];
+                  if (prefix_pending)
                     {
-                       /* Detach: send DETACH then exit loop */
-                       _proto_send(sock, _TSRV_MSG_DETACH, NULL, 0);
-                       running = 0;
-                       goto detach_exit;
+                       prefix_pending = 0;
+                       if (b == 0x64) /* 'd' — complete chord */
+                         {
+                            _proto_send(sock, _TSRV_MSG_DETACH, NULL, 0);
+                            running = 0;
+                            goto detach_exit;
+                         }
+                       /* Not a detach — emit the swallowed prefix then this byte */
+                       obuf[on++] = 0x02;
+                       obuf[on++] = (char)b;
+                    }
+                  else if (b == 0x02) /* Ctrl+b — start chord, swallow */
+                    {
+                       prefix_pending = 1;
+                    }
+                  else
+                    {
+                       obuf[on++] = (char)b;
                     }
                }
 
-             if (_proto_send(sock, _TSRV_MSG_INPUT, ibuf, (uint32_t)nr) < 0)
+             if (on > 0 &&
+                 _proto_send(sock, _TSRV_MSG_INPUT, obuf, (uint32_t)on) < 0)
                {
                   running = 0;
                   break;
@@ -1457,7 +1476,7 @@ cmd_attach(int argc, char **argv)
                                 break;
                              }
 
-                           /* Drain stdin — only check for detach key */
+                           /* Drain stdin — only check for detach chord: Ctrl+b d */
                            if (pfds[0].revents & POLLIN)
                              {
                                 char ibuf[256];
@@ -1466,12 +1485,23 @@ cmd_attach(int argc, char **argv)
                                   {
                                      for (ssize_t si = 0; si < nr; si++)
                                        {
-                                          if ((unsigned char)ibuf[si] == 0x1D)
+                                          unsigned char b = (unsigned char)ibuf[si];
+                                          if (prefix_pending)
                                             {
-                                               _proto_send(sock, _TSRV_MSG_DETACH, NULL, 0);
-                                               running = 0;
-                                               goto detach_exit;
+                                               prefix_pending = 0;
+                                               if (b == 0x64) /* 'd' — complete chord */
+                                                 {
+                                                    _proto_send(sock, _TSRV_MSG_DETACH, NULL, 0);
+                                                    running = 0;
+                                                    goto detach_exit;
+                                                 }
+                                               /* else: discard (paused) */
                                             }
+                                          else if (b == 0x02) /* Ctrl+b */
+                                            {
+                                               prefix_pending = 1;
+                                            }
+                                          /* else: discard (paused) */
                                        }
                                   }
                                 else if (nr == 0)
@@ -1593,7 +1623,7 @@ usage(const char *prog)
           "                        then launch terminology attached to it\n"
           "  attach <name>         Attach to a running background terminal\n"
           "                        (takes over the current terminal, like tmux attach)\n"
-          "                        Detach with Ctrl+] (Ctrl-bracket)\n"
+          "                        Detach with Ctrl+b d (tmux-style)\n"
           "\n"
           "Environment:\n"
           "  XDG_RUNTIME_DIR       Base directory for tymux sockets\n"

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

Reply via email to