From: Jonathan Gray Subject: Re: ksh: add OSC7 support To: ori@eigenstate.org Cc: tech@openbsd.org Date: Fri, 7 Nov 2025 14:26:41 +1100 On Thu, Nov 06, 2025 at 08:23:26PM -0500, ori@eigenstate.org wrote: > I use OSC7 in order to advertise the working directory to the > terminal emulator I use. While I can hack this together in ksh > with some scripts, it feels like it would be a better fit to > have directly in the shell, though I'm uncertain about that. > > It seems a bit odd to have support for this in tmux, but not > emit it in our own shell. > > The patch below adds a '\O' option to PS1. It needs to be > enabled explicitly, as: > > PS1=\O\h\$ > > I'd also considered printing it after every 'cd' command, > either unconditionally or behind a knob. > > Is there interest in this? If there is, is this the right > place to do it, or should we put it somewhere else? Does any other shell use \O like this? My preference is not to add more escape sequences. The spacing in this diff is not very knf like. "wish ksh" should be "which ksh"? > > diff b0824ea26cb2a850adf7ef5a41c70bb06f83050c uncommitted > --- a/bin/ksh/ksh.1 > +++ b/bin/ksh/ksh.1 > @@ -1618,6 +1618,10 @@ > .Dv $HOME > is abbreviated as > .Sq ~ . > +.It Sy \eO > +The OSC-7 escape code. > +This advertises the current working directory to > +terminal emulator under wish ksh is running. > .It Sy \e! > The current history number. > An unescaped > @@ -4282,7 +4286,7 @@ > .Ar n > blocks on files written by the shell and its child processes (files of any > size may be read). > -.It Fl H > +.It Fl// > Set the hard limit only (the default is to set both hard and soft limits). > .It Fl l Ar n > Impose a limit of > --- a/bin/ksh/lex.c > +++ b/bin/ksh/lex.c > @@ -1207,10 +1207,37 @@ > } > } > > +static char* > +osc7encode(char *p, char *e, char *s, int raw) > +{ > + static const char hex[] = "0123456789abcdef"; > + > + while(*s){ > + if((*s >= 'a' && *s <= 'z') > + || (*s >= 'A' && *s <= 'f') > + || (*s >= '0' && *s <= '9') > + || (strchr("/-_.~", *s) != NULL) > + || raw){ > + if(e - p < 2) > + break; > + *p++ = *s++; > + }else{ > + if(e - p < 4) > + break; > + *p++ = '%'; > + *p++ = hex[(*s>>4) & 0xf]; > + *p++ = hex[(*s>>0) & 0xf]; > + s++; > + } > + } > + *p = 0; > + return p; > +} > + > static int > dopprompt(const char *sp, int ntruncate, const char **spp, int doprint) > { > - char strbuf[1024], tmpbuf[1024], *p, *str, nbuf[32], delimiter = '\0'; > + char strbuf[1024], tmpbuf[1024], *p, *e, *str, nbuf[32], delimiter = '\0'; > int len, c, n, totlen = 0, indelimit = 0, counting = 1, delimitthis; > const char *cp = sp; > struct tm *tm; > @@ -1398,6 +1425,20 @@ > strbuf[1] = '\0'; > } else > strlcpy(strbuf, basename(p), sizeof strbuf); > + break; > + case 'O': > + str = str_val(global("PWD")); > + gethostname(tmpbuf, sizeof strbuf); > + if((e = strchr(tmpbuf, '.')) != NULL) > + *e = '\0'; > + > + p = strbuf; > + e = strbuf + sizeof(strbuf); > + p = osc7encode(p, e, "\033]7;file://", 1); > + p = osc7encode(p, e, tmpbuf, 0); > + p = osc7encode(p, e, "/", 0); > + p = osc7encode(p, e, str, 0); > + p = osc7encode(p, e, "\033", 1); > break; > case '!': /* '\' '!' history line number */ > snprintf(strbuf, sizeof strbuf, "%d", > >