commit c356e234ffd9fff1f39686fd3aa15ab39ec4790d
Author: meator <[email protected]>
Date:   Thu Oct 27 15:52:27 2022 +0200

    [st][patch][newterm] Add tmux support + update

diff --git a/st.suckless.org/patches/newterm/index.md 
b/st.suckless.org/patches/newterm/index.md
index 319512ff..42398ed9 100644
--- a/st.suckless.org/patches/newterm/index.md
+++ b/st.suckless.org/patches/newterm/index.md
@@ -16,6 +16,20 @@ will have no parent process).
 To have newterm working with tabbed, apply the st-newterm-0.8.2-tabbed.diff 
patch
 on top of st-newterm-0.8.2.diff.
 
+To have tmux support, apply the st-newterm-0.9-tmux.diff patch on top of
+st-newterm-0.9.diff.
+
+With the tmux patch, newterm won't launch a new terminal with the CWD of the 
tmux
+client itself, but it will use the CWD of the current process in the tmux 
session
+running under st.
+
+The tmux client must be a direct child of st in order to make newterm detect it
+(you'll need to use `exec tmux` or similar). If the child of st isn't a tmux
+client, newterm will fallback to the CWD of st's child (which is what newterm
+does without the tmux patch).
+
+The tmux patch only works on Linux.
+
 Download
 --------
 
@@ -23,9 +37,13 @@ Download
   * [st-newterm-0.8.2-tabbed.diff](st-newterm-0.8.2-tabbed.diff)
 * 
[st-newterm-orphan-20210712-4536f46.diff](st-newterm-orphan-20210712-4536f46.diff)
 * [st-newterm-20220221-0.8.5.diff](st-newterm-20220221-0.8.5.diff)
+* [st-newterm-0.9.diff](st-newterm-0.9.diff)
+  * [st-newterm-0.9-tabbed.diff](st-newterm-0.9-tabbed.diff)
+  * [st-newterm-0.9-tmux.diff](st-newterm-0.9-tmux.diff)
 
 Authors
 -------
 * Matías Lang
 * Stein Bakkeby (orphan version)
 * Gaspar Vardanyan (tabbed support)
+* [Meator](https://github.com/meator) - <[email protected]> (all of the 
st-newterm-0.9* patches)
diff --git a/st.suckless.org/patches/newterm/st-newterm-0.9-tabbed.diff 
b/st.suckless.org/patches/newterm/st-newterm-0.9-tabbed.diff
new file mode 100644
index 00000000..a32c3162
--- /dev/null
+++ b/st.suckless.org/patches/newterm/st-newterm-0.9-tabbed.diff
@@ -0,0 +1,38 @@
+From 88559b5cb6ed3f996fc00e923f9ded3c0b353fc5 Mon Sep 17 00:00:00 2001
+From: meator <[email protected]>
+Date: Wed, 26 Oct 2022 14:06:49 +0200
+Subject: [PATCH] Make newterm work with the tabbed patch
+
+This commit is an updated version of st-newterm-0.8.2-tabbed.diff.
+---
+ st.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/st.c b/st.c
+index 0261283..e4a9021 100644
+--- a/st.c
++++ b/st.c
+@@ -1061,6 +1061,7 @@ tswapscreen(void)
+ void
+ newterm(const Arg* a)
+ {
++      char *tabbed_win;
+       switch (fork()) {
+       case -1:
+               die("fork failed: %s
", strerror(errno));
+@@ -1073,7 +1074,11 @@ newterm(const Arg* a)
+                       break;
+               case 0:
+                       chdir_by_pid(pid);
+-                      execl("/proc/self/exe", argv0, NULL);
++                      tabbed_win = getenv("XEMBED");
++                      if (tabbed_win)
++                              execl("/proc/self/exe", argv0, "-w", 
tabbed_win, NULL);
++                      else
++                              execl("/proc/self/exe", argv0, NULL);
+                       _exit(1);
+                       break;
+               default:
+-- 
+2.38.0
+
diff --git a/st.suckless.org/patches/newterm/st-newterm-0.9-tmux.diff 
b/st.suckless.org/patches/newterm/st-newterm-0.9-tmux.diff
new file mode 100644
index 00000000..cd73e605
--- /dev/null
+++ b/st.suckless.org/patches/newterm/st-newterm-0.9-tmux.diff
@@ -0,0 +1,140 @@
+From 6640cf9809086d8cfb2363571d3e71a1a7a9f6bd Mon Sep 17 00:00:00 2001
+From: meator <[email protected]>
+Date: Tue, 25 Oct 2022 20:19:28 +0200
+Subject: [PATCH] Add support for tmux in newterm
+
+This commit tries to figure out if st's child is tmux and if so, it
+launches a shell with the CWD of the current process in the tmux session
+instead of the tmux client itself.
+
+This is heavily inspired by
+https://gist.github.com/TiddoLangerak/c61e1e48df91192f9554 (but
+converted to C).
+
+Tmux has to be a direct child of st. This means that you'll have to
+usually use the 'exec' shell builtin to attach tmux sessions.
+
+This patch only works on Linux. Other systems use different procfs which
+is incompatible or don't have procfs at all (or it's optional).
+---
+ st.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 82 insertions(+), 1 deletion(-)
+
+diff --git a/st.c b/st.c
+index 0261283..b95bf7a 100644
+--- a/st.c
++++ b/st.c
+@@ -221,6 +221,8 @@ static char base64dec_getc(const char **);
+ 
+ static ssize_t xwrite(int, const char *, size_t);
+ 
++static int gettmuxpts(void);
++
+ /* Globals */
+ static Term term;
+ static Selection sel;
+@@ -1061,6 +1063,12 @@ tswapscreen(void)
+ void
+ newterm(const Arg* a)
+ {
++      int pts;
++      FILE *fsession, *fpid;
++      char session[5];
++      char pidstr[10];
++      char buf[48];
++      size_t size;
+       switch (fork()) {
+       case -1:
+               die("fork failed: %s
", strerror(errno));
+@@ -1072,7 +1080,37 @@ newterm(const Arg* a)
+                       _exit(1);
+                       break;
+               case 0:
+-                      chdir_by_pid(pid);
++                      signal(SIGCHLD, SIG_DFL); /* pclose() needs to use 
wait() */
++                      pts = gettmuxpts();
++                      if (pts != -1) {
++                              snprintf(buf, sizeof buf, "tmux lsc -t 
/dev/pts/%d -F \"#{client_session}\"", pts);
++                              fsession = popen(buf, "r");
++                              if (!fsession) {
++                                      fprintf(stderr, "Couldn't launch 
tmux.");
++                                      _exit(1);
++                              }
++                              size = fread(session, 1, sizeof session, 
fsession);
++                              if (pclose(fsession) != 0 || size == 0) {
++                                      fprintf(stderr, "Couldn't get tmux 
session.");
++                                      _exit(1);
++                              }
++                              session[size - 1] = ' */
++
++                              snprintf(buf, sizeof buf, "tmux list-panes -st 
%s -F \"#{pane_pid}\"", session);
++                              fpid = popen(buf, "r");
++                              if (!fpid) {
++                                      fprintf(stderr, "Couldn't launch 
tmux.");
++                                      _exit(1);
++                              }
++                              size = fread(pidstr, 1, sizeof pidstr, fpid);
++                              if (pclose(fpid) != 0 || size == 0) {
++                                      fprintf(stderr, "Couldn't get tmux 
session.");
++                                      _exit(1);
++                              }
++                              pidstr[size - 1] = '++                  }
++
++                      chdir_by_pid(pts != -1 ? atol(pidstr) : pid);
+                       execl("/proc/self/exe", argv0, NULL);
+                       _exit(1);
+                       break;
+@@ -1092,6 +1130,49 @@ chdir_by_pid(pid_t pid)
+       return chdir(buf);
+ }
+ 
++/* returns the pty of tmux client or -1 if the child of st isn't tmux */
++static int
++gettmuxpts(void)
++{
++      char buf[32];
++      char comm[17];
++      int tty;
++      FILE *fstat;
++      FILE *fcomm;
++      size_t numread;
++
++      snprintf(buf, sizeof buf, "/proc/%ld/comm", (long)pid);
++
++      fcomm = fopen(buf, "r");
++      if (!fcomm) {
++              fprintf(stderr, "Couldn't open %s: %s
", buf, strerror(errno));
++              _exit(1);
++      }
++
++      numread = fread(comm, 1, sizeof comm - 1, fcomm);
++      comm[numread] = '++
++      fclose(fcomm);
++
++      if (strcmp("tmux: client
", comm) != 0)
++              return -1;
++
++      snprintf(buf, sizeof buf, "/proc/%ld/stat", (long)pid);
++      fstat = fopen(buf, "r");
++      if (!fstat) {
++              fprintf(stderr, "Couldn't open %s: %s
", buf, strerror(errno));
++              _exit(1);
++      }
++
++      /*
++       * We can't skip the second field with %*s because it contains a space 
so
++       * we skip strlen("tmux: client") + 2 for the braces which is 14.
++       */
++      fscanf(fstat, "%*d %*14c %*c %*d %*d %*d %d", &tty);
++      fclose(fstat);
++      return ((0xfff00000 & tty) >> 12) | (0xff & tty);
++}
++
+ void
+ tscrolldown(int orig, int n)
+ {
+-- 
+2.38.0
+
diff --git a/st.suckless.org/patches/newterm/st-newterm-0.9.diff 
b/st.suckless.org/patches/newterm/st-newterm-0.9.diff
new file mode 100644
index 00000000..5525e7a5
--- /dev/null
+++ b/st.suckless.org/patches/newterm/st-newterm-0.9.diff
@@ -0,0 +1,112 @@
+From e1cf625f4f225a007a5835421896089669195e02 Mon Sep 17 00:00:00 2001
+From: meator <[email protected]>
+Date: Wed, 26 Oct 2022 13:05:38 +0200
+Subject: [PATCH] Add shortcut to spawn new terminal in the current dir
+
+This commit is inspired by Santtu's st-newterm-20220221-0.8.5.diff. It
+removes the unused res variable, it makes use of _exit() instead of
+exit() and it replaces execlp() with execl() (PATH searching is useless
+when the path is absolute).
+---
+ config.def.h |  1 +
+ st.c         | 38 ++++++++++++++++++++++++++++++++++++++
+ st.h         |  1 +
+ 3 files changed, 40 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index 91ab8ca..7c75246 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -201,6 +201,7 @@ static Shortcut shortcuts[] = {
+       { TERMMOD,              XK_Y,           selpaste,       {.i =  0} },
+       { ShiftMask,            XK_Insert,      selpaste,       {.i =  0} },
+       { TERMMOD,              XK_Num_Lock,    numlock,        {.i =  0} },
++      { TERMMOD,              XK_Return,      newterm,        {.i =  0} },
+ };
+ 
+ /*
+diff --git a/st.c b/st.c
+index 62def59..0261283 100644
+--- a/st.c
++++ b/st.c
+@@ -20,6 +20,8 @@
+ #include "st.h"
+ #include "win.h"
+ 
++extern char *argv0;
++
+ #if   defined(__linux)
+  #include <pty.h>
+ #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
+@@ -153,6 +155,7 @@ typedef struct {
+ } STREscape;
+ 
+ static void execsh(char *, char **);
++static int chdir_by_pid(pid_t pid);
+ static void stty(char **);
+ static void sigchld(int);
+ static void ttywriteraw(const char *, size_t);
+@@ -806,6 +809,7 @@ ttynew(const char *line, char *cmd, const char *out, char 
**args)
+               if (pledge("stdio rpath tty proc", NULL) == -1)
+                       die("pledge
");
+ #endif
++              fcntl(m, F_SETFD, FD_CLOEXEC);
+               close(s);
+               cmdfd = m;
+               signal(SIGCHLD, sigchld);
+@@ -1054,6 +1058,40 @@ tswapscreen(void)
+       tfulldirt();
+ }
+ 
++void
++newterm(const Arg* a)
++{
++      switch (fork()) {
++      case -1:
++              die("fork failed: %s
", strerror(errno));
++              break;
++      case 0:
++              switch (fork()) {
++              case -1:
++                      fprintf(stderr, "fork failed: %s
", strerror(errno));
++                      _exit(1);
++                      break;
++              case 0:
++                      chdir_by_pid(pid);
++                      execl("/proc/self/exe", argv0, NULL);
++                      _exit(1);
++                      break;
++              default:
++                      _exit(0);
++              }
++      default:
++              wait(NULL);
++      }
++}
++
++static int
++chdir_by_pid(pid_t pid)
++{
++      char buf[32];
++      snprintf(buf, sizeof buf, "/proc/%ld/cwd", (long)pid);
++      return chdir(buf);
++}
++
+ void
+ tscrolldown(int orig, int n)
+ {
+diff --git a/st.h b/st.h
+index fd3b0d8..f2b03b0 100644
+--- a/st.h
++++ b/st.h
+@@ -81,6 +81,7 @@ void die(const char *, ...);
+ void redraw(void);
+ void draw(void);
+ 
++void newterm(const Arg *);
+ void printscreen(const Arg *);
+ void printsel(const Arg *);
+ void sendbreak(const Arg *);
+-- 
+2.38.0
+


Reply via email to