osc7: initial patch implementation (#154)
* osc7: initial patch implementation Closes #153 * osc7: avoid redundant use of realpath() * osc7: fix styling * Changing position of the OSC7_PATCH toggle in patches.def.h --------- Co-authored-by: Bakkeby <bakkeby@gmail.com>
This commit is contained in:
parent
3f1a5ed034
commit
c4c5113fbd
9 changed files with 136 additions and 11 deletions
|
|
@ -1,7 +1,15 @@
|
||||||
|
extern char* argv0;
|
||||||
|
|
||||||
|
static char*
|
||||||
|
getcwd_by_pid(pid_t pid) {
|
||||||
|
static char cwd[32];
|
||||||
|
snprintf(cwd, sizeof cwd, "/proc/%d/cwd", pid);
|
||||||
|
return cwd;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
newterm(const Arg* a)
|
newterm(const Arg* a)
|
||||||
{
|
{
|
||||||
int res;
|
|
||||||
switch (fork()) {
|
switch (fork()) {
|
||||||
case -1:
|
case -1:
|
||||||
die("fork failed: %s\n", strerror(errno));
|
die("fork failed: %s\n", strerror(errno));
|
||||||
|
|
@ -12,9 +20,23 @@ newterm(const Arg* a)
|
||||||
die("fork failed: %s\n", strerror(errno));
|
die("fork failed: %s\n", strerror(errno));
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
res = chdir(getcwd_by_pid(pid));
|
#if OSC7_PATCH
|
||||||
execlp("st", "./st", NULL);
|
if (term.cwd) {
|
||||||
break;
|
if (chdir(term.cwd) == 0) {
|
||||||
|
/* We need to put the working directory also in PWD, so that
|
||||||
|
* the shell starts in the right directory if `cwd` is a
|
||||||
|
* symlink. */
|
||||||
|
setenv("PWD", term.cwd, 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chdir(getcwd_by_pid(pid));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
chdir(getcwd_by_pid(pid));
|
||||||
|
#endif // OSC7_PATCH
|
||||||
|
|
||||||
|
execl("/proc/self/exe", argv0, NULL);
|
||||||
|
exit(1);
|
||||||
default:
|
default:
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
@ -22,9 +44,3 @@ newterm(const Arg* a)
|
||||||
wait(NULL);
|
wait(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *getcwd_by_pid(pid_t pid) {
|
|
||||||
char buf[32];
|
|
||||||
snprintf(buf, sizeof buf, "/proc/%d/cwd", pid);
|
|
||||||
return realpath(buf, NULL);
|
|
||||||
}
|
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
void newterm(const Arg *);
|
void newterm(const Arg *);
|
||||||
static char *getcwd_by_pid(pid_t pid);
|
|
||||||
74
patch/osc7.c
Normal file
74
patch/osc7.c
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
static int
|
||||||
|
hex2int(char c)
|
||||||
|
{
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
return c - '0';
|
||||||
|
else if (c >= 'a' && c <= 'f')
|
||||||
|
return c - 'a' + 10;
|
||||||
|
else if (c >= 'A' && c <= 'F')
|
||||||
|
return c - 'A' + 10;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
osc7parsecwd(const char *uri)
|
||||||
|
{
|
||||||
|
const char *auth, *host, *hostend;
|
||||||
|
char *path, decoded[PATH_MAX], thishost[_POSIX_HOST_NAME_MAX];
|
||||||
|
size_t i, decodedlen, hostlen, urilen;
|
||||||
|
int h1, h2;
|
||||||
|
if (!term.cwd) {
|
||||||
|
term.cwd = xmalloc(sizeof(decoded));
|
||||||
|
term.cwd[0] = '\0';
|
||||||
|
}
|
||||||
|
/* reset cwd if uri is empty */
|
||||||
|
if ((urilen = strlen(uri)) == 0) {
|
||||||
|
term.cwd[0] = '\0';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* decode uri */
|
||||||
|
for (decodedlen = 0, i = 0; i < urilen; i++) {
|
||||||
|
if (uri[i] == '%' && i <= urilen-3 &&
|
||||||
|
(h1 = hex2int(uri[i+1])) >= 0 && (h2 = hex2int(uri[i+2])) >= 0) {
|
||||||
|
decoded[decodedlen++] = (h1 << 4) | h2;
|
||||||
|
i += 2;
|
||||||
|
} else {
|
||||||
|
decoded[decodedlen++] = uri[i];
|
||||||
|
}
|
||||||
|
if (decodedlen == sizeof(decoded)) {
|
||||||
|
fprintf(stderr, "erresc (OSC 7): uri is too long\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
decoded[decodedlen] = '\0';
|
||||||
|
/* check scheme */
|
||||||
|
if (decodedlen < 5 || strncmp("file:", decoded, 5) != 0) {
|
||||||
|
fprintf(stderr, "erresc (OSC 7): scheme is not supported: '%s'\n", uri);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* find start of authority */
|
||||||
|
if (decodedlen < 7 || decoded[5] != '/' || decoded[6] != '/') {
|
||||||
|
fprintf(stderr, "erresc (OSC 7): invalid uri: '%s'\n", uri);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auth = decoded + 7;
|
||||||
|
/* find start of path and reset cwd if path is missing */
|
||||||
|
if ((path = strchr(auth, '/')) == NULL) {
|
||||||
|
term.cwd[0] = '\0';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* ignore path if host is not localhost */
|
||||||
|
host = ((host = memchr(auth, '@', path - auth)) != NULL) ? host+1 : auth;
|
||||||
|
hostend = ((hostend = memchr(host, ':', path - host)) != NULL) ? hostend : path;
|
||||||
|
hostlen = hostend - host;
|
||||||
|
if (gethostname(thishost, sizeof(thishost)) < 0)
|
||||||
|
thishost[0] = '\0';
|
||||||
|
if (hostlen > 0 &&
|
||||||
|
!(hostlen == 9 && strncmp("localhost", host, hostlen) == 0) &&
|
||||||
|
!(hostlen == strlen(thishost) && strncmp(host, thishost, hostlen) == 0)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy(term.cwd, path, decodedlen - (path - decoded) + 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
1
patch/osc7.h
Normal file
1
patch/osc7.h
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
static int osc7parsecwd(const char *);
|
||||||
|
|
@ -27,3 +27,6 @@
|
||||||
#if SYNC_PATCH
|
#if SYNC_PATCH
|
||||||
#include "sync.c"
|
#include "sync.c"
|
||||||
#endif
|
#endif
|
||||||
|
#if OSC7_PATCH
|
||||||
|
#include "osc7.c"
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -30,3 +30,6 @@
|
||||||
#if SYNC_PATCH
|
#if SYNC_PATCH
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if OSC7_PATCH
|
||||||
|
#include "osc7.h"
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -301,6 +301,14 @@
|
||||||
*/
|
*/
|
||||||
#define OPENURLONCLICK_PATCH 0
|
#define OPENURLONCLICK_PATCH 0
|
||||||
|
|
||||||
|
/* This patch allows st to fetch the current working directory through the OSC 7 escape
|
||||||
|
* sequence emitted by shells. Must be used with newterm patch.
|
||||||
|
*
|
||||||
|
* https://codeberg.org/dnkl/foot/wiki#spawning-new-terminal-instances-in-the-current-working-directory
|
||||||
|
* https://github.com/veltza/st-sx/commit/817865c2c6ed905af8849580e58bdcf399216fbd
|
||||||
|
*/
|
||||||
|
#define OSC7_PATCH 0
|
||||||
|
|
||||||
/* This patch allows jumping between prompts by utilizing the OSC 133 escape sequence
|
/* This patch allows jumping between prompts by utilizing the OSC 133 escape sequence
|
||||||
* emitted by shells. Must be used with either reflow or scrollback patch.
|
* emitted by shells. Must be used with either reflow or scrollback patch.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
18
st.c
18
st.c
|
|
@ -2654,6 +2654,11 @@ strhandle(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
#if OSC7_PATCH
|
||||||
|
case 7:
|
||||||
|
osc7parsecwd((const char *)strescseq.args[1]);
|
||||||
|
return;
|
||||||
|
#endif // OSC7_PATCH
|
||||||
case 8: /* Clear Hyperlinks */
|
case 8: /* Clear Hyperlinks */
|
||||||
return;
|
return;
|
||||||
case 10:
|
case 10:
|
||||||
|
|
@ -2856,6 +2861,19 @@ strparse(void)
|
||||||
if (*p == '\0')
|
if (*p == '\0')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* preserve semicolons in window titles, icon names and OSC 7 sequences */
|
||||||
|
if (strescseq.type == ']' && (
|
||||||
|
p[0] <= '2'
|
||||||
|
#if OSC7_PATCH
|
||||||
|
|| p[0] == '7'
|
||||||
|
#endif // OSC7_PATCH
|
||||||
|
) && p[1] == ';') {
|
||||||
|
strescseq.args[strescseq.narg++] = p;
|
||||||
|
strescseq.args[strescseq.narg++] = p + 2;
|
||||||
|
p[1] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while (strescseq.narg < STR_ARG_SIZ) {
|
while (strescseq.narg < STR_ARG_SIZ) {
|
||||||
strescseq.args[strescseq.narg++] = p;
|
strescseq.args[strescseq.narg++] = p;
|
||||||
while ((c = *p) != ';' && c != '\0')
|
while ((c = *p) != ';' && c != '\0')
|
||||||
|
|
|
||||||
3
st.h
3
st.h
|
|
@ -205,6 +205,9 @@ typedef struct {
|
||||||
ImageList *images_alt; /* sixel images for alternate screen */
|
ImageList *images_alt; /* sixel images for alternate screen */
|
||||||
#endif // SIXEL_PATCH
|
#endif // SIXEL_PATCH
|
||||||
Rune lastc; /* last printed char outside of sequence, 0 if control */
|
Rune lastc; /* last printed char outside of sequence, 0 if control */
|
||||||
|
#if OSC7_PATCH
|
||||||
|
char* cwd; /* current working directory */
|
||||||
|
#endif // OSC7_PATCH
|
||||||
} Term;
|
} Term;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue