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

git pushed a commit to branch tytab
in repository terminology.

View the commit online.

commit 2e64a40b4afd455f41a79255ade9e198324befe9
Author: [email protected] <[email protected]>
AuthorDate: Sat Mar 28 14:09:03 2026 -0600

    feat: add tytab CLI tool for tab and split management
    
    Provides a user-friendly command-line interface to the escape
    sequences for named panel targeting and tab creation.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
 src/bin/meson.build |   6 ++
 src/bin/tytab.c     | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 175 insertions(+)

diff --git a/src/bin/meson.build b/src/bin/meson.build
index f12f5d7a..b91324f5 100644
--- a/src/bin/meson.build
+++ b/src/bin/meson.build
@@ -48,6 +48,7 @@ tyq_sources = ['tycommon.c', 'tycommon.h', 'tyq.c']
 tycat_sources = ['tycommon.c', 'tycommon.h', 'tycat.c', 'extns.c', 'extns.h']
 tyls_sources = ['extns.c', 'extns.h', 'tyls.c', 'tycommon.c', 'tycommon.h']
 tysend_sources = ['tycommon.c', 'tycommon.h', 'tysend.c']
+tytab_sources = ['tycommon.c', 'tycommon.h', 'tytab.c']
 tyfuzz_sources = ['termptyesc.c', 'termptyesc.h',
                   'backlog.c', 'backlog.h',
                   'termptyops.c', 'termptyops.h',
@@ -127,6 +128,11 @@ executable('tysend',
            install: true,
            include_directories: config_dir,
            dependencies: terminology_dependencies)
+executable('tytab',
+           tytab_sources,
+           install: true,
+           include_directories: config_dir,
+           dependencies: terminology_dependencies)
 
 if fuzzing
   executable('tyfuzz',
diff --git a/src/bin/tytab.c b/src/bin/tytab.c
new file mode 100644
index 00000000..a9365c3e
--- /dev/null
+++ b/src/bin/tytab.c
@@ -0,0 +1,169 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "private.h"
+#include "tycommon.h"
+
+static void
+print_usage(const char *argv0)
+{
+   printf("Usage: %s " HELP_ARGUMENT_SHORT " name [NAME]\n"
+          "       %s " HELP_ARGUMENT_SHORT " new [NAME DIR] [-- CMD...]\n"
+          "\n"
+          "  Manage tabs and splits in Terminology.\n"
+          "\n"
+          "  Commands:\n"
+          "    name [NAME]              Set panel name (omit NAME to clear)\n"
+          "    new [NAME DIR] [-- CMD]  Create a new tab\n"
+          "\n"
+          "  NAME       Target panel name\n"
+          "  DIR        Split direction: left, right, top, bottom (or l, r, t, b)\n"
+          "  CMD        Command to run (default: shell)\n"
+          "\n"
+          HELP_ARGUMENT_DOC "\n"
+          "\n",
+          argv0, argv0);
+}
+
+static char
+_parse_direction(const char *s)
+{
+   if (!strcmp(s, "l") || !strcmp(s, "left"))   return 'l';
+   if (!strcmp(s, "r") || !strcmp(s, "right"))  return 'r';
+   if (!strcmp(s, "t") || !strcmp(s, "top"))    return 't';
+   if (!strcmp(s, "b") || !strcmp(s, "bottom")) return 'b';
+   return 0;
+}
+
+/* Find index of "--" in argv, or return -1 */
+static int
+_find_separator(int argc, char **argv, int start)
+{
+   int i;
+   for (i = start; i < argc; i++)
+     {
+        if (!strcmp(argv[i], "--"))
+          return i;
+     }
+   return -1;
+}
+
+/* Join argv[start..argc-1] with spaces into buf */
+static void
+_join_args(char *buf, size_t bufsz, int argc, char **argv, int start)
+{
+   size_t pos = 0;
+   int i;
+   for (i = start; i < argc && pos < bufsz - 1; i++)
+     {
+        if (i > start && pos < bufsz - 1)
+          buf[pos++] = ' ';
+        size_t len = strlen(argv[i]);
+        if (pos + len >= bufsz) len = bufsz - 1 - pos;
+        memcpy(buf + pos, argv[i], len);
+        pos += len;
+     }
+   buf[pos] = '\0';
+}
+
+int
+main(int argc, char **argv)
+{
+   char tbuf[8192];
+
+   ON_NOT_RUNNING_IN_TERMINOLOGY_EXIT_1();
+   ARGUMENT_ENTRY_CHECK(argc, argv, print_usage);
+
+   if (argc < 2)
+     {
+        print_usage(argv[0]);
+        return EXIT_FAILURE;
+     }
+
+   if (!strcmp(argv[1], "name"))
+     {
+        /* tytab name [NAME] */
+        if (argc >= 3)
+          {
+             if (strchr(argv[2], ';'))
+               {
+                  fprintf(stderr, "NAME must not contain ';'\n");
+                  return EXIT_FAILURE;
+               }
+             snprintf(tbuf, sizeof(tbuf), "%c}tn;%s", 0x1b, argv[2]);
+          }
+        else
+          snprintf(tbuf, sizeof(tbuf), "%c}tn;", 0x1b);
+
+        if (ty_write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1))
+          perror("write");
+     }
+   else if (!strcmp(argv[1], "new"))
+     {
+        /* tytab new [NAME DIR] [-- CMD...] */
+        int sep = _find_separator(argc, argv, 2);
+        int positional_end = (sep >= 0) ? sep : argc;
+        int positional_count = positional_end - 2;
+        const char *name = NULL;
+        char dir = 0;
+        char cmdbuf[4096];
+
+        cmdbuf[0] = '\0';
+
+        if (positional_count >= 2)
+          {
+             /* NAME and DIR provided */
+             name = argv[2];
+             if (strchr(name, ';'))
+               {
+                  fprintf(stderr, "NAME must not contain ';'\n");
+                  return EXIT_FAILURE;
+               }
+             dir = _parse_direction(argv[3]);
+             if (!dir)
+               {
+                  fprintf(stderr, "invalid direction: %s\n", argv[3]);
+                  return EXIT_FAILURE;
+               }
+          }
+        else if (positional_count == 1)
+          {
+             /* NAME without DIR is ambiguous — require both */
+             fprintf(stderr, "NAME requires a DIR argument\n");
+             print_usage(argv[0]);
+             return EXIT_FAILURE;
+          }
+        /* else: positional_count == 0, no name, no dir */
+
+        /* Build CMD from args after -- */
+        if (sep >= 0 && sep + 1 < argc)
+          _join_args(cmdbuf, sizeof(cmdbuf), argc, argv, sep + 1);
+
+        /* Format escape: tt[;NAME;DIR[;CMD]] */
+        if (name && dir)
+          {
+             if (cmdbuf[0])
+               snprintf(tbuf, sizeof(tbuf), "%c}tt;%s;%c;%s", 0x1b, name, dir, cmdbuf);
+             else
+               snprintf(tbuf, sizeof(tbuf), "%c}tt;%s;%c", 0x1b, name, dir);
+          }
+        else
+          {
+             if (cmdbuf[0])
+               snprintf(tbuf, sizeof(tbuf), "%c}tt;;;%s", 0x1b, cmdbuf);
+             else
+               snprintf(tbuf, sizeof(tbuf), "%c}tt", 0x1b);
+          }
+
+        if (ty_write(1, tbuf, strlen(tbuf) + 1) != (signed)(strlen(tbuf) + 1))
+          perror("write");
+     }
+   else
+     {
+        fprintf(stderr, "unknown command: %s\n", argv[1]);
+        print_usage(argv[0]);
+        return EXIT_FAILURE;
+     }
+
+   return EXIT_SUCCESS;
+}

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

Reply via email to