| st-newterm-0.9-tmux.diff - sites - public wiki contents of suckless.org | |
| git clone git://git.suckless.org/sites | |
| Log | |
| Files | |
| Refs | |
| --- | |
| st-newterm-0.9-tmux.diff (3772B) | |
| --- | |
| 1 From 6640cf9809086d8cfb2363571d3e71a1a7a9f6bd Mon Sep 17 00:00:00 2001 | |
| 2 From: meator <[email protected]> | |
| 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 … | |
| 55 + pts = gettmuxpts(); | |
| 56 + if (pts != -1) { | |
| 57 + snprintf(buf, sizeof buf, "tmux lsc -t … | |
| 58 + fsession = popen(buf, "r"); | |
| 59 + if (!fsession) { | |
| 60 + fprintf(stderr, "Couldn't launc… | |
| 61 + _exit(1); | |
| 62 + } | |
| 63 + size = fread(session, 1, sizeof session… | |
| 64 + if (pclose(fsession) != 0 || size == 0)… | |
| 65 + fprintf(stderr, "Couldn't get t… | |
| 66 + _exit(1); | |
| 67 + } | |
| 68 + session[size - 1] = '\0'; /* size - 1 i… | |
| 69 + | |
| 70 + snprintf(buf, sizeof buf, "tmux list-pa… | |
| 71 + fpid = popen(buf, "r"); | |
| 72 + if (!fpid) { | |
| 73 + fprintf(stderr, "Couldn't launc… | |
| 74 + _exit(1); | |
| 75 + } | |
| 76 + size = fread(pidstr, 1, sizeof pidstr, … | |
| 77 + if (pclose(fpid) != 0 || size == 0) { | |
| 78 + fprintf(stderr, "Couldn't get t… | |
| 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… | |
| 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… | |
| 123 + _exit(1); | |
| 124 + } | |
| 125 + | |
| 126 + /* | |
| 127 + * We can't skip the second field with %*s because it contains … | |
| 128 + * we skip strlen("tmux: client") + 2 for the braces which is 1… | |
| 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 |