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 05eba7893ca1969c9c39a75e70445a9cf6194ea3
Author: [email protected] <[email protected]>
AuthorDate: Mon May 4 21:53:29 2026 -0600
feat(tymux): add native Ctrl+b d detach chord in tymux input path
The user-visible detach gesture is implemented as a two-state machine in
_tymux_write_cb, the input forward path that routes every keystroke from
a native tymux widget to the daemon. Ctrl+b (0x02) is swallowed and sets
prefix_pending; if the next byte is 'd' (0x64), both bytes are dropped
and TSRV_MSG_DETACH is sent; otherwise, the pending 0x02 is emitted to
preserve literal Ctrl+b passthrough for programs like emacs/vim/readline.
This reuses the detach plumbing established earlier: DETACH → daemon
replies with CWD → daemon closes → client reads CWD into last_cwd → EOF
fires cb_exit → _smart_pty_exited calls _termio_tymux_demote. The user's
tab survives, the daemon stays in tymux list, and a fresh shell appears
at the inner shell's last cwd, matching the CLI proxy chord from cdc86dca.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
---
src/bin/termtymux.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++----
src/bin/termtymux.h | 3 ++-
2 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/src/bin/termtymux.c b/src/bin/termtymux.c
index 78498b30..dcd6bfb7 100644
--- a/src/bin/termtymux.c
+++ b/src/bin/termtymux.c
@@ -388,13 +388,55 @@ static void
_tymux_write_cb(const char *buf, int len, void *data)
{
TermTymux *ts = data;
+ char *out;
+ int on = 0;
+ int i;
+ Eina_Bool detach_now = EINA_FALSE;
- if (!ts || ts->sock_fd < 0 || len <= 0)
- return;
+ if (!ts || ts->sock_fd < 0 || len <= 0) return;
- if (termsrv_msg_send(ts->sock_fd, TSRV_MSG_INPUT,
- buf, (uint32_t)len) < 0)
+ /* Output may be up to len+1 bytes when a previous read ended with a
+ * pending prefix and the next read starts with a non-'d' byte. */
+ out = malloc((size_t)len + 1);
+ if (!out) return;
+
+ for (i = 0; i < len; i++)
+ {
+ unsigned char b = (unsigned char)buf[i];
+ if (ts->prefix_pending)
+ {
+ ts->prefix_pending = EINA_FALSE;
+ if (b == 0x64) /* 'd' — chord completes */
+ {
+ detach_now = EINA_TRUE;
+ /* swallow both 0x02 and 'd'; do not forward */
+ }
+ else
+ {
+ /* literal Ctrl+b passthrough */
+ out[on++] = 0x02;
+ out[on++] = (char)b;
+ }
+ }
+ else if (b == 0x02)
+ {
+ ts->prefix_pending = EINA_TRUE;
+ /* swallow; will be emitted on next byte if not 'd' */
+ }
+ else
+ {
+ out[on++] = (char)b;
+ }
+ }
+
+ if (on > 0 &&
+ termsrv_msg_send(ts->sock_fd, TSRV_MSG_INPUT,
+ out, (uint32_t)on) < 0)
ERR("termtymux: failed to send INPUT: %s", strerror(errno));
+ free(out);
+
+ if (detach_now)
+ termsrv_msg_send(ts->sock_fd, TSRV_MSG_DETACH, NULL, 0);
}
/* ── shadow Termpty ─────────────────────────────────────────────────── */
diff --git a/src/bin/termtymux.h b/src/bin/termtymux.h
index e0e74089..3d26a3a8 100644
--- a/src/bin/termtymux.h
+++ b/src/bin/termtymux.h
@@ -51,7 +51,8 @@ struct _TermTymux {
void *data;
} cb_pause, cb_resume;
- Eina_Bool paused; /* EINA_TRUE when session is paused by hijacker */
+ Eina_Bool paused; /* EINA_TRUE when session is paused by hijacker */
+ Eina_Bool prefix_pending; /* TRUE after Ctrl+b (0x02), waiting for 'd' */
};
/*
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.