Compare commits

..

No commits in common. "6499e884851d0a5df1518a33743d0dc303734237" and "56c4253a87f15968a41d0ef9149cf72af04ad39d" have entirely different histories.

13 changed files with 103 additions and 488 deletions

BIN
.st.h.swn

Binary file not shown.

BIN
.st.h.swo

Binary file not shown.

BIN
.st.h.swp

Binary file not shown.

View File

@ -90,10 +90,6 @@ int allowaltscreen = 1;
setting the clipboard text */ setting the clipboard text */
int allowwindowops = 0; int allowwindowops = 0;
/* allow programs to set the clipboard via OSC 52. This is what tmux uses
for set-clipboard, and what remote programs use to copy over ssh. */
int allowclipboard = 1;
/* /*
* draw latency range in ms - from new content/keypress/etc until drawing. * draw latency range in ms - from new content/keypress/etc until drawing.
* within this range, st draws when content stops arriving (idle). mostly it's * within this range, st draws when content stops arriving (idle). mostly it's

View File

@ -90,10 +90,6 @@ int allowaltscreen = 1;
setting the clipboard text */ setting the clipboard text */
int allowwindowops = 0; int allowwindowops = 0;
/* allow programs to set the clipboard via OSC 52. This is what tmux uses
for set-clipboard, and what remote programs use to copy over ssh. */
int allowclipboard = 1;
/* /*
* draw latency range in ms - from new content/keypress/etc until drawing. * draw latency range in ms - from new content/keypress/etc until drawing.
* within this range, st draws when content stops arriving (idle). mostly it's * within this range, st draws when content stops arriving (idle). mostly it's

120
kitty.c
View File

@ -2295,46 +2295,122 @@ kitty_find_virtual(uint32_t imgid, uint32_t plcid)
/* /*
* Blit the part of a virtual placement that corresponds to one screen cell. * Blit the part of a virtual placement that corresponds to one screen cell.
* (px, py) is the cell on screen, (row, col) the cell within the placement. * (px, py) is the cell on screen, (row, col) the cell within the placement.
*
* The whole placement is scaled once into the placement's pixmap cache
* (kitty_prepare), and each cell is then a cheap XRender copy out of it.
*/ */
static void static void
kitty_blit_cell(KittyPlacement *p, int px, int py, int row, int col) kitty_blit_cell(KittyPlacement *p, int px, int py, int row, int col)
{ {
KittyImage *im = p->image;
const unsigned char *base;
unsigned char *cell;
int cw = win.cw, ch = win.ch;
int fullw, fullh, sx0, sy0, x, y, i, n;
unsigned char *tile;
Pixmap pm;
XImage ximage;
Picture src, dstpic; Picture src, dstpic;
XRenderPictFormat *fmt; XRenderPictFormat *fmt;
XRenderPictureAttributes pa; XRenderPictureAttributes pa;
int w, h, bx, by, cw = win.cw, ch = win.ch; int bx, by;
int sx, sy, cellw, cellh;
if (!p->image || row >= p->rows || col >= p->cols) if (!im || row >= p->rows || col >= p->cols)
return;
if (!kitty_prepare(p, &w, &h))
return; return;
sx = col * cw; fullw = p->cols * cw;
sy = row * ch; fullh = p->rows * ch;
cellw = KMIN(cw, w - sx); if (fullw <= 0 || fullh <= 0)
cellh = KMIN(ch, h - sy);
if (cellw <= 0 || cellh <= 0)
return; return;
base = kitty_frame_pixels(im, im->current_frame);
if (!base)
return;
base += ((size_t)p->sy * im->width + p->sx) * 4;
/* scale just this cell out of the source rect */
sx0 = col * cw;
sy0 = row * ch;
if (!(cell = malloc((size_t)cw * ch * 4)))
return;
for (y = 0; y < ch; y++) {
double fy = ((double)(sy0 + y) + 0.5) * p->sh / fullh - 0.5;
int y0 = (int)(fy < 0 ? 0 : fy);
int y1 = KMIN(y0 + 1, p->sh - 1);
int wy = (int)((fy - y0) * 256);
if (wy < 0) wy = 0;
if (wy > 256) wy = 256;
for (x = 0; x < cw; x++) {
double fx = ((double)(sx0 + x) + 0.5) * p->sw / fullw - 0.5;
int x0 = (int)(fx < 0 ? 0 : fx);
int x1 = KMIN(x0 + 1, p->sw - 1);
int wx = (int)((fx - x0) * 256);
const unsigned char *q00, *q01, *q10, *q11;
unsigned char *o = cell + ((size_t)y * cw + x) * 4;
int c;
if (wx < 0) wx = 0;
if (wx > 256) wx = 256;
q00 = base + (size_t)y0 * im->width * 4 + x0 * 4;
q01 = base + (size_t)y0 * im->width * 4 + x1 * 4;
q10 = base + (size_t)y1 * im->width * 4 + x0 * 4;
q11 = base + (size_t)y1 * im->width * 4 + x1 * 4;
for (c = 0; c < 4; c++) {
int t = q00[c] * (256 - wx) + q01[c] * wx;
int b = q10[c] * (256 - wx) + q11[c] * wx;
o[c] = (unsigned char)((t * (256 - wy) + b * wy) >> 16);
}
}
}
tile = cell;
n = cw * ch;
for (i = 0; i < n; i++) {
unsigned char r = tile[4*i+0], g = tile[4*i+1];
unsigned char b = tile[4*i+2], a = tile[4*i+3];
tile[4*i+0] = (unsigned char)(b * a / 255);
tile[4*i+1] = (unsigned char)(g * a / 255);
tile[4*i+2] = (unsigned char)(r * a / 255);
tile[4*i+3] = a;
}
pm = XCreatePixmap(xw.dpy, xw.win, cw, ch, 32);
if (!pm) {
free(cell);
return;
}
memset(&ximage, 0, sizeof ximage);
ximage.format = ZPixmap;
ximage.data = (char *)tile;
ximage.width = cw;
ximage.height = ch;
ximage.byte_order = LSBFirst;
ximage.bitmap_bit_order = MSBFirst;
ximage.bits_per_pixel = 32;
ximage.bytes_per_line = cw * 4;
ximage.bitmap_unit = 32;
ximage.bitmap_pad = 32;
ximage.depth = 32;
XInitImage(&ximage);
{
GC gc = XCreateGC(xw.dpy, pm, 0, NULL);
XPutImage(xw.dpy, pm, gc, &ximage, 0, 0, 0, 0, cw, ch);
XFreeGC(xw.dpy, gc);
}
free(cell);
kitty_border(&bx, &by); kitty_border(&bx, &by);
memset(&pa, 0, sizeof pa); memset(&pa, 0, sizeof pa);
fmt = XRenderFindStandardFormat(xw.dpy, PictStandardARGB32); fmt = XRenderFindStandardFormat(xw.dpy, PictStandardARGB32);
if (!fmt)
return;
src = XRenderCreatePicture(xw.dpy, (Drawable)p->pixmap, fmt, 0, &pa);
fmt = XRenderFindVisualFormat(xw.dpy, xw.vis);
if (fmt) { if (fmt) {
dstpic = XRenderCreatePicture(xw.dpy, xw.buf, fmt, 0, &pa); src = XRenderCreatePicture(xw.dpy, pm, fmt, 0, &pa);
XRenderComposite(xw.dpy, PictOpOver, src, None, dstpic, sx, sy, 0, 0, fmt = XRenderFindVisualFormat(xw.dpy, xw.vis);
bx + px * cw, by + py * ch, cellw, cellh); if (fmt) {
XRenderFreePicture(xw.dpy, dstpic); dstpic = XRenderCreatePicture(xw.dpy, xw.buf, fmt, 0, &pa);
XRenderComposite(xw.dpy, PictOpOver, src, None, dstpic, 0, 0, 0, 0,
bx + px * cw, by + py * ch, cw, ch);
XRenderFreePicture(xw.dpy, dstpic);
}
XRenderFreePicture(xw.dpy, src);
} }
XRenderFreePicture(xw.dpy, src); XFreePixmap(xw.dpy, pm);
} }
/* scan the visible screen for placeholder glyphs and draw their images */ /* scan the visible screen for placeholder glyphs and draw their images */

View File

@ -61,30 +61,6 @@ clearurl(void)
url_y2 = -1; url_y2 = -1;
} }
#if OSC7_OSC8_PATCH
/* an explicit OSC 8 hyperlink takes precedence over text detection */
static char *
detecthyperlink(int col, int row, int draw)
{
int x1, y1, x2, y2;
uint32_t id = hyperlink_at(col, row, &x1, &y1, &x2, &y2);
const char *url;
if (!id || !(url = hyperlink_get(id)))
return NULL;
if (draw) {
url_x1 = x1;
url_x2 = x2;
url_y1 = y1;
url_y2 = y2;
url_maxcol = x2;
url_draw = 1;
term.dirty[y1] = 1;
}
return (char *)url;
}
#endif // OSC7_OSC8_PATCH
#if REFLOW_PATCH #if REFLOW_PATCH
char * char *
detecturl(int col, int row, int draw) detecturl(int col, int row, int draw)
@ -96,19 +72,11 @@ detecturl(int col, int row, int draw)
int row_start = row, col_start = col; int row_start = row, col_start = col;
int minrow = tisaltscr() ? 0 : term.scr - term.histf; int minrow = tisaltscr() ? 0 : term.scr - term.histf;
int maxrow = tisaltscr() ? term.row - 1 : term.scr + term.row - 1; int maxrow = tisaltscr() ? term.row - 1 : term.scr + term.row - 1;
#if OSC7_OSC8_PATCH
char *link;
#endif // OSC7_OSC8_PATCH
/* clear previously underlined url */ /* clear previously underlined url */
if (draw) if (draw)
clearurl(); clearurl();
#if OSC7_OSC8_PATCH
if ((link = detecthyperlink(col, row, draw)))
return link;
#endif // OSC7_OSC8_PATCH
url_maxcol = 0; url_maxcol = 0;
line = TLINE(row); line = TLINE(row);
@ -175,9 +143,6 @@ char *
detecturl(int col, int row, int draw) detecturl(int col, int row, int draw)
{ {
static char url[2048]; static char url[2048];
#if OSC7_OSC8_PATCH
char *link;
#endif // OSC7_OSC8_PATCH
int x1, y1, x2, y2, wrapped; int x1, y1, x2, y2, wrapped;
int row_start = row; int row_start = row;
int col_start = col; int col_start = col;
@ -197,11 +162,6 @@ detecturl(int col, int row, int draw)
if (draw) if (draw)
clearurl(); clearurl();
#if OSC7_OSC8_PATCH
if ((link = detecthyperlink(col, row, draw)))
return link;
#endif // OSC7_OSC8_PATCH
if (!isvalidurlchar(TLINEURL(row)[col].u)) if (!isvalidurlchar(TLINEURL(row)[col].u))
return NULL; return NULL;

View File

@ -68,9 +68,6 @@ tclearglyph(Glyph *gp, int usecurattr)
#if KITTY_GRAPHICS_PATCH #if KITTY_GRAPHICS_PATCH
gp->kitty = 0; gp->kitty = 0;
#endif // KITTY_GRAPHICS_PATCH #endif // KITTY_GRAPHICS_PATCH
#if OSC7_OSC8_PATCH
gp->link = 0;
#endif // OSC7_OSC8_PATCH
} }
#if SIXEL_PATCH #if SIXEL_PATCH

View File

@ -357,14 +357,6 @@
*/ */
#define KITTY_GRAPHICS_PATCH 0 #define KITTY_GRAPHICS_PATCH 0
/* This patch adds support for OSC 7 (current working directory reporting) and
* OSC 8 (hyperlinks). Shells and programs can mark ranges of text as links to
* arbitrary URLs; with the openurlonclick patch these become clickable and
* take precedence over URL text detection. The working directory reported by
* the shell is stored in term.cwd for use by e.g. new window shortcuts.
*/
#define OSC7_OSC8_PATCH 0
/* This patch adds SIXEL graphics support for st. /* This patch adds SIXEL graphics support for st.
* Note that patch/sixel.c/sixel_hls.c come from mintty, licensed under GPL. * Note that patch/sixel.c/sixel_hls.c come from mintty, licensed under GPL.
* Known issues: * Known issues:

View File

@ -357,14 +357,6 @@
*/ */
#define KITTY_GRAPHICS_PATCH 1 #define KITTY_GRAPHICS_PATCH 1
/* This patch adds support for OSC 7 (current working directory reporting) and
* OSC 8 (hyperlinks). Shells and programs can mark ranges of text as links to
* arbitrary URLs; with the openurlonclick patch these become clickable and
* take precedence over URL text detection. The working directory reported by
* the shell is stored in term.cwd for use by e.g. new window shortcuts.
*/
#define OSC7_OSC8_PATCH 1
/* This patch adds SIXEL graphics support for st. /* This patch adds SIXEL graphics support for st.
* Note that patch/sixel.c/sixel_hls.c come from mintty, licensed under GPL. * Note that patch/sixel.c/sixel_hls.c come from mintty, licensed under GPL.
* Known issues: * Known issues:

383
st.c
View File

@ -117,7 +117,6 @@ enum escape_state {
#if SIXEL_PATCH #if SIXEL_PATCH
ESC_DCS =128, ESC_DCS =128,
#endif // SIXEL_PATCH #endif // SIXEL_PATCH
ESC_DCS_IGNORE =256, /* discarding an unknown DCS until ST */
}; };
typedef struct { typedef struct {
@ -144,7 +143,6 @@ typedef struct {
char buf[ESC_BUF_SIZ]; /* raw string */ char buf[ESC_BUF_SIZ]; /* raw string */
size_t len; /* raw string length */ size_t len; /* raw string length */
char priv; char priv;
char prefix; /* '>', '<' or '=' private prefix */
int arg[ESC_ARG_SIZ]; int arg[ESC_ARG_SIZ];
int narg; /* nb of args */ int narg; /* nb of args */
char mode[2]; char mode[2];
@ -228,7 +226,6 @@ static void tsetdirt(int, int);
static void tsetscroll(int, int); static void tsetscroll(int, int);
static void tswapscreen(void); static void tswapscreen(void);
static void tsetmode(int, int, const int *, int); static void tsetmode(int, int, const int *, int);
static int tmodestatus(int, int);
static int twrite(const char *, int, int); static int twrite(const char *, int, int);
static void tcontrolcode(uchar ); static void tcontrolcode(uchar );
static void tdectest(char ); static void tdectest(char );
@ -273,115 +270,6 @@ static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF
#include "patch/st_include.h" #include "patch/st_include.h"
#if OSC7_OSC8_PATCH
/*
* OSC 8 hyperlinks. Each distinct (id, url) pair gets a numeric handle that
* is stored in Glyph.link. Links with an explicit id= parameter are shared
* between all cells using that id, so a link split across lines still counts
* as one link.
*/
typedef struct {
char *id; /* the id= parameter, or NULL */
char *url;
} Hyperlink;
static Hyperlink *hyperlinks; /* index 0 is unused (0 == no link) */
static uint32_t nhyperlinks, hyperlinkcap;
static uint32_t curlink; /* link applied to newly printed cells */
static uint32_t
hyperlink_add(const char *id, const char *url)
{
uint32_t i;
Hyperlink *h;
if (!url || !*url)
return 0;
/* reuse an existing entry for the same id and url */
for (i = 1; i < nhyperlinks; i++) {
h = &hyperlinks[i];
if (!strcmp(h->url, url) &&
((!id && !h->id) || (id && h->id && !strcmp(id, h->id))))
return i;
}
if (nhyperlinks + 1 > hyperlinkcap) {
uint32_t ncap = hyperlinkcap ? hyperlinkcap * 2 : 64;
hyperlinks = xrealloc(hyperlinks, ncap * sizeof *hyperlinks);
if (!nhyperlinks) {
hyperlinks[0].id = hyperlinks[0].url = NULL;
nhyperlinks = 1;
}
hyperlinkcap = ncap;
}
h = &hyperlinks[nhyperlinks];
h->id = (id && *id) ? xstrdup(id) : NULL;
h->url = xstrdup(url);
return nhyperlinks++;
}
const char *
hyperlink_get(uint32_t id)
{
if (id == 0 || id >= nhyperlinks)
return NULL;
return hyperlinks[id].url;
}
/* handle "OSC 8 ; params ; url": params is a ':'-separated key=value list */
static void
hyperlink_osc(const char *params, const char *url)
{
char idbuf[256], *id = NULL;
const char *p = params;
while (p && *p) {
const char *end = strchr(p, ':');
size_t n = end ? (size_t)(end - p) : strlen(p);
if (n > 3 && !strncmp(p, "id=", 3)) {
n = MIN(n - 3, sizeof idbuf - 1);
memcpy(idbuf, p + 3, n);
idbuf[n] = '\0';
id = idbuf;
}
p = end ? end + 1 : NULL;
}
curlink = hyperlink_add(id, url);
}
/*
* Find the extent of the link at (col, row) on the visible screen. Returns
* the link handle, or 0 if the cell is not part of a link. The returned
* rectangle covers the contiguous run on this row; use hyperlink_get() for
* the url.
*/
uint32_t
hyperlink_at(int col, int row, int *x1, int *y1, int *x2, int *y2)
{
Line line;
uint32_t id;
int x;
if (row < 0 || row >= term.row || col < 0 || col >= term.col)
return 0;
#if REFLOW_PATCH || SCROLLBACK_PATCH
line = TLINE(row);
#else
line = term.line[row];
#endif
if (!(id = line[col].link))
return 0;
for (x = col; x > 0 && line[x-1].link == id; x--);
*x1 = x;
for (x = col; x < term.col-1 && line[x+1].link == id; x++);
*x2 = x;
*y1 = *y2 = row;
return id;
}
#endif // OSC7_OSC8_PATCH
ssize_t ssize_t
xwrite(int fd, const char *s, size_t len) xwrite(int fd, const char *s, size_t len)
{ {
@ -909,16 +797,6 @@ execsh(char *cmd, char **args)
unsetenv("COLUMNS"); unsetenv("COLUMNS");
unsetenv("LINES"); unsetenv("LINES");
unsetenv("TERMCAP"); unsetenv("TERMCAP");
/*
* A new st window is never inside a multiplexer, even when st itself
* was launched from one. Programs such as kitten icat use these to
* decide whether to wrap escape codes for tmux, which breaks them.
*/
unsetenv("TMUX");
unsetenv("TMUX_PANE");
unsetenv("STY");
unsetenv("ZELLIJ");
unsetenv("ZELLIJ_SESSION_NAME");
setenv("LOGNAME", pw->pw_name, 1); setenv("LOGNAME", pw->pw_name, 1);
setenv("USER", pw->pw_name, 1); setenv("USER", pw->pw_name, 1);
setenv("SHELL", sh, 1); setenv("SHELL", sh, 1);
@ -1326,9 +1204,6 @@ treset(void)
term.top = 0; term.top = 0;
term.bot = term.row - 1; term.bot = term.row - 1;
term.mode = MODE_WRAP|MODE_UTF8; term.mode = MODE_WRAP|MODE_UTF8;
#if OSC7_OSC8_PATCH
curlink = 0;
#endif // OSC7_OSC8_PATCH
memset(term.trantbl, CS_USA, sizeof(term.trantbl)); memset(term.trantbl, CS_USA, sizeof(term.trantbl));
term.charset = 0; term.charset = 0;
#if REFLOW_PATCH #if REFLOW_PATCH
@ -1633,13 +1508,9 @@ csiparse(void)
int sep = ';'; /* colon or semi-colon, but not both */ int sep = ';'; /* colon or semi-colon, but not both */
csiescseq.narg = 0; csiescseq.narg = 0;
csiescseq.prefix = '\0';
if (*p == '?') { if (*p == '?') {
csiescseq.priv = 1; csiescseq.priv = 1;
p++; p++;
} else if (*p == '>' || *p == '<' || *p == '=') {
csiescseq.prefix = *p;
p++;
} }
csiescseq.buf[csiescseq.len] = '\0'; csiescseq.buf[csiescseq.len] = '\0';
@ -1739,10 +1610,6 @@ tsetchar(Rune u, const Glyph *attr, int x, int y)
term.line[y][x].mode |= ATTR_BOXDRAW; term.line[y][x].mode |= ATTR_BOXDRAW;
#endif // BOXDRAW_PATCH #endif // BOXDRAW_PATCH
#if OSC7_OSC8_PATCH
term.line[y][x].link = curlink;
#endif // OSC7_OSC8_PATCH
#if KITTY_GRAPHICS_PATCH #if KITTY_GRAPHICS_PATCH
term.line[y][x].kitty = 0; term.line[y][x].kitty = 0;
if (u == KITTY_PLACEHOLDER) if (u == KITTY_PLACEHOLDER)
@ -2084,50 +1951,6 @@ tsetscroll(int t, int b)
term.bot = b; term.bot = b;
} }
/* DECRQM: report the state of a mode */
static int
tmodestatus(int priv, int mode)
{
int wm = win.mode;
if (priv) {
switch (mode) {
case 1: return (wm & MODE_APPCURSOR) ? 1 : 2;
case 6: return (term.c.state & CURSOR_ORIGIN) ? 1 : 2;
case 7: return IS_SET(MODE_WRAP) ? 1 : 2;
case 12: return 0;
case 25: return (wm & MODE_HIDE) ? 2 : 1;
case 47:
case 1047:
case 1049: return IS_SET(MODE_ALTSCREEN) ? 1 : 2;
case 9: return (wm & MODE_MOUSEX10) ? 1 : 2;
case 1000: return (wm & MODE_MOUSEBTN) ? 1 : 2;
case 1002: return (wm & MODE_MOUSEMOTION) ? 1 : 2;
case 1003: return (wm & MODE_MOUSEMANY) ? 1 : 2;
case 1004: return (wm & MODE_FOCUS) ? 1 : 2;
case 1006: return (wm & MODE_MOUSESGR) ? 1 : 2;
case 1034: return (wm & MODE_8BIT) ? 1 : 2;
case 2004: return (wm & MODE_BRCKTPASTE) ? 1 : 2;
#if SYNC_PATCH
case 2026: return su ? 1 : 2;
#endif // SYNC_PATCH
case 2031: return 4; /* theme change notifications: not supported */
#if SIXEL_PATCH
case 80: return IS_SET(MODE_SIXEL_SDM) ? 1 : 2;
case 8452: return IS_SET(MODE_SIXEL_CUR_RT) ? 1 : 2;
#endif // SIXEL_PATCH
}
return 0;
}
switch (mode) {
case 2: return 4; /* KAM, always reset */
case 4: return IS_SET(MODE_INSERT) ? 1 : 2;
case 12: return IS_SET(MODE_ECHO) ? 2 : 1;
case 20: return IS_SET(MODE_CRLF) ? 1 : 2;
}
return 0;
}
void void
tsetmode(int priv, int set, const int *args, int narg) tsetmode(int priv, int set, const int *args, int narg)
{ {
@ -2186,8 +2009,6 @@ tsetmode(int priv, int set, const int *args, int narg)
case 1004: /* 1004: send focus events to tty */ case 1004: /* 1004: send focus events to tty */
xsetmode(set, MODE_FOCUS); xsetmode(set, MODE_FOCUS);
break; break;
case 7727: /* 7727: extended keys (tmux/mintty), not supported */
break;
case 1006: /* 1006: extended reporting mode */ case 1006: /* 1006: extended reporting mode */
xsetmode(set, MODE_MOUSESGR); xsetmode(set, MODE_MOUSESGR);
break; break;
@ -2342,22 +2163,6 @@ csihandle(void)
} }
break; break;
case 'c': /* DA -- Device Attributes */ case 'c': /* DA -- Device Attributes */
if (csiescseq.prefix == '>') {
/*
* DA2 -- Secondary Device Attributes: CSI > Pp ; Pv ; Pc c
* Pp = 0 (VT100 class), Pv = firmware version, Pc = 0.
* tmux and others use this to fingerprint the terminal.
*/
if (csiescseq.arg[0] == 0)
ttywrite("\033[>0;95;0c", 10, 0);
break;
}
if (csiescseq.prefix == '=') {
/* DA3 -- Tertiary Device Attributes: unit id, all zeroes */
if (csiescseq.arg[0] == 0)
ttywrite("\033P!|00000000\033\\", 14, 0);
break;
}
if (csiescseq.arg[0] == 0) if (csiescseq.arg[0] == 0)
ttywrite(vtiden, strlen(vtiden), 0); ttywrite(vtiden, strlen(vtiden), 0);
break; break;
@ -2664,18 +2469,6 @@ csihandle(void)
term.c.y+1, term.c.x+1); term.c.y+1, term.c.x+1);
ttywrite(buffer, len, 0); ttywrite(buffer, len, 0);
break; break;
case 996: /* colour scheme (dark/light) report: CSI ? 997 ; Ps n */
if (csiescseq.priv) {
unsigned char r, g, b;
int dark = 1;
if (!xgetcolor(defaultbg, &r, &g, &b))
dark = (299*r + 587*g + 114*b) / 1000 < 128;
len = snprintf(buffer, sizeof(buffer), "\033[?997;%dn",
dark ? 1 : 2);
ttywrite(buffer, len, 0);
break;
}
goto unknown;
default: default:
goto unknown; goto unknown;
} }
@ -2742,47 +2535,9 @@ csihandle(void)
} }
break; break;
#endif // CSI_22_23_PATCH | SIXEL_PATCH #endif // CSI_22_23_PATCH | SIXEL_PATCH
case 'u': case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */
if (csiescseq.priv) {
/* CSI ? u -- kitty keyboard protocol: query flags. We do not
* implement the protocol, so answer with no flags set. */
ttywrite("\033[?0u", 5, 0);
break;
}
if (csiescseq.prefix == '>' || csiescseq.prefix == '<' ||
csiescseq.prefix == '=') {
/* CSI > flags u (push), CSI < flags u (pop), CSI = flags ; mode u
* (set): kitty keyboard protocol, silently ignored. */
break;
}
/* DECRC -- Restore cursor position (ANSI.SYS) */
tcursor(CURSOR_LOAD); tcursor(CURSOR_LOAD);
break; break;
case 'q':
if (csiescseq.prefix == '>') {
/* XTVERSION -- CSI > Ps q: report terminal name and version */
n = snprintf(buffer, sizeof(buffer), "\033P>|st(%s)\033\\", VERSION);
ttywrite(buffer, n, 0);
break;
}
goto unknown;
case '$':
switch (csiescseq.mode[1]) {
case 'p': /* DECRQM -- request mode */
/*
* Reply: CSI ? Pd ; Ps $ y (ANSI: CSI Pd ; Ps $ y)
* Ps: 0 not recognized, 1 set, 2 reset,
* 3 permanently set, 4 permanently reset
*/
n = snprintf(buffer, sizeof(buffer), "\033[%s%d;%d$y",
csiescseq.priv ? "?" : "", csiescseq.arg[0],
tmodestatus(csiescseq.priv, csiescseq.arg[0]));
ttywrite(buffer, n, 0);
break;
default:
goto unknown;
}
break;
case ' ': case ' ':
switch (csiescseq.mode[1]) { switch (csiescseq.mode[1]) {
case 'q': /* DECSCUSR -- Set Cursor Style */ case 'q': /* DECSCUSR -- Set Cursor Style */
@ -2913,7 +2668,7 @@ strhandle(void)
#endif // CSI_22_23_PATCH #endif // CSI_22_23_PATCH
return; return;
case 52: case 52:
if (narg > 2 && (allowwindowops || allowclipboard)) { if (narg > 2 && allowwindowops) {
dec = base64dec(strescseq.args[2]); dec = base64dec(strescseq.args[2]);
if (dec) { if (dec) {
xsetsel(dec); xsetsel(dec);
@ -2923,29 +2678,8 @@ strhandle(void)
} }
} }
return; return;
#if OSC7_OSC8_PATCH
case 7: /* current working directory: file://host/path */
if (narg > 1) {
p = strescseq.args[1];
if (!strncmp(p, "file://", 7)) {
/* skip the host part */
p += 7;
p = strchr(p, '/');
}
free(term.cwd);
term.cwd = (p && *p == '/') ? xstrdup(p) : NULL;
}
return;
case 8: /* hyperlink: OSC 8 ; params ; url */
if (narg > 2 && strescseq.args[2][0])
hyperlink_osc(strescseq.args[1], strescseq.args[2]);
else
curlink = 0;
return;
#else
case 8: /* Clear Hyperlinks */ case 8: /* Clear Hyperlinks */
return; return;
#endif // OSC7_OSC8_PATCH
case 10: case 10:
case 11: case 11:
case 12: case 12:
@ -3411,13 +3145,9 @@ dcshandle(void)
switch (csiescseq.mode[0]) { switch (csiescseq.mode[0]) {
default: default:
unknown: unknown:
/* fprintf(stderr, "erresc: unknown csi ");
* An unknown DCS, e.g. the "DCS tmux;" passthrough wrapper or csidump();
* XTGETTCAP. Its body must not be interpreted, so discard every /* die(""); */
* byte until the terminating ST. Note the body may contain ESC ESC
* (tmux doubles them), which must not end the string.
*/
term.esc |= ESC_DCS_IGNORE;
break; break;
#if SYNC_PATCH #if SYNC_PATCH
case '=': case '=':
@ -3587,23 +3317,6 @@ tputc(Rune u)
* receives a ESC, a SUB, a ST or any other C1 control * receives a ESC, a SUB, a ST or any other C1 control
* character. * character.
*/ */
if (term.esc & ESC_DCS_IGNORE) {
static int sawesc;
if (sawesc) {
sawesc = 0;
if (u == '\\') {
term.esc = 0;
return;
}
/* ESC ESC or ESC <other>: still inside the payload */
if (u != 033)
return;
}
if (u == 033)
sawesc = 1;
return;
}
if (term.esc & ESC_STR) { if (term.esc & ESC_STR) {
if (u == '\a' || u == 030 || u == 032 || u == 033 || if (u == '\a' || u == 030 || u == 032 || u == 033 ||
ISCONTROLC1(u)) { ISCONTROLC1(u)) {
@ -3770,84 +3483,6 @@ check_control_code:
} }
} }
/*
* Print a run of plain printable ASCII characters using the current cursor
* attributes, writing whole cells directly into the current line. Returns the
* number of bytes consumed, or 0 when the fast path does not apply and the
* caller must fall back to tputc().
*/
static int
tputcrun(const char *buf, int buflen)
{
Glyph attr = term.c.attr;
Glyph *gp;
int i, run, avail;
/* Only handle the simple, overwhelmingly common case. */
if (term.esc || (term.mode & (MODE_PRINT|MODE_INSERT|MODE_SIXEL)) ||
term.trantbl[term.charset] == CS_GRAPHIC0 ||
(term.c.state & CURSOR_WRAPNEXT) ||
sel.mode != SEL_IDLE || sel.ob.x != -1)
return 0;
avail = term.col - term.c.x;
if (avail <= 0)
return 0;
/* Count leading printable ASCII bytes, bounded by the line width. */
for (run = 0; run < buflen && run < avail; run++) {
unsigned char c = (unsigned char)buf[run];
if (c < 0x20 || c >= 0x7f)
break;
}
if (run < 2)
return 0; /* not worth it; keep tputc's semantics */
attr.mode |= ATTR_SET;
attr.mode &= ~(ATTR_WIDE|ATTR_WDUMMY|ATTR_BOXDRAW|ATTR_KITTYPH);
#if OSC7_OSC8_PATCH
attr.link = curlink;
#endif // OSC7_OSC8_PATCH
#if KITTY_GRAPHICS_PATCH
attr.kitty = 0;
#endif // KITTY_GRAPHICS_PATCH
gp = &term.line[term.c.y][term.c.x];
/* A wide glyph may straddle the start of the run. */
if (gp->mode & ATTR_WDUMMY) {
if (term.c.x == 0)
return 0;
gp[-1].u = ' ';
gp[-1].mode &= ~ATTR_WIDE;
}
/* ...or the end of it. */
if (run < avail && (gp[run].mode & ATTR_WDUMMY)) {
gp[run].u = ' ';
gp[run].mode &= ~ATTR_WDUMMY;
}
for (i = 0; i < run; i++) {
gp[i] = attr;
gp[i].u = (unsigned char)buf[i];
}
term.dirty[term.c.y] = 1;
term.lastc = (unsigned char)buf[run-1];
if (term.c.x + run < term.col) {
term.c.x += run;
} else {
term.c.x = term.col - 1;
#if REFLOW_PATCH
term.wrapcwidth[IS_SET(MODE_ALTSCREEN)] = 1;
#endif // REFLOW_PATCH
term.c.state |= CURSOR_WRAPNEXT;
}
return run;
}
int int
twrite(const char *buf, int buflen, int show_ctrl) twrite(const char *buf, int buflen, int show_ctrl)
{ {
@ -3861,14 +3496,6 @@ twrite(const char *buf, int buflen, int show_ctrl)
#endif // SYNC_PATCH #endif // SYNC_PATCH
for (n = 0; n < buflen; n += charsize) { for (n = 0; n < buflen; n += charsize) {
/*
* Fast path: a run of plain printable ASCII printed with the
* current attributes onto the current line. This skips the
* per-character tputc/tsetchar dispatch, which dominates the
* profile while streaming large amounts of text.
*/
if (!show_ctrl && (charsize = tputcrun(buf + n, buflen - n)) > 0)
continue;
#if SIXEL_PATCH #if SIXEL_PATCH
if (IS_SET(MODE_SIXEL) && sixel_st.state != PS_ESC) { if (IS_SET(MODE_SIXEL) && sixel_st.state != PS_ESC) {
charsize = sixel_parser_parse(&sixel_st, (const unsigned char*)buf + n, buflen - n); charsize = sixel_parser_parse(&sixel_st, (const unsigned char*)buf + n, buflen - n);

12
st.h
View File

@ -150,9 +150,6 @@ typedef struct {
#if KITTY_GRAPHICS_PATCH #if KITTY_GRAPHICS_PATCH
uint32_t kitty; /* kitty Unicode placeholder row/column/msb */ uint32_t kitty; /* kitty Unicode placeholder row/column/msb */
#endif // KITTY_GRAPHICS_PATCH #endif // KITTY_GRAPHICS_PATCH
#if OSC7_OSC8_PATCH
uint32_t link; /* OSC 8 hyperlink id, 0 == none */
#endif // OSC7_OSC8_PATCH
} Glyph; } Glyph;
typedef Glyph *Line; typedef Glyph *Line;
@ -211,9 +208,6 @@ 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_OSC8_PATCH
char *cwd; /* working directory reported via OSC 7, or NULL */
#endif // OSC7_OSC8_PATCH
} Term; } Term;
typedef union { typedef union {
@ -382,11 +376,6 @@ char *getsel(void);
size_t utf8encode(Rune, char *); size_t utf8encode(Rune, char *);
#if OSC7_OSC8_PATCH
const char *hyperlink_get(uint32_t id);
uint32_t hyperlink_at(int col, int row, int *x1, int *y1, int *x2, int *y2);
#endif // OSC7_OSC8_PATCH
void *xmalloc(size_t); void *xmalloc(size_t);
void *xrealloc(void *, size_t); void *xrealloc(void *, size_t);
char *xstrdup(const char *); char *xstrdup(const char *);
@ -415,7 +404,6 @@ extern wchar_t *kbds_ldelim;
#endif // KEYBOARDSELECT_PATCH #endif // KEYBOARDSELECT_PATCH
extern int allowaltscreen; extern int allowaltscreen;
extern int allowwindowops; extern int allowwindowops;
extern int allowclipboard;
extern char *termname; extern char *termname;
extern unsigned int tabspaces; extern unsigned int tabspaces;
extern unsigned int defaultfg; extern unsigned int defaultfg;

View File

@ -199,20 +199,11 @@ st-mono| simpleterm monocolor,
# rep=%p1%c\E[%p2%{1}%-%db, # rep=%p1%c\E[%p2%{1}%-%db,
# tmux extensions, see TERMINFO EXTENSIONS in tmux(1) # tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
Tc, Tc,
RGB,
Ms=\E]52;%p1%s;%p2%s\007, Ms=\E]52;%p1%s;%p2%s\007,
Se=\E[2 q, Se=\E[2 q,
Ss=\E[%p1%d q, Ss=\E[%p1%d q,
# sync patch / SYNC_PATCH # sync patch / SYNC_PATCH
Sync=\EP=%p1%ds\E\\, Sync=\EP=%p1%ds\E\\,
# undercurl patch / UNDERCURL_PATCH: styled and coloured underlines
Smulx=\E[4:%p1%dm,
Setulc=\E[58:2::%p1%{65536}%/%d:%p1%{256}%/%{255}%&%d:%p1%{255}%&%dm,
# focus events (mode 1004), used by tmux focus-events
kxIN=\E[I,
kxOUT=\E[O,
# hyperlinks / OSC7_OSC8_PATCH
Hls=\E]8;id=%p1%s;%p2%s\E\\,
st| simpleterm, st| simpleterm,
use=st-mono, use=st-mono,