st-newterm-0.9-tmux.diff (3772B)
1 From 6640cf9809086d8cfb2363571d3e71a1a7a9f6bd Mon Sep 17 00:00:00 2001 2 From: meator <meator.dev@gmail.com> 3 Date: Tue, 25 Oct 2022 20:19:28 +0200 4 Subject: [PATCH] Add support for tmux in newterm 5 6 This commit tries to figure out if st's child is tmux and if so, it 7 launches a shell with the CWD of the current process in the tmux session 8 instead of the tmux client itself. 9 10 This is heavily inspired by 11 https://gist.github.com/TiddoLangerak/c61e1e48df91192f9554 (but 12 converted to C). 13 14 Tmux has to be a direct child of st. This means that you'll have to 15 usually use the 'exec' shell builtin to attach tmux sessions. 16 17 This patch only works on Linux. Other systems use different procfs which 18 is incompatible or don't have procfs at all (or it's optional). 19 --- 20 st.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 21 1 file changed, 82 insertions(+), 1 deletion(-) 22 23 diff --git a/st.c b/st.c 24 index 0261283..b95bf7a 100644 25 --- a/st.c 26 +++ b/st.c 27 @@ -221,6 +221,8 @@ static char base64dec_getc(const char **); 28 29 static ssize_t xwrite(int, const char *, size_t); 30 31 +static int gettmuxpts(void); 32 + 33 /* Globals */ 34 static Term term; 35 static Selection sel; 36 @@ -1061,6 +1063,12 @@ tswapscreen(void) 37 void 38 newterm(const Arg* a) 39 { 40 + int pts; 41 + FILE *fsession, *fpid; 42 + char session[5]; 43 + char pidstr[10]; 44 + char buf[48]; 45 + size_t size; 46 switch (fork()) { 47 case -1: 48 die("fork failed: %s\n", strerror(errno)); 49 @@ -1072,7 +1080,37 @@ newterm(const Arg* a) 50 _exit(1); 51 break; 52 case 0: 53 - chdir_by_pid(pid); 54 + signal(SIGCHLD, SIG_DFL); /* pclose() needs to use wait() */ 55 + pts = gettmuxpts(); 56 + if (pts != -1) { 57 + snprintf(buf, sizeof buf, "tmux lsc -t /dev/pts/%d -F \"#{client_session}\"", pts); 58 + fsession = popen(buf, "r"); 59 + if (!fsession) { 60 + fprintf(stderr, "Couldn't launch tmux."); 61 + _exit(1); 62 + } 63 + size = fread(session, 1, sizeof session, fsession); 64 + if (pclose(fsession) != 0 || size == 0) { 65 + fprintf(stderr, "Couldn't get tmux session."); 66 + _exit(1); 67 + } 68 + session[size - 1] = '\0'; /* size - 1 is used to also trim the \n */ 69 + 70 + snprintf(buf, sizeof buf, "tmux list-panes -st %s -F \"#{pane_pid}\"", session); 71 + fpid = popen(buf, "r"); 72 + if (!fpid) { 73 + fprintf(stderr, "Couldn't launch tmux."); 74 + _exit(1); 75 + } 76 + size = fread(pidstr, 1, sizeof pidstr, fpid); 77 + if (pclose(fpid) != 0 || size == 0) { 78 + fprintf(stderr, "Couldn't get tmux session."); 79 + _exit(1); 80 + } 81 + pidstr[size - 1] = '\0'; 82 + } 83 + 84 + chdir_by_pid(pts != -1 ? atol(pidstr) : pid); 85 execl("/proc/self/exe", argv0, NULL); 86 _exit(1); 87 break; 88 @@ -1092,6 +1130,49 @@ chdir_by_pid(pid_t pid) 89 return chdir(buf); 90 } 91 92 +/* returns the pty of tmux client or -1 if the child of st isn't tmux */ 93 +static int 94 +gettmuxpts(void) 95 +{ 96 + char buf[32]; 97 + char comm[17]; 98 + int tty; 99 + FILE *fstat; 100 + FILE *fcomm; 101 + size_t numread; 102 + 103 + snprintf(buf, sizeof buf, "/proc/%ld/comm", (long)pid); 104 + 105 + fcomm = fopen(buf, "r"); 106 + if (!fcomm) { 107 + fprintf(stderr, "Couldn't open %s: %s\n", buf, strerror(errno)); 108 + _exit(1); 109 + } 110 + 111 + numread = fread(comm, 1, sizeof comm - 1, fcomm); 112 + comm[numread] = '\0'; 113 + 114 + fclose(fcomm); 115 + 116 + if (strcmp("tmux: client\n", comm) != 0) 117 + return -1; 118 + 119 + snprintf(buf, sizeof buf, "/proc/%ld/stat", (long)pid); 120 + fstat = fopen(buf, "r"); 121 + if (!fstat) { 122 + fprintf(stderr, "Couldn't open %s: %s\n", buf, strerror(errno)); 123 + _exit(1); 124 + } 125 + 126 + /* 127 + * We can't skip the second field with %*s because it contains a space so 128 + * we skip strlen("tmux: client") + 2 for the braces which is 14. 129 + */ 130 + fscanf(fstat, "%*d %*14c %*c %*d %*d %*d %d", &tty); 131 + fclose(fstat); 132 + return ((0xfff00000 & tty) >> 12) | (0xff & tty); 133 +} 134 + 135 void 136 tscrolldown(int orig, int n) 137 { 138 -- 139 2.38.0 140